TrinityCore
ConditionMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ConditionMgr.h"
19#include "AchievementMgr.h"
20#include "AreaTrigger.h"
22#include "BattlePetMgr.h"
23#include "BattlegroundScript.h"
24#include "Containers.h"
26#include "DB2Stores.h"
27#include "DatabaseEnv.h"
28#include "GameEventMgr.h"
29#include "GameObject.h"
30#include "GameTime.h"
31#include "Group.h"
32#include "InstanceScenario.h"
33#include "InstanceScript.h"
34#include "Item.h"
35#include "LFGMgr.h"
36#include "LanguageMgr.h"
37#include "Log.h"
38#include "LootMgr.h"
39#include "Map.h"
40#include "ObjectAccessor.h"
41#include "ObjectMgr.h"
42#include "Pet.h"
43#include "PhasingHandler.h"
44#include "Player.h"
45#include "RaceMask.h"
46#include "RealmList.h"
47#include "ReputationMgr.h"
48#include "ScriptMgr.h"
49#include "Spell.h"
50#include "SpellAuraEffects.h"
51#include "SpellAuras.h"
52#include "SpellMgr.h"
53#include "World.h"
54#include "WorldSession.h"
55#include "WorldStateMgr.h"
56#include "WowTime.h"
57#include <random>
58#include <sstream>
59
61{
62 "None",
63 "Creature Loot",
64 "Disenchant Loot",
65 "Fishing Loot",
66 "GameObject Loot",
67 "Item Loot",
68 "Mail Loot",
69 "Milling Loot",
70 "Pickpocketing Loot",
71 "Prospecting Loot",
72 "Reference Loot",
73 "Skinning Loot",
74 "Spell Loot",
75 "Spell Impl. Target",
76 "Gossip Menu",
77 "Gossip Menu Option",
78 "Creature Vehicle",
79 "Spell Expl. Target",
80 "Spell Click Event",
81 "Quest Available",
82 "Unused",
83 "Vehicle Spell",
84 "SmartScript",
85 "Npc Vendor",
86 "Spell Proc",
87 "Terrain Swap",
88 "Phase",
89 "Graveyard",
90 "AreaTrigger",
91 "ConversationLine",
92 "AreaTrigger Client Triggered",
93 "Trainer Spell",
94 "Object Visibility (by ID)",
95 "Spawn Group",
96 "Player Condition"
97};
98
100{
101 { .Name = "None", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
102 { .Name = "Aura", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
103 { .Name = "Item Stored", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
104 { .Name = "Item Equipped", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
105 { .Name = "Zone", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
106 { .Name = "Reputation", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
107 { .Name = "Team", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
108 { .Name = "Skill", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
109 { .Name = "Quest Rewarded", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
110 { .Name = "Quest Taken", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
111 { .Name = "Drunken", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
112 { .Name = "WorldState", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
113 { .Name = "Active Event", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
114 { .Name = "Instance Info", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
115 { .Name = "Quest None", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
116 { .Name = "Class", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
117 { .Name = "Race", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
118 { .Name = "Achievement", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
119 { .Name = "Title", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
120 { .Name = "SpawnMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
121 { .Name = "Gender", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
122 { .Name = "Unit State", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
123 { .Name = "Map", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
124 { .Name = "Area", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
125 { .Name = "CreatureType", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
126 { .Name = "Spell Known", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
127 { .Name = "Phase", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
128 { .Name = "Level", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
129 { .Name = "Quest Completed", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
130 { .Name = "Near Creature", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
131 { .Name = "Near GameObject", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
132 { .Name = "Object Entry or Guid", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
133 { .Name = "Object TypeMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
134 { .Name = "Relation", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
135 { .Name = "Reaction", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
136 { .Name = "Distance", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
137 { .Name = "Alive", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
138 { .Name = "Health Value", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
139 { .Name = "Health Pct", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
140 { .Name = "Realm Achievement", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
141 { .Name = "In Water", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
142 { .Name = "Terrain Swap", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
143 { .Name = "Sit/stand state", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
144 { .Name = "Daily Quest Completed", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
145 { .Name = "Charmed", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
146 { .Name = "Pet type", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
147 { .Name = "On Taxi", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
148 { .Name = "Quest state mask", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
149 { .Name = "Quest objective progress", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
150 { .Name = "Map Difficulty", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
151 { .Name = "Is Gamemaster", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
152 { .Name = "Object Entry or Guid", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
153 { .Name = "Object TypeMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
154 { .Name = "BattlePet Species Learned", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
155 { .Name = "On Scenario Step", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
156 { .Name = "Scene In Progress", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
157 { .Name = "Player Condition", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
158 { .Name = "Private Object", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
159 { .Name = "String ID", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = true },
160 { .Name = "Label", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
161};
162
164{
165 mConditionTargets[0] = target0;
166 mConditionTargets[1] = target1;
167 mConditionTargets[2] = target2;
168 if (target0)
169 mConditionMap = target0->GetMap();
170 else if (target1)
171 mConditionMap = target1->GetMap();
172 else if (target2)
173 mConditionMap = target2->GetMap();
174 else
175 mConditionMap = nullptr;
176 mLastFailedCondition = nullptr;
177}
178
180{
181 std::fill(std::begin(mConditionTargets), std::end(mConditionTargets), nullptr);
182 mConditionMap = map;
183 mLastFailedCondition = nullptr;
184}
185
186std::size_t ConditionId::GetHash() const
187{
188 std::size_t hashVal = 0;
192 return hashVal;
193}
194
195// Checks if object meets the condition
196// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI)
198{
200
201 Map const* map = sourceInfo.mConditionMap;
202 bool condMeets = false;
203 bool needsObject = false;
204 switch (ConditionType)
205 {
206 case CONDITION_NONE:
207 condMeets = true; // empty condition, always met
208 break;
210 condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1);
211 break;
213 {
214 if (InstanceMap const* instanceMap = map->ToInstanceMap())
215 {
216 if (InstanceScript const* instance = instanceMap->GetInstanceScript())
217 {
218 switch (ConditionValue3)
219 {
221 condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
222 break;
224 condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
225 break;
227 condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
228 break;
229 default:
230 condMeets = false;
231 break;
232 }
233 }
234 }
235 else if (BattlegroundMap const* bgMap = map->ToBattlegroundMap())
236 {
237 ZoneScript const* zoneScript = bgMap->GetBattlegroundScript();
238 switch (ConditionValue3)
239 {
241 condMeets = zoneScript->GetData(ConditionValue1) == ConditionValue2;
242 break;
244 condMeets = zoneScript->GetData64(ConditionValue1) == ConditionValue2;
245 break;
246 default:
247 condMeets = false;
248 break;
249 }
250 }
251 break;
252 }
253 case CONDITION_MAPID:
254 condMeets = map->GetId() == ConditionValue1;
255 break;
257 {
258 condMeets = sWorldStateMgr->GetValue(ConditionValue1, map) == int32(ConditionValue2);
259 break;
260 }
262 {
263 AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
264 if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
265 condMeets = true;
266 break;
267 }
269 {
270 condMeets = map->GetDifficultyID() == ConditionValue1;
271 break;
272 }
274 {
275 if (InstanceMap const* instanceMap = map->ToInstanceMap())
276 if (Scenario const* scenario = instanceMap->GetInstanceScenario())
277 if (ScenarioStepEntry const* step = scenario->GetStep())
278 condMeets = step->ID == ConditionValue1;
279 break;
280 }
281 default:
282 needsObject = true;
283 break;
284 }
285
286 WorldObject const* object = sourceInfo.mConditionTargets[ConditionTarget];
287 // object not present, return false
288 if (needsObject && !object)
289 {
290 TC_LOG_DEBUG("condition", "Condition object not found for {}", ToString());
291 return false;
292 }
293 switch (ConditionType)
294 {
295 case CONDITION_AURA:
296 {
297 if (Unit const* unit = object->ToUnit())
298 condMeets = unit->HasAuraEffect(ConditionValue1, ConditionValue2);
299 break;
300 }
301 case CONDITION_ITEM:
302 {
303 if (Player const* player = object->ToPlayer())
304 {
305 // don't allow 0 items (it's checked during table load)
307 bool checkBank = ConditionValue3 ? true : false;
308 condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
309 }
310 break;
311 }
313 {
314 if (Player const* player = object->ToPlayer())
315 condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1);
316 break;
317 }
318 case CONDITION_ZONEID:
319 condMeets = object->GetZoneId() == ConditionValue1;
320 break;
322 {
323 if (Player const* player = object->ToPlayer())
324 {
325 if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1))
326 condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))) != 0;
327 }
328 break;
329 }
331 {
332 if (Player const* player = object->ToPlayer())
333 condMeets = player->HasAchieved(ConditionValue1);
334 break;
335 }
336 case CONDITION_TEAM:
337 {
338 if (Player const* player = object->ToPlayer())
339 condMeets = player->GetTeam() == Team(ConditionValue1);
340 break;
341 }
342 case CONDITION_CLASS:
343 {
344 if (Unit const* unit = object->ToUnit())
345 condMeets = (unit->GetClassMask() & ConditionValue1) != 0;
346 break;
347 }
348 case CONDITION_RACE:
349 {
350 if (Unit const* unit = object->ToUnit())
351 condMeets = Trinity::RaceMask<uint32>{ ConditionValue1 }.HasRace(unit->GetRace());
352 break;
353 }
354 case CONDITION_GENDER:
355 {
356 if (Player const* player = object->ToPlayer())
357 condMeets = player->GetNativeGender() == Gender(ConditionValue1);
358 break;
359 }
360 case CONDITION_SKILL:
361 {
362 if (Player const* player = object->ToPlayer())
363 condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2;
364 break;
365 }
367 {
368 if (Player const* player = object->ToPlayer())
369 condMeets = player->GetQuestRewardStatus(ConditionValue1);
370 break;
371 }
373 {
374 if (Player const* player = object->ToPlayer())
375 {
376 QuestStatus status = player->GetQuestStatus(ConditionValue1);
377 condMeets = (status == QUEST_STATUS_INCOMPLETE);
378 }
379 break;
380 }
382 {
383 if (Player const* player = object->ToPlayer())
384 {
385 QuestStatus status = player->GetQuestStatus(ConditionValue1);
386 condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1));
387 }
388 break;
389 }
391 {
392 if (Player const* player = object->ToPlayer())
393 {
394 QuestStatus status = player->GetQuestStatus(ConditionValue1);
395 condMeets = (status == QUEST_STATUS_NONE);
396 }
397 break;
398 }
399 case CONDITION_AREAID:
400 condMeets = DB2Manager::IsInArea(object->GetAreaId(), ConditionValue1);
401 break;
402 case CONDITION_SPELL:
403 {
404 if (Player const* player = object->ToPlayer())
405 condMeets = player->HasSpell(ConditionValue1);
406 break;
407 }
408 case CONDITION_LEVEL:
409 {
410 if (Unit const* unit = object->ToUnit())
411 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), static_cast<uint32>(unit->GetLevel()), ConditionValue1);
412 break;
413 }
415 {
416 if (Player const* player = object->ToPlayer())
417 condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1;
418 break;
419 }
421 {
422 condMeets = object->FindNearestCreature(ConditionValue1, (float)ConditionValue2, bool(!ConditionValue3)) != nullptr;
423 break;
424 }
426 {
427 condMeets = object->FindNearestGameObject(ConditionValue1, (float)ConditionValue2) != nullptr;
428 break;
429 }
431 {
432 if (uint32(object->GetTypeId()) == ConditionValue1)
433 {
434 condMeets = !ConditionValue2 || (object->GetEntry() == ConditionValue2);
435
436 if (ConditionValue3)
437 {
438 switch (object->GetTypeId())
439 {
440 case TYPEID_UNIT:
441 condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3;
442 break;
444 condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3;
445 break;
446 default:
447 break;
448 }
449 }
450 }
451 break;
452 }
454 {
455 condMeets = object->isType(ConditionValue1);
456 break;
457 }
459 {
460 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
461 {
462 Unit const* toUnit = toObject->ToUnit();
463 Unit const* unit = object->ToUnit();
464 if (toUnit && unit)
465 {
466 switch (static_cast<RelationType>(ConditionValue2))
467 {
468 case RELATION_SELF:
469 condMeets = unit == toUnit;
470 break;
472 condMeets = unit->IsInPartyWith(toUnit);
473 break;
475 condMeets = unit->IsInRaidWith(toUnit);
476 break;
478 condMeets = unit->GetOwnerGUID() == toUnit->GetGUID();
479 break;
481 condMeets = unit->IsOnVehicle(toUnit);
482 break;
484 condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
485 break;
486 default:
487 break;
488 }
489 }
490 }
491 break;
492 }
494 {
495 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
496 {
497 Unit const* toUnit = toObject->ToUnit();
498 Unit const* unit = object->ToUnit();
499 if (toUnit && unit)
500 condMeets = ((1 << unit->GetReactionTo(toUnit)) & ConditionValue2) != 0;
501 }
502 break;
503 }
505 {
506 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
507 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3), object->GetDistance(toObject), static_cast<float>(ConditionValue2));
508 break;
509 }
510 case CONDITION_ALIVE:
511 {
512 if (Unit const* unit = object->ToUnit())
513 condMeets = unit->IsAlive();
514 break;
515 }
516 case CONDITION_HP_VAL:
517 {
518 if (Unit const* unit = object->ToUnit())
519 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealth(), static_cast<uint64>(ConditionValue1));
520 break;
521 }
522 case CONDITION_HP_PCT:
523 {
524 if (Unit const* unit = object->ToUnit())
525 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealthPct(), static_cast<float>(ConditionValue1));
526 break;
527 }
529 {
530 condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
531 break;
532 }
533 case CONDITION_TITLE:
534 {
535 if (Player const* player = object->ToPlayer())
536 condMeets = player->HasTitle(ConditionValue1);
537 break;
538 }
540 {
541 if (Unit const* unit = object->ToUnit())
542 condMeets = unit->HasUnitState(ConditionValue1);
543 break;
544 }
546 {
547 if (Creature const* creature = object->ToCreature())
548 condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
549 break;
550 }
552 {
553 if (Unit const* unit = object->ToUnit())
554 condMeets = unit->IsInWater();
555 break;
556 }
558 {
559 condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1);
560 break;
561 }
563 {
564 if (Unit const* unit = object->ToUnit())
565 {
566 if (ConditionValue1 == 0)
567 condMeets = (unit->GetStandState() == UnitStandStateType(ConditionValue2));
568 else if (ConditionValue2 == 0)
569 condMeets = unit->IsStandState();
570 else if (ConditionValue2 == 1)
571 condMeets = unit->IsSitState();
572 }
573 break;
574 }
576 {
577 if (Player const* player = object->ToPlayer())
578 condMeets = player->IsDailyQuestDone(ConditionValue1);
579 break;
580 }
582 {
583 if (Unit const* unit = object->ToUnit())
584 condMeets = unit->IsCharmed();
585 break;
586 }
588 {
589 if (Player const* player = object->ToPlayer())
590 if (Pet const* pet = player->GetPet())
591 condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0);
592 break;
593 }
594 case CONDITION_TAXI:
595 {
596 if (Player const* player = object->ToPlayer())
597 condMeets = player->IsInFlight();
598 break;
599 }
601 {
602 if (Player const* player = object->ToPlayer())
603 {
604 if (
605 ((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_NONE)) ||
606 ((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_COMPLETE)) ||
607 ((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_INCOMPLETE)) ||
608 ((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_FAILED)) ||
609 ((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1))
610 )
611 condMeets = true;
612 }
613 break;
614 }
616 {
617 if (Player const* player = object->ToPlayer())
618 {
619 QuestObjective const* obj = sObjectMgr->GetQuestObjective(ConditionValue1);
620 if (!obj)
621 break;
622
623 Quest const* quest = sObjectMgr->GetQuestTemplate(obj->QuestID);
624 if (!quest)
625 break;
626
627 uint16 slot = player->FindQuestSlot(obj->QuestID);
628 if (slot >= MAX_QUEST_LOG_SIZE)
629 break;
630
631 condMeets = player->GetQuestSlotObjectiveData(slot, *obj) == int32(ConditionValue3);
632 }
633 break;
634 }
636 {
637 if (Player const* player = object->ToPlayer())
638 {
639 if (ConditionValue1 == 1)
640 condMeets = player->CanBeGameMaster();
641 else
642 condMeets = player->IsGameMaster();
643 }
644 break;
645 }
647 {
648 if (Player const* player = object->ToPlayer())
649 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3),
650 player->GetSession()->GetBattlePetMgr()->GetPetCount(sBattlePetSpeciesStore.AssertEntry(ConditionValue1), player->GetGUID()),
651 static_cast<uint8>(ConditionValue2));
652 break;
653 }
655 {
656 if (Player const* player = object->ToPlayer())
657 condMeets = player->GetSceneMgr().GetActiveSceneCount(ConditionValue1) > 0;
658 break;
659 }
661 {
662 if (Player const* player = object->ToPlayer())
664 break;
665 }
667 {
668 condMeets = !object->GetPrivateObjectOwner().IsEmpty();
669 break;
670 }
672 {
673 if (Creature const* creature = object->ToCreature())
674 condMeets = creature->HasStringId(ConditionStringValue1);
675 else if (GameObject const* go = object->ToGameObject())
676 condMeets = go->HasStringId(ConditionStringValue1);
677 break;
678 }
679 case CONDITION_LABEL:
680 {
681 if (Creature const* creature = object->ToCreature())
682 condMeets = creature->HasLabel(ConditionValue1);
683 else if (GameObject const* go = object->ToGameObject())
684 condMeets = go->HasLabel(ConditionValue1);
685 break;
686 }
687 default:
688 break;
689 }
690
692 condMeets = !condMeets;
693
694 if (!condMeets)
695 sourceInfo.mLastFailedCondition = this;
696
697 return condMeets && sScriptMgr->OnConditionCheck(this, sourceInfo); // Returns true by default.;
698}
699
701{
702 // build mask of types for which condition can return true
703 // this is used for speeding up gridsearches
705 return (GRID_MAP_TYPE_MASK_ALL);
706 uint32 mask = 0;
707 switch (ConditionType)
708 {
709 case CONDITION_NONE:
711 break;
712 case CONDITION_AURA:
714 break;
715 case CONDITION_ITEM:
717 break;
720 break;
721 case CONDITION_ZONEID:
723 break;
726 break;
729 break;
730 case CONDITION_TEAM:
732 break;
733 case CONDITION_CLASS:
735 break;
736 case CONDITION_RACE:
738 break;
739 case CONDITION_SKILL:
741 break;
744 break;
747 break;
750 break;
753 break;
756 break;
759 break;
760 case CONDITION_MAPID:
762 break;
763 case CONDITION_AREAID:
765 break;
766 case CONDITION_SPELL:
768 break;
769 case CONDITION_LEVEL:
771 break;
774 break;
777 break;
780 break;
782 switch (ConditionValue1)
783 {
784 case TYPEID_UNIT:
786 break;
787 case TYPEID_PLAYER:
789 break;
792 break;
793 case TYPEID_CORPSE:
795 break;
798 break;
799 default:
800 break;
801 }
802 break;
814 break;
817 break;
820 break;
823 break;
824 case CONDITION_ALIVE:
826 break;
827 case CONDITION_HP_VAL:
829 break;
830 case CONDITION_HP_PCT:
832 break;
835 break;
838 break;
839 case CONDITION_TITLE:
841 break;
842 case CONDITION_GENDER:
844 break;
847 break;
850 break;
853 break;
856 break;
859 break;
862 break;
865 break;
868 break;
871 break;
872 case CONDITION_TAXI:
874 break;
877 break;
880 break;
883 break;
886 break;
889 break;
892 break;
895 break;
898 break;
900 mask |= GRID_MAP_TYPE_MASK_ALL & ~GRID_MAP_TYPE_MASK_PLAYER;
901 break;
904 break;
905 case CONDITION_LABEL:
907 break;
908 default:
909 ABORT_MSG("Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
910 break;
911 }
912 return mask;
913}
914
916{
917 // returns number of targets which are available for given source type
918 switch (SourceType)
919 {
931 return 2;
932 default:
933 return 1;
934 }
935}
936
937std::string Condition::ToString(bool ext /*= false*/) const
938{
939 std::ostringstream ss;
940 ss << "[Condition ";
941 ss << "SourceType: " << SourceType;
945 ss << " (Reference)";
946 else
947 ss << " (Unknown)";
949 ss << ", SourceGroup: " << SourceGroup;
950 ss << ", SourceEntry: " << SourceEntry;
952 ss << ", SourceId: " << SourceId;
953
954 if (ext)
955 {
956 ss << ", ConditionType: " << ConditionType;
959 else
960 ss << " (Unknown)";
961 }
962
963 ss << "]";
964 return ss.str();
965}
966
968
970{
971 Clean();
972}
973
975{
976 if (conditions.empty())
978 // groupId, typeMask
979 std::map<uint32, uint32> elseGroupSearcherTypeMasks;
980 for (ConditionContainer::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
981 {
982 // no point of having not loaded conditions in list
983 ASSERT(i->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
984 std::map<uint32, uint32>::const_iterator itr = elseGroupSearcherTypeMasks.find(i->ElseGroup);
985 // group not filled yet, fill with widest mask possible
986 if (itr == elseGroupSearcherTypeMasks.end())
987 elseGroupSearcherTypeMasks[i->ElseGroup] = GRID_MAP_TYPE_MASK_ALL;
988 // no point of checking anymore, empty mask
989 else if (!itr->second)
990 continue;
991
992 if (i->ReferenceId) // handle reference
993 {
994 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ i->ReferenceId, 0, 0 });
995 ASSERT(ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
996 elseGroupSearcherTypeMasks[i->ElseGroup] &= GetSearcherTypeMaskForConditionList(*(ref->second));
997 }
998 else // handle normal condition
999 {
1000 // object will match conditions in one ElseGroupStore only when it matches all of them
1001 // so, let's find a smallest possible mask which satisfies all conditions
1002 elseGroupSearcherTypeMasks[i->ElseGroup] &= i->GetSearcherTypeMaskForCondition();
1003 }
1004 }
1005 // object will match condition when one of the checks in ElseGroupStore is matching
1006 // so, let's include all possible masks
1007 uint32 mask = 0;
1008 for (std::map<uint32, uint32>::const_iterator i = elseGroupSearcherTypeMasks.begin(); i != elseGroupSearcherTypeMasks.end(); ++i)
1009 mask |= i->second;
1010
1011 return mask;
1012}
1013
1015{
1016 // groupId, groupCheckPassed
1017 std::map<uint32, bool> elseGroupStore;
1018 for (Condition const& condition : conditions)
1019 {
1020 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition.ToString(), condition.ConditionValue1);
1021 if (condition.isLoaded())
1022 {
1024 std::map<uint32, bool>::iterator itr = elseGroupStore.try_emplace(condition.ElseGroup, true).first;
1025 if (!itr->second)
1026 continue;
1027
1028 if (condition.ReferenceId)//handle reference
1029 {
1030 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1032 {
1033 bool condMeets = IsObjectMeetToConditionList(sourceInfo, *ref->second);
1034 if (condition.NegativeCondition)
1035 condMeets = !condMeets;
1036
1037 if (!condMeets)
1038 itr->second = false;
1039 }
1040 else
1041 {
1042 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} Reference template -{} not found",
1043 condition.ToString(), condition.ReferenceId); // checked at loading, should never happen
1044 }
1045
1046 }
1047 else //handle normal condition
1048 {
1049 if (!condition.Meets(sourceInfo))
1050 itr->second = false;
1051 }
1052 }
1053 }
1054 for (std::map<uint32, bool>::const_iterator i = elseGroupStore.begin(); i != elseGroupStore.end(); ++i)
1055 if (i->second)
1056 return true;
1057
1058 return false;
1059}
1060
1062{
1063 ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
1064 return IsObjectMeetToConditions(srcInfo, conditions);
1065}
1066
1067bool ConditionMgr::IsObjectMeetToConditions(WorldObject const* object1, WorldObject const* object2, ConditionContainer const& conditions) const
1068{
1069 ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2);
1070 return IsObjectMeetToConditions(srcInfo, conditions);
1071}
1072
1074{
1075 if (conditions.empty())
1076 return true;
1077
1078 TC_LOG_DEBUG("condition", "ConditionMgr::IsObjectMeetToConditions");
1079 return IsObjectMeetToConditionList(sourceInfo, conditions);
1080}
1081
1083{
1084 return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
1096 sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
1101 sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT ||
1102 sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR ||
1103 sourceType == CONDITION_SOURCE_TYPE_PHASE ||
1104 sourceType == CONDITION_SOURCE_TYPE_GRAVEYARD ||
1105 sourceType == CONDITION_SOURCE_TYPE_AREATRIGGER ||
1109}
1110
1112{
1113 return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
1114}
1115
1117{
1118 switch (sourceType)
1119 {
1121 switch (conditionType)
1122 {
1123 case CONDITION_NONE:
1126 case CONDITION_MAPID:
1131 return true;
1132 default:
1133 return false;
1134 }
1135 break;
1136 default:
1137 break;
1138 }
1139 return true;
1140}
1141
1143{
1144 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1145 {
1146 auto i = ConditionStore[sourceType].find({ 0, int32(entry), 0 });
1147 if (i != ConditionStore[sourceType].end())
1148 {
1149 TC_LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type {} and entry {}", uint32(sourceType), entry);
1150 return IsObjectMeetToConditions(sourceInfo, *i->second);
1151 }
1152 }
1153
1154 return true;
1155}
1156
1157bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, WorldObject const* target0, WorldObject const* target1 /*= nullptr*/, WorldObject const* target2 /*= nullptr*/) const
1158{
1159 ConditionSourceInfo conditionSource(target0, target1, target2);
1160 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1161}
1162
1164{
1165 ConditionSourceInfo conditionSource(map);
1166 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1167}
1168
1170{
1171 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1172 return ConditionStore[sourceType].contains({ 0, int32(entry), 0 });
1173
1174 return false;
1175}
1176
1177bool ConditionMgr::IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const
1178{
1179 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1181 {
1182 TC_LOG_DEBUG("condition", "IsObjectMeetingSpellClickConditions: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1183 ConditionSourceInfo sourceInfo(clicker, target);
1184 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1185 }
1186 return true;
1187}
1188
1190{
1191 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1193 {
1194 TC_LOG_DEBUG("condition", "HasConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1195 return true;
1196 }
1197 return false;
1198}
1199
1200bool ConditionMgr::IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const
1201{
1202 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].find({ creatureId, int32(spellId), 0 });
1204 {
1205 TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId);
1206 ConditionSourceInfo sourceInfo(player, vehicle);
1207 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1208 }
1209 return true;
1210}
1211
1212bool ConditionMgr::IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const
1213{
1214 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].find({ eventId + 1, int32(entryOrGuid), sourceType });
1216 {
1217 TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId);
1218 ConditionSourceInfo sourceInfo(unit, baseObject);
1219 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1220 }
1221 return true;
1222}
1223
1224bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const
1225{
1226 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ creatureId, int32(itemId), 0 });
1228 {
1229 TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId);
1230 ConditionSourceInfo sourceInfo(player, vendor);
1231 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1232 }
1233 return true;
1234}
1235
1237{
1239}
1240
1241ConditionContainer const* ConditionMgr::GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const
1242{
1243 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].find({ areaTriggerId, isServerSide ? 1 : 0, 0 });
1245 return itr->second.get();
1246 return nullptr;
1247}
1248
1250{
1251 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ trainerId, int32(spellId), 0 });
1253 {
1254 TC_LOG_DEBUG("condition", "IsObjectMeetingTrainerSpellConditions: found conditions for trainer id {} spell {}", trainerId, spellId);
1255 return IsObjectMeetToConditions(player, *itr->second);
1256 }
1257 return true;
1258}
1259
1261{
1264 {
1265 TC_LOG_DEBUG("condition", "IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {} entry {} guid {}", obj->GetTypeId(), obj->GetEntry(), obj->GetGUID().ToString());
1266 return IsObjectMeetToConditions(seer, obj, *itr->second);
1267 }
1268 return true;
1269}
1270
1272{
1273 static ConditionMgr instance;
1274 return &instance;
1275}
1276
1278{
1279 uint32 oldMSTime = getMSTime();
1280
1281 Clean();
1282
1283 //must clear all custom handled cases (groupped types) before reload
1284 if (isReload)
1285 {
1286 sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
1287
1288 sObjectMgr->UnloadPhaseConditions();
1289 }
1290
1291 QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
1292 "ConditionValue1, ConditionValue2, ConditionValue3, ConditionStringValue1, "
1293 "NegativeCondition, ErrorType, ErrorTextId, ScriptName FROM conditions");
1294
1295 if (!result)
1296 {
1297 TC_LOG_INFO("server.loading", ">> Loaded 0 conditions. DB table `conditions` is empty!");
1298 return;
1299 }
1300
1301 uint32 count = 0;
1302
1303 auto getOrInitConditions = [this](ConditionSourceType sourceType, ConditionId const& id)
1304 {
1305 auto [itr, inserted] = ConditionStore[sourceType].try_emplace(id, nullptr);
1306 if (inserted)
1307 itr->second = std::make_shared<std::vector<Condition>>();
1308 return itr->second;
1309 };
1310
1311 do
1312 {
1313 Field* fields = result->Fetch();
1314
1315 Condition cond;
1316 int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
1317 cond.SourceGroup = fields[1].GetUInt32();
1318 cond.SourceEntry = fields[2].GetInt32();
1319 cond.SourceId = fields[3].GetInt32();
1320 cond.ElseGroup = fields[4].GetUInt32();
1321 int32 iConditionTypeOrReference = fields[5].GetInt32();
1322 cond.ConditionTarget = fields[6].GetUInt8();
1323 cond.ConditionValue1 = fields[7].GetUInt32();
1324 cond.ConditionValue2 = fields[8].GetUInt32();
1325 cond.ConditionValue3 = fields[9].GetUInt32();
1326 cond.ConditionStringValue1 = fields[10].GetString();
1327 cond.NegativeCondition = fields[11].GetBool();
1328 cond.ErrorType = fields[12].GetUInt32();
1329 cond.ErrorTextId = fields[13].GetUInt32();
1330 cond.ScriptId = sObjectMgr->GetScriptId(fields[14].GetString());
1331
1332 if (iConditionTypeOrReference >= 0)
1333 cond.ConditionType = ConditionTypes(iConditionTypeOrReference);
1334
1335 if (iSourceTypeOrReferenceId >= 0)
1336 cond.SourceType = ConditionSourceType(iSourceTypeOrReferenceId);
1337
1338 if (iConditionTypeOrReference < 0)//it has a reference
1339 {
1340 if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip
1341 {
1342 TC_LOG_ERROR("sql.sql", "Condition reference {} is referencing self, skipped", iSourceTypeOrReferenceId);
1343 continue;
1344 }
1345
1346 cond.ReferenceId = uint32(-iConditionTypeOrReference);
1347
1348 char const* rowType = "reference template";
1349 if (iSourceTypeOrReferenceId >= 0)
1350 rowType = "reference";
1351 //check for useless data
1352 if (cond.ConditionTarget)
1353 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionTarget);
1354 if (cond.ConditionValue1)
1355 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue1);
1356 if (cond.ConditionValue2)
1357 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue2);
1358 if (cond.ConditionValue3)
1359 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3);
1360 }
1361 else if (!isConditionTypeValid(&cond))//doesn't have reference, validate ConditionType
1362 continue;
1363
1364 if (iSourceTypeOrReferenceId < 0)//it is a reference template
1365 {
1366 if (cond.SourceGroup)
1367 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceGroup ({})!", iSourceTypeOrReferenceId, cond.SourceGroup);
1368 if (cond.SourceEntry)
1369 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceEntry ({})!", iSourceTypeOrReferenceId, cond.SourceEntry);
1370 if (cond.SourceId)
1371 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceId ({})!", iSourceTypeOrReferenceId, cond.SourceId);
1372
1374 cond.SourceGroup = -iSourceTypeOrReferenceId;
1375 }
1376 else if (!isSourceTypeValid(&cond)) //if not a reference and SourceType is invalid, skip
1377 continue;
1378
1379 //Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
1380 if (cond.SourceGroup && !CanHaveSourceGroupSet(cond.SourceType))
1381 {
1382 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond.ToString(), cond.SourceGroup);
1383 continue;
1384 }
1385 if (cond.SourceId && !CanHaveSourceIdSet(cond.SourceType))
1386 {
1387 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond.ToString(), cond.SourceId);
1388 continue;
1389 }
1390
1392 {
1393 TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond.ToString(), cond.ErrorType);
1394 cond.ErrorType = 0;
1395 }
1396
1397 if (cond.ErrorTextId && !cond.ErrorType)
1398 {
1399 TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond.ToString(), cond.ErrorTextId);
1400 cond.ErrorTextId = 0;
1401 }
1402
1403 getOrInitConditions(cond.SourceType, { cond.SourceGroup, cond.SourceEntry, cond.SourceId })->emplace_back(std::move(cond));
1404 ++count;
1405 }
1406 while (result->NextRow());
1407
1408 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE])
1409 addToLootTemplate(id, conditions, LootTemplates_Creature.GetLootForConditionFill(id.SourceGroup));
1410
1411 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE])
1413
1414 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE])
1415 addToLootTemplate(id, conditions, LootTemplates_Fishing.GetLootForConditionFill(id.SourceGroup));
1416
1417 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE])
1419
1420 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE])
1421 addToLootTemplate(id, conditions, LootTemplates_Item.GetLootForConditionFill(id.SourceGroup));
1422
1423 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE])
1424 addToLootTemplate(id, conditions, LootTemplates_Mail.GetLootForConditionFill(id.SourceGroup));
1425
1426 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE])
1427 addToLootTemplate(id, conditions, LootTemplates_Milling.GetLootForConditionFill(id.SourceGroup));
1428
1431
1434
1435 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE])
1436 addToLootTemplate(id, conditions, LootTemplates_Reference.GetLootForConditionFill(id.SourceGroup));
1437
1438 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE])
1439 addToLootTemplate(id, conditions, LootTemplates_Skinning.GetLootForConditionFill(id.SourceGroup));
1440
1441 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE])
1442 addToLootTemplate(id, conditions, LootTemplates_Spell.GetLootForConditionFill(id.SourceGroup));
1443
1444 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU])
1445 addToGossipMenus(id, conditions);
1446
1447 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION])
1448 addToGossipMenuItems(id, conditions);
1449
1451 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT])
1452 for (Condition const& condition : *conditions)
1453 if (condition.ConditionType == CONDITION_AURA)
1454 SpellsUsedInSpellClickConditions.insert(condition.ConditionValue1);
1455
1456 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET])
1457 for (Condition const& condition : *conditions)
1459
1460 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PHASE])
1461 addToPhases(id, conditions);
1462
1463 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GRAVEYARD])
1464 addToGraveyardData(id, conditions);
1465
1466 struct
1467 {
1468 bool operator()(uint32 playerConditionId, std::vector<Condition> const& conditions, ConditionEntriesByTypeArray const& store) const
1469 {
1470 return std::any_of(conditions.begin(), conditions.end(), [&](Condition const& condition)
1471 {
1472 if (condition.ConditionType == CONDITION_PLAYER_CONDITION)
1473 {
1474 if (condition.ConditionValue1 == playerConditionId)
1475 return true;
1476 auto playerCondItr = store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].find({ 0, int32(condition.ConditionValue1), 0 });
1477 if (playerCondItr != store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].end())
1478 if (operator()(playerConditionId, *playerCondItr->second, store))
1479 return true;
1480 }
1481 else if (condition.ReferenceId)
1482 {
1483 auto refItr = store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1484 if (refItr != store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end())
1485 if (operator()(playerConditionId, *refItr->second, store))
1486 return true;
1487 }
1488 return false;
1489 });
1490 }
1491 } isPlayerConditionIdUsedByCondition;
1492
1493 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PLAYER_CONDITION])
1494 {
1495 if (isPlayerConditionIdUsedByCondition(id.SourceEntry, *conditions, ConditionStore))
1496 {
1497 TC_LOG_ERROR("sql.sql", "[Condition SourceType: CONDITION_SOURCE_TYPE_PLAYER_CONDITION, SourceGroup: {}, SourceEntry: {}, SourceId: {}] "
1498 "has a circular reference to player condition id {}, removed all conditions for this SourceEntry!",
1499 id.SourceGroup, id.SourceEntry, id.SourceId, id.SourceEntry);
1500 conditions->clear();
1501 }
1502 }
1503
1504 TC_LOG_INFO("server.loading", ">> Loaded {} conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1505}
1506
1507void ConditionMgr::addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const
1508{
1509 if (!loot)
1510 {
1511 for (Condition const& condition : *conditions)
1512 TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", condition.ToString(), id.SourceGroup);
1513 return;
1514 }
1515
1516 if (loot->LinkConditions(id, ConditionsReference{ conditions }))
1517 return;
1518
1519 for (Condition const& condition : *conditions)
1520 TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
1521}
1522
1523void ConditionMgr::addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1524{
1525 GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(id.SourceGroup);
1526
1527 if (pMenuBounds.first != pMenuBounds.second)
1528 {
1529 for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
1530 if (itr->second.MenuID == id.SourceGroup && (itr->second.TextID == uint32(id.SourceEntry) || id.SourceEntry == 0))
1531 itr->second.Conditions = { conditions };
1532
1533 return;
1534 }
1535
1536 for (Condition const& condition : *conditions)
1537 TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", condition.ToString(), id.SourceGroup);
1538}
1539
1540void ConditionMgr::addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1541{
1542 Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(id.SourceGroup);
1543 for (auto& [_, gossipMenuItem] : pMenuItemBounds)
1544 {
1545 if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == uint32(id.SourceEntry))
1546 {
1547 gossipMenuItem.Conditions = { conditions };
1548 return;
1549 }
1550 }
1551
1552 for (Condition const& condition : *conditions)
1553 TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", condition.ToString(), id.SourceGroup, id.SourceEntry);
1554}
1555
1557{
1558 sSpellMgr->ForEachSpellInfoDifficulty(cond.SourceEntry, [&](SpellInfo const* spellInfo)
1559 {
1560 uint32 conditionEffMask = cond.SourceGroup;
1561 std::list<uint32> sharedMasks;
1562 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1563 {
1564 // additional checks by condition type
1565 if (conditionEffMask & (1 << spellEffectInfo.EffectIndex))
1566 {
1567 switch (cond.ConditionType)
1568 {
1569 case CONDITION_OBJECT_ENTRY_GUID:
1570 {
1571 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
1572 if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond.ConditionValue1 != TYPEID_UNIT && cond.ConditionValue1 != TYPEID_PLAYER)
1573 {
1574 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1575 "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER));
1576 return;
1577 }
1578
1579 if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond.ConditionValue1 != TYPEID_GAMEOBJECT)
1580 {
1581 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1582 "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT));
1583 return;
1584 }
1585
1586 if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond.ConditionValue1 != TYPEID_CORPSE)
1587 {
1588 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1589 "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE));
1590 return;
1591 }
1592 break;
1593 }
1594 default:
1595 break;
1596 }
1597 }
1598
1599 // check if effect is already a part of some shared mask
1600 auto itr = std::find_if(sharedMasks.begin(), sharedMasks.end(), [&](uint32 mask) { return !!(mask & (1 << spellEffectInfo.EffectIndex)); });
1601 if (itr != sharedMasks.end())
1602 continue;
1603
1604 // build new shared mask with found effect
1605 uint32 sharedMask = 1 << spellEffectInfo.EffectIndex;
1606 for (size_t effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo->GetEffects().size(); ++effIndex)
1607 if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions)
1608 sharedMask |= 1 << effIndex;
1609
1610 sharedMasks.push_back(sharedMask);
1611 }
1612
1613 for (uint32 effectMask : sharedMasks)
1614 {
1615 // some effect indexes should have same data
1616 if (uint32 commonMask = effectMask & conditionEffMask)
1617 {
1618 size_t firstEffIndex = 0;
1619 for (; firstEffIndex < spellInfo->GetEffects().size(); ++firstEffIndex)
1620 if ((1 << firstEffIndex) & effectMask)
1621 break;
1622
1623 if (firstEffIndex >= spellInfo->GetEffects().size())
1624 return;
1625
1626 // get shared data
1627 std::shared_ptr<ConditionContainer> sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions;
1628
1629 // there's already data entry for that sharedMask
1630 if (sharedList)
1631 {
1632 // we have overlapping masks in db
1633 if (conditionEffMask != effectMask)
1634 {
1635 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup {} (spell effectMask) set - "
1636 "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty {}).",
1637 cond.ToString(), cond.SourceGroup, uint32(spellInfo->Difficulty));
1638 return;
1639 }
1640 }
1641 // no data for shared mask, we can create new submask
1642 else
1643 {
1644 // add new list, create new shared mask
1645 sharedList = std::make_shared<ConditionContainer>();
1646 bool assigned = false;
1647 for (size_t i = firstEffIndex; i < spellInfo->GetEffects().size(); ++i)
1648 {
1649 if ((1 << i) & commonMask)
1650 {
1651 const_cast<SpellEffectInfo&>(spellInfo->GetEffect(SpellEffIndex(i))).ImplicitTargetConditions = sharedList;
1652 assigned = true;
1653 }
1654 }
1655
1656 if (!assigned)
1657 break;
1658 }
1659 sharedList->push_back(cond);
1660 break;
1661 }
1662 }
1663 });
1664}
1665
1666void ConditionMgr::addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1667{
1668 if (!id.SourceEntry)
1669 {
1670 if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(id.SourceGroup))
1671 {
1672 bool found = false;
1673 for (uint32 areaId : phaseInfo->Areas)
1674 {
1675 if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(areaId)))
1676 {
1677 for (PhaseAreaInfo& phase : *phases)
1678 {
1679 if (phase.PhaseInfo->Id == id.SourceGroup)
1680 {
1681 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1682 found = true;
1683 }
1684 }
1685 }
1686 }
1687
1688 if (found)
1689 return;
1690 }
1691 }
1692 else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(id.SourceEntry)))
1693 {
1694 for (PhaseAreaInfo& phase : *phases)
1695 {
1696 if (phase.PhaseInfo->Id == id.SourceGroup)
1697 {
1698 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1699 return;
1700 }
1701 }
1702 }
1703
1704 for (Condition const& condition : *conditions)
1705 TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
1706}
1707
1708void ConditionMgr::addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1709{
1710 if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(id.SourceEntry, id.SourceGroup)))
1711 {
1712 graveyard->Conditions = { conditions };
1713 return;
1714 }
1715
1716 for (Condition const& condition : *conditions)
1717 TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", condition.ToString(), id.SourceEntry, id.SourceGroup);
1718}
1719
1721{
1722 switch (cond->SourceType)
1723 {
1725 {
1727 {
1728 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->ToString());
1729 return false;
1730 }
1731 break;
1732 }
1734 {
1736 {
1737 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->ToString());
1738 return false;
1739 }
1740 break;
1741 }
1743 {
1745 {
1746 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->ToString());
1747 return false;
1748 }
1749 break;
1750 }
1752 {
1754 {
1755 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->ToString());
1756 return false;
1757 }
1758 break;
1759 }
1761 {
1763 {
1764 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->ToString());
1765 return false;
1766 }
1767 break;
1768 }
1770 {
1772 {
1773 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->ToString());
1774 return false;
1775 }
1776 break;
1777 }
1779 {
1781 {
1782 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->ToString());
1783 return false;
1784 }
1785 break;
1786 }
1788 {
1790 {
1791 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->ToString());
1792 return false;
1793 }
1794 break;
1795 }
1797 {
1799 {
1800 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->ToString());
1801 return false;
1802 }
1803 break;
1804 }
1806 {
1808 {
1809 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->ToString());
1810 return false;
1811 }
1812 break;
1813 }
1815 {
1817 {
1818 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->ToString());
1819 return false;
1820 }
1821 break;
1822 }
1824 {
1826 {
1827 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->ToString());
1828 return false;
1829 }
1830 break;
1831 }
1833 {
1834 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1835 if (!spellInfo)
1836 {
1837 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", cond->ToString());
1838 return false;
1839 }
1840
1841 if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup)
1842 {
1843 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup (spell effectMask) set, ignoring.", cond->ToString());
1844 return false;
1845 }
1846
1847 uint32 origGroup = cond->SourceGroup;
1848
1849 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1850 {
1851 if (!((1 << spellEffectInfo.EffectIndex) & cond->SourceGroup))
1852 continue;
1853
1854 if (spellEffectInfo.ChainTargets > 0)
1855 continue;
1856
1857 switch (spellEffectInfo.TargetA.GetSelectionCategory())
1858 {
1864 continue;
1865 default:
1866 break;
1867 }
1868
1869 switch (spellEffectInfo.TargetB.GetSelectionCategory())
1870 {
1876 continue;
1877 default:
1878 break;
1879 }
1880
1881 switch (spellEffectInfo.Effect)
1882 {
1893 continue;
1894 default:
1895 break;
1896 }
1897
1898 TC_LOG_ERROR("sql.sql", "SourceEntry {} SourceGroup {} in `condition` table - spell {} does not have implicit targets of types: _AREA_, _CONE_, _NEARBY_, __CHAIN__ or is not SPELL_EFFECT_PERSISTENT_AREA_AURA or SPELL_EFFECT_APPLY_AREA_AURA_* for effect {}, SourceGroup needs correction, ignoring.", cond->SourceEntry, origGroup, cond->SourceEntry, uint32(spellEffectInfo.EffectIndex));
1899 cond->SourceGroup &= ~(1 << spellEffectInfo.EffectIndex);
1900 }
1901 // all effects were removed, no need to add the condition at all
1902 if (!cond->SourceGroup)
1903 return false;
1904 break;
1905 }
1907 {
1908 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
1909 {
1910 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString());
1911 return false;
1912 }
1913 break;
1914 }
1917 {
1918 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1919 if (!spellProto)
1920 {
1921 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", cond->ToString());
1922 return false;
1923 }
1924 break;
1925 }
1927 if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry))
1928 {
1929 TC_LOG_ERROR("sql.sql", "{} SourceEntry specifies non-existing quest, skipped.", cond->ToString());
1930 return false;
1931 }
1932 break;
1934 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1935 {
1936 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString());
1937 return false;
1938 }
1939
1940 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
1941 {
1942 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", cond->ToString());
1943 return false;
1944 }
1945 break;
1947 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1948 {
1949 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString());
1950 return false;
1951 }
1952
1953 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
1954 {
1955 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", cond->ToString());
1956 return false;
1957 }
1958 break;
1960 {
1961 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1962 {
1963 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString());
1964 return false;
1965 }
1966 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(cond->SourceEntry);
1967 if (!itemTemplate)
1968 {
1969 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, item does not exist, ignoring.", cond->ToString());
1970 return false;
1971 }
1972 break;
1973 }
1975 {
1976 if (!sMapStore.LookupEntry(cond->SourceEntry))
1977 {
1978 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in Map.db2, ignoring.", cond->ToString());
1979 return false;
1980 }
1981 break;
1982 }
1984 {
1985 if (cond->SourceEntry && !sAreaTableStore.LookupEntry(cond->SourceEntry))
1986 {
1987 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in AreaTable.db2, ignoring.", cond->ToString());
1988 return false;
1989 }
1990 break;
1991 }
1993 if (!sObjectMgr->FindGraveyardData(cond->SourceEntry, cond->SourceGroup))
1994 {
1995 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `graveyard_zone`, ignoring.", cond->ToString());
1996 return false;
1997 }
1998 break;
2000 if (cond->SourceEntry != 0 && cond->SourceEntry != 1)
2001 {
2002 TC_LOG_ERROR("sql.sql", "{} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring.", cond->ToString());
2003 return false;
2004 }
2005 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), cond->SourceEntry == 1 }))
2006 {
2007 TC_LOG_ERROR("sql.sql", "{} in `condition` table, does not exist in `areatrigger_template`, ignoring.", cond->ToString());
2008 return false;
2009 }
2010 break;
2012 if (!sConversationDataStore->GetConversationLineTemplate(cond->SourceEntry))
2013 {
2014 TC_LOG_ERROR("sql.sql", "{} does not exist in `conversation_line_template`, ignoring.", cond->ToString());
2015 return false;
2016 }
2017 break;
2019 if (!sAreaTriggerStore.LookupEntry(cond->SourceEntry))
2020 {
2021 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exists in AreaTrigger.db2, ignoring.", cond->ToString());
2022 return false;
2023 }
2024 break;
2026 {
2027 if (!sObjectMgr->GetTrainer(cond->SourceGroup))
2028 {
2029 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `trainer`, ignoring.", cond->ToString());
2030 return false;
2031 }
2032 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
2033 {
2034 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", cond->ToString());
2035 return false;
2036 }
2037 break;
2038 }
2040 {
2041 if (cond->SourceGroup <= 0 || cond->SourceGroup >= NUM_CLIENT_OBJECT_TYPES)
2042 {
2043 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, is no valid object type, ignoring.", cond->ToString());
2044 return false;
2045 }
2046
2047 if (cond->SourceGroup == TYPEID_UNIT)
2048 {
2049 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
2050 {
2051 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", cond->ToString());
2052 return false;
2053 }
2054 }
2055 else if (cond->SourceGroup == TYPEID_GAMEOBJECT)
2056 {
2057 if (!sObjectMgr->GetGameObjectTemplate(cond->SourceEntry))
2058 {
2059 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `gameobject_template`, ignoring.", cond->ToString());
2060 return false;
2061 }
2062 }
2063 else
2064 {
2065 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, uses unchecked type id, ignoring.", cond->ToString());
2066 return false;
2067 }
2068 break;
2069 }
2071 {
2072 SpawnGroupTemplateData const* spawnGroup = sObjectMgr->GetSpawnGroupData(cond->SourceEntry);
2073 if (!spawnGroup)
2074 {
2075 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `spawn_group_template`, ignoring.", cond->ToString());
2076 return false;
2077 }
2078 if (spawnGroup->flags & (SPAWNGROUP_FLAG_SYSTEM))
2079 {
2080 TC_LOG_ERROR("sql.sql", "{} in `spawn_group_template` table cannot have SPAWNGROUP_FLAG_SYSTEM flags, ignoring.", cond->ToString());
2081 return false;
2082 }
2083 break;
2084 }
2089 break;
2090 default:
2091 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionSourceType in `condition` table, ignoring.", cond->ToString());
2092 return false;
2093 }
2094
2095 return true;
2096}
2097
2099{
2100 switch (cond->ConditionType)
2101 {
2102 case CONDITION_AURA:
2103 {
2104 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE);
2105 if (!spellInfo)
2106 {
2107 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped.", cond->ToString(true), cond->ConditionValue1);
2108 return false;
2109 }
2110
2111 if (cond->ConditionValue2 >= spellInfo->GetEffects().size())
2112 {
2113 TC_LOG_ERROR("sql.sql", "{} spell {} has non existing effect index ({}) (must be 0..{}), skipped.",
2114 cond->ToString(true), cond->ConditionValue1, cond->ConditionValue2, spellInfo->GetEffects().size() - 1);
2115 return false;
2116 }
2117
2118 if (!spellInfo->GetEffect(SpellEffIndex(cond->ConditionValue2)).IsAura())
2119 {
2120 TC_LOG_ERROR("sql.sql", "{} spell {} effect index {} is not an aura, skipped.",
2121 cond->ToString(true), cond->ConditionValue1, cond->ConditionValue2);
2122 return false;
2123 }
2124 break;
2125 }
2126 case CONDITION_ITEM:
2127 {
2128 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2129 if (!proto)
2130 {
2131 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", cond->ToString(true), cond->ConditionValue1);
2132 return false;
2133 }
2134
2135 if (!cond->ConditionValue2)
2136 {
2137 TC_LOG_ERROR("sql.sql", "{} Zero item count in ConditionValue2, skipped.", cond->ToString(true));
2138 return false;
2139 }
2140 break;
2141 }
2143 {
2144 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2145 if (!proto)
2146 {
2147 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", cond->ToString(true), cond->ConditionValue1);
2148 return false;
2149 }
2150 break;
2151 }
2152 case CONDITION_ZONEID:
2153 {
2154 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
2155 if (!areaEntry)
2156 {
2157 TC_LOG_ERROR("sql.sql", "{} Area ({}) does not exist, skipped.", cond->ToString(true), cond->ConditionValue1);
2158 return false;
2159 }
2160
2161 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2162 {
2163 TC_LOG_ERROR("sql.sql", "{} requires to be in area ({}) which is a subzone but zone expected, skipped.", cond->ToString(true), cond->ConditionValue1);
2164 return false;
2165 }
2166 break;
2167 }
2169 {
2170 FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1);
2171 if (!factionEntry)
2172 {
2173 TC_LOG_ERROR("sql.sql", "{} has non existing faction ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2174 return false;
2175 }
2176 break;
2177 }
2178 case CONDITION_TEAM:
2179 {
2180 if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE)
2181 {
2182 TC_LOG_ERROR("sql.sql", "{} specifies unknown team ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2183 return false;
2184 }
2185 break;
2186 }
2187 case CONDITION_SKILL:
2188 {
2189 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1);
2190 if (!pSkill)
2191 {
2192 TC_LOG_ERROR("sql.sql", "{} specifies non-existing skill ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2193 return false;
2194 }
2195
2196 if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue())
2197 {
2198 TC_LOG_ERROR("sql.sql", "{} specifies skill ({}) with invalid value ({}), skipped.", cond->ToString(true), cond->ConditionValue1, cond->ConditionValue2);
2199 return false;
2200 }
2201 break;
2202 }
2204 if (cond->ConditionValue2 >= (1 << MAX_QUEST_STATUS))
2205 {
2206 TC_LOG_ERROR("sql.sql", "{} has invalid state mask ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2207 return false;
2208 }
2209 [[fallthrough]];
2215 {
2216 if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1))
2217 {
2218 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2219 return false;
2220 }
2221 break;
2222 }
2224 {
2225 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2226 if (cond->ConditionValue1 >= events.size() || !events[cond->ConditionValue1].isValid())
2227 {
2228 TC_LOG_ERROR("sql.sql", "{} has non existing event id ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2229 return false;
2230 }
2231 break;
2232 }
2234 {
2235 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2236 if (!achievement)
2237 {
2238 TC_LOG_ERROR("sql.sql", "{} has non existing achivement id ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2239 return false;
2240 }
2241 break;
2242 }
2243 case CONDITION_CLASS:
2244 {
2246 {
2247 TC_LOG_ERROR("sql.sql", "{} has non existing classmask ({}), skipped.", cond->ToString(true), cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE);
2248 return false;
2249 }
2250 break;
2251 }
2252 case CONDITION_RACE:
2253 {
2254 Trinity::RaceMask<uint64> invalidRaceMask = Trinity::RaceMask<uint64>{ cond->ConditionValue1 } & ~RACEMASK_ALL_PLAYABLE;
2255 if (!invalidRaceMask.IsEmpty()) // uint32 works thanks to weird index remapping in racemask
2256 {
2257 TC_LOG_ERROR("sql.sql", "{} has non existing racemask ({}), skipped.", cond->ToString(true), invalidRaceMask.RawValue);
2258 return false;
2259 }
2260 break;
2261 }
2262 case CONDITION_GENDER:
2263 {
2265 {
2266 TC_LOG_ERROR("sql.sql", "{} has invalid gender ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2267 return false;
2268 }
2269 break;
2270 }
2271 case CONDITION_MAPID:
2272 {
2273 MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1);
2274 if (!me)
2275 {
2276 TC_LOG_ERROR("sql.sql", "{} has non existing map ({}), skipped", cond->ToString(true), cond->ConditionValue1);
2277 return false;
2278 }
2279 break;
2280 }
2281 case CONDITION_SPELL:
2282 {
2283 if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE))
2284 {
2285 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped", cond->ToString(true), cond->ConditionValue1);
2286 return false;
2287 }
2288 break;
2289 }
2290 case CONDITION_LEVEL:
2291 {
2292 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2293 {
2294 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2295 return false;
2296 }
2297 break;
2298 }
2300 {
2301 if (cond->ConditionValue1 > DRUNKEN_SMASHED)
2302 {
2303 TC_LOG_ERROR("sql.sql", "{} has invalid state ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2304 return false;
2305 }
2306 break;
2307 }
2309 {
2310 if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1))
2311 {
2312 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped", cond->ToString(true), cond->ConditionValue1);
2313 return false;
2314 }
2315 break;
2316 }
2318 {
2319 if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1))
2320 {
2321 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", cond->ToString(), cond->ConditionValue1);
2322 return false;
2323 }
2324 break;
2325 }
2329 [[fallthrough]];
2331 {
2332 switch (cond->ConditionValue1)
2333 {
2334 case TYPEID_UNIT:
2335 if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2))
2336 {
2337 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2338 return false;
2339 }
2340 if (cond->ConditionValue3)
2341 {
2342 if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(cond->ConditionValue3))
2343 {
2344 if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2)
2345 {
2346 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match creature entry ({}), skipped.", cond->ToString(true), cond->ConditionValue3, cond->ConditionValue2);
2347 return false;
2348 }
2349 }
2350 else
2351 {
2352 TC_LOG_ERROR("sql.sql", "{} has non existing creature guid ({}), skipped.", cond->ToString(true), cond->ConditionValue3);
2353 return false;
2354 }
2355 }
2356 break;
2357 case TYPEID_GAMEOBJECT:
2358 if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2))
2359 {
2360 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2361 return false;
2362 }
2363 if (cond->ConditionValue3)
2364 {
2365 if (GameObjectData const* goData = sObjectMgr->GetGameObjectData(cond->ConditionValue3))
2366 {
2367 if (cond->ConditionValue2 && goData->id != cond->ConditionValue2)
2368 {
2369 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match gameobject entry ({}), skipped.", cond->ToString(true), cond->ConditionValue3, cond->ConditionValue2);
2370 return false;
2371 }
2372 }
2373 else
2374 {
2375 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject guid ({}), skipped.", cond->ToString(true), cond->ConditionValue3);
2376 return false;
2377 }
2378 }
2379 break;
2380 case TYPEID_PLAYER:
2381 case TYPEID_CORPSE:
2382 if (cond->ConditionValue2)
2384 if (cond->ConditionValue3)
2386 break;
2387 default:
2388 TC_LOG_ERROR("sql.sql", "{} has wrong typeid set ({}), skipped", cond->ToString(true), cond->ConditionValue1);
2389 return false;
2390 }
2391 break;
2392 }
2396 [[fallthrough]];
2398 {
2400 {
2401 TC_LOG_ERROR("sql.sql", "{} has invalid typemask set ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2402 return false;
2403 }
2404 break;
2405 }
2407 {
2409 {
2410 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2411 return false;
2412 }
2413 if (cond->ConditionValue1 == cond->ConditionTarget)
2414 {
2415 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2416 return false;
2417 }
2418 if (cond->ConditionValue2 >= RELATION_MAX)
2419 {
2420 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(RelationType) ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2421 return false;
2422 }
2423 break;
2424 }
2426 {
2428 {
2429 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2430 return false;
2431 }
2432 if (cond->ConditionValue1 == cond->ConditionTarget)
2433 {
2434 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2435 return false;
2436 }
2437 if (!cond->ConditionValue2)
2438 {
2439 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(rankMask) ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2440 return false;
2441 }
2442 break;
2443 }
2445 {
2447 {
2448 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2449 return false;
2450 }
2451 if (cond->ConditionValue1 == cond->ConditionTarget)
2452 {
2453 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2454 return false;
2455 }
2456 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2457 {
2458 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", cond->ToString(true), cond->ConditionValue3);
2459 return false;
2460 }
2461 break;
2462 }
2463 case CONDITION_HP_VAL:
2464 {
2465 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2466 {
2467 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2468 return false;
2469 }
2470 break;
2471 }
2472 case CONDITION_HP_PCT:
2473 {
2474 if (cond->ConditionValue1 > 100)
2475 {
2476 TC_LOG_ERROR("sql.sql", "{} has too big percent value ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2477 return false;
2478 }
2479 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2480 {
2481 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", cond->ToString(true), cond->ConditionValue2);
2482 return false;
2483 }
2484 break;
2485 }
2487 {
2488 if (!sWorldStateMgr->GetWorldStateTemplate(cond->ConditionValue1))
2489 {
2490 TC_LOG_ERROR("sql.sql", "{} has non existing world state in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2491 return false;
2492 }
2493 break;
2494 }
2495 case CONDITION_PHASEID:
2496 {
2497 if (!sPhaseStore.LookupEntry(cond->ConditionValue1))
2498 {
2499 TC_LOG_ERROR("sql.sql", "{} has nonexistent phaseid in value1 ({}), skipped", cond->ToString(true), cond->ConditionValue1);
2500 return false;
2501 }
2502 break;
2503 }
2504 case CONDITION_TITLE:
2505 {
2506 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1);
2507 if (!titleEntry)
2508 {
2509 TC_LOG_ERROR("sql.sql", "{} has non existing title in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2510 return false;
2511 }
2512 break;
2513 }
2515 {
2516 TC_LOG_ERROR("sql.sql", "{} using deprecated condition type CONDITION_SPAWNMASK.", cond->ToString(true));
2517 return false;
2518 }
2520 {
2522 {
2523 TC_LOG_ERROR("sql.sql", "{} has non existing UnitState in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2524 return false;
2525 }
2526 break;
2527 }
2529 {
2531 {
2532 TC_LOG_ERROR("sql.sql", "{} has non existing CreatureType in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2533 return false;
2534 }
2535 break;
2536 }
2538 {
2539 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2540 if (!achievement)
2541 {
2542 TC_LOG_ERROR("sql.sql", "{} has non existing realm first achivement id ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2543 return false;
2544 }
2545 break;
2546 }
2548 {
2549 bool valid = false;
2550 switch (cond->ConditionValue1)
2551 {
2552 case 0:
2554 break;
2555 case 1:
2556 valid = cond->ConditionValue2 <= 1;
2557 break;
2558 default:
2559 valid = false;
2560 break;
2561 }
2562 if (!valid)
2563 {
2564 TC_LOG_ERROR("sql.sql", "{} has non-existing stand state ({},{}), skipped.", cond->ToString(true), cond->ConditionValue1, cond->ConditionValue2);
2565 return false;
2566 }
2567 break;
2568 }
2570 {
2571 QuestObjective const* obj = sObjectMgr->GetQuestObjective(cond->ConditionValue1);
2572 if (!obj)
2573 {
2574 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest objective ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2575 return false;
2576 }
2577 int32 limit = obj->IsStoringFlag() ? 1 : obj->Amount;
2578 if (int32(cond->ConditionValue3) > limit)
2579 {
2580 TC_LOG_ERROR("sql.sql", "{} has quest objective count {} in value3, but quest objective {} has a maximum objective count of {}, skipped.", cond->ToString(true), cond->ConditionValue3, cond->ConditionValue1, limit);
2581 return false;
2582 }
2583 break;
2584 }
2585 case CONDITION_PET_TYPE:
2586 if (cond->ConditionValue1 >= (1 << MAX_PET_TYPE))
2587 {
2588 TC_LOG_ERROR("sql.sql", "{} has non-existing pet type {}, skipped.", cond->ToString(true), cond->ConditionValue1);
2589 return false;
2590 }
2591 break;
2594 {
2595 TC_LOG_ERROR("sql.sql", "{} has unsupported ConditionValue3 {} (INSTANCE_INFO_GUID_DATA), skipped.", cond->ToString(true), cond->ConditionValue3);
2596 return false;
2597 }
2598 break;
2599 case CONDITION_AREAID:
2600 case CONDITION_ALIVE:
2601 case CONDITION_IN_WATER:
2603 case CONDITION_CHARMED:
2604 case CONDITION_TAXI:
2608 case CONDITION_LABEL:
2609 break;
2611 if (!sDifficultyStore.LookupEntry(cond->ConditionValue1))
2612 {
2613 TC_LOG_ERROR("sql.sql", "{} has non existing difficulty in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2614 return false;
2615 }
2616 break;
2618 if (!sBattlePetSpeciesStore.LookupEntry(cond->ConditionValue1))
2619 {
2620 TC_LOG_ERROR("sql.sql", "{} has non existing BattlePet SpeciesId in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2621 return false;
2622 }
2624 {
2625 TC_LOG_ERROR("sql.sql", "{} has invalid (greater than {}) value2 ({}), skipped.", cond->ToString(true),
2627 return false;
2628 }
2629 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2630 {
2631 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", cond->ToString(true), cond->ConditionValue3);
2632 return false;
2633 }
2634 break;
2636 {
2637 if (!sScenarioStepStore.LookupEntry(cond->ConditionValue1))
2638 {
2639 TC_LOG_ERROR("sql.sql", "{} has non existing ScenarioStep in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2640 return false;
2641 }
2642 break;
2643 }
2645 {
2646 if (!sSceneScriptPackageStore.LookupEntry(cond->ConditionValue1))
2647 {
2648 TC_LOG_ERROR("sql.sql", "{} has non existing SceneScriptPackageId in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2649 return false;
2650 }
2651 break;
2652 }
2654 {
2655 if (!sPlayerConditionStore.LookupEntry(cond->ConditionValue1))
2656 {
2657 TC_LOG_ERROR("sql.sql", "{} has non existing PlayerConditionId in value1 ({}), skipped.", cond->ToString(true), cond->ConditionValue1);
2658 return false;
2659 }
2660 break;
2661 }
2662 default:
2663 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionType in `condition` table, ignoring.", cond->ToString());
2664 return false;
2665 }
2666
2668 {
2669 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect ConditionTarget set, ignoring.", cond->ToString(true));
2670 return false;
2671 }
2672
2681
2682 return true;
2683}
2684
2686{
2687 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionValue{} ({})!", cond->ToString(true), index, value);
2688}
2689
2690void ConditionMgr::LogUselessConditionValue(Condition const* cond, uint8 index, std::string_view value)
2691{
2692 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionStringValue{} ({})!", cond->ToString(true), index, value);
2693}
2694
2696{
2697 for (std::unordered_map<ConditionId, std::shared_ptr<std::vector<Condition>>>& conditionsMap : ConditionStore)
2698 conditionsMap.clear();
2699
2701}
2702
2703inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
2704{
2705 switch (comparisonType)
2706 {
2707 case 1:
2708 return value1 == value2;
2709 case 2:
2710 return value1 != value2;
2711 case 3:
2712 return value1 > value2;
2713 case 4:
2714 return value1 >= value2;
2715 case 5:
2716 return value1 < value2;
2717 case 6:
2718 return value1 <= value2;
2719 default:
2720 break;
2721 }
2722 return false;
2723}
2724
2725template<std::size_t N>
2726inline bool PlayerConditionLogic(uint32 logic, std::array<bool, N>& results)
2727{
2728 static_assert(N < 8, "Logic array size must be equal to or less than 8");
2729
2730 for (std::size_t i = 0; i < results.size(); ++i)
2731 if ((logic >> (16 + i)) & 1)
2732 results[i] ^= true;
2733
2734 bool result = results[0];
2735 for (std::size_t i = 1; i < results.size(); ++i)
2736 {
2737 switch ((logic >> (2 * (i - 1))) & 3)
2738 {
2739 case 1:
2740 result = result && results[i];
2741 break;
2742 case 2:
2743 result = result || results[i];
2744 break;
2745 default:
2746 break;
2747 }
2748 }
2749
2750 return result;
2751}
2752
2754{
2755 Group const* group = player->GetGroup();
2756 if (!group)
2757 return 0;
2758
2759 switch (status)
2760 {
2762 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) ? 1 : 0;
2764 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) &&
2765 sLFGMgr->selectedRandomLfgDungeon(player->GetGUID()) ? 1 : 0;
2767 {
2768 if (!sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()))
2769 return 0;
2770
2771 uint32 selectedRandomDungeon = sLFGMgr->GetSelectedRandomDungeon(player->GetGUID());
2772 if (!selectedRandomDungeon)
2773 return 0;
2774
2775 if (lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(selectedRandomDungeon, player->GetLevel()))
2776 if (Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest))
2777 if (player->CanRewardQuest(quest, false))
2778 return 1;
2779 return 0;
2780 }
2782 break;
2784 break;
2786 break;
2788 break;
2790 break;
2791 default:
2792 break;
2793 }
2794
2795 return 0;
2796}
2797
2799{
2800 if (!conditionId)
2801 return true;
2802
2803 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_PLAYER_CONDITION, conditionId, player))
2804 return false;
2805
2806 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
2807 return IsPlayerMeetingCondition(player, playerCondition);
2808
2809 return true;
2810}
2811
2813{
2814 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(condition->ContentTuningID, player->m_playerData->CtrOptions->ConditionalFlags))
2815 {
2816 uint8 minLevel = condition->Flags & 0x800 ? levels->MinLevelWithDelta : levels->MinLevel;
2817 uint8 maxLevel = 0;
2818 if (!(condition->Flags & 0x20))
2819 maxLevel = condition->Flags & 0x800 ? levels->MaxLevelWithDelta : levels->MaxLevel;
2820
2821 if (condition->Flags & 0x80)
2822 {
2823 if (minLevel && player->GetLevel() >= minLevel && (!maxLevel || player->GetLevel() <= maxLevel))
2824 return false;
2825
2826 if (maxLevel && player->GetLevel() <= maxLevel && (!minLevel || player->GetLevel() >= minLevel))
2827 return false;
2828 }
2829 else
2830 {
2831 if (minLevel && player->GetLevel() < minLevel)
2832 return false;
2833
2834 if (maxLevel && player->GetLevel() > maxLevel)
2835 return false;
2836 }
2837 }
2838
2839 if (!condition->RaceMask.IsEmpty() && !condition->RaceMask.HasRace(player->GetRace()))
2840 return false;
2841
2842 if (condition->ClassMask && !(player->GetClassMask() & condition->ClassMask))
2843 return false;
2844
2845 if (condition->Gender >= 0 && player->GetGender() != condition->Gender)
2846 return false;
2847
2848 if (condition->NativeGender >= 0 && player->GetNativeGender() != condition->NativeGender)
2849 return false;
2850
2851 if (condition->PowerType != -1 && condition->PowerTypeComp)
2852 {
2853 int32 requiredPowerValue = condition->Flags & 4 ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
2854 if (!PlayerConditionCompare(condition->PowerTypeComp, player->GetPower(Powers(condition->PowerType)), requiredPowerValue))
2855 return false;
2856 }
2857
2858 if (condition->ChrSpecializationIndex >= 0 || condition->ChrSpecializationRole >= 0)
2859 {
2861 {
2862 if (condition->ChrSpecializationIndex >= 0 && spec->OrderIndex != condition->ChrSpecializationIndex)
2863 return false;
2864
2865 if (condition->ChrSpecializationRole >= 0 && spec->Role != condition->ChrSpecializationRole)
2866 return false;
2867 }
2868 }
2869
2870 if (condition->SkillID[0] || condition->SkillID[1] || condition->SkillID[2] || condition->SkillID[3])
2871 {
2872 std::array<bool, std::tuple_size_v<decltype(condition->SkillID)>> results;
2873 results.fill(true);
2874 for (std::size_t i = 0; i < condition->SkillID.size(); ++i)
2875 {
2876 if (condition->SkillID[i])
2877 {
2878 uint16 skillValue = player->GetSkillValue(condition->SkillID[i]);
2879 results[i] = skillValue != 0 && skillValue > condition->MinSkill[i] && skillValue < condition->MaxSkill[i];
2880 }
2881 }
2882
2883 if (!PlayerConditionLogic(condition->SkillLogic, results))
2884 return false;
2885 }
2886
2887 if (condition->LanguageID)
2888 {
2889 int32 languageSkill = 0;
2891 languageSkill = 300;
2892 else
2893 {
2894 for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(Language(condition->LanguageID)))
2895 languageSkill = std::max<int32>(languageSkill, player->GetSkillValue(languageDesc.second.SkillId));
2896 }
2897
2898 if (condition->MinLanguage && languageSkill < condition->MinLanguage)
2899 return false;
2900
2901 if (condition->MaxLanguage && languageSkill > condition->MaxLanguage)
2902 return false;
2903 }
2904
2905 if (condition->MinFactionID[0] || condition->MinFactionID[1] || condition->MinFactionID[2] || condition->MaxFactionID)
2906 {
2907 if (!condition->MinFactionID[0] && !condition->MinFactionID[1] && !condition->MinFactionID[2])
2908 {
2909 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
2910 {
2911 if (*forcedRank > ReputationRank(condition->MaxReputation))
2912 return false;
2913 }
2914 else if (sFactionStore.HasRecord(condition->MaxReputation) && player->GetReputationRank(condition->MaxFactionID) > ReputationRank(condition->MaxReputation))
2915 return false;
2916 }
2917 else
2918 {
2919 std::array<bool, std::tuple_size_v<decltype(condition->MinFactionID)> + 1> results;
2920 results.fill(true);
2921 for (std::size_t i = 0; i < condition->MinFactionID.size(); ++i)
2922 {
2923 if (sFactionStore.HasRecord(condition->MinFactionID[i]))
2924 {
2925 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MinFactionID[i]))
2926 results[i] = *forcedRank >= ReputationRank(condition->MinReputation[i]);
2927 else
2928 results[i] = player->GetReputationRank(condition->MinFactionID[i]) >= ReputationRank(condition->MinReputation[i]);
2929 }
2930 }
2931
2932 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
2933 results[3] = *forcedRank <= ReputationRank(condition->MaxReputation);
2934 else if (sFactionStore.HasRecord(condition->MaxReputation))
2935 results[3] = player->GetReputationRank(condition->MaxFactionID) <= ReputationRank(condition->MaxReputation);
2936
2937 if (!PlayerConditionLogic(condition->ReputationLogic, results))
2938 return false;
2939 }
2940 }
2941
2942 if (condition->CurrentPvpFaction)
2943 {
2944 int8 team;
2945 if (player->GetMap()->IsBattlegroundOrArena())
2946 team = player->m_playerData->ArenaFaction;
2947 else
2948 team = player->GetTeamId() == TEAM_ALLIANCE ? 1 : 0;
2949
2950 if (condition->CurrentPvpFaction - 1 != team)
2951 return false;
2952 }
2953
2954 if (condition->PvpMedal && !((1 << (condition->PvpMedal - 1)) & *player->m_activePlayerData->PvpMedals))
2955 return false;
2956
2957 if (condition->LifetimeMaxPVPRank && player->m_activePlayerData->LifetimeMaxRank != condition->LifetimeMaxPVPRank)
2958 return false;
2959
2960 if (condition->MovementFlags[0] && !(player->GetUnitMovementFlags() & condition->MovementFlags[0]))
2961 return false;
2962
2963 if (condition->MovementFlags[1] && !(player->GetExtraUnitMovementFlags() & condition->MovementFlags[1]))
2964 return false;
2965
2966 if (condition->WeaponSubclassMask)
2967 {
2969 if (!mainHand || !((1 << mainHand->GetTemplate()->GetSubClass()) & condition->WeaponSubclassMask))
2970 return false;
2971 }
2972
2973 if (condition->PartyStatus)
2974 {
2975 Group const* group = player->GetGroup();
2976 switch (condition->PartyStatus)
2977 {
2978 case 1:
2979 if (group)
2980 return false;
2981 break;
2982 case 2:
2983 if (!group)
2984 return false;
2985 break;
2986 case 3:
2987 if (!group || group->isRaidGroup())
2988 return false;
2989 break;
2990 case 4:
2991 if (!group || !group->isRaidGroup())
2992 return false;
2993 break;
2994 case 5:
2995 if (group && group->isRaidGroup())
2996 return false;
2997 break;
2998 default:
2999 break;
3000 }
3001 }
3002
3003 if (condition->PrevQuestID[0])
3004 {
3005 std::array<bool, std::tuple_size_v<decltype(condition->PrevQuestID)>> results;
3006 results.fill(true);
3007 for (std::size_t i = 0; i < condition->PrevQuestID.size(); ++i)
3008 results[i] = player->IsQuestCompletedBitSet(condition->PrevQuestID[i]);
3009
3010 if (!PlayerConditionLogic(condition->PrevQuestLogic, results))
3011 return false;
3012 }
3013
3014 if (condition->CurrQuestID[0])
3015 {
3016 std::array<bool, std::tuple_size_v<decltype(condition->CurrQuestID)>> results;
3017 results.fill(true);
3018 for (std::size_t i = 0; i < condition->CurrQuestID.size(); ++i)
3019 if (condition->CurrQuestID[i])
3020 results[i] = player->FindQuestSlot(condition->CurrQuestID[i]) != MAX_QUEST_LOG_SIZE;
3021
3022 if (!PlayerConditionLogic(condition->CurrQuestLogic, results))
3023 return false;
3024 }
3025
3026 if (condition->CurrentCompletedQuestID[0])
3027 {
3028 std::array<bool, std::tuple_size_v<decltype(condition->CurrentCompletedQuestID)>> results;
3029 results.fill(true);
3030 for (std::size_t i = 0; i < condition->CurrentCompletedQuestID.size(); ++i)
3031 if (condition->CurrentCompletedQuestID[i])
3032 results[i] = player->GetQuestStatus(condition->CurrentCompletedQuestID[i]) == QUEST_STATUS_COMPLETE;
3033
3034 if (!PlayerConditionLogic(condition->CurrentCompletedQuestLogic, results))
3035 return false;
3036 }
3037
3038 if (condition->SpellID[0])
3039 {
3040 std::array<bool, std::tuple_size_v<decltype(condition->SpellID)>> results;
3041 results.fill(true);
3042 for (std::size_t i = 0; i < condition->SpellID.size(); ++i)
3043 if (condition->SpellID[i])
3044 results[i] = player->HasSpell(condition->SpellID[i]);
3045
3046 if (!PlayerConditionLogic(condition->SpellLogic, results))
3047 return false;
3048 }
3049
3050 if (condition->ItemID[0])
3051 {
3052 std::array<bool, std::tuple_size_v<decltype(condition->ItemID)>> results;
3053 results.fill(true);
3054 for (std::size_t i = 0; i < condition->ItemID.size(); ++i)
3055 if (condition->ItemID[i])
3056 results[i] = player->GetItemCount(condition->ItemID[i], condition->ItemFlags != 0) >= condition->ItemCount[i];
3057
3058 if (!PlayerConditionLogic(condition->ItemLogic, results))
3059 return false;
3060 }
3061
3062 if (condition->CurrencyID[0])
3063 {
3064 std::array<bool, std::tuple_size_v<decltype(condition->CurrencyID)>> results;
3065 results.fill(true);
3066 for (std::size_t i = 0; i < condition->CurrencyID.size(); ++i)
3067 if (condition->CurrencyID[i])
3068 results[i] = player->GetCurrencyQuantity(condition->CurrencyID[i]) >= condition->CurrencyCount[i];
3069
3070 if (!PlayerConditionLogic(condition->CurrencyLogic, results))
3071 return false;
3072 }
3073
3074 if (condition->Explored[0] || condition->Explored[1])
3075 {
3076 for (std::size_t i = 0; i < condition->Explored.size(); ++i)
3077 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(condition->Explored[i]))
3078 if (!player->HasExploredZone(area->ID))
3079 return false;
3080 }
3081
3082 if (condition->AuraSpellID[0])
3083 {
3084 std::array<bool, std::tuple_size_v<decltype(condition->AuraSpellID)>> results;
3085 results.fill(true);
3086 for (std::size_t i = 0; i < condition->AuraSpellID.size(); ++i)
3087 {
3088 if (condition->AuraSpellID[i])
3089 {
3090 if (condition->AuraStacks[i])
3091 results[i] = player->GetAuraCount(condition->AuraSpellID[i]) >= condition->AuraStacks[i];
3092 else
3093 results[i] = player->HasAura(condition->AuraSpellID[i]);
3094 }
3095 }
3096
3097 if (!PlayerConditionLogic(condition->AuraSpellLogic, results))
3098 return false;
3099 }
3100
3101 if (condition->Time[0])
3102 {
3103 WowTime time0;
3104 time0.SetPackedTime(condition->Time[0]);
3105
3106 if (condition->Time[1])
3107 {
3108 WowTime time1;
3109 time1.SetPackedTime(condition->Time[1]);
3110
3111 if (!GameTime::GetWowTime()->IsInRange(time0, time1))
3112 return false;
3113 }
3114 else if (*GameTime::GetWowTime() != time0)
3115 return false;
3116 }
3117
3118 if (condition->WorldStateExpressionID)
3119 {
3120 WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(condition->WorldStateExpressionID);
3121 if (!worldStateExpression)
3122 return false;
3123
3124 if (!IsMeetingWorldStateExpression(player->GetMap(), worldStateExpression))
3125 return false;
3126 }
3127
3128 if (condition->WeatherID)
3129 if (player->GetMap()->GetZoneWeather(player->GetZoneId()) != WeatherState(condition->WeatherID))
3130 return false;
3131
3132 if (condition->Achievement[0])
3133 {
3134 std::array<bool, std::tuple_size_v<decltype(condition->Achievement)>> results;
3135 results.fill(true);
3136 for (std::size_t i = 0; i < condition->Achievement.size(); ++i)
3137 {
3138 if (condition->Achievement[i])
3139 {
3140 // if (condition->Flags & 2) { any character on account completed it } else { current character only }
3141 // TODO: part of accountwide achievements
3142 results[i] = player->HasAchieved(condition->Achievement[i]);
3143 }
3144 }
3145
3146 if (!PlayerConditionLogic(condition->AchievementLogic, results))
3147 return false;
3148 }
3149
3150 if (condition->LfgStatus[0])
3151 {
3152 std::array<bool, std::tuple_size_v<decltype(condition->LfgStatus)>> results;
3153 results.fill(true);
3154 for (std::size_t i = 0; i < condition->LfgStatus.size(); ++i)
3155 if (condition->LfgStatus[i])
3156 results[i] = PlayerConditionCompare(condition->LfgCompare[i],
3158 condition->LfgValue[i]);
3159
3160 if (!PlayerConditionLogic(condition->LfgLogic, results))
3161 return false;
3162 }
3163
3164 if (condition->AreaID[0])
3165 {
3166 std::array<bool, std::tuple_size_v<decltype(condition->AreaID)>> results;
3167 results.fill(true);
3168 for (std::size_t i = 0; i < condition->AreaID.size(); ++i)
3169 if (condition->AreaID[i])
3170 results[i] = DB2Manager::IsInArea(player->GetAreaId(), condition->AreaID[i]);
3171
3172 if (!PlayerConditionLogic(condition->AreaLogic, results))
3173 return false;
3174 }
3175
3176 if (condition->MinExpansionLevel != -1 && player->GetSession()->GetExpansion() < condition->MinExpansionLevel)
3177 return false;
3178
3179 if (condition->MaxExpansionLevel != -1 && player->GetSession()->GetExpansion() > condition->MaxExpansionLevel)
3180 return false;
3181
3182 if (condition->MinExpansionLevel != -1 && condition->MinExpansionTier != -1 && !player->IsGameMaster()
3183 && ((condition->MinExpansionLevel == int32(sWorld->getIntConfig(CONFIG_EXPANSION)) && condition->MinExpansionTier > 0) /*TODO: implement tier*/
3184 || condition->MinExpansionLevel > int32(sWorld->getIntConfig(CONFIG_EXPANSION))))
3185 return false;
3186
3187 if (condition->PhaseID || condition->PhaseGroupID || condition->PhaseUseFlags)
3188 if (!PhasingHandler::InDbPhaseShift(player, condition->PhaseUseFlags, condition->PhaseID, condition->PhaseGroupID))
3189 return false;
3190
3191 if (condition->QuestKillID)
3192 {
3193 Quest const* quest = sObjectMgr->GetQuestTemplate(condition->QuestKillID);
3194 uint16 questSlot = player->FindQuestSlot(condition->QuestKillID);
3195 if (quest && player->GetQuestStatus(condition->QuestKillID) != QUEST_STATUS_COMPLETE && questSlot < MAX_QUEST_LOG_SIZE)
3196 {
3197 std::array<bool, std::tuple_size_v<decltype(condition->QuestKillMonster)>> results;
3198 results.fill(true);
3199 for (std::size_t i = 0; i < condition->QuestKillMonster.size(); ++i)
3200 {
3201 if (condition->QuestKillMonster[i])
3202 {
3203 auto objectiveItr = std::find_if(quest->GetObjectives().begin(), quest->GetObjectives().end(), [condition, i](QuestObjective const& objective) -> bool
3204 {
3205 return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == condition->QuestKillMonster[i];
3206 });
3207 if (objectiveItr != quest->GetObjectives().end())
3208 results[i] = player->GetQuestSlotObjectiveData(questSlot, *objectiveItr) >= objectiveItr->Amount;
3209 }
3210 }
3211
3212 if (!PlayerConditionLogic(condition->QuestKillLogic, results))
3213 return false;
3214 }
3215 }
3216
3217 if (condition->MinAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) < condition->MinAvgItemLevel)
3218 return false;
3219
3220 if (condition->MaxAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) > condition->MaxAvgItemLevel)
3221 return false;
3222
3223 if (condition->MinAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) < condition->MinAvgEquippedItemLevel)
3224 return false;
3225
3226 if (condition->MaxAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) > condition->MaxAvgEquippedItemLevel)
3227 return false;
3228
3229 if (condition->ModifierTreeID && !player->ModifierTreeSatisfied(condition->ModifierTreeID))
3230 return false;
3231
3232 if (condition->CovenantID && player->m_playerData->CovenantID != condition->CovenantID)
3233 return false;
3234
3235 if (std::any_of(condition->TraitNodeEntryID.begin(), condition->TraitNodeEntryID.end(), [](int32 traitNodeEntryId) { return traitNodeEntryId != 0; }))
3236 {
3237 auto getTraitNodeEntryRank = [player](int32 traitNodeEntryId) -> Optional<uint16>
3238 {
3239 for (UF::TraitConfig const& traitConfig : player->m_activePlayerData->TraitConfigs)
3240 {
3241 if (TraitConfigType(*traitConfig.Type) == TraitConfigType::Combat)
3242 {
3243 if (int32(*player->m_activePlayerData->ActiveCombatTraitConfigID) != traitConfig.ID
3245 continue;
3246 }
3247
3248 for (UF::TraitEntry const& traitEntry : traitConfig.Entries)
3249 if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
3250 return traitEntry.Rank;
3251 }
3252 return {};
3253 };
3254
3255 std::array<bool, std::tuple_size_v<decltype(condition->TraitNodeEntryID)>> results;
3256 results.fill(true);
3257 for (std::size_t i = 0; i < condition->TraitNodeEntryID.size(); ++i)
3258 {
3259 if (!condition->TraitNodeEntryID[i])
3260 continue;
3261
3262 Optional<int32> rank = getTraitNodeEntryRank(condition->TraitNodeEntryID[i]);
3263 if (!rank)
3264 results[i] = false;
3265 else if (condition->TraitNodeEntryMinRank[i] && rank < condition->TraitNodeEntryMinRank[i])
3266 results[i] = false;
3267 else if (condition->TraitNodeEntryMaxRank[i] && rank > condition->TraitNodeEntryMaxRank[i])
3268 results[i] = false;
3269 }
3270
3271 if (!PlayerConditionLogic(condition->TraitNodeEntryLogic, results))
3272 return false;
3273 }
3274
3275 return true;
3276}
3277
3278ByteBuffer HexToBytes(const std::string& hex)
3279{
3280 ByteBuffer buffer(hex.length() / 2, ByteBuffer::Resize{});
3281 Trinity::Impl::HexStrToByteArray(hex, buffer.contents(), buffer.size());
3282 return buffer;
3283}
3284
3286{
3287 // WSE_FUNCTION_NONE
3288 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3289 {
3290 return 0;
3291 },
3292
3293 // WSE_FUNCTION_RANDOM
3294 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3295 {
3296 return irand(std::min(arg1, arg2), std::max(arg1, arg2));
3297 },
3298
3299 // WSE_FUNCTION_MONTH
3300 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3301 {
3302 return GameTime::GetDateAndTime()->tm_mon + 1;
3303 },
3304
3305 // WSE_FUNCTION_DAY
3306 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3307 {
3308 return GameTime::GetDateAndTime()->tm_mday + 1;
3309 },
3310
3311 // WSE_FUNCTION_TIME_OF_DAY
3312 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3313 {
3314 tm const* localTime = GameTime::GetDateAndTime();
3315 return localTime->tm_hour * MINUTE + localTime->tm_min;
3316 },
3317
3318 // WSE_FUNCTION_REGION
3319 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3320 {
3321 return sRealmList->GetCurrentRealmId().Region;
3322 },
3323
3324 // WSE_FUNCTION_CLOCK_HOUR
3325 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3326 {
3327 uint32 currentHour = GameTime::GetDateAndTime()->tm_hour + 1;
3328 return currentHour <= 12 ? (currentHour ? currentHour : 12) : currentHour - 12;
3329 },
3330
3331 // WSE_FUNCTION_OLD_DIFFICULTY_ID
3332 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3333 {
3334 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(map->GetDifficultyID()))
3335 return difficulty->OldEnumValue;
3336
3337 return -1;
3338 },
3339
3340 // WSE_FUNCTION_HOLIDAY_START
3341 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3342 {
3343 return 0;
3344 },
3345
3346 // WSE_FUNCTION_HOLIDAY_LEFT
3347 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3348 {
3349 return 0;
3350 },
3351
3352 // WSE_FUNCTION_HOLIDAY_ACTIVE
3353 [](Map const* /*map*/, uint32 arg1, uint32 /*arg2*/) -> int32
3354 {
3355 return int32(IsHolidayActive(HolidayIds(arg1)));
3356 },
3357
3358 // WSE_FUNCTION_TIMER_CURRENT_TIME
3359 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3360 {
3361 return GameTime::GetGameTime();
3362 },
3363
3364 // WSE_FUNCTION_WEEK_NUMBER
3365 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3366 {
3367 time_t now = GameTime::GetGameTime();
3368 uint32 raidOrigin = 1135695600;
3369 if (Cfg_RegionsEntry const* region = sCfgRegionsStore.LookupEntry(sRealmList->GetCurrentRealmId().Region))
3370 raidOrigin = region->Raidorigin;
3371
3372 return (now - raidOrigin) / WEEK;
3373 },
3374
3375 // WSE_FUNCTION_UNK13
3376 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3377 {
3378 return 0;
3379 },
3380
3381 // WSE_FUNCTION_UNK14
3382 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3383 {
3384 return 0;
3385 },
3386
3387 // WSE_FUNCTION_DIFFICULTY_ID
3388 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3389 {
3390 return map->GetDifficultyID();
3391 },
3392
3393 // WSE_FUNCTION_WAR_MODE_ACTIVE
3394 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3395 {
3396 // check if current zone/map is bound to war mode
3397 return 0;
3398 },
3399
3400 // WSE_FUNCTION_UNK17
3401 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3402 {
3403 return 0;
3404 },
3405
3406 // WSE_FUNCTION_UNK18
3407 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3408 {
3409 return 0;
3410 },
3411
3412 // WSE_FUNCTION_UNK19
3413 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3414 {
3415 return 0;
3416 },
3417
3418 // WSE_FUNCTION_UNK20
3419 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3420 {
3421 return 0;
3422 },
3423
3424 // WSE_FUNCTION_UNK21
3425 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3426 {
3427 return 0;
3428 },
3429
3430 // WSE_FUNCTION_WORLD_STATE_EXPRESSION
3431 [](Map const* map, uint32 arg1, uint32 /*arg2*/) -> int32
3432 {
3433 if (WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(arg1))
3434 return ConditionMgr::IsMeetingWorldStateExpression(map, worldStateExpression);
3435
3436 return 0;
3437 },
3438
3439 // WSE_FUNCTION_KEYSTONE_AFFIX
3440 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3441 {
3442 return 0;
3443 },
3444
3445 // WSE_FUNCTION_UNK24
3446 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3447 {
3448 return 0;
3449 },
3450
3451 // WSE_FUNCTION_UNK25
3452 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3453 {
3454 return 0;
3455 },
3456
3457 // WSE_FUNCTION_UNK26
3458 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3459 {
3460 return 0;
3461 },
3462
3463 // WSE_FUNCTION_UNK27
3464 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3465 {
3466 return 0;
3467 },
3468
3469 // WSE_FUNCTION_KEYSTONE_LEVEL
3470 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3471 {
3472 return 0;
3473 },
3474
3475 // WSE_FUNCTION_UNK29
3476 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3477 {
3478 return 0;
3479 },
3480
3481 // WSE_FUNCTION_UNK30
3482 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3483 {
3484 return 0;
3485 },
3486
3487 // WSE_FUNCTION_UNK31
3488 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3489 {
3490 return 0;
3491 },
3492
3493 // WSE_FUNCTION_UNK32
3494 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3495 {
3496 return 0;
3497 },
3498
3499 // WSE_FUNCTION_MERSENNE_RANDOM
3500 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3501 {
3502 if (arg1 == 1)
3503 return 1;
3504
3505 // init with predetermined seed
3506 std::mt19937 mt(arg2 ? arg2 : 1);
3507 return mt() % arg1 + 1;
3508 },
3509
3510 // WSE_FUNCTION_UNK34
3511 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3512 {
3513 return 0;
3514 },
3515
3516 // WSE_FUNCTION_UNK35
3517 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3518 {
3519 return 0;
3520 },
3521
3522 // WSE_FUNCTION_UNK36
3523 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3524 {
3525 return 0;
3526 },
3527
3528 // WSE_FUNCTION_UI_WIDGET_DATA
3529 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3530 {
3531 return 0;
3532 },
3533
3534 // WSE_FUNCTION_TIME_EVENT_PASSED
3535 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3536 {
3537 return 0;
3538 },
3539};
3540
3542{
3544 int32 value = 0;
3545
3546 switch (valueType)
3547 {
3549 {
3550 value = buffer.read<int32>();
3551 break;
3552 }
3554 {
3555 uint32 worldStateId = buffer.read<uint32>();
3556 value = sWorldStateMgr->GetValue(worldStateId, map);
3557 break;
3558 }
3560 {
3561 uint32 functionType = buffer.read<uint32>();
3562 int32 arg1 = EvalSingleValue(buffer, map);
3563 int32 arg2 = EvalSingleValue(buffer, map);
3564
3565 if (functionType >= WSE_FUNCTION_MAX)
3566 return 0;
3567
3568 value = WorldStateExpressionFunctions[functionType](map, arg1, arg2);
3569 break;
3570 }
3571 default:
3572 break;
3573 }
3574
3575 return value;
3576}
3577
3578int32 EvalValue(ByteBuffer& buffer, Map const* map)
3579{
3580 int32 leftValue = EvalSingleValue(buffer, map);
3581
3583 if (operatorType == WorldStateExpressionOperatorType::None)
3584 return leftValue;
3585
3586 int32 rightValue = EvalSingleValue(buffer, map);
3587
3588 switch (operatorType)
3589 {
3590 case WorldStateExpressionOperatorType::Sum: return leftValue + rightValue;
3591 case WorldStateExpressionOperatorType::Substraction: return leftValue - rightValue;
3592 case WorldStateExpressionOperatorType::Multiplication: return leftValue * rightValue;
3593 case WorldStateExpressionOperatorType::Division: return !rightValue ? 0 : leftValue / rightValue;
3594 case WorldStateExpressionOperatorType::Remainder: return !rightValue ? 0 : leftValue % rightValue;
3595 default:
3596 break;
3597 }
3598
3599 return leftValue;
3600}
3601
3602bool EvalRelOp(ByteBuffer& buffer, Map const* map)
3603{
3604 int32 leftValue = EvalValue(buffer, map);
3605
3607 if (compareLogic == WorldStateExpressionComparisonType::None)
3608 return leftValue != 0;
3609
3610 int32 rightValue = EvalValue(buffer, map);
3611
3612 switch (compareLogic)
3613 {
3614 case WorldStateExpressionComparisonType::Equal: return leftValue == rightValue;
3615 case WorldStateExpressionComparisonType::NotEqual: return leftValue != rightValue;
3616 case WorldStateExpressionComparisonType::Less: return leftValue < rightValue;
3617 case WorldStateExpressionComparisonType::LessOrEqual: return leftValue <= rightValue;
3618 case WorldStateExpressionComparisonType::Greater: return leftValue > rightValue;
3619 case WorldStateExpressionComparisonType::GreaterOrEqual: return leftValue >= rightValue;
3620 default:
3621 break;
3622 }
3623
3624 return false;
3625}
3626
3628{
3629 ByteBuffer buffer = HexToBytes(expression->Expression);
3630 if (buffer.empty())
3631 return false;
3632
3633 bool enabled = buffer.read<bool>();
3634 if (!enabled)
3635 return false;
3636
3637 bool finalResult = EvalRelOp(buffer, map);
3639
3640 while (resultLogic != WorldStateExpressionLogic::None)
3641 {
3642 bool secondResult = EvalRelOp(buffer, map);
3643
3644 switch (resultLogic)
3645 {
3646 case WorldStateExpressionLogic::And: finalResult = finalResult && secondResult; break;
3647 case WorldStateExpressionLogic::Or: finalResult = finalResult || secondResult; break;
3648 case WorldStateExpressionLogic::Xor: finalResult = finalResult != secondResult; break;
3649 default:
3650 break;
3651 }
3652
3653 if (buffer.rpos() >= buffer.size())
3654 break;
3655
3656 resultLogic = buffer.read<WorldStateExpressionLogic>();
3657 }
3658
3659 return finalResult;
3660}
3661
3662int32 GetUnitConditionVariable(Unit const* unit, Unit const* otherUnit, UnitConditionVariable variable, int32 value)
3663{
3664 switch (variable)
3665 {
3667 return unit->GetRace();
3669 return unit->GetClass();
3671 return unit->GetLevel();
3673 return unit == otherUnit;
3675 return otherUnit && unit->GetCharmerOrOwnerGUID() == otherUnit->GetGUID();
3677 return otherUnit && otherUnit->GetCharmerOrOwnerGUID() == unit->GetGUID();
3679 return otherUnit && otherUnit->GetTarget() == unit->GetGUID();
3681 return otherUnit && unit->IsValidAssistTarget(otherUnit);
3683 return otherUnit && unit->IsValidAttackTarget(otherUnit);
3685 return !unit->GetCharmedGUID().IsEmpty() || !unit->GetMinionGUID().IsEmpty();
3687 if (Player const* player = unit->ToPlayer())
3688 return player->GetWeaponForAttack(BASE_ATTACK) || player->GetWeaponForAttack(OFF_ATTACK);
3689 return unit->GetVirtualItemId(0) || unit->GetVirtualItemId(1);
3691 return unit->GetHealthPct();
3693 return unit->GetPowerPct(POWER_MANA);
3695 return unit->GetPowerPct(POWER_RAGE);
3697 return unit->GetPowerPct(POWER_ENERGY);
3699 return unit->GetPower(POWER_COMBO_POINTS);
3701 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3702 {
3703 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0;
3704 }) != nullptr ? value : 0;
3706 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3707 {
3708 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3709 }) != nullptr ? value : 0;
3711 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3712 {
3713 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3714 }) != nullptr ? value : 0;
3716 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3717 {
3718 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0;
3719 }) != nullptr ? value : 0;
3721 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3722 {
3723 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3724 }) != nullptr ? value : 0;
3726 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3727 {
3728 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3729 }) != nullptr ? value : 0;
3731 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3732 {
3733 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
3734 }) != nullptr ? value : 0;
3736 break;
3738 break;
3740 break;
3742 break;
3744 break;
3746 break;
3748 break;
3750 return unit->IsInCombat();
3754 case UnitConditionVariable::IsCastingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3755 return unit->GetCurrentSpell(CURRENT_GENERIC_SPELL) != nullptr;
3757 case UnitConditionVariable::IsChannelingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3758 return unit->GetChannelSpellId() != 0;
3760 return std::count_if(unit->getAttackers().begin(), unit->getAttackers().end(), [unit](Unit* attacker)
3761 {
3762 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3763 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3764 distance += 1.0f;
3765 return unit->GetExactDistSq(attacker) < distance * distance;
3766 });
3768 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
3770 return otherUnit ? int32(unit->GetExactDist(otherUnit)) : 0;
3772 if (otherUnit)
3773 {
3774 float distance = std::max(unit->GetCombatReach() + otherUnit->GetCombatReach() + 1.3333334f, 5.0f);
3776 distance += 1.0f;
3777 return unit->GetExactDistSq(otherUnit) < distance * distance;
3778 }
3779 return 0;
3781 break;
3787 return unit->GetThreatManager().GetThreatListSize();
3789 break;
3791 break;
3793 break;
3795 break;
3797 break;
3799 break;
3801 break;
3803 break;
3805 break;
3807 return unit->getAttackers().size();
3809 return std::count_if(unit->getAttackers().begin(), unit->getAttackers().end(), [unit](Unit* attacker)
3810 {
3811 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3812 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3813 distance += 1.0f;
3814 return unit->GetExactDistSq(attacker) >= distance * distance;
3815 });
3817 return unit->GetCreatureType();
3819 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3820 {
3821 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3822 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3823 distance += 1.0f;
3824 return unit->GetExactDistSq(target) < distance * distance;
3825 }
3826 return 0;
3828 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3829 {
3830 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3831 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3832 distance += 1.0f;
3833 return unit->GetExactDistSq(target) >= distance * distance;
3834 }
3835 return 0;
3837 return unit->GetHealth();
3839 return unit->HasSpell(value) ? value : 0;
3841 return value >= 0 && value < int32(TOTAL_AURAS) && std::find_if(unit->GetAuraEffectsByType(AuraType(value)).begin(), unit->GetAuraEffectsByType(AuraType(value)).end(), [unit](AuraEffect const* aurEff)
3842 {
3843 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) != 0;
3844 }) != unit->GetAuraEffectsByType(AuraType(value)).end();
3846 break;
3848 return unit->IsPlayer();
3850 break;
3852 break;
3854 break;
3856 break;
3858 return !unit->GetCritterGUID().IsEmpty();
3860 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM].IsEmpty();
3862 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_2].IsEmpty();
3864 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_3].IsEmpty();
3866 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_4].IsEmpty();
3868 break;
3870 return unit->GetEntry();
3872 break;
3874 return unit->HasAura(value) ? value : 0;
3876 return otherUnit && unit->GetReactionTo(otherUnit) <= REP_HOSTILE;
3878 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3881 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3884 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3887 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3890 return unit->IsCreature() && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED);
3892 return unit->GetHealth() == 0;
3894 break;
3896 return unit->GetMountDisplayId() != 0;
3898 return unit->IsCreature() && unit->ToCreature()->HasLabel(value) ? value : 0;
3900 return otherUnit && (otherUnit->GetCharmerGUID() == unit->GetGUID() || otherUnit->GetCreatorGUID() == unit->GetGUID());
3902 return otherUnit && (unit->GetCharmerGUID() == otherUnit->GetGUID() || unit->GetCreatorGUID() == otherUnit->GetGUID());
3904 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
3906 return unit->GetGender();
3908 if (Optional<ContentTuningLevels> levelRange = sDB2Manager.GetContentTuningData(value, 0))
3909 return unit->GetLevel() >= levelRange->MinLevel && unit->GetLevel() <= levelRange->MaxLevel ? value : 0;
3910 return 0;
3912 return unit->IsFlying();
3914 return unit->IsHovering();
3916 return value >= 0 && value < int32(TOTAL_AURAS) && std::find_if(unit->GetAuraEffectsByType(AuraType(value)).begin(), unit->GetAuraEffectsByType(AuraType(value)).end(), [unit](AuraEffect const* aurEff)
3917 {
3918 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) == 0;
3919 }) != unit->GetAuraEffectsByType(AuraType(value)).end();
3921 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3922 {
3923 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
3924 }) != nullptr ? value : 0;
3925 default:
3926 break;
3927 }
3928
3929 return 0;
3930}
3931
3932bool ConditionMgr::IsUnitMeetingCondition(Unit const* unit, Unit const* otherUnit, UnitConditionEntry const* condition)
3933{
3934 for (size_t i = 0; i < MAX_UNIT_CONDITION_VALUES; ++i)
3935 {
3936 if (!condition->Variable[i])
3937 break;
3938
3939 int32 unitValue = GetUnitConditionVariable(unit, otherUnit, UnitConditionVariable(condition->Variable[i]), condition->Value[i]);
3940 bool meets = false;
3941 switch (UnitConditionOp(condition->Op[i]))
3942 {
3944 meets = unitValue == condition->Value[i];
3945 break;
3947 meets = unitValue != condition->Value[i];
3948 break;
3950 meets = unitValue < condition->Value[i];
3951 break;
3953 meets = unitValue <= condition->Value[i];
3954 break;
3956 meets = unitValue > condition->Value[i];
3957 break;
3959 meets = unitValue >= condition->Value[i];
3960 break;
3961 default:
3962 break;
3963 }
3964
3965 if (condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr))
3966 {
3967 if (meets)
3968 return true;
3969 }
3970 else if (!meets)
3971 return false;
3972 }
3973
3974 return !condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr);
3975}
#define sAchievementMgr
#define sAreaTriggerDataStore
@ MINUTE
Definition: Common.h:29
@ WEEK
Definition: Common.h:32
bool PlayerConditionLogic(uint32 logic, std::array< bool, N > &results)
bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
int32 GetUnitConditionVariable(Unit const *unit, Unit const *otherUnit, UnitConditionVariable variable, int32 value)
bool EvalRelOp(ByteBuffer &buffer, Map const *map)
int32 EvalSingleValue(ByteBuffer &buffer, Map const *map)
ByteBuffer HexToBytes(const std::string &hex)
int32 EvalValue(ByteBuffer &buffer, Map const *map)
std::vector< Condition > ConditionContainer
Definition: ConditionMgr.h:292
#define sConditionMgr
Definition: ConditionMgr.h:368
ConditionSourceType
Definition: ConditionMgr.h:154
@ CONDITION_SOURCE_TYPE_MAX
Definition: ConditionMgr.h:193
@ CONDITION_SOURCE_TYPE_CONVERSATION_LINE
Definition: ConditionMgr.h:184
@ CONDITION_SOURCE_TYPE_VEHICLE_SPELL
Definition: ConditionMgr.h:176
@ CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE
Definition: ConditionMgr.h:157
@ CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE
Definition: ConditionMgr.h:165
@ CONDITION_SOURCE_TYPE_TERRAIN_SWAP
Definition: ConditionMgr.h:180
@ CONDITION_SOURCE_TYPE_NPC_VENDOR
Definition: ConditionMgr.h:178
@ CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION
Definition: ConditionMgr.h:170
@ CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT
Definition: ConditionMgr.h:173
@ CONDITION_SOURCE_TYPE_REFERENCE_CONDITION
Definition: ConditionMgr.h:192
@ CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE
Definition: ConditionMgr.h:161
@ CONDITION_SOURCE_TYPE_PHASE
Definition: ConditionMgr.h:181
@ CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE
Definition: ConditionMgr.h:167
@ CONDITION_SOURCE_TYPE_SMART_EVENT
Definition: ConditionMgr.h:177
@ CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE
Definition: ConditionMgr.h:163
@ CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE
Definition: ConditionMgr.h:164
@ CONDITION_SOURCE_TYPE_AREATRIGGER_CLIENT_TRIGGERED
Definition: ConditionMgr.h:185
@ CONDITION_SOURCE_TYPE_AREATRIGGER
Definition: ConditionMgr.h:183
@ CONDITION_SOURCE_TYPE_PLAYER_CONDITION
Definition: ConditionMgr.h:189
@ CONDITION_SOURCE_TYPE_SPAWN_GROUP
Definition: ConditionMgr.h:188
@ CONDITION_SOURCE_TYPE_SPELL
Definition: ConditionMgr.h:172
@ CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE
Definition: ConditionMgr.h:158
@ CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY
Definition: ConditionMgr.h:187
@ CONDITION_SOURCE_TYPE_GOSSIP_MENU
Definition: ConditionMgr.h:169
@ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE
Definition: ConditionMgr.h:171
@ CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE
Definition: ConditionMgr.h:160
@ CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET
Definition: ConditionMgr.h:168
@ CONDITION_SOURCE_TYPE_GRAVEYARD
Definition: ConditionMgr.h:182
@ CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE
Definition: ConditionMgr.h:166
@ CONDITION_SOURCE_TYPE_TRAINER_SPELL
Definition: ConditionMgr.h:186
@ CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE
Definition: ConditionMgr.h:156
@ CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE
Definition: ConditionMgr.h:159
@ CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE
Definition: ConditionMgr.h:162
@ CONDITION_SOURCE_TYPE_SPELL_PROC
Definition: ConditionMgr.h:179
@ CONDITION_SOURCE_TYPE_QUEST_AVAILABLE
Definition: ConditionMgr.h:174
@ CONDITION_SOURCE_TYPE_NONE
Definition: ConditionMgr.h:155
@ CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED
Definition: ConditionMgr.h:191
std::array< ConditionsByEntryMap, CONDITION_SOURCE_TYPE_MAX > ConditionEntriesByTypeArray
Definition: ConditionMgr.h:294
@ INSTANCE_INFO_DATA64
Definition: ConditionMgr.h:212
@ INSTANCE_INFO_DATA
Definition: ConditionMgr.h:209
@ INSTANCE_INFO_BOSS_STATE
Definition: ConditionMgr.h:211
@ INSTANCE_INFO_GUID_DATA
Definition: ConditionMgr.h:210
@ MAX_CONDITION_TARGETS
Definition: ConditionMgr.h:217
ConditionTypes
Definition: ConditionMgr.h:60
@ CONDITION_TAXI
Definition: ConditionMgr.h:107
@ CONDITION_MAPID
Definition: ConditionMgr.h:83
@ CONDITION_SKILL
Definition: ConditionMgr.h:68
@ CONDITION_RACE
Definition: ConditionMgr.h:77
@ CONDITION_STRING_ID
Definition: ConditionMgr.h:119
@ CONDITION_PHASEID
Definition: ConditionMgr.h:87
@ CONDITION_REACTION_TO
Definition: ConditionMgr.h:95
@ CONDITION_NEAR_GAMEOBJECT
Definition: ConditionMgr.h:91
@ CONDITION_QUESTREWARDED
Definition: ConditionMgr.h:69
@ CONDITION_REALM_ACHIEVEMENT
Definition: ConditionMgr.h:100
@ CONDITION_QUEST_OBJECTIVE_PROGRESS
Definition: ConditionMgr.h:109
@ CONDITION_DAILY_QUEST_DONE
Definition: ConditionMgr.h:104
@ CONDITION_ACTIVE_EVENT
Definition: ConditionMgr.h:73
@ CONDITION_SPAWNMASK_DEPRECATED
Definition: ConditionMgr.h:80
@ CONDITION_INSTANCE_INFO
Definition: ConditionMgr.h:74
@ CONDITION_RELATION_TO
Definition: ConditionMgr.h:94
@ CONDITION_PRIVATE_OBJECT
Definition: ConditionMgr.h:118
@ CONDITION_STAND_STATE
Definition: ConditionMgr.h:103
@ CONDITION_LABEL
Definition: ConditionMgr.h:120
@ CONDITION_DRUNKENSTATE
Definition: ConditionMgr.h:71
@ CONDITION_AURA
Definition: ConditionMgr.h:62
@ CONDITION_ACHIEVEMENT
Definition: ConditionMgr.h:78
@ CONDITION_OBJECT_ENTRY_GUID
Definition: ConditionMgr.h:112
@ CONDITION_PET_TYPE
Definition: ConditionMgr.h:106
@ CONDITION_DIFFICULTY_ID
Definition: ConditionMgr.h:110
@ CONDITION_DISTANCE_TO
Definition: ConditionMgr.h:96
@ CONDITION_SCENARIO_STEP
Definition: ConditionMgr.h:115
@ CONDITION_HP_VAL
Definition: ConditionMgr.h:98
@ CONDITION_BATTLE_PET_COUNT
Definition: ConditionMgr.h:114
@ CONDITION_GENDER
Definition: ConditionMgr.h:81
@ CONDITION_GAMEMASTER
Definition: ConditionMgr.h:111
@ CONDITION_TERRAIN_SWAP
Definition: ConditionMgr.h:102
@ CONDITION_REPUTATION_RANK
Definition: ConditionMgr.h:66
@ CONDITION_HP_PCT
Definition: ConditionMgr.h:99
@ CONDITION_QUEST_COMPLETE
Definition: ConditionMgr.h:89
@ CONDITION_MAX
Definition: ConditionMgr.h:121
@ CONDITION_SPELL
Definition: ConditionMgr.h:86
@ CONDITION_ZONEID
Definition: ConditionMgr.h:65
@ CONDITION_OBJECT_ENTRY_GUID_LEGACY
Definition: ConditionMgr.h:92
@ CONDITION_CHARMED
Definition: ConditionMgr.h:105
@ CONDITION_TYPE_MASK
Definition: ConditionMgr.h:113
@ CONDITION_AREAID
Definition: ConditionMgr.h:84
@ CONDITION_IN_WATER
Definition: ConditionMgr.h:101
@ CONDITION_ITEM
Definition: ConditionMgr.h:63
@ CONDITION_WORLD_STATE
Definition: ConditionMgr.h:72
@ CONDITION_CLASS
Definition: ConditionMgr.h:76
@ CONDITION_TEAM
Definition: ConditionMgr.h:67
@ CONDITION_NONE
Definition: ConditionMgr.h:61
@ CONDITION_QUEST_NONE
Definition: ConditionMgr.h:75
@ CONDITION_QUESTSTATE
Definition: ConditionMgr.h:108
@ CONDITION_ITEM_EQUIPPED
Definition: ConditionMgr.h:64
@ CONDITION_SCENE_IN_PROGRESS
Definition: ConditionMgr.h:116
@ CONDITION_LEVEL
Definition: ConditionMgr.h:88
@ CONDITION_QUESTTAKEN
Definition: ConditionMgr.h:70
@ CONDITION_PLAYER_CONDITION
Definition: ConditionMgr.h:117
@ CONDITION_NEAR_CREATURE
Definition: ConditionMgr.h:90
@ CONDITION_TITLE
Definition: ConditionMgr.h:79
@ CONDITION_ALIVE
Definition: ConditionMgr.h:97
@ CONDITION_CREATURE_TYPE
Definition: ConditionMgr.h:85
@ CONDITION_TYPE_MASK_LEGACY
Definition: ConditionMgr.h:93
@ CONDITION_UNIT_STATE
Definition: ConditionMgr.h:82
RelationType
Definition: ConditionMgr.h:197
@ RELATION_IN_PARTY
Definition: ConditionMgr.h:199
@ RELATION_IN_RAID_OR_PARTY
Definition: ConditionMgr.h:200
@ RELATION_CREATED_BY
Definition: ConditionMgr.h:203
@ RELATION_MAX
Definition: ConditionMgr.h:204
@ RELATION_SELF
Definition: ConditionMgr.h:198
@ RELATION_PASSENGER_OF
Definition: ConditionMgr.h:202
@ RELATION_OWNED_BY
Definition: ConditionMgr.h:201
#define sConversationDataStore
DB2Storage< PhaseEntry > sPhaseStore("Phase.db2", &PhaseLoadInfo::Instance)
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< SkillLineEntry > sSkillLineStore("SkillLine.db2", &SkillLineLoadInfo::Instance)
DB2Storage< AchievementEntry > sAchievementStore("Achievement.db2", &AchievementLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< WorldStateExpressionEntry > sWorldStateExpressionStore("WorldStateExpression.db2", &WorldStateExpressionLoadInfo::Instance)
DB2Storage< CharTitlesEntry > sCharTitlesStore("CharTitles.db2", &CharTitlesLoadInfo::Instance)
DB2Storage< ChrSpecializationEntry > sChrSpecializationStore("ChrSpecialization.db2", &ChrSpecializationLoadInfo::Instance)
DB2Storage< SceneScriptPackageEntry > sSceneScriptPackageStore("SceneScriptPackage.db2", &SceneScriptPackageLoadInfo::Instance)
DB2Storage< ScenarioStepEntry > sScenarioStepStore("ScenarioStep.db2", &ScenarioStepLoadInfo::Instance)
DB2Storage< BattlePetSpeciesEntry > sBattlePetSpeciesStore("BattlePetSpecies.db2", &BattlePetSpeciesLoadInfo::Instance)
DB2Storage< AreaTriggerEntry > sAreaTriggerStore("AreaTrigger.db2", &AreaTriggerLoadInfo::Instance)
DB2Storage< Cfg_RegionsEntry > sCfgRegionsStore("Cfg_Regions.db2", &CfgRegionsLoadInfo::Instance)
DB2Storage< PlayerConditionEntry > sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:554
#define MAX_UNIT_CONDITION_VALUES
TraitConfigType
Definition: DBCEnums.h:2357
PlayerConditionLfgStatus
Definition: DBCEnums.h:1916
@ DIFFICULTY_NONE
Definition: DBCEnums.h:919
#define MAX_EFFECT_MASK
Definition: DBCEnums.h:2122
TraitCombatConfigFlags
Definition: DBCEnums.h:2328
UnitConditionVariable
Definition: DBCEnums.h:2488
WorldStateExpressionFunctions
Definition: DBCEnums.h:2713
@ WSE_FUNCTION_MAX
Definition: DBCEnums.h:2754
WorldStateExpressionValueType
Definition: DBCEnums.h:2677
UnitConditionOp
Definition: DBCEnums.h:2478
WorldStateExpressionComparisonType
Definition: DBCEnums.h:2692
WorldStateExpressionLogic
Definition: DBCEnums.h:2684
WorldStateExpressionOperatorType
Definition: DBCEnums.h:2703
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define ABORT_MSG
Definition: Errors.h:75
#define ASSERT
Definition: Errors.h:68
bool IsHolidayActive(HolidayIds id)
#define sGameEventMgr
Definition: GameEventMgr.h:177
@ GRID_MAP_TYPE_MASK_PLAYER
Definition: GridDefines.h:80
@ GRID_MAP_TYPE_MASK_CREATURE
Definition: GridDefines.h:77
@ GRID_MAP_TYPE_MASK_ALL
Definition: GridDefines.h:84
@ GRID_MAP_TYPE_MASK_GAMEOBJECT
Definition: GridDefines.h:79
@ GRID_MAP_TYPE_MASK_CORPSE
Definition: GridDefines.h:76
@ GRID_MAP_TYPE_MASK_AREATRIGGER
Definition: GridDefines.h:81
EncounterState
#define sLFGMgr
Definition: LFGMgr.h:512
#define sLanguageMgr
Definition: LanguageMgr.h:97
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition: Log.h:179
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
#define TC_LOG_INFO(filterType__, message__,...)
Definition: Log.h:182
LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false)
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true)
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
LootStore LootTemplates_Item("item_loot_template", "item entry", true)
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true)
LootStore LootTemplates_Reference("reference_loot_template", "reference id", false)
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true)
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true)
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false)
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true)
@ TYPEID_AREATRIGGER
Definition: ObjectGuid.h:48
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:45
@ TYPEID_UNIT
Definition: ObjectGuid.h:42
@ TYPEID_CORPSE
Definition: ObjectGuid.h:47
@ TYPEID_PLAYER
Definition: ObjectGuid.h:43
@ TYPEMASK_UNIT
Definition: ObjectGuid.h:62
@ TYPEMASK_CORPSE
Definition: ObjectGuid.h:67
@ TYPEMASK_GAMEOBJECT
Definition: ObjectGuid.h:65
@ TYPEMASK_PLAYER
Definition: ObjectGuid.h:63
@ TYPEMASK_AREATRIGGER
Definition: ObjectGuid.h:68
#define NUM_CLIENT_OBJECT_TYPES
Definition: ObjectGuid.h:53
#define sObjectMgr
Definition: ObjectMgr.h:1986
std::pair< GossipMenusContainer::iterator, GossipMenusContainer::iterator > GossipMenusMapBoundsNonConst
Definition: ObjectMgr.h:783
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ MAX_PET_TYPE
Definition: PetDefines.h:33
@ EQUIPMENT_SLOT_MAINHAND
Definition: Player.h:669
#define INVENTORY_SLOT_BAG_0
Definition: Player.h:648
@ DRUNKEN_SMASHED
Definition: Player.h:444
#define MAX_QUEST_LOG_SIZE
Definition: QuestDef.h:45
QuestStatus
Definition: QuestDef.h:145
@ QUEST_STATUS_REWARDED
Definition: QuestDef.h:152
@ QUEST_STATUS_FAILED
Definition: QuestDef.h:151
@ QUEST_STATUS_INCOMPLETE
Definition: QuestDef.h:149
@ QUEST_STATUS_NONE
Definition: QuestDef.h:146
@ MAX_QUEST_STATUS
Definition: QuestDef.h:153
@ QUEST_STATUS_COMPLETE
Definition: QuestDef.h:147
int32 irand(int32 min, int32 max)
Definition: Random.cpp:35
#define sRealmList
Definition: RealmList.h:93
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition: ScriptMgr.h:1417
SpellEffIndex
Definition: SharedDefines.h:29
Language
Gender
@ CREATURE_TYPE_GAS_CLOUD
@ TEAM_ALLIANCE
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY
@ SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY_NONRANDOM
@ SPELL_EFFECT_APPLY_AURA_ON_PET
@ SPELL_EFFECT_APPLY_AREA_AURA_PET
@ SPELL_EFFECT_APPLY_AREA_AURA_RAID
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
@ SPELL_EFFECT_APPLY_AREA_AURA_SUMMONS
@ SPELL_EFFECT_APPLY_AREA_AURA_OWNER
@ SUMMON_SLOT_TOTEM
@ SUMMON_SLOT_TOTEM_4
@ SUMMON_SLOT_TOTEM_3
@ SUMMON_SLOT_TOTEM_2
@ OFF_ATTACK
@ BASE_ATTACK
Team
@ ALLIANCE
@ HORDE
Powers
@ POWER_RAGE
@ POWER_ENERGY
@ POWER_COMBO_POINTS
@ POWER_MANA
ReputationRank
@ REP_HOSTILE
#define CLASSMASK_ALL_PLAYABLE
HolidayIds
@ SPAWNGROUP_FLAG_SYSTEM
Definition: SpawnData.h:55
AuraType
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_COMPREHEND_LANGUAGE
@ TOTAL_AURAS
@ AFLAG_NEGATIVE
@ TARGET_SELECT_CATEGORY_CONE
Definition: SpellInfo.h:47
@ TARGET_SELECT_CATEGORY_AREA
Definition: SpellInfo.h:48
@ TARGET_SELECT_CATEGORY_NEARBY
Definition: SpellInfo.h:46
@ TARGET_SELECT_CATEGORY_LINE
Definition: SpellInfo.h:50
@ TARGET_SELECT_CATEGORY_TRAJ
Definition: SpellInfo.h:49
#define sSpellMgr
Definition: SpellMgr.h:855
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
UnitStandStateType
Definition: UnitDefines.h:41
@ UNIT_STAND_STATE_SUBMERGED
Definition: UnitDefines.h:51
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:386
@ MOVEMENTFLAG_STRAFE_LEFT
Definition: UnitDefines.h:388
@ MOVEMENTFLAG_BACKWARD
Definition: UnitDefines.h:387
@ MOVEMENTFLAG_STRAFE_RIGHT
Definition: UnitDefines.h:389
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:170
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:594
@ UNIT_STATE_ALL_STATE_SUPPORTED
Definition: Unit.h:289
bool CompareValues(ComparisionType type, T val1, T val2)
Definition: Util.h:506
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:528
ComparisionType
Definition: Util.h:496
@ COMP_TYPE_MAX
Definition: Util.h:502
#define sWorldStateMgr
Definition: WorldStateMgr.h:50
uint16 GetFlags() const
Definition: SpellAuras.h:83
Aura * GetBase() const
Definition: SpellAuras.h:80
uint32 GetEffectMask() const
Definition: SpellAuras.h:84
Aura * GetBase() const
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
SpellInfo const * GetSpellInfo() const
Definition: SpellAuras.h:137
size_t rpos() const
Definition: ByteBuffer.h:425
size_t size() const
Definition: ByteBuffer.h:566
bool empty() const
Definition: ByteBuffer.h:567
uint8 * contents()
Definition: ByteBuffer.h:552
bool isConditionTypeValid(Condition *cond) const
bool IsSpellUsedInSpellClickConditions(uint32 spellId) const
std::unordered_set< uint32 > SpellsUsedInSpellClickConditions
Definition: ConditionMgr.h:365
void addToLootTemplate(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions, LootTemplate *loot) const
bool IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const *player, Creature const *vendor) const
bool IsObjectMeetToConditions(WorldObject const *object, ConditionContainer const &conditions) const
bool isSourceTypeValid(Condition *cond) const
uint32 GetSearcherTypeMaskForConditionList(ConditionContainer const &conditions) const
bool IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, ConditionSourceInfo &sourceInfo) const
static ConditionMgr * instance()
static bool IsMeetingWorldStateExpression(Map const *map, WorldStateExpressionEntry const *expression)
void addToGraveyardData(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions) const
bool HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const
bool IsObjectMeetToConditionList(ConditionSourceInfo &sourceInfo, ConditionContainer const &conditions) const
bool IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const *clicker, WorldObject const *target) const
static bool IsUnitMeetingCondition(Unit const *unit, Unit const *otherUnit, UnitConditionEntry const *condition)
bool HasConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const
static void LogUselessConditionValue(Condition const *cond, uint8 index, uint32 value)
bool IsMapMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, Map const *map) const
bool IsObjectMeetingTrainerSpellConditions(uint32 trainerId, uint32 spellId, Player *player) const
ConditionEntriesByTypeArray ConditionStore
Definition: ConditionMgr.h:363
ConditionContainer const * GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const
void addToSpellImplicitTargetConditions(Condition const &cond) const
static bool IsPlayerMeetingCondition(Player const *player, uint32 conditionId)
bool IsObjectMeetingVisibilityByObjectIdConditions(WorldObject const *obj, WorldObject const *seer) const
void addToPhases(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions) const
bool IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const *unit, WorldObject const *baseObject) const
static bool CanHaveSourceGroupSet(ConditionSourceType sourceType)
void addToGossipMenuItems(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions) const
void addToGossipMenus(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions) const
static char const *const StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED]
Definition: ConditionMgr.h:345
static uint32 GetPlayerConditionLfgValue(Player const *player, PlayerConditionLfgStatus status)
static bool CanHaveConditionType(ConditionSourceType sourceType, ConditionTypes conditionType)
static bool CanHaveSourceIdSet(ConditionSourceType sourceType)
static ConditionTypeInfo const StaticConditionTypeData[CONDITION_MAX]
Definition: ConditionMgr.h:346
bool IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const *player, Unit const *vehicle) const
void LoadConditions(bool isReload=false)
bool HasLabel(int32 cretureLabel) const
Definition: Creature.cpp:3352
static bool IsInArea(uint32 objectAreaId, uint32 areaId)
Definition: DB2Stores.cpp:1980
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
Class used to access individual fields of database query result.
Definition: Field.h:93
uint8 GetUInt8() const
Definition: Field.cpp:29
std::string GetString() const
Definition: Field.cpp:125
bool GetBool() const
Definition: Field.h:101
uint32 GetUInt32() const
Definition: Field.cpp:61
int32 GetInt32() const
Definition: Field.cpp:69
std::vector< GameEventData > GameEventDataMap
Definition: GameEventMgr.h:103
Definition: Group.h:205
bool isRaidGroup() const
Definition: Group.cpp:1637
Definition: Item.h:170
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1179
LootTemplate * GetLootForConditionFill(uint32 loot_id)
Definition: LootMgr.cpp:207
bool HaveLootFor(uint32 loot_id) const
Definition: LootMgr.h:94
bool LinkConditions(ConditionId const &id, ConditionsReference reference)
Definition: LootMgr.cpp:986
Definition: Map.h:223
bool IsBattlegroundOrArena() const
Definition: Map.cpp:3318
BattlegroundMap * ToBattlegroundMap()
Definition: Map.h:491
Difficulty GetDifficultyID() const
Definition: Map.h:358
uint32 GetId() const
Definition: Map.cpp:3206
InstanceMap * ToInstanceMap()
Definition: Map.h:488
WeatherState GetZoneWeather(uint32 zoneId) const
Definition: Map.cpp:3959
bool IsEmpty() const
Definition: ObjectGuid.h:322
std::string ToString() const
Definition: ObjectGuid.cpp:757
static Creature * ToCreature(Object *o)
Definition: Object.h:255
bool IsPlayer() const
Definition: Object.h:248
static Unit * ToUnit(Object *o)
Definition: Object.h:261
static GameObject * ToGameObject(Object *o)
Definition: Object.h:267
TypeID GetTypeId() const
Definition: Object.h:209
uint32 GetEntry() const
Definition: Object.h:197
bool IsCreature() const
Definition: Object.h:254
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:195
static Player * ToPlayer(Object *o)
Definition: Object.h:249
Definition: Pet.h:40
static bool InDbPhaseShift(WorldObject const *object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1932
UF::UpdateField< UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER > m_playerData
Definition: Player.h:2967
Gender GetNativeGender() const override
Definition: Player.h:1286
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6050
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition: Player.h:2968
uint16 FindQuestSlot(uint32 quest_id) const
Definition: Player.cpp:16424
bool IsQuestCompletedBitSet(uint32 questId) const
Definition: Player.cpp:16553
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14659
uint32 GetItemCount(uint32 item, bool inBankAlso=false, Item *skipItem=nullptr) const
Definition: Player.cpp:9584
bool HasAchieved(uint32 achievementId) const
Definition: Player.cpp:27212
WorldSession * GetSession() const
Definition: Player.h:2195
Item * GetItemByPos(uint16 pos) const
Definition: Player.cpp:9655
bool ModifierTreeSatisfied(uint32 modifierTreeId) const
Definition: Player.cpp:27250
TeamId GetTeamId() const
Definition: Player.h:2335
bool HasExploredZone(uint32 areaId) const
Definition: Player.cpp:6436
bool IsGameMaster() const
Definition: Player.h:1247
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:16010
static bool IsValidGender(uint8 Gender)
Definition: Player.h:1798
ReputationRank GetReputationRank(uint32 faction_id) const
Definition: Player.cpp:6529
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3794
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2708
int32 GetQuestSlotObjectiveData(uint16 slot, QuestObjective const &objective) const
Definition: Player.cpp:16462
ChrSpecializationEntry const * GetPrimarySpecializationEntry() const
Definition: Player.cpp:30398
ReputationMgr & GetReputationMgr()
Definition: Player.h:2350
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition: Player.cpp:873
uint32 GetCurrencyQuantity(uint32 id) const
Definition: Player.cpp:7407
QuestObjectives const & GetObjectives() const
Definition: QuestDef.h:665
ReputationRank const * GetForcedRankIfAny(FactionTemplateEntry const *factionTemplateEntry) const
bool IsAura() const
Definition: SpellInfo.cpp:461
::Difficulty const Difficulty
Definition: SpellInfo.h:323
uint32 Dispel
Definition: SpellInfo.h:325
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2527
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
Definition: SpellInfo.cpp:2557
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition: SpellInfo.h:581
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:580
size_t GetThreatListSize() const
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition: IteratorPair.h:32
Definition: Unit.h:631
uint32 GetChannelSpellId() const
Definition: Unit.h:1414
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1333
float GetHealthPct() const
Definition: Unit.h:792
uint32 GetUnitMovementFlags() const
Definition: Unit.h:1707
ThreatManager & GetThreatManager()
Definition: Unit.h:1073
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4756
uint8 GetClass() const
Definition: Unit.h:760
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition: Unit.h:1491
uint32 GetClassMask() const
Definition: Unit.h:762
uint32 GetMountDisplayId() const
Definition: Unit.h:908
ObjectGuid GetOwnerGUID() const override
Definition: Unit.h:1182
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:841
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1202
float GetCombatReach() const override
Definition: Unit.h:701
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9791
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1207
virtual bool HasSpell(uint32) const
Definition: Unit.h:1079
ObjectGuid GetCreatorGUID() const override
Definition: Unit.h:1184
bool IsOnVehicle(Unit const *vehicle) const
Definition: Unit.cpp:11859
Gender GetGender() const
Definition: Unit.h:763
uint32 GetCreatureType() const
Definition: Unit.cpp:9227
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition: Unit.cpp:4792
uint32 GetVirtualItemId(uint32 slot) const
Definition: Unit.cpp:13996
uint32 GetAuraCount(uint32 spellId) const
Definition: Unit.cpp:4717
bool IsHovering() const
Definition: Unit.h:1146
ObjectGuid GetMinionGUID() const
Definition: Unit.h:1186
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:1706
uint64 GetHealth() const
Definition: Unit.h:784
AttackerSet const & getAttackers() const
Definition: Unit.h:720
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:4743
ObjectGuid GetCritterGUID() const
Definition: Unit.h:1190
uint32 GetExtraUnitMovementFlags() const
Definition: Unit.h:1713
int32 GetPower(Powers power) const
Definition: Unit.cpp:9782
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11930
float GetPowerPct(Powers power) const
Definition: Unit.h:816
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4733
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1199
bool IsFlying() const
Definition: Unit.h:1779
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4575
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11911
ObjectGuid GetTarget() const
Definition: Unit.h:1803
uint8 GetLevel() const
Definition: Unit.h:753
uint8 GetRace() const
Definition: Unit.h:757
bool IsInCombat() const
Definition: Unit.h:1053
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1456
constexpr uint32 GetMapId() const
Definition: Position.h:215
Map * GetMap() const
Definition: Object.h:762
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3105
ReputationRank GetReactionTo(WorldObject const *target) const
Definition: Object.cpp:2804
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3258
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1143
uint32 GetAreaId() const
Definition: Object.h:684
uint32 GetZoneId() const
Definition: Object.h:683
uint8 GetExpansion() const
void SetPackedTime(uint32 packedTime)
Definition: WowTime.cpp:34
bool IsInRange(WowTime const &from, WowTime const &to) const
Definition: WowTime.cpp:173
virtual uint32 GetData(uint32) const
Definition: ZoneScript.h:99
virtual uint64 GetData64(uint32) const
Definition: ZoneScript.h:95
#define sWorld
Definition: World.h:927
WeatherState
Definition: Weather.h:46
@ CONFIG_EXPANSION
Definition: World.h:307
ObjectData const creatureData[]
@ DEFAULT_MAX_BATTLE_PETS_PER_SPECIES
Definition: BattlePetMgr.h:32
WowTime const * GetWowTime()
Definition: GameTime.cpp:97
tm const * GetDateAndTime()
Definition: GameTime.cpp:87
time_t GetGameTime()
Definition: GameTime.cpp:44
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_COMMON_API void HexStrToByteArray(std::string_view str, uint8 *out, size_t outlen, bool reverse=false)
Definition: Util.cpp:837
constexpr TypeMask ConvertLegacyTypeMask(uint32 legacyTypeMask)
Definition: ObjectGuid.h:489
constexpr ::TypeID ConvertLegacyTypeID(TypeID legacyTypeID)
Definition: ObjectGuid.h:458
void hash_combine(std::size_t &seed, T const &val)
Definition: Hash.h:28
constexpr std::size_t size()
Definition: UpdateField.h:769
TC_PROTO_API ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FieldOptions, ::google::protobuf::internal::MessageTypeTraits< ::bgs::protocol::FieldRestriction >, 11, false > valid
uint16 ParentAreaID
Definition: DB2Structure.h:131
EnumFlag< AreaFlags > GetFlags() const
Definition: DB2Structure.h:153
EnumFlag< ChrSpecializationFlag > GetFlags() const
Definition: DB2Structure.h:895
ChrSpecializationRole GetRole() const
Definition: DB2Structure.h:896
std::size_t GetHash() const
uint32 SourceGroup
Definition: ConditionMgr.h:231
uint32 SourceId
Definition: ConditionMgr.h:233
int32 SourceEntry
Definition: ConditionMgr.h:232
ConditionSourceInfo(WorldObject const *target0, WorldObject const *target1=nullptr, WorldObject const *target2=nullptr)
Condition const * mLastFailedCondition
Definition: ConditionMgr.h:224
WorldObject const * mConditionTargets[MAX_CONDITION_TARGETS]
Definition: ConditionMgr.h:222
Map const * mConditionMap
Definition: ConditionMgr.h:223
uint32 SourceGroup
Definition: ConditionMgr.h:249
ConditionTypes ConditionType
Definition: ConditionMgr.h:253
std::string ToString(bool ext=false) const
std::string ConditionStringValue1
Definition: ConditionMgr.h:257
uint32 GetSearcherTypeMaskForCondition() const
uint32 ErrorType
Definition: ConditionMgr.h:258
uint32 SourceId
Definition: ConditionMgr.h:251
int32 SourceEntry
Definition: ConditionMgr.h:250
uint32 ElseGroup
Definition: ConditionMgr.h:252
uint32 ScriptId
Definition: ConditionMgr.h:261
bool NegativeCondition
Definition: ConditionMgr.h:263
ConditionSourceType SourceType
Definition: ConditionMgr.h:248
uint32 ConditionValue2
Definition: ConditionMgr.h:255
uint8 ConditionTarget
Definition: ConditionMgr.h:262
uint32 ReferenceId
Definition: ConditionMgr.h:260
uint32 ErrorTextId
Definition: ConditionMgr.h:259
uint32 ConditionValue3
Definition: ConditionMgr.h:256
uint32 GetMaxAvailableConditionTargets() const
uint32 ConditionValue1
Definition: ConditionMgr.h:254
bool Meets(ConditionSourceInfo &sourceInfo) const
uint32 GetSubClass() const
Definition: ItemTemplate.h:819
std::array< int32, 4 > AuraSpellID
std::array< int32, 4 > TraitNodeEntryID
std::array< uint32, 4 > ItemCount
std::array< uint32, 2 > Time
std::array< uint32, 4 > LfgValue
std::array< uint8, 4 > LfgCompare
std::array< uint16, 4 > MaxSkill
std::array< uint16, 4 > TraitNodeEntryMaxRank
std::array< uint16, 4 > Achievement
uint32 CurrentCompletedQuestLogic
std::array< int32, 4 > CurrentCompletedQuestID
std::array< uint8, 4 > LfgStatus
std::array< int32, 4 > PrevQuestID
std::array< int32, 4 > CurrQuestID
std::array< uint16, 4 > SkillID
std::array< int32, 2 > MovementFlags
std::array< uint16, 2 > Explored
std::array< uint32, 3 > MinFactionID
std::array< uint32, 4 > CurrencyCount
std::array< uint8, 4 > AuraStacks
std::array< uint16, 4 > AreaID
std::array< uint32, 6 > QuestKillMonster
std::array< uint16, 4 > MinSkill
std::array< uint8, 3 > MinReputation
std::array< uint16, 4 > TraitNodeEntryMinRank
std::array< int32, 4 > ItemID
Trinity::RaceMask< int64 > RaceMask
std::array< int32, 4 > SpellID
std::array< uint32, 4 > CurrencyID
float GetExactDist(float x, float y, float z) const
Definition: Position.h:128
constexpr float GetExactDistSq(float x, float y, float z) const
Definition: Position.h:120
bool IsStoringFlag() const
Definition: QuestDef.h:511
uint32 QuestID
Definition: QuestDef.h:478
int32 Amount
Definition: QuestDef.h:482
SpawnGroupFlags flags
Definition: SpawnData.h:71
constexpr bool HasRace(uint8 raceId) const
Definition: RaceMask.h:95
constexpr bool IsEmpty() const
Definition: RaceMask.h:154
UpdateField< int32, 4, 6 > Type
Definition: UpdateFields.h:818
DynamicUpdateField< UF::TraitEntry, 0, 1 > Entries
Definition: UpdateFields.h:814
UpdateField< int32, 0, 3 > ID
Definition: UpdateFields.h:816
UpdateField< int32, 8, 10 > CombatConfigFlags
Definition: UpdateFields.h:821
int32 TraitNodeEntryID
Definition: UpdateFields.h:790
EnumFlag< UnitConditionFlags > GetFlags() const
std::array< int32, MAX_UNIT_CONDITION_VALUES > Value
std::array< uint8, MAX_UNIT_CONDITION_VALUES > Variable
std::array< uint8, MAX_UNIT_CONDITION_VALUES > Op
Reward info.
Definition: LFGMgr.h:234