TrinityCore
Loading...
Searching...
No Matches
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 "CollectionMgr.h"
25#include "Containers.h"
27#include "DB2Stores.h"
28#include "DatabaseEnv.h"
29#include "GameEventMgr.h"
30#include "GameObject.h"
31#include "GameTime.h"
32#include "Group.h"
33#include "InstanceScenario.h"
34#include "InstanceScript.h"
35#include "Item.h"
36#include "LFGMgr.h"
37#include "LanguageMgr.h"
38#include "Log.h"
39#include "LootMgr.h"
40#include "Map.h"
41#include "ObjectAccessor.h"
42#include "ObjectMgr.h"
43#include "Pet.h"
44#include "PhasingHandler.h"
45#include "Player.h"
46#include "PlayerChoice.h"
47#include "RaceMask.h"
48#include "RealmList.h"
49#include "ReputationMgr.h"
50#include "ScriptMgr.h"
51#include "Spell.h"
52#include "SpellAuraEffects.h"
53#include "SpellAuras.h"
54#include "SpellMgr.h"
55#include "World.h"
56#include "WorldSession.h"
57#include "WorldStateMgr.h"
58#include "WowTime.h"
59#include <random>
60
62{
63 "None",
64 "Creature Loot",
65 "Disenchant Loot",
66 "Fishing Loot",
67 "GameObject Loot",
68 "Item Loot",
69 "Mail Loot",
70 "Milling Loot",
71 "Pickpocketing Loot",
72 "Prospecting Loot",
73 "Reference Loot",
74 "Skinning Loot",
75 "Spell Loot",
76 "Spell Impl. Target",
77 "Gossip Menu",
78 "Gossip Menu Option",
79 "Creature Vehicle",
80 "Spell Expl. Target",
81 "Spell Click Event",
82 "Quest Available",
83 "Unused",
84 "Vehicle Spell",
85 "SmartScript",
86 "Npc Vendor",
87 "Spell Proc",
88 "Terrain Swap",
89 "Phase",
90 "Graveyard",
91 "AreaTrigger",
92 "ConversationLine",
93 "AreaTrigger Client Triggered",
94 "Trainer Spell",
95 "Object Visibility (by ID)",
96 "Spawn Group",
97 "Player Condition",
98 "Skill Line Ability",
99 "Player Choice Response"
100};
101
103{
104 { .Name = "None", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
105 { .Name = "Aura", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
106 { .Name = "Item Stored", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
107 { .Name = "Item Equipped", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
108 { .Name = "Zone", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
109 { .Name = "Reputation", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
110 { .Name = "Team", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
111 { .Name = "Skill", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
112 { .Name = "Quest Rewarded", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
113 { .Name = "Quest Taken", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
114 { .Name = "Drunken", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
115 { .Name = "WorldState", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
116 { .Name = "Active Event", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
117 { .Name = "Instance Info", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
118 { .Name = "Quest None", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
119 { .Name = "Class", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
120 { .Name = "Race", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
121 { .Name = "Achievement", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
122 { .Name = "Title", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
123 { .Name = "SpawnMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
124 { .Name = "Gender", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
125 { .Name = "Unit State", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
126 { .Name = "Map", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
127 { .Name = "Area", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
128 { .Name = "CreatureType", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
129 { .Name = "Spell Known", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
130 { .Name = "Phase", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
131 { .Name = "Level", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
132 { .Name = "Quest Completed", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
133 { .Name = "Near Creature", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
134 { .Name = "Near GameObject", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
135 { .Name = "Object Entry or Guid", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
136 { .Name = "Object TypeMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
137 { .Name = "Relation", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
138 { .Name = "Reaction", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
139 { .Name = "Distance", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
140 { .Name = "Alive", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
141 { .Name = "Health Value", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
142 { .Name = "Health Pct", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
143 { .Name = "Realm Achievement", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
144 { .Name = "In Water", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
145 { .Name = "Terrain Swap", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
146 { .Name = "Sit/stand state", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
147 { .Name = "Daily Quest Completed", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
148 { .Name = "Charmed", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
149 { .Name = "Pet type", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
150 { .Name = "On Taxi", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
151 { .Name = "Quest state mask", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
152 { .Name = "Quest objective progress", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
153 { .Name = "Map Difficulty", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
154 { .Name = "Is Gamemaster", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
155 { .Name = "Object Entry or Guid", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
156 { .Name = "Object TypeMask", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
157 { .Name = "BattlePet Species Learned", .HasConditionValue1 = true, .HasConditionValue2 = true, .HasConditionValue3 = true, .HasConditionStringValue1 = false },
158 { .Name = "On Scenario Step", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
159 { .Name = "Scene In Progress", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
160 { .Name = "Player Condition", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
161 { .Name = "Private Object", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
162 { .Name = "String ID", .HasConditionValue1 = false, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = true },
163 { .Name = "Label", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false },
164 { .Name = "Group status", .HasConditionValue1 = true, .HasConditionValue2 = false, .HasConditionValue3 = false, .HasConditionStringValue1 = false }
165};
166
167static bool MeetsGroupStatusCondition(Player const* player, GroupStatusCondition status)
168{
169 Group const* group = player->GetGroup();
170 switch (status)
171 {
173 return group == nullptr;
175 return group != nullptr;
177 return group && !group->isRaidGroup();
179 return group && group->isRaidGroup();
181 return !group || !group->isRaidGroup();
182 }
183 return false;
184}
185
186ConditionSourceInfo::ConditionSourceInfo(WorldObject const* target0, WorldObject const* target1, WorldObject const* target2) :
187 mConditionTargets({ target0, target1, target2 }),
188 mConditionMap(nullptr),
189 mLastFailedCondition(nullptr)
190{
191 if (WorldObject const* target = Coalesce<WorldObject const>(target0, target1, target2))
192 mConditionMap = target->GetMap();
193}
194
196 mConditionTargets(),
197 mConditionMap(map),
198 mLastFailedCondition(nullptr)
199{
200}
201
202std::size_t ConditionId::GetHash() const
203{
207 hash.UpdateData(SourceId);
208 return hash.Value;
209}
210
211// Checks if object meets the condition
212// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI)
214{
216
217 Map const* map = sourceInfo.mConditionMap;
218 bool condMeets = false;
219 bool needsObject = false;
220 switch (ConditionType)
221 {
222 case CONDITION_NONE:
223 condMeets = true; // empty condition, always met
224 break;
226 condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1);
227 break;
229 {
230 if (InstanceMap const* instanceMap = map->ToInstanceMap())
231 {
232 if (InstanceScript const* instance = instanceMap->GetInstanceScript())
233 {
234 switch (ConditionValue3)
235 {
237 condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
238 break;
240 condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
241 break;
243 condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
244 break;
245 default:
246 condMeets = false;
247 break;
248 }
249 }
250 }
251 else if (BattlegroundMap const* bgMap = map->ToBattlegroundMap())
252 {
253 ZoneScript const* zoneScript = bgMap->GetBattlegroundScript();
254 switch (ConditionValue3)
255 {
257 condMeets = zoneScript->GetData(ConditionValue1) == ConditionValue2;
258 break;
260 condMeets = zoneScript->GetData64(ConditionValue1) == ConditionValue2;
261 break;
262 default:
263 condMeets = false;
264 break;
265 }
266 }
267 break;
268 }
269 case CONDITION_MAPID:
270 condMeets = map->GetId() == ConditionValue1;
271 break;
273 {
275 break;
276 }
278 {
279 AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
280 if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
281 condMeets = true;
282 break;
283 }
285 {
286 condMeets = map->GetDifficultyID() == int32(ConditionValue1);
287 break;
288 }
290 {
291 if (InstanceMap const* instanceMap = map->ToInstanceMap())
292 if (Scenario const* scenario = instanceMap->GetInstanceScenario())
293 if (ScenarioStepEntry const* step = scenario->GetStep())
294 condMeets = step->ID == ConditionValue1;
295 break;
296 }
297 default:
298 needsObject = true;
299 break;
300 }
301
302 WorldObject const* object = sourceInfo.mConditionTargets[ConditionTarget];
303 // object not present, return false
304 if (needsObject && !object)
305 {
306 TC_LOG_DEBUG("condition", "Condition object not found for {}", *this);
307 return false;
308 }
309 switch (ConditionType)
310 {
311 case CONDITION_AURA:
312 {
313 if (Unit const* unit = object->ToUnit())
314 condMeets = unit->HasAuraEffect(ConditionValue1, ConditionValue2);
315 break;
316 }
317 case CONDITION_ITEM:
318 {
319 if (Player const* player = object->ToPlayer())
320 {
321 // don't allow 0 items (it's checked during table load)
323 bool checkBank = ConditionValue3 ? true : false;
324 condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
325 }
326 break;
327 }
329 {
330 if (Player const* player = object->ToPlayer())
331 condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1);
332 break;
333 }
334 case CONDITION_ZONEID:
335 condMeets = object->GetZoneId() == ConditionValue1;
336 break;
338 {
339 if (Player const* player = object->ToPlayer())
340 {
341 if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1))
342 condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))) != 0;
343 }
344 break;
345 }
347 {
348 if (Player const* player = object->ToPlayer())
349 condMeets = player->HasAchieved(ConditionValue1);
350 break;
351 }
352 case CONDITION_TEAM:
353 {
354 if (Player const* player = object->ToPlayer())
355 condMeets = player->GetTeam() == Team(ConditionValue1);
356 break;
357 }
358 case CONDITION_CLASS:
359 {
360 if (Unit const* unit = object->ToUnit())
361 condMeets = (unit->GetClassMask() & ConditionValue1) != 0;
362 break;
363 }
364 case CONDITION_RACE:
365 {
366 if (Unit const* unit = object->ToUnit())
367 condMeets = Trinity::RaceMask<uint32>{ ConditionValue1 }.HasRace(unit->GetRace());
368 break;
369 }
370 case CONDITION_GENDER:
371 {
372 if (Player const* player = object->ToPlayer())
373 condMeets = player->GetNativeGender() == Gender(ConditionValue1);
374 break;
375 }
376 case CONDITION_SKILL:
377 {
378 if (Player const* player = object->ToPlayer())
379 condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2;
380 break;
381 }
383 {
384 if (Player const* player = object->ToPlayer())
385 condMeets = player->GetQuestRewardStatus(ConditionValue1);
386 break;
387 }
389 {
390 if (Player const* player = object->ToPlayer())
391 {
392 QuestStatus status = player->GetQuestStatus(ConditionValue1);
393 condMeets = (status == QUEST_STATUS_INCOMPLETE);
394 }
395 break;
396 }
398 {
399 if (Player const* player = object->ToPlayer())
400 {
401 QuestStatus status = player->GetQuestStatus(ConditionValue1);
402 condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1));
403 }
404 break;
405 }
407 {
408 if (Player const* player = object->ToPlayer())
409 {
410 QuestStatus status = player->GetQuestStatus(ConditionValue1);
411 condMeets = (status == QUEST_STATUS_NONE);
412 }
413 break;
414 }
415 case CONDITION_AREAID:
416 condMeets = DB2Manager::IsInArea(object->GetAreaId(), ConditionValue1);
417 break;
418 case CONDITION_SPELL:
419 {
420 if (Player const* player = object->ToPlayer())
421 condMeets = player->HasSpell(ConditionValue1);
422 break;
423 }
424 case CONDITION_LEVEL:
425 {
426 if (Unit const* unit = object->ToUnit())
427 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), static_cast<uint32>(unit->GetLevel()), ConditionValue1);
428 break;
429 }
431 {
432 if (Player const* player = object->ToPlayer())
433 condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1;
434 break;
435 }
437 {
438 condMeets = object->FindNearestCreature(ConditionValue1, (float)ConditionValue2, bool(!ConditionValue3)) != nullptr;
439 break;
440 }
442 {
443 condMeets = object->FindNearestGameObject(ConditionValue1, (float)ConditionValue2) != nullptr;
444 break;
445 }
447 {
448 if (uint32(object->GetTypeId()) == ConditionValue1)
449 {
450 condMeets = !ConditionValue2 || (object->GetEntry() == ConditionValue2);
451
452 if (ConditionValue3)
453 {
454 switch (object->GetTypeId())
455 {
456 case TYPEID_UNIT:
457 condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3;
458 break;
460 condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3;
461 break;
462 default:
463 break;
464 }
465 }
466 }
467 break;
468 }
470 {
471 condMeets = object->isType(TypeMask(ConditionValue1));
472 break;
473 }
475 {
476 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
477 {
478 Unit const* toUnit = toObject->ToUnit();
479 Unit const* unit = object->ToUnit();
480 if (toUnit && unit)
481 {
482 switch (static_cast<RelationType>(ConditionValue2))
483 {
484 case RELATION_SELF:
485 condMeets = unit == toUnit;
486 break;
488 condMeets = unit->IsInPartyWith(toUnit);
489 break;
491 condMeets = unit->IsInRaidWith(toUnit);
492 break;
494 condMeets = unit->GetOwnerGUID() == toUnit->GetGUID();
495 break;
497 condMeets = unit->IsOnVehicle(toUnit);
498 break;
500 condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
501 break;
502 default:
503 break;
504 }
505 }
506 }
507 break;
508 }
510 {
511 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
512 {
513 Unit const* toUnit = toObject->ToUnit();
514 Unit const* unit = object->ToUnit();
515 if (toUnit && unit)
516 condMeets = ((1 << unit->GetReactionTo(toUnit)) & ConditionValue2) != 0;
517 }
518 break;
519 }
521 {
522 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
523 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3), object->GetDistance(toObject), static_cast<float>(ConditionValue2));
524 break;
525 }
526 case CONDITION_ALIVE:
527 {
528 if (Unit const* unit = object->ToUnit())
529 condMeets = unit->IsAlive();
530 break;
531 }
532 case CONDITION_HP_VAL:
533 {
534 if (Unit const* unit = object->ToUnit())
535 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealth(), static_cast<uint64>(ConditionValue1));
536 break;
537 }
538 case CONDITION_HP_PCT:
539 {
540 if (Unit const* unit = object->ToUnit())
541 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealthPct(), static_cast<float>(ConditionValue1));
542 break;
543 }
545 {
546 condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
547 break;
548 }
549 case CONDITION_TITLE:
550 {
551 if (Player const* player = object->ToPlayer())
552 condMeets = player->HasTitle(ConditionValue1);
553 break;
554 }
556 {
557 if (Unit const* unit = object->ToUnit())
558 condMeets = unit->HasUnitState(ConditionValue1);
559 break;
560 }
562 {
563 if (Creature const* creature = object->ToCreature())
564 condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
565 break;
566 }
568 {
569 if (Unit const* unit = object->ToUnit())
570 condMeets = unit->IsInWater();
571 break;
572 }
574 {
575 condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1);
576 break;
577 }
579 {
580 if (Unit const* unit = object->ToUnit())
581 {
582 if (ConditionValue1 == 0)
583 condMeets = (unit->GetStandState() == UnitStandStateType(ConditionValue2));
584 else if (ConditionValue2 == 0)
585 condMeets = unit->IsStandState();
586 else if (ConditionValue2 == 1)
587 condMeets = unit->IsSitState();
588 }
589 break;
590 }
592 {
593 if (Player const* player = object->ToPlayer())
594 condMeets = player->IsDailyQuestDone(ConditionValue1);
595 break;
596 }
598 {
599 if (Unit const* unit = object->ToUnit())
600 condMeets = unit->IsCharmed();
601 break;
602 }
604 {
605 if (Player const* player = object->ToPlayer())
606 if (Pet const* pet = player->GetPet())
607 condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0);
608 break;
609 }
610 case CONDITION_TAXI:
611 {
612 if (Player const* player = object->ToPlayer())
613 condMeets = player->IsInFlight();
614 break;
615 }
617 {
618 if (Player const* player = object->ToPlayer())
619 {
620 if (
621 ((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_NONE)) ||
622 ((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_COMPLETE)) ||
623 ((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_INCOMPLETE)) ||
624 ((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_FAILED)) ||
625 ((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1))
626 )
627 condMeets = true;
628 }
629 break;
630 }
632 {
633 if (Player const* player = object->ToPlayer())
634 {
635 QuestObjective const* obj = sObjectMgr->GetQuestObjective(ConditionValue1);
636 if (!obj)
637 break;
638
639 Quest const* quest = sObjectMgr->GetQuestTemplate(obj->QuestID);
640 if (!quest)
641 break;
642
643 uint16 slot = player->FindQuestSlot(obj->QuestID);
644 if (slot >= MAX_QUEST_LOG_SIZE)
645 break;
646
647 condMeets = player->GetQuestSlotObjectiveData(slot, *obj) == int32(ConditionValue3);
648 }
649 break;
650 }
652 {
653 if (Player const* player = object->ToPlayer())
654 {
655 if (ConditionValue1 == 1)
656 condMeets = player->CanBeGameMaster();
657 else
658 condMeets = player->IsGameMaster();
659 }
660 break;
661 }
663 {
664 if (Player const* player = object->ToPlayer())
665 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3),
666 player->GetSession()->GetBattlePetMgr()->GetPetCount(sBattlePetSpeciesStore.AssertEntry(ConditionValue1), player->GetGUID()),
667 static_cast<uint8>(ConditionValue2));
668 break;
669 }
671 {
672 if (Player const* player = object->ToPlayer())
673 condMeets = player->GetSceneMgr().GetActiveSceneCount(ConditionValue1) > 0;
674 break;
675 }
677 {
678 if (Player const* player = object->ToPlayer())
680 break;
681 }
683 {
684 condMeets = !object->GetPrivateObjectOwner().IsEmpty();
685 break;
686 }
688 {
689 if (Creature const* creature = object->ToCreature())
690 condMeets = creature->HasStringId(ConditionStringValue1);
691 else if (GameObject const* go = object->ToGameObject())
692 condMeets = go->HasStringId(ConditionStringValue1);
693 break;
694 }
695 case CONDITION_LABEL:
696 {
697 if (Creature const* creature = object->ToCreature())
698 condMeets = creature->HasLabel(ConditionValue1);
699 else if (GameObject const* go = object->ToGameObject())
700 condMeets = go->HasLabel(ConditionValue1);
701 break;
702 }
704 {
705 if (Player const* player = object->ToPlayer())
707 break;
708 }
709 default:
710 break;
711 }
712
714 condMeets = !condMeets;
715
716 if (!condMeets)
717 sourceInfo.mLastFailedCondition = this;
718
719 return condMeets && sScriptMgr->OnConditionCheck(this, sourceInfo); // Returns true by default.;
720}
721
723{
724 // build mask of types for which condition can return true
725 // this is used for speeding up gridsearches
727 return (GRID_MAP_TYPE_MASK_ALL);
728 uint32 mask = 0;
729 switch (ConditionType)
730 {
731 case CONDITION_NONE:
733 break;
734 case CONDITION_AURA:
736 break;
737 case CONDITION_ITEM:
739 break;
742 break;
743 case CONDITION_ZONEID:
745 break;
748 break;
751 break;
752 case CONDITION_TEAM:
754 break;
755 case CONDITION_CLASS:
757 break;
758 case CONDITION_RACE:
760 break;
761 case CONDITION_SKILL:
763 break;
766 break;
769 break;
772 break;
775 break;
778 break;
781 break;
782 case CONDITION_MAPID:
784 break;
785 case CONDITION_AREAID:
787 break;
788 case CONDITION_SPELL:
790 break;
791 case CONDITION_LEVEL:
793 break;
796 break;
799 break;
802 break;
804 switch (ConditionValue1)
805 {
806 case TYPEID_UNIT:
808 break;
809 case TYPEID_PLAYER:
811 break;
814 break;
815 case TYPEID_CORPSE:
817 break;
820 break;
821 default:
822 break;
823 }
824 break;
836 break;
839 break;
842 break;
845 break;
846 case CONDITION_ALIVE:
848 break;
849 case CONDITION_HP_VAL:
851 break;
852 case CONDITION_HP_PCT:
854 break;
857 break;
860 break;
861 case CONDITION_TITLE:
863 break;
864 case CONDITION_GENDER:
866 break;
869 break;
872 break;
875 break;
878 break;
881 break;
884 break;
887 break;
890 break;
893 break;
894 case CONDITION_TAXI:
896 break;
899 break;
902 break;
905 break;
908 break;
911 break;
914 break;
917 break;
920 break;
922 mask |= GRID_MAP_TYPE_MASK_ALL & ~GRID_MAP_TYPE_MASK_PLAYER;
923 break;
926 break;
927 case CONDITION_LABEL:
929 break;
932 break;
933 default:
934 ABORT_MSG("Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
935 break;
936 }
937 return mask;
938}
939
961
962template <typename FormatContext>
963auto fmt::formatter<Condition>::format(Condition const& condition, FormatContext& ctx) -> decltype(ctx.out())
964{
965 ctx.advance_to(std::ranges::copy("[Condition SourceType: ("sv, ctx.out()).out);
966 if (condition.SourceType < CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED)
967 ctx.advance_to(std::ranges::copy(ConditionMgr::StaticSourceTypeData[condition.SourceType], CStringSentinel, ctx.out()).out);
968 else if (condition.SourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION)
969 ctx.advance_to(std::ranges::copy("Reference"sv, ctx.out()).out);
970 else
971 ctx.advance_to(std::ranges::copy("Unknown"sv, ctx.out()).out);
972
973 *ctx.out() = ')';
974
975 std::array<char, 20> buf;
976
977 if (ConditionMgr::CanHaveSourceGroupSet(condition.SourceType))
978 {
979 ctx.advance_to(std::ranges::copy(", SourceGroup: "sv, ctx.out()).out);
980 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceGroup).ptr, ctx.out()).out);
981 }
982
983 ctx.advance_to(std::ranges::copy(", SourceEntry: "sv, ctx.out()).out);
984 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceEntry).ptr, ctx.out()).out);
985
986 if (ConditionMgr::CanHaveSourceIdSet(condition.SourceType))
987 {
988 ctx.advance_to(std::ranges::copy(", SourceId: "sv, ctx.out()).out);
989 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceId).ptr, ctx.out()).out);
990 }
991
992 ctx.advance_to(std::ranges::copy(", ConditionType: "sv, ctx.out()).out);
993 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), int32(condition.ConditionType)).ptr, ctx.out()).out);
994 ctx.advance_to(std::ranges::copy(" ("sv, ctx.out()).out);
995 if (condition.ConditionType < CONDITION_MAX)
996 ctx.advance_to(std::ranges::copy(ConditionMgr::StaticConditionTypeData[condition.ConditionType].Name, CStringSentinel, ctx.out()).out);
997 else
998 ctx.advance_to(std::ranges::copy("Unknown"sv, ctx.out()).out);
999
1000 ctx.advance_to(std::ranges::copy(")]"sv, ctx.out()).out);
1001
1002 return ctx.out();
1003}
1004
1005ConditionMgr::ConditionMgr() = default;
1006
1011
1013{
1014 if (conditions.empty())
1016 // groupId, typeMask
1017 std::map<uint32, uint32> elseGroupSearcherTypeMasks;
1018 for (ConditionContainer::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
1019 {
1020 // no point of having not loaded conditions in list
1021 ASSERT(i->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
1022 // group not filled yet, fill with widest mask possible
1023 auto itr = elseGroupSearcherTypeMasks.try_emplace(i->ElseGroup, GRID_MAP_TYPE_MASK_ALL).first;
1024 // no point of checking anymore, empty mask
1025 if (!itr->second)
1026 continue;
1027
1028 if (i->ReferenceId) // handle reference
1029 {
1030 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ i->ReferenceId, 0, 0 });
1031 ASSERT(ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
1032 itr->second &= GetSearcherTypeMaskForConditionList(*(ref->second));
1033 }
1034 else // handle normal condition
1035 {
1036 // object will match conditions in one ElseGroupStore only when it matches all of them
1037 // so, let's find a smallest possible mask which satisfies all conditions
1038 itr->second &= i->GetSearcherTypeMaskForCondition();
1039 }
1040 }
1041 // object will match condition when one of the checks in ElseGroupStore is matching
1042 // so, let's include all possible masks
1043 uint32 mask = 0;
1044 for (std::map<uint32, uint32>::const_iterator i = elseGroupSearcherTypeMasks.begin(); i != elseGroupSearcherTypeMasks.end(); ++i)
1045 mask |= i->second;
1046
1047 return mask;
1048}
1049
1051{
1052 // groupId, groupCheckPassed
1053 std::map<uint32, bool> elseGroupStore;
1054 for (Condition const& condition : conditions)
1055 {
1056 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition, condition.ConditionValue1);
1057 if (condition.isLoaded())
1058 {
1060 std::map<uint32, bool>::iterator itr = elseGroupStore.try_emplace(condition.ElseGroup, true).first;
1061 if (!itr->second)
1062 continue;
1063
1064 if (condition.ReferenceId)//handle reference
1065 {
1066 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1068 {
1069 bool condMeets = IsObjectMeetToConditionList(sourceInfo, *ref->second);
1070 if (condition.NegativeCondition)
1071 condMeets = !condMeets;
1072
1073 if (!condMeets)
1074 itr->second = false;
1075 }
1076 else
1077 {
1078 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} Reference template -{} not found",
1079 condition, condition.ReferenceId); // checked at loading, should never happen
1080 }
1081
1082 }
1083 else //handle normal condition
1084 {
1085 if (!condition.Meets(sourceInfo))
1086 itr->second = false;
1087 }
1088 }
1089 }
1090 for (std::map<uint32, bool>::const_iterator i = elseGroupStore.begin(); i != elseGroupStore.end(); ++i)
1091 if (i->second)
1092 return true;
1093
1094 return false;
1095}
1096
1098{
1099 ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
1100 return IsObjectMeetToConditions(srcInfo, conditions);
1101}
1102
1103bool ConditionMgr::IsObjectMeetToConditions(WorldObject const* object1, WorldObject const* object2, ConditionContainer const& conditions) const
1104{
1105 ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2);
1106 return IsObjectMeetToConditions(srcInfo, conditions);
1107}
1108
1110{
1111 if (conditions.empty())
1112 return true;
1113
1114 TC_LOG_DEBUG("condition", "ConditionMgr::IsObjectMeetToConditions");
1115 return IsObjectMeetToConditionList(sourceInfo, conditions);
1116}
1117
1119{
1120 return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
1132 sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
1137 sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT ||
1138 sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR ||
1139 sourceType == CONDITION_SOURCE_TYPE_PHASE ||
1140 sourceType == CONDITION_SOURCE_TYPE_GRAVEYARD ||
1141 sourceType == CONDITION_SOURCE_TYPE_AREATRIGGER ||
1146}
1147
1149{
1150 return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
1151}
1152
1154{
1155 switch (sourceType)
1156 {
1158 switch (conditionType)
1159 {
1160 case CONDITION_NONE:
1163 case CONDITION_MAPID:
1168 return true;
1169 default:
1170 return false;
1171 }
1172 break;
1173 default:
1174 break;
1175 }
1176 return true;
1177}
1178
1180{
1181 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1182 {
1183 auto i = ConditionStore[sourceType].find({ 0, int32(entry), 0 });
1184 if (i != ConditionStore[sourceType].end())
1185 {
1186 TC_LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type {} and entry {}", uint32(sourceType), entry);
1187 return IsObjectMeetToConditions(sourceInfo, *i->second);
1188 }
1189 }
1190
1191 return true;
1192}
1193
1194bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, WorldObject const* target0, WorldObject const* target1 /*= nullptr*/, WorldObject const* target2 /*= nullptr*/) const
1195{
1196 ConditionSourceInfo conditionSource(target0, target1, target2);
1197 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1198}
1199
1201{
1202 ConditionSourceInfo conditionSource(map);
1203 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1204}
1205
1207{
1208 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1209 return ConditionStore[sourceType].contains({ 0, int32(entry), 0 });
1210
1211 return false;
1212}
1213
1214bool ConditionMgr::IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const
1215{
1216 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1218 {
1219 TC_LOG_DEBUG("condition", "IsObjectMeetingSpellClickConditions: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1220 ConditionSourceInfo sourceInfo(clicker, target);
1221 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1222 }
1223 return true;
1224}
1225
1227{
1228 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1230 {
1231 TC_LOG_DEBUG("condition", "HasConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1232 return true;
1233 }
1234 return false;
1235}
1236
1237bool ConditionMgr::IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const
1238{
1239 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].find({ creatureId, int32(spellId), 0 });
1241 {
1242 TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId);
1243 ConditionSourceInfo sourceInfo(player, vehicle);
1244 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1245 }
1246 return true;
1247}
1248
1249bool ConditionMgr::IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const
1250{
1251 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].find({ eventId + 1, int32(entryOrGuid), sourceType });
1253 {
1254 TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId);
1255 ConditionSourceInfo sourceInfo(unit, baseObject);
1256 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1257 }
1258 return true;
1259}
1260
1261bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const
1262{
1263 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ creatureId, int32(itemId), 0 });
1265 {
1266 TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId);
1267 ConditionSourceInfo sourceInfo(player, vendor);
1268 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1269 }
1270 return true;
1271}
1272
1273bool ConditionMgr::IsObjectMeetingPlayerChoiceResponseConditions(uint32 playerChoiceId, int32 playerChoiceResponseId, Player const* player) const
1274{
1275 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_PLAYER_CHOICE_RESPONSE].find({ .SourceGroup = playerChoiceId, .SourceEntry = playerChoiceResponseId, .SourceId = 0 });
1277 {
1278 TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", playerChoiceId, playerChoiceResponseId);
1279 return IsObjectMeetToConditions(player, *itr->second);
1280 }
1281 return true;
1282}
1283
1288
1289ConditionContainer const* ConditionMgr::GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const
1290{
1291 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].find({ areaTriggerId, isServerSide ? 1 : 0, 0 });
1293 return itr->second.get();
1294 return nullptr;
1295}
1296
1298{
1299 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ trainerId, int32(spellId), 0 });
1301 {
1302 TC_LOG_DEBUG("condition", "IsObjectMeetingTrainerSpellConditions: found conditions for trainer id {} spell {}", trainerId, spellId);
1303 return IsObjectMeetToConditions(player, *itr->second);
1304 }
1305 return true;
1306}
1307
1309{
1312 {
1313 TC_LOG_DEBUG("condition", "IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {} entry {} guid {}", obj->GetTypeId(), obj->GetEntry(), obj->GetGUID());
1314 return IsObjectMeetToConditions(seer, obj, *itr->second);
1315 }
1316 return true;
1317}
1318
1320{
1321 static ConditionMgr instance;
1322 return &instance;
1323}
1324
1326{
1327 uint32 oldMSTime = getMSTime();
1328
1329 Clean();
1330
1331 //must clear all custom handled cases (groupped types) before reload
1332 if (isReload)
1333 {
1334 sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
1335
1336 sObjectMgr->UnloadPhaseConditions();
1337 }
1338
1339 QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
1340 "ConditionValue1, ConditionValue2, ConditionValue3, ConditionStringValue1, "
1341 "NegativeCondition, ErrorType, ErrorTextId, ScriptName FROM conditions");
1342
1343 if (!result)
1344 {
1345 TC_LOG_INFO("server.loading", ">> Loaded 0 conditions. DB table `conditions` is empty!");
1346 return;
1347 }
1348
1349 uint32 count = 0;
1350
1351 auto getOrInitConditions = [this](ConditionSourceType sourceType, ConditionId const& id)
1352 {
1353 auto [itr, inserted] = ConditionStore[sourceType].try_emplace(id, nullptr);
1354 if (inserted)
1355 itr->second = std::make_shared<std::vector<Condition>>();
1356 return itr->second;
1357 };
1358
1359 do
1360 {
1361 Field* fields = result->Fetch();
1362
1363 Condition cond;
1364 int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
1365 cond.SourceGroup = fields[1].GetUInt32();
1366 cond.SourceEntry = fields[2].GetInt32();
1367 cond.SourceId = fields[3].GetInt32();
1368 cond.ElseGroup = fields[4].GetUInt32();
1369 int32 iConditionTypeOrReference = fields[5].GetInt32();
1370 cond.ConditionTarget = fields[6].GetUInt8();
1371 cond.ConditionValue1 = fields[7].GetUInt32();
1372 cond.ConditionValue2 = fields[8].GetUInt32();
1373 cond.ConditionValue3 = fields[9].GetUInt32();
1374 cond.ConditionStringValue1 = fields[10].GetString();
1375 cond.NegativeCondition = fields[11].GetBool();
1376 cond.ErrorType = fields[12].GetUInt32();
1377 cond.ErrorTextId = fields[13].GetUInt32();
1378 cond.ScriptId = sObjectMgr->GetScriptId(fields[14].GetStringView());
1379
1380 if (iConditionTypeOrReference >= 0)
1381 cond.ConditionType = ConditionTypes(iConditionTypeOrReference);
1382
1383 if (iSourceTypeOrReferenceId >= 0)
1384 cond.SourceType = ConditionSourceType(iSourceTypeOrReferenceId);
1385
1386 if (iConditionTypeOrReference < 0)//it has a reference
1387 {
1388 if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip
1389 {
1390 TC_LOG_ERROR("sql.sql", "Condition reference {} is referencing self, skipped", iSourceTypeOrReferenceId);
1391 continue;
1392 }
1393
1394 cond.ReferenceId = uint32(-iConditionTypeOrReference);
1395
1396 char const* rowType = "reference template";
1397 if (iSourceTypeOrReferenceId >= 0)
1398 rowType = "reference";
1399 //check for useless data
1400 if (cond.ConditionTarget)
1401 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionTarget);
1402 if (cond.ConditionValue1)
1403 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue1);
1404 if (cond.ConditionValue2)
1405 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue2);
1406 if (cond.ConditionValue3)
1407 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3);
1408 }
1409 else if (!isConditionTypeValid(&cond))//doesn't have reference, validate ConditionType
1410 continue;
1411
1412 if (iSourceTypeOrReferenceId < 0)//it is a reference template
1413 {
1414 if (cond.SourceGroup)
1415 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceGroup ({})!", iSourceTypeOrReferenceId, cond.SourceGroup);
1416 if (cond.SourceEntry)
1417 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceEntry ({})!", iSourceTypeOrReferenceId, cond.SourceEntry);
1418 if (cond.SourceId)
1419 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceId ({})!", iSourceTypeOrReferenceId, cond.SourceId);
1420
1422 cond.SourceGroup = -iSourceTypeOrReferenceId;
1423 }
1424 else if (!isSourceTypeValid(&cond)) //if not a reference and SourceType is invalid, skip
1425 continue;
1426
1427 //Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
1428 if (cond.SourceGroup && !CanHaveSourceGroupSet(cond.SourceType))
1429 {
1430 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond, cond.SourceGroup);
1431 continue;
1432 }
1433 if (cond.SourceId && !CanHaveSourceIdSet(cond.SourceType))
1434 {
1435 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond, cond.SourceId);
1436 continue;
1437 }
1438
1440 {
1441 TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond, cond.ErrorType);
1442 cond.ErrorType = 0;
1443 }
1444
1445 if (cond.ErrorTextId && !cond.ErrorType)
1446 {
1447 TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond, cond.ErrorTextId);
1448 cond.ErrorTextId = 0;
1449 }
1450
1451 getOrInitConditions(cond.SourceType, { cond.SourceGroup, cond.SourceEntry, cond.SourceId })->emplace_back(std::move(cond));
1452 ++count;
1453 }
1454 while (result->NextRow());
1455
1456 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE])
1457 addToLootTemplate(id, conditions, LootTemplates_Creature.GetLootForConditionFill(id.SourceGroup));
1458
1459 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE])
1461
1462 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE])
1463 addToLootTemplate(id, conditions, LootTemplates_Fishing.GetLootForConditionFill(id.SourceGroup));
1464
1465 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE])
1467
1468 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE])
1469 addToLootTemplate(id, conditions, LootTemplates_Item.GetLootForConditionFill(id.SourceGroup));
1470
1471 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE])
1472 addToLootTemplate(id, conditions, LootTemplates_Mail.GetLootForConditionFill(id.SourceGroup));
1473
1474 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE])
1475 addToLootTemplate(id, conditions, LootTemplates_Milling.GetLootForConditionFill(id.SourceGroup));
1476
1479
1482
1483 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE])
1484 addToLootTemplate(id, conditions, LootTemplates_Reference.GetLootForConditionFill(id.SourceGroup));
1485
1486 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE])
1487 addToLootTemplate(id, conditions, LootTemplates_Skinning.GetLootForConditionFill(id.SourceGroup));
1488
1489 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE])
1490 addToLootTemplate(id, conditions, LootTemplates_Spell.GetLootForConditionFill(id.SourceGroup));
1491
1492 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU])
1493 addToGossipMenus(id, conditions);
1494
1495 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION])
1496 addToGossipMenuItems(id, conditions);
1497
1499 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT])
1500 for (Condition const& condition : *conditions)
1501 if (condition.ConditionType == CONDITION_AURA)
1502 SpellsUsedInSpellClickConditions.insert(condition.ConditionValue1);
1503
1504 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET])
1505 for (Condition const& condition : *conditions)
1507
1508 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PHASE])
1509 addToPhases(id, conditions);
1510
1511 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GRAVEYARD])
1512 addToGraveyardData(id, conditions);
1513
1514 struct
1515 {
1516 bool operator()(uint32 playerConditionId, std::vector<Condition> const& conditions, ConditionEntriesByTypeArray const& store) const
1517 {
1518 return std::ranges::any_of(conditions, [&](Condition const& condition)
1519 {
1521 {
1522 if (condition.ConditionValue1 == playerConditionId)
1523 return true;
1524 auto playerCondItr = store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].find({ 0, int32(condition.ConditionValue1), 0 });
1525 if (playerCondItr != store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].end())
1526 if (operator()(playerConditionId, *playerCondItr->second, store))
1527 return true;
1528 }
1529 else if (condition.ReferenceId)
1530 {
1531 auto refItr = store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1532 if (refItr != store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end())
1533 if (operator()(playerConditionId, *refItr->second, store))
1534 return true;
1535 }
1536 return false;
1537 });
1538 }
1539 } isPlayerConditionIdUsedByCondition;
1540
1541 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PLAYER_CONDITION])
1542 {
1543 if (isPlayerConditionIdUsedByCondition(id.SourceEntry, *conditions, ConditionStore))
1544 {
1545 TC_LOG_ERROR("sql.sql", "[Condition SourceType: CONDITION_SOURCE_TYPE_PLAYER_CONDITION, SourceGroup: {}, SourceEntry: {}, SourceId: {}] "
1546 "has a circular reference to player condition id {}, removed all conditions for this SourceEntry!",
1547 id.SourceGroup, id.SourceEntry, id.SourceId, id.SourceEntry);
1548 conditions->clear();
1549 }
1550 }
1551
1552 TC_LOG_INFO("server.loading", ">> Loaded {} conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1553}
1554
1555void ConditionMgr::addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const
1556{
1557 if (!loot)
1558 {
1559 for (Condition const& condition : *conditions)
1560 TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", condition, id.SourceGroup);
1561 return;
1562 }
1563
1564 if (loot->LinkConditions(id, ConditionsReference{ conditions }))
1565 return;
1566
1567 for (Condition const& condition : *conditions)
1568 TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", condition, id.SourceEntry, id.SourceGroup);
1569}
1570
1571void ConditionMgr::addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1572{
1573 GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(id.SourceGroup);
1574
1575 if (pMenuBounds.first != pMenuBounds.second)
1576 {
1577 for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
1578 if (itr->second.MenuID == id.SourceGroup && (itr->second.TextID == uint32(id.SourceEntry) || id.SourceEntry == 0))
1579 itr->second.Conditions = { conditions };
1580
1581 return;
1582 }
1583
1584 for (Condition const& condition : *conditions)
1585 TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", condition, id.SourceGroup);
1586}
1587
1588void ConditionMgr::addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1589{
1590 Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(id.SourceGroup);
1591 for (auto& [_, gossipMenuItem] : pMenuItemBounds)
1592 {
1593 if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == uint32(id.SourceEntry))
1594 {
1595 gossipMenuItem.Conditions = { conditions };
1596 return;
1597 }
1598 }
1599
1600 for (Condition const& condition : *conditions)
1601 TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", condition, id.SourceGroup, id.SourceEntry);
1602}
1603
1605{
1606 sSpellMgr->ForEachSpellInfoDifficulty(cond.SourceEntry, [&](SpellInfo const* spellInfo)
1607 {
1608 uint32 conditionEffMask = cond.SourceGroup;
1609 std::list<uint32> sharedMasks;
1610 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1611 {
1612 // additional checks by condition type
1613 if (conditionEffMask & (1 << spellEffectInfo.EffectIndex))
1614 {
1615 switch (cond.ConditionType)
1616 {
1617 case CONDITION_OBJECT_ENTRY_GUID:
1618 {
1619 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
1620 if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond.ConditionValue1 != TYPEID_UNIT && cond.ConditionValue1 != TYPEID_PLAYER)
1621 {
1622 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1623 "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER));
1624 return;
1625 }
1626
1627 if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond.ConditionValue1 != TYPEID_GAMEOBJECT)
1628 {
1629 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1630 "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT));
1631 return;
1632 }
1633
1634 if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond.ConditionValue1 != TYPEID_CORPSE)
1635 {
1636 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1637 "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE));
1638 return;
1639 }
1640 break;
1641 }
1642 default:
1643 break;
1644 }
1645 }
1646
1647 // check if effect is already a part of some shared mask
1648 auto itr = std::find_if(sharedMasks.begin(), sharedMasks.end(), [&](uint32 mask) { return !!(mask & (1 << spellEffectInfo.EffectIndex)); });
1649 if (itr != sharedMasks.end())
1650 continue;
1651
1652 // build new shared mask with found effect
1653 uint32 sharedMask = 1 << spellEffectInfo.EffectIndex;
1654 for (size_t effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo->GetEffects().size(); ++effIndex)
1655 if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions)
1656 sharedMask |= 1 << effIndex;
1657
1658 sharedMasks.push_back(sharedMask);
1659 }
1660
1661 for (uint32 effectMask : sharedMasks)
1662 {
1663 // some effect indexes should have same data
1664 if (uint32 commonMask = effectMask & conditionEffMask)
1665 {
1666 size_t firstEffIndex = 0;
1667 for (; firstEffIndex < spellInfo->GetEffects().size(); ++firstEffIndex)
1668 if ((1 << firstEffIndex) & effectMask)
1669 break;
1670
1671 if (firstEffIndex >= spellInfo->GetEffects().size())
1672 return;
1673
1674 // get shared data
1675 std::shared_ptr<ConditionContainer> sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions;
1676
1677 // there's already data entry for that sharedMask
1678 if (sharedList)
1679 {
1680 // we have overlapping masks in db
1681 if (conditionEffMask != effectMask)
1682 {
1683 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup {} (spell effectMask) set - "
1684 "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty {}).",
1685 cond, cond.SourceGroup, uint32(spellInfo->Difficulty));
1686 return;
1687 }
1688 }
1689 // no data for shared mask, we can create new submask
1690 else
1691 {
1692 // add new list, create new shared mask
1693 sharedList = std::make_shared<ConditionContainer>();
1694 bool assigned = false;
1695 for (size_t i = firstEffIndex; i < spellInfo->GetEffects().size(); ++i)
1696 {
1697 if ((1 << i) & commonMask)
1698 {
1699 const_cast<SpellEffectInfo&>(spellInfo->GetEffect(SpellEffIndex(i))).ImplicitTargetConditions = sharedList;
1700 assigned = true;
1701 }
1702 }
1703
1704 if (!assigned)
1705 break;
1706 }
1707 sharedList->push_back(cond);
1708 break;
1709 }
1710 }
1711 });
1712}
1713
1714void ConditionMgr::addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1715{
1716 if (!id.SourceEntry)
1717 {
1718 if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(id.SourceGroup))
1719 {
1720 bool found = false;
1721 for (uint32 areaId : phaseInfo->Areas)
1722 {
1723 if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(areaId)))
1724 {
1725 for (PhaseAreaInfo& phase : *phases)
1726 {
1727 if (phase.PhaseInfo->Id == id.SourceGroup)
1728 {
1729 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1730 found = true;
1731 }
1732 }
1733 }
1734 }
1735
1736 if (found)
1737 return;
1738 }
1739 }
1740 else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(id.SourceEntry)))
1741 {
1742 for (PhaseAreaInfo& phase : *phases)
1743 {
1744 if (phase.PhaseInfo->Id == id.SourceGroup)
1745 {
1746 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1747 return;
1748 }
1749 }
1750 }
1751
1752 for (Condition const& condition : *conditions)
1753 TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", condition, id.SourceEntry, id.SourceGroup);
1754}
1755
1756void ConditionMgr::addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1757{
1758 if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(id.SourceEntry, id.SourceGroup)))
1759 {
1760 graveyard->Conditions = { conditions };
1761 return;
1762 }
1763
1764 for (Condition const& condition : *conditions)
1765 TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", condition, id.SourceEntry, id.SourceGroup);
1766}
1767
1769{
1770 switch (cond->SourceType)
1771 {
1773 {
1775 {
1776 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_loot_template`, ignoring.", *cond);
1777 return false;
1778 }
1779 break;
1780 }
1782 {
1784 {
1785 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", *cond);
1786 return false;
1787 }
1788 break;
1789 }
1791 {
1793 {
1794 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `fishing_loot_template`, ignoring.", *cond);
1795 return false;
1796 }
1797 break;
1798 }
1800 {
1802 {
1803 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", *cond);
1804 return false;
1805 }
1806 break;
1807 }
1809 {
1811 {
1812 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `item_loot_template`, ignoring.", *cond);
1813 return false;
1814 }
1815 break;
1816 }
1818 {
1820 {
1821 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `mail_loot_template`, ignoring.", *cond);
1822 return false;
1823 }
1824 break;
1825 }
1827 {
1829 {
1830 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `milling_loot_template`, ignoring.", *cond);
1831 return false;
1832 }
1833 break;
1834 }
1836 {
1838 {
1839 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", *cond);
1840 return false;
1841 }
1842 break;
1843 }
1845 {
1847 {
1848 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", *cond);
1849 return false;
1850 }
1851 break;
1852 }
1854 {
1856 {
1857 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `reference_loot_template`, ignoring.", *cond);
1858 return false;
1859 }
1860 break;
1861 }
1863 {
1865 {
1866 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `skinning_loot_template`, ignoring.", *cond);
1867 return false;
1868 }
1869 break;
1870 }
1872 {
1874 {
1875 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `spell_loot_template`, ignoring.", *cond);
1876 return false;
1877 }
1878 break;
1879 }
1881 {
1882 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1883 if (!spellInfo)
1884 {
1885 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1886 return false;
1887 }
1888
1889 if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup)
1890 {
1891 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup (spell effectMask) set, ignoring.", *cond);
1892 return false;
1893 }
1894
1895 uint32 origGroup = cond->SourceGroup;
1896
1897 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1898 {
1899 if (!((1 << spellEffectInfo.EffectIndex) & cond->SourceGroup))
1900 continue;
1901
1902 if (spellEffectInfo.ChainTargets > 0)
1903 continue;
1904
1905 switch (spellEffectInfo.TargetA.GetSelectionCategory())
1906 {
1912 continue;
1913 default:
1914 break;
1915 }
1916
1917 switch (spellEffectInfo.TargetB.GetSelectionCategory())
1918 {
1924 continue;
1925 default:
1926 break;
1927 }
1928
1929 switch (spellEffectInfo.Effect)
1930 {
1941 continue;
1942 default:
1943 break;
1944 }
1945
1946 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));
1947 cond->SourceGroup &= ~(1 << spellEffectInfo.EffectIndex);
1948 }
1949 // all effects were removed, no need to add the condition at all
1950 if (!cond->SourceGroup)
1951 return false;
1952 break;
1953 }
1955 {
1956 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
1957 {
1958 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1959 return false;
1960 }
1961 break;
1962 }
1965 {
1966 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1967 if (!spellProto)
1968 {
1969 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1970 return false;
1971 }
1972 break;
1973 }
1975 if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry))
1976 {
1977 TC_LOG_ERROR("sql.sql", "{} SourceEntry specifies non-existing quest, skipped.", *cond);
1978 return false;
1979 }
1980 break;
1982 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1983 {
1984 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1985 return false;
1986 }
1987
1988 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
1989 {
1990 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1991 return false;
1992 }
1993 break;
1995 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1996 {
1997 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1998 return false;
1999 }
2000
2001 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
2002 {
2003 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
2004 return false;
2005 }
2006 break;
2008 {
2009 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
2010 {
2011 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
2012 return false;
2013 }
2014 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(cond->SourceEntry);
2015 if (!itemTemplate)
2016 {
2017 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, item does not exist, ignoring.", *cond);
2018 return false;
2019 }
2020 break;
2021 }
2023 {
2024 if (!sMapStore.LookupEntry(cond->SourceEntry))
2025 {
2026 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in Map.db2, ignoring.", *cond);
2027 return false;
2028 }
2029 break;
2030 }
2032 {
2033 if (cond->SourceEntry && !sAreaTableStore.LookupEntry(cond->SourceEntry))
2034 {
2035 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in AreaTable.db2, ignoring.", *cond);
2036 return false;
2037 }
2038 break;
2039 }
2041 if (!sObjectMgr->FindGraveyardData(cond->SourceEntry, cond->SourceGroup))
2042 {
2043 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `graveyard_zone`, ignoring.", *cond);
2044 return false;
2045 }
2046 break;
2048 if (cond->SourceEntry != 0 && cond->SourceEntry != 1)
2049 {
2050 TC_LOG_ERROR("sql.sql", "{} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring.", *cond);
2051 return false;
2052 }
2053 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), cond->SourceEntry == 1 }))
2054 {
2055 TC_LOG_ERROR("sql.sql", "{} in `condition` table, does not exist in `areatrigger_template`, ignoring.", *cond);
2056 return false;
2057 }
2058 break;
2060 if (!sConversationDataStore->GetConversationLineTemplate(cond->SourceEntry))
2061 {
2062 TC_LOG_ERROR("sql.sql", "{} does not exist in `conversation_line_template`, ignoring.", *cond);
2063 return false;
2064 }
2065 break;
2067 if (!sAreaTriggerStore.LookupEntry(cond->SourceEntry))
2068 {
2069 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exists in AreaTrigger.db2, ignoring.", *cond);
2070 return false;
2071 }
2072 break;
2074 {
2075 if (!sObjectMgr->GetTrainer(cond->SourceGroup))
2076 {
2077 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `trainer`, ignoring.", *cond);
2078 return false;
2079 }
2080 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
2081 {
2082 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
2083 return false;
2084 }
2085 break;
2086 }
2088 {
2089 if (cond->SourceGroup <= 0 || cond->SourceGroup >= NUM_CLIENT_OBJECT_TYPES)
2090 {
2091 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, is no valid object type, ignoring.", *cond);
2092 return false;
2093 }
2094
2095 if (cond->SourceGroup == TYPEID_UNIT)
2096 {
2097 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
2098 {
2099 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
2100 return false;
2101 }
2102 }
2103 else if (cond->SourceGroup == TYPEID_GAMEOBJECT)
2104 {
2105 if (!sObjectMgr->GetGameObjectTemplate(cond->SourceEntry))
2106 {
2107 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `gameobject_template`, ignoring.", *cond);
2108 return false;
2109 }
2110 }
2111 else
2112 {
2113 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, uses unchecked type id, ignoring.", *cond);
2114 return false;
2115 }
2116 break;
2117 }
2119 {
2120 SpawnGroupTemplateData const* spawnGroup = sObjectMgr->GetSpawnGroupData(cond->SourceEntry);
2121 if (!spawnGroup)
2122 {
2123 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `spawn_group_template`, ignoring.", *cond);
2124 return false;
2125 }
2126 if (spawnGroup->flags & (SPAWNGROUP_FLAG_SYSTEM))
2127 {
2128 TC_LOG_ERROR("sql.sql", "{} in `spawn_group_template` table cannot have SPAWNGROUP_FLAG_SYSTEM flags, ignoring.", *cond);
2129 return false;
2130 }
2131 break;
2132 }
2134 {
2135 SkillLineAbilityEntry const* skillLineAbility = sSkillLineAbilityStore.LookupEntry(cond->SourceEntry);
2136 if (!skillLineAbility)
2137 {
2138 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in SkillLineAbility.db2, ignoring.", *cond);
2139 return false;
2140 }
2142 {
2143 TC_LOG_ERROR("sql.sql", "{} in SkillLineAbility.db2 does not have AcquireMethod = {} (LearnedOrAutomaticCharLevel), ignoring.",
2145 return false;
2146 }
2147 break;
2148 }
2150 {
2151 PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(cond->SourceGroup);
2152 if (!playerChoice)
2153 {
2154 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `playerchoice`, ignoring.", *cond);
2155 return false;
2156 }
2157 if (!playerChoice->GetResponse(cond->SourceEntry))
2158 {
2159 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `playerchoice_response`, ignoring.", *cond);
2160 return false;
2161 }
2162 break;
2163 }
2168 break;
2169 default:
2170 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionSourceType in `condition` table, ignoring.", *cond);
2171 return false;
2172 }
2173
2174 return true;
2175}
2176
2178{
2179 switch (cond->ConditionType)
2180 {
2181 case CONDITION_NONE:
2182 {
2183 if (!cond->NegativeCondition && !cond->ScriptId)
2184 {
2185 TC_LOG_ERROR("sql.sql", "{} must have `NegativeCondition` or `ScriptName` in `condition` table, ignoring.", *cond);
2186 return false;
2187 }
2188 break;
2189 }
2190 case CONDITION_AURA:
2191 {
2192 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE);
2193 if (!spellInfo)
2194 {
2195 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped.", *cond, cond->ConditionValue1);
2196 return false;
2197 }
2198
2199 if (cond->ConditionValue2 >= spellInfo->GetEffects().size())
2200 {
2201 TC_LOG_ERROR("sql.sql", "{} spell {} has non existing effect index ({}) (must be 0..{}), skipped.",
2202 *cond, cond->ConditionValue1, cond->ConditionValue2, spellInfo->GetEffects().size() - 1);
2203 return false;
2204 }
2205
2206 if (!spellInfo->GetEffect(SpellEffIndex(cond->ConditionValue2)).IsAura())
2207 {
2208 TC_LOG_ERROR("sql.sql", "{} spell {} effect index {} is not an aura, skipped.",
2209 *cond, cond->ConditionValue1, cond->ConditionValue2);
2210 return false;
2211 }
2212 break;
2213 }
2214 case CONDITION_ITEM:
2215 {
2216 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2217 if (!proto)
2218 {
2219 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2220 return false;
2221 }
2222
2223 if (!cond->ConditionValue2)
2224 {
2225 TC_LOG_ERROR("sql.sql", "{} Zero item count in ConditionValue2, skipped.", *cond);
2226 return false;
2227 }
2228 break;
2229 }
2231 {
2232 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2233 if (!proto)
2234 {
2235 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2236 return false;
2237 }
2238 break;
2239 }
2240 case CONDITION_ZONEID:
2241 {
2242 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
2243 if (!areaEntry)
2244 {
2245 TC_LOG_ERROR("sql.sql", "{} Area ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2246 return false;
2247 }
2248
2249 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2250 {
2251 TC_LOG_ERROR("sql.sql", "{} requires to be in area ({}) which is a subzone but zone expected, skipped.", *cond, cond->ConditionValue1);
2252 return false;
2253 }
2254 break;
2255 }
2257 {
2258 FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1);
2259 if (!factionEntry)
2260 {
2261 TC_LOG_ERROR("sql.sql", "{} has non existing faction ({}), skipped.", *cond, cond->ConditionValue1);
2262 return false;
2263 }
2264 break;
2265 }
2266 case CONDITION_TEAM:
2267 {
2268 if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE)
2269 {
2270 TC_LOG_ERROR("sql.sql", "{} specifies unknown team ({}), skipped.", *cond, cond->ConditionValue1);
2271 return false;
2272 }
2273 break;
2274 }
2275 case CONDITION_SKILL:
2276 {
2277 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1);
2278 if (!pSkill)
2279 {
2280 TC_LOG_ERROR("sql.sql", "{} specifies non-existing skill ({}), skipped.", *cond, cond->ConditionValue1);
2281 return false;
2282 }
2283
2284 if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue())
2285 {
2286 TC_LOG_ERROR("sql.sql", "{} specifies skill ({}) with invalid value ({}), skipped.", *cond, cond->ConditionValue1, cond->ConditionValue2);
2287 return false;
2288 }
2289 break;
2290 }
2292 if (cond->ConditionValue2 >= (1 << MAX_QUEST_STATUS))
2293 {
2294 TC_LOG_ERROR("sql.sql", "{} has invalid state mask ({}), skipped.", *cond, cond->ConditionValue2);
2295 return false;
2296 }
2297 [[fallthrough]];
2303 {
2304 if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1))
2305 {
2306 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest ({}), skipped.", *cond, cond->ConditionValue1);
2307 return false;
2308 }
2309 break;
2310 }
2312 {
2313 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2314 if (cond->ConditionValue1 >= events.size() || !events[cond->ConditionValue1].isValid())
2315 {
2316 TC_LOG_ERROR("sql.sql", "{} has non existing event id ({}), skipped.", *cond, cond->ConditionValue1);
2317 return false;
2318 }
2319 break;
2320 }
2322 {
2323 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2324 if (!achievement)
2325 {
2326 TC_LOG_ERROR("sql.sql", "{} has non existing achivement id ({}), skipped.", *cond, cond->ConditionValue1);
2327 return false;
2328 }
2329 break;
2330 }
2331 case CONDITION_CLASS:
2332 {
2334 {
2335 TC_LOG_ERROR("sql.sql", "{} has non existing classmask ({}), skipped.", *cond, cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE);
2336 return false;
2337 }
2338 break;
2339 }
2340 case CONDITION_RACE:
2341 {
2342 Trinity::RaceMask<uint64> invalidRaceMask = Trinity::RaceMask<uint64>{ cond->ConditionValue1 } & ~RACEMASK_ALL_PLAYABLE;
2343 if (!invalidRaceMask.IsEmpty()) // uint32 works thanks to weird index remapping in racemask
2344 {
2345 TC_LOG_ERROR("sql.sql", "{} has non existing racemask ({}), skipped.", *cond, invalidRaceMask.RawValue[0]);
2346 return false;
2347 }
2348 break;
2349 }
2350 case CONDITION_GENDER:
2351 {
2353 {
2354 TC_LOG_ERROR("sql.sql", "{} has invalid gender ({}), skipped.", *cond, cond->ConditionValue1);
2355 return false;
2356 }
2357 break;
2358 }
2359 case CONDITION_MAPID:
2360 {
2361 MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1);
2362 if (!me)
2363 {
2364 TC_LOG_ERROR("sql.sql", "{} has non existing map ({}), skipped", *cond, cond->ConditionValue1);
2365 return false;
2366 }
2367 break;
2368 }
2369 case CONDITION_SPELL:
2370 {
2371 if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE))
2372 {
2373 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped", *cond, cond->ConditionValue1);
2374 return false;
2375 }
2376 break;
2377 }
2378 case CONDITION_LEVEL:
2379 {
2380 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2381 {
2382 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2383 return false;
2384 }
2385 break;
2386 }
2388 {
2389 if (cond->ConditionValue1 > DRUNKEN_SMASHED)
2390 {
2391 TC_LOG_ERROR("sql.sql", "{} has invalid state ({}), skipped.", *cond, cond->ConditionValue1);
2392 return false;
2393 }
2394 break;
2395 }
2397 {
2398 if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1))
2399 {
2400 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped", *cond, cond->ConditionValue1);
2401 return false;
2402 }
2403 break;
2404 }
2406 {
2407 if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1))
2408 {
2409 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", *cond, cond->ConditionValue1);
2410 return false;
2411 }
2412 break;
2413 }
2417 [[fallthrough]];
2419 {
2420 switch (cond->ConditionValue1)
2421 {
2422 case TYPEID_UNIT:
2423 if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2))
2424 {
2425 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped.", *cond, cond->ConditionValue2);
2426 return false;
2427 }
2428 if (cond->ConditionValue3)
2429 {
2430 if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(cond->ConditionValue3))
2431 {
2432 if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2)
2433 {
2434 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match creature entry ({}), skipped.", *cond, cond->ConditionValue3, cond->ConditionValue2);
2435 return false;
2436 }
2437 }
2438 else
2439 {
2440 TC_LOG_ERROR("sql.sql", "{} has non existing creature guid ({}), skipped.", *cond, cond->ConditionValue3);
2441 return false;
2442 }
2443 }
2444 break;
2445 case TYPEID_GAMEOBJECT:
2446 if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2))
2447 {
2448 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", *cond, cond->ConditionValue2);
2449 return false;
2450 }
2451 if (cond->ConditionValue3)
2452 {
2453 if (GameObjectData const* goData = sObjectMgr->GetGameObjectData(cond->ConditionValue3))
2454 {
2455 if (cond->ConditionValue2 && goData->id != cond->ConditionValue2)
2456 {
2457 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match gameobject entry ({}), skipped.", *cond, cond->ConditionValue3, cond->ConditionValue2);
2458 return false;
2459 }
2460 }
2461 else
2462 {
2463 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject guid ({}), skipped.", *cond, cond->ConditionValue3);
2464 return false;
2465 }
2466 }
2467 break;
2468 case TYPEID_PLAYER:
2469 case TYPEID_CORPSE:
2470 if (cond->ConditionValue2)
2472 if (cond->ConditionValue3)
2474 break;
2475 default:
2476 TC_LOG_ERROR("sql.sql", "{} has wrong typeid set ({}), skipped", *cond, cond->ConditionValue1);
2477 return false;
2478 }
2479 break;
2480 }
2484 [[fallthrough]];
2486 {
2488 {
2489 TC_LOG_ERROR("sql.sql", "{} has invalid typemask set ({}), skipped.", *cond, cond->ConditionValue2);
2490 return false;
2491 }
2492 break;
2493 }
2495 {
2497 {
2498 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2499 return false;
2500 }
2501 if (cond->ConditionValue1 == cond->ConditionTarget)
2502 {
2503 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2504 return false;
2505 }
2506 if (cond->ConditionValue2 >= RELATION_MAX)
2507 {
2508 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(RelationType) ({}), skipped.", *cond, cond->ConditionValue2);
2509 return false;
2510 }
2511 break;
2512 }
2514 {
2516 {
2517 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2518 return false;
2519 }
2520 if (cond->ConditionValue1 == cond->ConditionTarget)
2521 {
2522 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2523 return false;
2524 }
2525 if (!cond->ConditionValue2)
2526 {
2527 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(rankMask) ({}), skipped.", *cond, cond->ConditionValue2);
2528 return false;
2529 }
2530 break;
2531 }
2533 {
2535 {
2536 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2537 return false;
2538 }
2539 if (cond->ConditionValue1 == cond->ConditionTarget)
2540 {
2541 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2542 return false;
2543 }
2544 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2545 {
2546 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue3);
2547 return false;
2548 }
2549 break;
2550 }
2551 case CONDITION_HP_VAL:
2552 {
2553 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2554 {
2555 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2556 return false;
2557 }
2558 break;
2559 }
2560 case CONDITION_HP_PCT:
2561 {
2562 if (cond->ConditionValue1 > 100)
2563 {
2564 TC_LOG_ERROR("sql.sql", "{} has too big percent value ({}), skipped.", *cond, cond->ConditionValue1);
2565 return false;
2566 }
2567 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2568 {
2569 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2570 return false;
2571 }
2572 break;
2573 }
2575 {
2577 {
2578 TC_LOG_ERROR("sql.sql", "{} has non existing world state in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2579 return false;
2580 }
2581 break;
2582 }
2583 case CONDITION_PHASEID:
2584 {
2585 if (!sPhaseStore.LookupEntry(cond->ConditionValue1))
2586 {
2587 TC_LOG_ERROR("sql.sql", "{} has nonexistent phaseid in value1 ({}), skipped", *cond, cond->ConditionValue1);
2588 return false;
2589 }
2590 break;
2591 }
2592 case CONDITION_TITLE:
2593 {
2594 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1);
2595 if (!titleEntry)
2596 {
2597 TC_LOG_ERROR("sql.sql", "{} has non existing title in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2598 return false;
2599 }
2600 break;
2601 }
2603 {
2604 TC_LOG_ERROR("sql.sql", "{} using deprecated condition type CONDITION_SPAWNMASK.", *cond);
2605 return false;
2606 }
2608 {
2610 {
2611 TC_LOG_ERROR("sql.sql", "{} has non existing UnitState in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2612 return false;
2613 }
2614 break;
2615 }
2617 {
2619 {
2620 TC_LOG_ERROR("sql.sql", "{} has non existing CreatureType in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2621 return false;
2622 }
2623 break;
2624 }
2626 {
2627 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2628 if (!achievement)
2629 {
2630 TC_LOG_ERROR("sql.sql", "{} has non existing realm first achivement id ({}), skipped.", *cond, cond->ConditionValue1);
2631 return false;
2632 }
2633 break;
2634 }
2636 {
2637 bool valid = false;
2638 switch (cond->ConditionValue1)
2639 {
2640 case 0:
2642 break;
2643 case 1:
2644 valid = cond->ConditionValue2 <= 1;
2645 break;
2646 default:
2647 valid = false;
2648 break;
2649 }
2650 if (!valid)
2651 {
2652 TC_LOG_ERROR("sql.sql", "{} has non-existing stand state ({},{}), skipped.", *cond, cond->ConditionValue1, cond->ConditionValue2);
2653 return false;
2654 }
2655 break;
2656 }
2658 {
2659 QuestObjective const* obj = sObjectMgr->GetQuestObjective(cond->ConditionValue1);
2660 if (!obj)
2661 {
2662 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest objective ({}), skipped.", *cond, cond->ConditionValue1);
2663 return false;
2664 }
2665 int32 limit = obj->IsStoringFlag() ? 1 : obj->Amount;
2666 if (int32(cond->ConditionValue3) > limit)
2667 {
2668 TC_LOG_ERROR("sql.sql", "{} has quest objective count {} in value3, but quest objective {} has a maximum objective count of {}, skipped.", *cond, cond->ConditionValue3, cond->ConditionValue1, limit);
2669 return false;
2670 }
2671 break;
2672 }
2673 case CONDITION_PET_TYPE:
2674 if (cond->ConditionValue1 >= (1 << MAX_PET_TYPE))
2675 {
2676 TC_LOG_ERROR("sql.sql", "{} has non-existing pet type {}, skipped.", *cond, cond->ConditionValue1);
2677 return false;
2678 }
2679 break;
2682 {
2683 TC_LOG_ERROR("sql.sql", "{} has unsupported ConditionValue3 {} (INSTANCE_INFO_GUID_DATA), skipped.", *cond, cond->ConditionValue3);
2684 return false;
2685 }
2686 break;
2689 {
2690 TC_LOG_ERROR("sql.sql", "{} has non invalid group status condition value1 ({}), skipped.", *cond, cond->ConditionValue1);
2691 return false;
2692 }
2693 break;
2694 case CONDITION_AREAID:
2695 case CONDITION_ALIVE:
2696 case CONDITION_IN_WATER:
2698 case CONDITION_CHARMED:
2699 case CONDITION_TAXI:
2703 case CONDITION_LABEL:
2704 break;
2706 if (!sDifficultyStore.LookupEntry(cond->ConditionValue1))
2707 {
2708 TC_LOG_ERROR("sql.sql", "{} has non existing difficulty in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2709 return false;
2710 }
2711 break;
2713 if (!sBattlePetSpeciesStore.LookupEntry(cond->ConditionValue1))
2714 {
2715 TC_LOG_ERROR("sql.sql", "{} has non existing BattlePet SpeciesId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2716 return false;
2717 }
2719 {
2720 TC_LOG_ERROR("sql.sql", "{} has invalid (greater than {}) value2 ({}), skipped.", *cond,
2722 return false;
2723 }
2724 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2725 {
2726 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue3);
2727 return false;
2728 }
2729 break;
2731 {
2732 if (!sScenarioStepStore.LookupEntry(cond->ConditionValue1))
2733 {
2734 TC_LOG_ERROR("sql.sql", "{} has non existing ScenarioStep in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2735 return false;
2736 }
2737 break;
2738 }
2740 {
2741 if (!sSceneScriptPackageStore.LookupEntry(cond->ConditionValue1))
2742 {
2743 TC_LOG_ERROR("sql.sql", "{} has non existing SceneScriptPackageId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2744 return false;
2745 }
2746 break;
2747 }
2749 {
2750 if (!sPlayerConditionStore.LookupEntry(cond->ConditionValue1))
2751 {
2752 TC_LOG_ERROR("sql.sql", "{} has non existing PlayerConditionId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2753 return false;
2754 }
2755 break;
2756 }
2757 default:
2758 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionType in `condition` table, ignoring.", *cond);
2759 return false;
2760 }
2761
2763 {
2764 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect ConditionTarget set, ignoring.", *cond);
2765 return false;
2766 }
2767
2776
2777 return true;
2778}
2779
2781{
2782 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionValue{} ({})!", *cond, index, value);
2783}
2784
2785void ConditionMgr::LogUselessConditionValue(Condition const* cond, uint8 index, std::string const& value)
2786{
2787 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionStringValue{} ({})!", *cond, index, value);
2788}
2789
2791{
2792 for (std::unordered_map<ConditionId, std::shared_ptr<std::vector<Condition>>>& conditionsMap : ConditionStore)
2793 conditionsMap.clear();
2794
2796}
2797
2798inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
2799{
2800 switch (comparisonType)
2801 {
2802 case 1:
2803 return value1 == value2;
2804 case 2:
2805 return value1 != value2;
2806 case 3:
2807 return value1 > value2;
2808 case 4:
2809 return value1 >= value2;
2810 case 5:
2811 return value1 < value2;
2812 case 6:
2813 return value1 <= value2;
2814 default:
2815 break;
2816 }
2817 return false;
2818}
2819
2820template <std::size_t N>
2821inline bool PlayerConditionLogic(uint32 logic, std::bitset<N>& results)
2822{
2823 static_assert(N < 8, "Logic array size must be equal to or less than 8");
2824
2825 uint32 resultsMask = results.to_ulong() ^ (logic >> 16);
2826 uint32 result = resultsMask & 1;
2827 for (std::size_t i = 1; i < results.size(); ++i)
2828 {
2829 switch ((logic >> (2 * (i - 1))) & 3)
2830 {
2831 case 1:
2832 result &= (resultsMask >> i) & 1;
2833 break;
2834 case 2:
2835 result |= (resultsMask >> i) & 1;
2836 break;
2837 default:
2838 break;
2839 }
2840 }
2841
2842 return result != 0;
2843}
2844
2845template <typename T, std::size_t N, typename... ExtraParams, Trinity::invocable_r<bool, Player const*, T, typename ExtraParams::value_type...> Predicate>
2846inline static std::bitset<N> GetPlayerConditionSingleResult(Predicate predicate, Player const* player, std::array<T, N> const& conditions, ExtraParams const&... params)
2847{
2848 static_assert(((std::tuple_size_v<ExtraParams> == N) && ...));
2849 std::bitset<N> results;
2850
2851 for (std::size_t i = 0; i < N; ++i)
2852 if (predicate(player, conditions[i], params[i]...))
2853 results[i] = true;
2854
2855 return results;
2856}
2857
2859{
2860 Group const* group = player->GetGroup();
2861 if (!group)
2862 return 0;
2863
2864 switch (status)
2865 {
2867 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) ? 1 : 0;
2869 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) &&
2870 sLFGMgr->selectedRandomLfgDungeon(player->GetGUID()) ? 1 : 0;
2872 {
2873 if (!sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()))
2874 return 0;
2875
2876 uint32 selectedRandomDungeon = sLFGMgr->GetSelectedRandomDungeon(player->GetGUID());
2877 if (!selectedRandomDungeon)
2878 return 0;
2879
2880 if (lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(selectedRandomDungeon, player->GetLevel()))
2881 if (Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest))
2882 if (player->CanRewardQuest(quest, false))
2883 return 1;
2884 return 0;
2885 }
2887 break;
2889 break;
2891 break;
2893 break;
2895 break;
2896 default:
2897 break;
2898 }
2899
2900 return 0;
2901}
2902
2904{
2905 if (!conditionId)
2906 return true;
2907
2908 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_PLAYER_CONDITION, conditionId, player))
2909 return false;
2910
2911 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
2912 return IsPlayerMeetingCondition(player, playerCondition) != playerCondition->GetFlags().HasFlag(PlayerConditionFlags::Invert);
2913
2914 return true;
2915}
2916
2918{
2919 if (condition->GetFlags().HasFlag(PlayerConditionFlags::Disabled))
2920 return true;
2921
2922 if (condition->GetFlags().HasFlag(PlayerConditionFlags::IsAtMaxExpansionLevel))
2923 {
2924 uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
2925 if (level < GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION)))
2926 return false;
2927 }
2928
2929 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(condition->ContentTuningID, player->m_playerData->CtrOptions->ConditionalFlags))
2930 {
2931 uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
2932 uint8 minLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MinLevelWithDelta : levels->MinLevel;
2933 uint8 maxLevel = 0;
2934 if (!condition->GetFlags().HasFlag(PlayerConditionFlags::WithinOrAboveRecord))
2935 maxLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MaxLevelWithDelta : levels->MaxLevel;
2936
2937 if (condition->GetFlags().HasFlag(PlayerConditionFlags::InvertContentTuning))
2938 {
2939 if (minLevel && level >= minLevel && (!maxLevel || level <= maxLevel))
2940 return false;
2941
2942 if (maxLevel && level <= maxLevel && (!minLevel || level >= minLevel))
2943 return false;
2944 }
2945 else
2946 {
2947 if (minLevel && level < minLevel)
2948 return false;
2949
2950 if (maxLevel && level > maxLevel)
2951 return false;
2952 }
2953 }
2954
2955 if (!condition->RaceMask.IsEmpty() && !condition->RaceMask.HasRace(player->GetRace()))
2956 return false;
2957
2958 if (condition->ClassMask && !(player->GetClassMask() & condition->ClassMask))
2959 return false;
2960
2961 if (condition->Gender >= 0 && player->GetGender() != condition->Gender)
2962 return false;
2963
2964 if (condition->NativeGender >= 0 && player->GetNativeGender() != condition->NativeGender)
2965 return false;
2966
2967 if (condition->PowerType != -1 && condition->PowerTypeComp)
2968 {
2969 int32 requiredPowerValue = condition->GetFlags().HasFlag(PlayerConditionFlags::ComparePowerToMax) ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
2970 if (!PlayerConditionCompare(condition->PowerTypeComp, player->GetPower(Powers(condition->PowerType)), requiredPowerValue))
2971 return false;
2972 }
2973
2974 if (condition->ChrSpecializationIndex >= 0 || condition->ChrSpecializationRole >= 0)
2975 {
2977 {
2978 if (condition->ChrSpecializationIndex >= 0 && spec->OrderIndex != condition->ChrSpecializationIndex)
2979 return false;
2980
2981 if (condition->ChrSpecializationRole >= 0 && spec->Role != condition->ChrSpecializationRole)
2982 return false;
2983 }
2984 }
2985
2986 if (std::ranges::any_of(condition->SkillID, [](uint32 skillId) { return skillId != 0; }))
2987 {
2988 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 skillId, uint32 minSkill, uint32 maxSkill)
2989 {
2990 if (!skillId)
2991 return true;
2992
2993 uint16 skillValue = player->GetSkillValue(skillId);
2994 return skillValue != 0 && skillValue > minSkill && skillValue < maxSkill;
2995 }, player, condition->SkillID, condition->MinSkill, condition->MaxSkill);
2996
2997 if (!PlayerConditionLogic(condition->SkillLogic, results))
2998 return false;
2999 }
3000
3001 if (condition->LanguageID)
3002 {
3003 int32 languageSkill = 0;
3005 languageSkill = 300;
3006 else
3007 {
3008 for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(Language(condition->LanguageID)))
3009 languageSkill = std::max<int32>(languageSkill, player->GetSkillValue(languageDesc.second.SkillId));
3010 }
3011
3012 if (condition->MinLanguage && languageSkill < int32(condition->MinLanguage))
3013 return false;
3014
3015 if (condition->MaxLanguage && languageSkill > condition->MaxLanguage)
3016 return false;
3017 }
3018
3019 if (condition->MinFactionID[0] || condition->MinFactionID[1] || condition->MinFactionID[2] || condition->MaxFactionID)
3020 {
3021 auto isMinFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 minReputationRank)
3022 {
3023 if (!sFactionStore.HasRecord(factionId))
3024 return true;
3025
3026 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
3027 return *forcedRank >= ReputationRank(minReputationRank);
3028
3029 return player->GetReputationRank(factionId) >= ReputationRank(minReputationRank);
3030 };
3031
3032 auto isMaxFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 maxReputationRank)
3033 {
3034 if (!sFactionStore.HasRecord(factionId))
3035 return true;
3036
3037 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
3038 return *forcedRank <= ReputationRank(maxReputationRank);
3039
3040 return player->GetReputationRank(factionId) <= ReputationRank(maxReputationRank);
3041 };
3042
3043 if (!condition->MinFactionID[0] && !condition->MinFactionID[1] && !condition->MinFactionID[2])
3044 {
3045 if (!isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
3046 return false;
3047 }
3048 else
3049 {
3050 auto minFactionResults = GetPlayerConditionSingleResult(isMinFactionConditionSatisfied, player, condition->MinFactionID, condition->MinReputation);
3051 std::bitset<minFactionResults.size() + 1> results(minFactionResults.to_ulong());
3052 if (isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
3053 results[3] = true;
3054
3055 if (!PlayerConditionLogic(condition->ReputationLogic, results))
3056 return false;
3057 }
3058 }
3059
3060 if (condition->CurrentPvpFaction)
3061 {
3062 int8 team;
3063 if (player->GetMap()->IsBattlegroundOrArena())
3064 team = player->m_playerData->ArenaFaction;
3065 else
3066 team = player->GetTeamId() == TEAM_ALLIANCE ? 1 : 0;
3067
3068 if (condition->CurrentPvpFaction - 1 != team)
3069 return false;
3070 }
3071
3072 if (condition->PvpMedal && !((1 << (condition->PvpMedal - 1)) & *player->m_activePlayerData->PvpMedals))
3073 return false;
3074
3075 if (condition->LifetimeMaxPVPRank && player->m_activePlayerData->LifetimeMaxRank != condition->LifetimeMaxPVPRank)
3076 return false;
3077
3078 if (condition->MovementFlags)
3079 {
3080 static constexpr MovementFlags PlayerConditionSupportedMovementFlags = MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD
3084
3085 MovementFlags requiredFlags = MovementFlags(condition->MovementFlags) & PlayerConditionSupportedMovementFlags;
3086 if ((player->GetUnitMovementFlags() & requiredFlags) != requiredFlags)
3087 return false;
3088 }
3089
3090 if (condition->WeaponSubclassMask)
3091 {
3093 if (!mainHand || !((1 << mainHand->GetTemplate()->GetSubClass()) & condition->WeaponSubclassMask))
3094 return false;
3095 }
3096
3097 if (condition->PartyStatus)
3098 if (!MeetsGroupStatusCondition(player, GroupStatusCondition(condition->PartyStatus - 1)))
3099 return false;
3100
3101 if (condition->PrevQuestID[0])
3102 {
3103 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3104 {
3105 return !questId || player->IsQuestCompletedBitSet(questId);
3106 }, player, condition->PrevQuestID);
3107
3108 if (!PlayerConditionLogic(condition->PrevQuestLogic, results))
3109 return false;
3110 }
3111
3112 if (condition->CurrQuestID[0])
3113 {
3114 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3115 {
3116 return !questId || player->FindQuestSlot(questId) != MAX_QUEST_LOG_SIZE;
3117 }, player, condition->CurrQuestID);
3118
3119 if (!PlayerConditionLogic(condition->CurrQuestLogic, results))
3120 return false;
3121 }
3122
3123 if (condition->CurrentCompletedQuestID[0])
3124 {
3125 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3126 {
3127 return !questId || player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE;
3128 }, player, condition->CurrentCompletedQuestID);
3129
3130 if (!PlayerConditionLogic(condition->CurrentCompletedQuestLogic, results))
3131 return false;
3132 }
3133
3134 if (condition->SpellID[0])
3135 {
3136 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId)
3137 {
3138 return !spellId || player->HasSpell(spellId);
3139 }, player, condition->SpellID);
3140
3141 if (!PlayerConditionLogic(condition->SpellLogic, results))
3142 return false;
3143 }
3144
3145 if (condition->ItemID[0])
3146 {
3147 auto results = GetPlayerConditionSingleResult([itemFlags = condition->ItemFlags](Player const* player, uint32 itemId, uint32 itemCount)
3148 {
3149 if (!itemId)
3150 return true;
3151
3152 EnumFlag<ItemSearchLocation> where = ItemSearchLocation::Equipment;
3153 if ((itemFlags & 1) != 0) // include banks
3154 where |= ItemSearchLocation::Bank | ItemSearchLocation::ReagentBank | ItemSearchLocation::AccountBank;
3155 if ((itemFlags & 2) == 0) // ignore inventory
3156 where |= ItemSearchLocation::Inventory;
3157
3158 uint32 foundCount = 0;
3159 bool foundItemCount = !player->ForEachItem(where, [&](Item const* item)
3160 {
3161 if (item->GetEntry() == uint32(itemId))
3162 {
3163 foundCount += item->GetCount();
3164 if (foundCount >= itemCount)
3165 return ItemSearchCallbackResult::Stop;
3166 }
3167
3168 return ItemSearchCallbackResult::Continue;
3169 });
3170
3171 if (foundItemCount)
3172 return true;
3173
3174 if (itemCount == 1 && sDB2Manager.IsToyItem(itemId) && player->GetSession()->GetCollectionMgr()->HasToy(itemId))
3175 return true;
3176
3177 return false;
3178 }, player, condition->ItemID, condition->ItemCount);
3179
3180 if (!PlayerConditionLogic(condition->ItemLogic, results))
3181 return false;
3182 }
3183
3184 if (condition->CurrencyID[0])
3185 {
3186 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 currencyId, uint32 count)
3187 {
3188 return !currencyId || player->GetCurrencyQuantity(currencyId) >= count;
3189 }, player, condition->CurrencyID, condition->CurrencyCount);
3190
3191 if (!PlayerConditionLogic(condition->CurrencyLogic, results))
3192 return false;
3193 }
3194
3195 if (condition->Explored[0] || condition->Explored[1])
3196 {
3197 for (std::size_t i = 0; i < condition->Explored.size(); ++i)
3198 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(condition->Explored[i]))
3199 if (!player->HasExploredZone(area->ID))
3200 return false;
3201 }
3202
3203 if (condition->AuraSpellID[0])
3204 {
3205 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId, uint32 count)
3206 {
3207 if (!spellId)
3208 return true;
3209
3210 if (count)
3211 return player->GetAuraCount(spellId) >= count;
3212
3213 return player->HasAura(spellId);
3214 }, player, condition->AuraSpellID, condition->AuraStacks);
3215
3216 if (!PlayerConditionLogic(condition->AuraSpellLogic, results))
3217 return false;
3218 }
3219
3220 if (condition->Time[0])
3221 {
3222 WowTime time0;
3223 time0.SetPackedTime(condition->Time[0]);
3224
3225 if (condition->Time[1])
3226 {
3227 WowTime time1;
3228 time1.SetPackedTime(condition->Time[1]);
3229
3230 if (!GameTime::GetWowTime()->IsInRange(time0, time1))
3231 return false;
3232 }
3233 else if (*GameTime::GetWowTime() != time0)
3234 return false;
3235 }
3236
3237 if (condition->WorldStateExpressionID)
3238 {
3239 WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(condition->WorldStateExpressionID);
3240 if (!worldStateExpression)
3241 return false;
3242
3243 if (!IsMeetingWorldStateExpression(player->GetMap(), worldStateExpression))
3244 return false;
3245 }
3246
3247 if (condition->WeatherID)
3248 if (player->GetMap()->GetZoneWeather(player->GetZoneId()) != WeatherState(condition->WeatherID))
3249 return false;
3250
3251 if (condition->Achievement[0])
3252 {
3253 auto results = GetPlayerConditionSingleResult([flags = condition->GetFlags()](Player const* player, uint32 achievementId)
3254 {
3255 if (!achievementId)
3256 return true;
3257 (void)flags;
3258 // if (flags.HasFlag(PlayerConditionFlags::CheckAchievementsOnAllChars)) { any character on account completed it } else { current character only }
3259 // TODO: part of accountwide achievements
3260 return player->HasAchieved(achievementId);
3261 }, player, condition->Achievement);
3262
3263 if (!PlayerConditionLogic(condition->AchievementLogic, results))
3264 return false;
3265 }
3266
3267 if (condition->LfgStatus[0])
3268 {
3269 auto results = GetPlayerConditionSingleResult([](Player const* player, uint8 status, uint8 compare, uint32 value)
3270 {
3271 return !status || PlayerConditionCompare(compare, GetPlayerConditionLfgValue(player, PlayerConditionLfgStatus(status)), value);
3272 }, player, condition->LfgStatus, condition->LfgCompare, condition->LfgValue);
3273
3274 if (!PlayerConditionLogic(condition->LfgLogic, results))
3275 return false;
3276 }
3277
3278 if (condition->AreaID[0])
3279 {
3280 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 areaId)
3281 {
3282 return !areaId || DB2Manager::IsInArea(player->GetAreaId(), areaId);
3283 }, player, condition->AreaID);
3284
3285 if (!PlayerConditionLogic(condition->AreaLogic, results))
3286 return false;
3287 }
3288
3289 if (condition->MinExpansionLevel != -1 && player->GetSession()->GetExpansion() < condition->MinExpansionLevel)
3290 return false;
3291
3292 if (condition->MaxExpansionLevel != -1 && player->GetSession()->GetExpansion() > condition->MaxExpansionLevel)
3293 return false;
3294
3295 if (condition->MinExpansionLevel != -1 && condition->MinExpansionTier != -1 && !player->IsGameMaster()
3296 && ((condition->MinExpansionLevel == int32(sWorld->getIntConfig(CONFIG_EXPANSION)) && condition->MinExpansionTier > 0) /*TODO: implement tier*/
3297 || condition->MinExpansionLevel > int32(sWorld->getIntConfig(CONFIG_EXPANSION))))
3298 return false;
3299
3300 if (condition->PhaseID || condition->PhaseGroupID || condition->PhaseUseFlags)
3301 if (!PhasingHandler::InDbPhaseShift(player, condition->PhaseUseFlags, condition->PhaseID, condition->PhaseGroupID))
3302 return false;
3303
3304 if (condition->QuestKillID)
3305 {
3306 Quest const* quest = sObjectMgr->GetQuestTemplate(condition->QuestKillID);
3307 uint16 questSlot = player->FindQuestSlot(condition->QuestKillID);
3308 if (quest && player->GetQuestStatus(condition->QuestKillID) != QUEST_STATUS_COMPLETE && questSlot < MAX_QUEST_LOG_SIZE)
3309 {
3310 auto results = GetPlayerConditionSingleResult([questSlot, quest](Player const* player, uint32 creatureId)
3311 {
3312 if (!creatureId)
3313 return true;
3314
3315 auto objectiveItr = std::ranges::find_if(quest->GetObjectives(), [creatureId](QuestObjective const& objective) -> bool
3316 {
3317 return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == creatureId;
3318 });
3319 return objectiveItr == quest->GetObjectives().end() || player->GetQuestSlotObjectiveData(questSlot, *objectiveItr) >= objectiveItr->Amount;
3320 }, player, condition->QuestKillMonster);
3321
3322 if (!PlayerConditionLogic(condition->QuestKillLogic, results))
3323 return false;
3324 }
3325 }
3326
3327 if (condition->MinAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) < condition->MinAvgItemLevel)
3328 return false;
3329
3330 if (condition->MaxAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) > condition->MaxAvgItemLevel)
3331 return false;
3332
3333 if (condition->MinAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) < condition->MinAvgEquippedItemLevel)
3334 return false;
3335
3336 if (condition->MaxAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) > condition->MaxAvgEquippedItemLevel)
3337 return false;
3338
3339 if (condition->ModifierTreeID && player->ModifierTreeSatisfied(condition->ModifierTreeID) == condition->GetFlags().HasFlag(PlayerConditionFlags::InvertModifierTree))
3340 return false;
3341
3342 if (condition->CovenantID && player->m_playerData->CovenantID != condition->CovenantID)
3343 return false;
3344
3345 if (std::ranges::any_of(condition->TraitNodeEntryID, [](int32 traitNodeEntryId) { return traitNodeEntryId != 0; }))
3346 {
3347 auto results = GetPlayerConditionSingleResult([](Player const* player, int32 traitNodeEntryId, uint16 minRank, uint16 maxRank)
3348 {
3349 if (!traitNodeEntryId)
3350 return true;
3351
3352 Optional<uint16> rank = [&]() -> Optional<uint16>
3353 {
3354 for (auto const& [_, traitConfig] : player->m_activePlayerData->TraitConfigs)
3355 {
3356 if (TraitConfigType(*traitConfig.value.Type) == TraitConfigType::Combat)
3357 {
3358 if (int32(*player->m_activePlayerData->ActiveCombatTraitConfigID) != *traitConfig.value.ID
3359 || !EnumFlag(TraitCombatConfigFlags(*traitConfig.value.CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::ActiveForSpec))
3360 continue;
3361 }
3362
3363 for (UF::TraitEntry const& traitEntry : traitConfig.value.Entries)
3364 if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
3365 return traitEntry.Rank;
3366 }
3367 return {};
3368 }();
3369
3370 return rank
3371 && (!minRank || *rank >= minRank)
3372 && (!maxRank || *rank <= maxRank);
3373 }, player, condition->TraitNodeEntryID, condition->TraitNodeEntryMinRank, condition->TraitNodeEntryMaxRank);
3374
3375 if (!PlayerConditionLogic(condition->TraitNodeEntryLogic, results))
3376 return false;
3377 }
3378
3379 return true;
3380}
3381
3383{
3384 // WSE_FUNCTION_NONE
3385 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3386 {
3387 return 0;
3388 },
3389
3390 // WSE_FUNCTION_RANDOM
3391 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3392 {
3393 return irand(std::min(arg1, arg2), std::max(arg1, arg2));
3394 },
3395
3396 // WSE_FUNCTION_MONTH
3397 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3398 {
3399 return GameTime::GetDateAndTime()->tm_mon + 1;
3400 },
3401
3402 // WSE_FUNCTION_DAY
3403 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3404 {
3405 return GameTime::GetDateAndTime()->tm_mday + 1;
3406 },
3407
3408 // WSE_FUNCTION_TIME_OF_DAY
3409 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3410 {
3411 tm const* localTime = GameTime::GetDateAndTime();
3412 return localTime->tm_hour * MINUTE + localTime->tm_min;
3413 },
3414
3415 // WSE_FUNCTION_REGION
3416 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3417 {
3418 return sRealmList->GetCurrentRealmId().Region;
3419 },
3420
3421 // WSE_FUNCTION_CLOCK_HOUR
3422 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3423 {
3424 int32 currentHour = GameTime::GetDateAndTime()->tm_hour + 1;
3425 return currentHour <= 12 ? (currentHour ? currentHour : 12) : currentHour - 12;
3426 },
3427
3428 // WSE_FUNCTION_OLD_DIFFICULTY_ID
3429 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3430 {
3431 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(map->GetDifficultyID()))
3432 return difficulty->OldEnumValue;
3433
3434 return -1;
3435 },
3436
3437 // WSE_FUNCTION_HOLIDAY_START
3438 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3439 {
3440 return 0;
3441 },
3442
3443 // WSE_FUNCTION_HOLIDAY_LEFT
3444 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3445 {
3446 return 0;
3447 },
3448
3449 // WSE_FUNCTION_HOLIDAY_ACTIVE
3450 [](Map const* /*map*/, uint32 arg1, uint32 /*arg2*/) -> int32
3451 {
3452 return int32(IsHolidayActive(HolidayIds(arg1)));
3453 },
3454
3455 // WSE_FUNCTION_TIMER_CURRENT_TIME
3456 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3457 {
3458 return GameTime::GetGameTime();
3459 },
3460
3461 // WSE_FUNCTION_WEEK_NUMBER
3462 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3463 {
3464 time_t now = GameTime::GetGameTime();
3465 uint32 raidOrigin = 1135695600;
3466 if (Cfg_RegionsEntry const* region = sCfgRegionsStore.LookupEntry(sRealmList->GetCurrentRealmId().Region))
3467 raidOrigin = region->Raidorigin;
3468
3469 return (now - raidOrigin) / WEEK;
3470 },
3471
3472 // WSE_FUNCTION_UNK13
3473 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3474 {
3475 return 0;
3476 },
3477
3478 // WSE_FUNCTION_UNK14
3479 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3480 {
3481 return 0;
3482 },
3483
3484 // WSE_FUNCTION_DIFFICULTY_ID
3485 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3486 {
3487 return map->GetDifficultyID();
3488 },
3489
3490 // WSE_FUNCTION_WAR_MODE_ACTIVE
3491 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3492 {
3493 // check if current zone/map is bound to war mode
3494 return 0;
3495 },
3496
3497 // WSE_FUNCTION_UNK17
3498 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3499 {
3500 return 0;
3501 },
3502
3503 // WSE_FUNCTION_UNK18
3504 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3505 {
3506 return 0;
3507 },
3508
3509 // WSE_FUNCTION_UNK19
3510 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3511 {
3512 return 0;
3513 },
3514
3515 // WSE_FUNCTION_UNK20
3516 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3517 {
3518 return 0;
3519 },
3520
3521 // WSE_FUNCTION_UNK21
3522 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3523 {
3524 return 0;
3525 },
3526
3527 // WSE_FUNCTION_WORLD_STATE_EXPRESSION
3528 [](Map const* map, uint32 arg1, uint32 /*arg2*/) -> int32
3529 {
3530 if (WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(arg1))
3531 return ConditionMgr::IsMeetingWorldStateExpression(map, worldStateExpression);
3532
3533 return 0;
3534 },
3535
3536 // WSE_FUNCTION_KEYSTONE_AFFIX
3537 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3538 {
3539 return 0;
3540 },
3541
3542 // WSE_FUNCTION_UNK24
3543 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3544 {
3545 return 0;
3546 },
3547
3548 // WSE_FUNCTION_UNK25
3549 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3550 {
3551 return 0;
3552 },
3553
3554 // WSE_FUNCTION_UNK26
3555 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3556 {
3557 return 0;
3558 },
3559
3560 // WSE_FUNCTION_UNK27
3561 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3562 {
3563 return 0;
3564 },
3565
3566 // WSE_FUNCTION_KEYSTONE_LEVEL
3567 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3568 {
3569 return 0;
3570 },
3571
3572 // WSE_FUNCTION_UNK29
3573 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3574 {
3575 return 0;
3576 },
3577
3578 // WSE_FUNCTION_UNK30
3579 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3580 {
3581 return 0;
3582 },
3583
3584 // WSE_FUNCTION_UNK31
3585 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3586 {
3587 return 0;
3588 },
3589
3590 // WSE_FUNCTION_UNK32
3591 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3592 {
3593 return 0;
3594 },
3595
3596 // WSE_FUNCTION_MERSENNE_RANDOM
3597 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3598 {
3599 if (arg1 == 1)
3600 return 1;
3601
3602 // init with predetermined seed
3603 std::mt19937 mt(arg2 ? arg2 : 1);
3604 return mt() % arg1 + 1;
3605 },
3606
3607 // WSE_FUNCTION_UNK34
3608 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3609 {
3610 return 0;
3611 },
3612
3613 // WSE_FUNCTION_UNK35
3614 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3615 {
3616 return 0;
3617 },
3618
3619 // WSE_FUNCTION_UNK36
3620 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3621 {
3622 return 0;
3623 },
3624
3625 // WSE_FUNCTION_UI_WIDGET_DATA
3626 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3627 {
3628 return 0;
3629 },
3630
3631 // WSE_FUNCTION_TIME_EVENT_PASSED
3632 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3633 {
3634 return 0;
3635 },
3636};
3637
3639{
3641 int32 value = 0;
3642
3643 switch (valueType)
3644 {
3646 {
3647 value = buffer.read<int32>();
3648 break;
3649 }
3651 {
3652 int32 worldStateId = buffer.read<int32>();
3653 value = WorldStateMgr::GetValue(worldStateId, map);
3654 break;
3655 }
3657 {
3658 uint32 functionType = buffer.read<uint32>();
3659 int32 arg1 = EvalSingleValue(buffer, map);
3660 int32 arg2 = EvalSingleValue(buffer, map);
3661
3662 if (functionType >= WSE_FUNCTION_MAX)
3663 return 0;
3664
3665 value = WorldStateExpressionFunctions[functionType](map, arg1, arg2);
3666 break;
3667 }
3668 default:
3669 break;
3670 }
3671
3672 return value;
3673}
3674
3675int32 EvalValue(ByteBuffer& buffer, Map const* map)
3676{
3677 int32 leftValue = EvalSingleValue(buffer, map);
3678
3680 if (operatorType == WorldStateExpressionOperatorType::None)
3681 return leftValue;
3682
3683 int32 rightValue = EvalSingleValue(buffer, map);
3684
3685 switch (operatorType)
3686 {
3687 case WorldStateExpressionOperatorType::Sum: return leftValue + rightValue;
3688 case WorldStateExpressionOperatorType::Substraction: return leftValue - rightValue;
3689 case WorldStateExpressionOperatorType::Multiplication: return leftValue * rightValue;
3690 case WorldStateExpressionOperatorType::Division: return !rightValue ? 0 : leftValue / rightValue;
3691 case WorldStateExpressionOperatorType::Remainder: return !rightValue ? 0 : leftValue % rightValue;
3692 default:
3693 break;
3694 }
3695
3696 return leftValue;
3697}
3698
3699bool EvalRelOp(ByteBuffer& buffer, Map const* map)
3700{
3701 int32 leftValue = EvalValue(buffer, map);
3702
3704 if (compareLogic == WorldStateExpressionComparisonType::None)
3705 return leftValue != 0;
3706
3707 int32 rightValue = EvalValue(buffer, map);
3708
3709 switch (compareLogic)
3710 {
3711 case WorldStateExpressionComparisonType::Equal: return leftValue == rightValue;
3712 case WorldStateExpressionComparisonType::NotEqual: return leftValue != rightValue;
3713 case WorldStateExpressionComparisonType::Less: return leftValue < rightValue;
3714 case WorldStateExpressionComparisonType::LessOrEqual: return leftValue <= rightValue;
3715 case WorldStateExpressionComparisonType::Greater: return leftValue > rightValue;
3716 case WorldStateExpressionComparisonType::GreaterOrEqual: return leftValue >= rightValue;
3717 default:
3718 break;
3719 }
3720
3721 return false;
3722}
3723
3725{
3726 ByteBuffer buffer(HexStrToByteVector(expression->Expression));
3727 if (buffer.empty())
3728 return false;
3729
3730 uint8 enabled = buffer.read<uint8>();
3731 if (!enabled)
3732 return false;
3733
3734 bool finalResult = EvalRelOp(buffer, map);
3735
3736 do
3737 {
3739 if (resultLogic == WorldStateExpressionLogic::None)
3740 break;
3741
3742 bool secondResult = EvalRelOp(buffer, map);
3743
3744 switch (resultLogic)
3745 {
3746 case WorldStateExpressionLogic::And: finalResult = finalResult && secondResult; break;
3747 case WorldStateExpressionLogic::Or: finalResult = finalResult || secondResult; break;
3748 case WorldStateExpressionLogic::Xor: finalResult = finalResult != secondResult; break;
3749 default:
3750 break;
3751 }
3752 } while (buffer.rpos() < buffer.size());
3753
3754 return finalResult;
3755}
3756catch (std::exception const& e)
3757{
3758 TC_LOG_ERROR("condition", "Failed to parse WorldStateExpression {}: {}", expression->ID, e.what());
3759 return false;
3760}
3761
3762int32 GetUnitConditionVariable(Unit const* unit, Unit const* otherUnit, UnitConditionVariable variable, int32 value)
3763{
3764 switch (variable)
3765 {
3767 return unit->GetRace();
3769 return unit->GetClass();
3771 return unit->GetLevel();
3773 return unit == otherUnit;
3775 return otherUnit && unit->GetCharmerOrOwnerGUID() == otherUnit->GetGUID();
3777 return otherUnit && otherUnit->GetCharmerOrOwnerGUID() == unit->GetGUID();
3779 return otherUnit && otherUnit->GetTarget() == unit->GetGUID();
3781 return otherUnit && unit->IsValidAssistTarget(otherUnit);
3783 return otherUnit && unit->IsValidAttackTarget(otherUnit);
3785 return !unit->GetCharmedGUID().IsEmpty() || !unit->GetMinionGUID().IsEmpty();
3787 if (Player const* player = unit->ToPlayer())
3788 return player->GetWeaponForAttack(BASE_ATTACK) || player->GetWeaponForAttack(OFF_ATTACK);
3789 return unit->GetVirtualItemId(0) || unit->GetVirtualItemId(1);
3791 return unit->GetHealthPct();
3793 return unit->GetPowerPct(POWER_MANA);
3795 return unit->GetPowerPct(POWER_RAGE);
3797 return unit->GetPowerPct(POWER_ENERGY);
3799 return unit->GetPower(POWER_COMBO_POINTS);
3801 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3802 {
3803 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0;
3804 }) != nullptr ? value : 0;
3806 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3807 {
3808 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3809 }) != nullptr ? value : 0;
3811 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3812 {
3813 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3814 }) != nullptr ? value : 0;
3816 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3817 {
3818 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0;
3819 }) != nullptr ? value : 0;
3821 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3822 {
3823 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3824 }) != nullptr ? value : 0;
3826 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3827 {
3828 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3829 }) != nullptr ? value : 0;
3831 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3832 {
3833 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
3834 }) != nullptr ? value : 0;
3836 break;
3838 break;
3840 break;
3842 break;
3844 break;
3846 break;
3848 break;
3850 return unit->IsInCombat();
3854 case UnitConditionVariable::IsCastingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3855 return unit->GetCurrentSpell(CURRENT_GENERIC_SPELL) != nullptr;
3857 case UnitConditionVariable::IsChannelingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3858 return unit->GetChannelSpellId() != 0;
3860 return std::ranges::count_if(unit->getAttackers(), [unit](Unit const* attacker)
3861 {
3862 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3863 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3864 distance += 1.0f;
3865 return unit->GetExactDistSq(attacker) < distance * distance;
3866 });
3868 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
3870 return otherUnit ? int32(unit->GetExactDist(otherUnit)) : 0;
3872 if (otherUnit)
3873 {
3874 float distance = std::max(unit->GetCombatReach() + otherUnit->GetCombatReach() + 1.3333334f, 5.0f);
3876 distance += 1.0f;
3877 return unit->GetExactDistSq(otherUnit) < distance * distance;
3878 }
3879 return 0;
3881 break;
3887 return unit->GetThreatManager().GetThreatListSize();
3889 break;
3891 break;
3893 break;
3895 break;
3897 break;
3899 break;
3901 break;
3903 break;
3905 break;
3907 return unit->getAttackers().size();
3909 return std::ranges::count_if(unit->getAttackers(), [unit](Unit const* attacker)
3910 {
3911 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3912 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3913 distance += 1.0f;
3914 return unit->GetExactDistSq(attacker) >= distance * distance;
3915 });
3917 return unit->GetCreatureType();
3919 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3920 {
3921 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3922 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3923 distance += 1.0f;
3924 return unit->GetExactDistSq(target) < distance * distance;
3925 }
3926 return 0;
3928 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3929 {
3930 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3931 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3932 distance += 1.0f;
3933 return unit->GetExactDistSq(target) >= distance * distance;
3934 }
3935 return 0;
3937 return unit->GetHealth();
3939 return unit->HasSpell(value) ? value : 0;
3941 return value >= 0 && value < int32(TOTAL_AURAS) && std::find_if(unit->GetAuraEffectsByType(AuraType(value)).begin(), unit->GetAuraEffectsByType(AuraType(value)).end(), [unit](AuraEffect const* aurEff)
3942 {
3943 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) != 0;
3944 }) != unit->GetAuraEffectsByType(AuraType(value)).end();
3946 break;
3948 return unit->IsPlayer();
3950 break;
3952 break;
3954 break;
3956 break;
3958 return !unit->GetCritterGUID().IsEmpty();
3960 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM].IsEmpty();
3962 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_2].IsEmpty();
3964 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_3].IsEmpty();
3966 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_4].IsEmpty();
3968 break;
3970 return unit->GetEntry();
3972 break;
3974 return unit->HasAura(value) ? value : 0;
3976 return otherUnit && unit->GetReactionTo(otherUnit) <= REP_HOSTILE;
3978 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3981 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3984 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3987 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3990 return unit->IsCreature() && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED);
3992 return unit->GetHealth() == 0;
3994 break;
3996 return unit->GetMountDisplayId() != 0;
3998 return unit->IsCreature() && unit->ToCreature()->HasLabel(value) ? value : 0;
4000 return otherUnit && (otherUnit->GetCharmerGUID() == unit->GetGUID() || otherUnit->GetCreatorGUID() == unit->GetGUID());
4002 return otherUnit && (unit->GetCharmerGUID() == otherUnit->GetGUID() || unit->GetCreatorGUID() == otherUnit->GetGUID());
4004 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
4006 return unit->GetGender();
4008 if (Optional<ContentTuningLevels> levelRange = sDB2Manager.GetContentTuningData(value, {}))
4009 return unit->GetLevel() >= levelRange->MinLevel && unit->GetLevel() <= levelRange->MaxLevel ? value : 0;
4010 return 0;
4012 return unit->IsFlying();
4014 return unit->IsHovering();
4016 return value >= 0 && value < int32(TOTAL_AURAS) && std::ranges::any_of(unit->GetAuraEffectsByType(AuraType(value)), [unit](AuraEffect const* aurEff)
4017 {
4018 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) == 0;
4019 });
4021 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
4022 {
4023 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
4024 }) != nullptr ? value : 0;
4025 default:
4026 break;
4027 }
4028
4029 return 0;
4030}
4031
4032bool ConditionMgr::IsUnitMeetingCondition(Unit const* unit, Unit const* otherUnit, UnitConditionEntry const* condition)
4033{
4034 for (size_t i = 0; i < MAX_UNIT_CONDITION_VALUES; ++i)
4035 {
4036 if (!condition->Variable[i])
4037 break;
4038
4039 int32 unitValue = GetUnitConditionVariable(unit, otherUnit, UnitConditionVariable(condition->Variable[i]), condition->Value[i]);
4040 bool meets = false;
4041 switch (UnitConditionOp(condition->Op[i]))
4042 {
4044 meets = unitValue == condition->Value[i];
4045 break;
4047 meets = unitValue != condition->Value[i];
4048 break;
4050 meets = unitValue < condition->Value[i];
4051 break;
4053 meets = unitValue <= condition->Value[i];
4054 break;
4056 meets = unitValue > condition->Value[i];
4057 break;
4059 meets = unitValue >= condition->Value[i];
4060 break;
4061 default:
4062 break;
4063 }
4064
4065 if (condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr))
4066 {
4067 if (meets)
4068 return true;
4069 }
4070 else if (!meets)
4071 return false;
4072 }
4073
4074 return !condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr);
4075}
#define sAchievementMgr
#define sAreaTriggerDataStore
@ MINUTE
Definition Common.h:32
@ WEEK
Definition Common.h:35
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)
static std::bitset< N > GetPlayerConditionSingleResult(Predicate predicate, Player const *player, std::array< T, N > const &conditions, ExtraParams const &... params)
static bool MeetsGroupStatusCondition(Player const *player, GroupStatusCondition status)
bool PlayerConditionLogic(uint32 logic, std::bitset< N > &results)
int32 EvalValue(ByteBuffer &buffer, Map const *map)
std::vector< Condition > ConditionContainer
#define sConditionMgr
ConditionSourceType
@ CONDITION_SOURCE_TYPE_MAX
@ CONDITION_SOURCE_TYPE_CONVERSATION_LINE
@ CONDITION_SOURCE_TYPE_VEHICLE_SPELL
@ CONDITION_SOURCE_TYPE_SKILL_LINE_ABILITY
@ CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_TERRAIN_SWAP
@ CONDITION_SOURCE_TYPE_NPC_VENDOR
@ CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION
@ CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT
@ CONDITION_SOURCE_TYPE_REFERENCE_CONDITION
@ CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_PHASE
@ CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_SMART_EVENT
@ CONDITION_SOURCE_TYPE_PLAYER_CHOICE_RESPONSE
@ CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_AREATRIGGER_CLIENT_TRIGGERED
@ CONDITION_SOURCE_TYPE_AREATRIGGER
@ CONDITION_SOURCE_TYPE_PLAYER_CONDITION
@ CONDITION_SOURCE_TYPE_SPAWN_GROUP
@ CONDITION_SOURCE_TYPE_SPELL
@ CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY
@ CONDITION_SOURCE_TYPE_GOSSIP_MENU
@ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE
@ CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET
@ CONDITION_SOURCE_TYPE_GRAVEYARD
@ CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_TRAINER_SPELL
@ CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE
@ CONDITION_SOURCE_TYPE_SPELL_PROC
@ CONDITION_SOURCE_TYPE_QUEST_AVAILABLE
@ CONDITION_SOURCE_TYPE_NONE
@ CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED
std::array< ConditionsByEntryMap, CONDITION_SOURCE_TYPE_MAX > ConditionEntriesByTypeArray
@ INSTANCE_INFO_DATA64
@ INSTANCE_INFO_DATA
@ INSTANCE_INFO_BOSS_STATE
@ INSTANCE_INFO_GUID_DATA
@ MAX_CONDITION_TARGETS
GroupStatusCondition
ConditionTypes
@ CONDITION_TAXI
@ CONDITION_MAPID
@ CONDITION_SKILL
@ CONDITION_RACE
@ CONDITION_STRING_ID
@ CONDITION_PHASEID
@ CONDITION_REACTION_TO
@ CONDITION_NEAR_GAMEOBJECT
@ CONDITION_QUESTREWARDED
@ CONDITION_REALM_ACHIEVEMENT
@ CONDITION_GROUP_STATUS
@ CONDITION_QUEST_OBJECTIVE_PROGRESS
@ CONDITION_DAILY_QUEST_DONE
@ CONDITION_ACTIVE_EVENT
@ CONDITION_SPAWNMASK_DEPRECATED
@ CONDITION_INSTANCE_INFO
@ CONDITION_RELATION_TO
@ CONDITION_PRIVATE_OBJECT
@ CONDITION_STAND_STATE
@ CONDITION_LABEL
@ CONDITION_DRUNKENSTATE
@ CONDITION_AURA
@ CONDITION_ACHIEVEMENT
@ CONDITION_OBJECT_ENTRY_GUID
@ CONDITION_PET_TYPE
@ CONDITION_DIFFICULTY_ID
@ CONDITION_DISTANCE_TO
@ CONDITION_SCENARIO_STEP
@ CONDITION_HP_VAL
@ CONDITION_BATTLE_PET_COUNT
@ CONDITION_GENDER
@ CONDITION_GAMEMASTER
@ CONDITION_TERRAIN_SWAP
@ CONDITION_REPUTATION_RANK
@ CONDITION_HP_PCT
@ CONDITION_QUEST_COMPLETE
@ CONDITION_MAX
@ CONDITION_SPELL
@ CONDITION_ZONEID
@ CONDITION_OBJECT_ENTRY_GUID_LEGACY
@ CONDITION_CHARMED
@ CONDITION_TYPE_MASK
@ CONDITION_AREAID
@ CONDITION_IN_WATER
@ CONDITION_ITEM
@ CONDITION_WORLD_STATE
@ CONDITION_CLASS
@ CONDITION_TEAM
@ CONDITION_NONE
@ CONDITION_QUEST_NONE
@ CONDITION_QUESTSTATE
@ CONDITION_ITEM_EQUIPPED
@ CONDITION_SCENE_IN_PROGRESS
@ CONDITION_LEVEL
@ CONDITION_QUESTTAKEN
@ CONDITION_PLAYER_CONDITION
@ CONDITION_NEAR_CREATURE
@ CONDITION_TITLE
@ CONDITION_ALIVE
@ CONDITION_CREATURE_TYPE
@ CONDITION_TYPE_MASK_LEGACY
@ CONDITION_UNIT_STATE
RelationType
@ RELATION_IN_PARTY
@ RELATION_IN_RAID_OR_PARTY
@ RELATION_CREATED_BY
@ RELATION_MAX
@ RELATION_SELF
@ RELATION_PASSENGER_OF
@ RELATION_OWNED_BY
#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< SkillLineAbilityEntry > sSkillLineAbilityStore("SkillLineAbility.db2", &SkillLineAbilityLoadInfo::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:579
#define MAX_UNIT_CONDITION_VALUES
TraitConfigType
Definition DBCEnums.h:2871
PlayerConditionLfgStatus
Definition DBCEnums.h:2208
#define MAX_EFFECT_MASK
Definition DBCEnums.h:2451
TraitCombatConfigFlags
Definition DBCEnums.h:2841
UnitConditionVariable
Definition DBCEnums.h:3010
WorldStateExpressionFunctions
Definition DBCEnums.h:3256
@ WSE_FUNCTION_MAX
Definition DBCEnums.h:3297
WorldStateExpressionValueType
Definition DBCEnums.h:3220
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
UnitConditionOp
Definition DBCEnums.h:3000
WorldStateExpressionComparisonType
Definition DBCEnums.h:3235
WorldStateExpressionLogic
Definition DBCEnums.h:3227
WorldStateExpressionOperatorType
Definition DBCEnums.h:3246
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
std::unordered_set< uint32 > params[2]
uint16 flags
#define ABORT_MSG
Definition Errors.h:80
#define ASSERT
Definition Errors.h:72
bool IsHolidayActive(HolidayIds id)
#define sGameEventMgr
@ 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:515
#define sLanguageMgr
Definition LanguageMgr.h:97
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
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)
MovementFlags
@ MOVEMENTFLAG_PITCH_DOWN
@ MOVEMENTFLAG_PITCH_UP
@ MOVEMENTFLAG_RIGHT
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_STRAFE_LEFT
@ MOVEMENTFLAG_BACKWARD
@ MOVEMENTFLAG_DISABLE_GRAVITY
@ MOVEMENTFLAG_ROOT
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_LEFT
@ MOVEMENTFLAG_STRAFE_RIGHT
@ MOVEMENTFLAG_SWIMMING
@ MOVEMENTFLAG_WALKING
@ TYPEID_AREATRIGGER
Definition ObjectGuid.h:49
@ NUM_CLIENT_OBJECT_TYPES
Definition ObjectGuid.h:57
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:46
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_CORPSE
Definition ObjectGuid.h:48
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
TypeMask
Definition ObjectGuid.h:61
@ TYPEMASK_UNIT
Definition ObjectGuid.h:67
@ TYPEMASK_CORPSE
Definition ObjectGuid.h:72
@ TYPEMASK_GAMEOBJECT
Definition ObjectGuid.h:70
@ TYPEMASK_PLAYER
Definition ObjectGuid.h:68
@ TYPEMASK_AREATRIGGER
Definition ObjectGuid.h:73
#define sObjectMgr
Definition ObjectMgr.h:1873
std::pair< GossipMenusContainer::iterator, GossipMenusContainer::iterator > GossipMenusMapBoundsNonConst
Definition ObjectMgr.h:777
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:730
constexpr uint8 INVENTORY_SLOT_BAG_0
Definition Player.h:706
@ DRUNKEN_SMASHED
Definition Player.h:505
#define MAX_QUEST_LOG_SIZE
Definition QuestDef.h:43
QuestStatus
Definition QuestDef.h:142
@ QUEST_STATUS_REWARDED
Definition QuestDef.h:149
@ QUEST_STATUS_FAILED
Definition QuestDef.h:148
@ QUEST_STATUS_INCOMPLETE
Definition QuestDef.h:146
@ QUEST_STATUS_NONE
Definition QuestDef.h:143
@ MAX_QUEST_STATUS
Definition QuestDef.h:150
@ QUEST_STATUS_COMPLETE
Definition QuestDef.h:144
int32 irand(int32 min, int32 max)
Definition Random.cpp:36
#define sRealmList
Definition RealmList.h:95
#define sScriptMgr
Definition ScriptMgr.h:1449
SpellEffIndex
@ 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
Language
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
Gender
@ CREATURE_TYPE_GAS_CLOUD
@ TEAM_ALLIANCE
@ SUMMON_SLOT_TOTEM
@ SUMMON_SLOT_TOTEM_4
@ SUMMON_SLOT_TOTEM_3
@ SUMMON_SLOT_TOTEM_2
@ OFF_ATTACK
@ BASE_ATTACK
@ 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:56
@ 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:812
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
@ UNIT_FLAG_PLAYER_CONTROLLED
@ CURRENT_GENERIC_SPELL
Definition Unit.h:610
@ UNIT_STATE_ALL_STATE_SUPPORTED
Definition Unit.h:306
bool CompareValues(ComparisionType type, T val1, T val2)
Definition Util.h:543
std::vector< uint8 > HexStrToByteVector(std::string_view str, bool reverse=false)
Definition Util.h:449
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
struct CStringSentinel_T CStringSentinel
ComparisionType
Definition Util.h:533
@ COMP_TYPE_MAX
Definition Util.h:539
uint16 GetFlags() const
Definition SpellAuras.h:85
Aura * GetBase() const
Definition SpellAuras.h:82
uint32 GetEffectMask() const
Definition SpellAuras.h:86
Aura * GetBase() const
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:182
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsCreature() const
Definition BaseEntity.h:172
bool IsPlayer() const
Definition BaseEntity.h:173
TypeID GetTypeId() const
Definition BaseEntity.h:166
size_t rpos() const
Definition ByteBuffer.h:449
size_t size() const
Definition ByteBuffer.h:580
bool empty() const
Definition ByteBuffer.h:581
bool HasToy(uint32 itemId) const
bool isConditionTypeValid(Condition *cond) const
bool IsSpellUsedInSpellClickConditions(uint32 spellId) const
std::unordered_set< uint32 > SpellsUsedInSpellClickConditions
void addToLootTemplate(ConditionId const &id, std::shared_ptr< std::vector< Condition > > conditions, LootTemplate *loot) const
bool IsObjectMeetingPlayerChoiceResponseConditions(uint32 playerChoiceId, int32 playerChoiceResponseId, Player const *player) 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
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]
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]
bool IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const *player, Unit const *vehicle) const
void LoadConditions(bool isReload=false)
bool HasLabel(int32 cretureLabel) const
static bool IsInArea(uint32 objectAreaId, uint32 areaId)
constexpr bool HasFlag(T flag) const
Definition EnumFlag.h:106
Class used to access individual fields of database query result.
Definition Field.h:94
bool GetBool() const noexcept
Definition Field.h:102
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
int32 GetInt32() const noexcept
Definition Field.cpp:64
std::string GetString() const noexcept
Definition Field.cpp:113
std::vector< GameEventData > GameEventDataMap
Definition Group.h:209
bool isRaidGroup() const
Definition Group.cpp:1598
Definition Item.h:185
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
LootTemplate * GetLootForConditionFill(uint32 loot_id)
Definition LootMgr.cpp:212
bool HaveLootFor(uint32 loot_id) const
Definition LootMgr.h:92
bool LinkConditions(ConditionId const &id, ConditionsReference reference)
Definition LootMgr.cpp:985
Definition Map.h:227
bool IsBattlegroundOrArena() const
Definition Map.cpp:3405
BattlegroundMap * ToBattlegroundMap()
Definition Map.h:498
Difficulty GetDifficultyID() const
Definition Map.h:363
uint32 GetId() const
Definition Map.cpp:3288
InstanceMap * ToInstanceMap()
Definition Map.h:495
WeatherState GetZoneWeather(uint32 zoneId) const
Definition Map.cpp:4046
bool IsEmpty() const
Definition ObjectGuid.h:362
Player * ToPlayer()
Definition Object.h:126
GameObject * ToGameObject()
Definition Object.h:131
uint32 GetEntry() const
Definition Object.h:89
Creature * ToCreature()
Definition Object.h:121
Unit * ToUnit()
Definition Object.h:116
Definition Pet.h:40
static bool InDbPhaseShift(WorldObject const *object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
ChrSpecialization GetPrimarySpecialization() const
Definition Player.h:1993
UF::UpdateField< UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER > m_playerData
Definition Player.h:3047
Gender GetNativeGender() const override
Definition Player.h:1334
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5920
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3048
uint16 FindQuestSlot(uint32 quest_id) const
Definition Player.cpp:16350
bool IsQuestCompletedBitSet(uint32 questId) const
Definition Player.cpp:16484
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition Player.cpp:14576
WorldSession * GetSession() const
Definition Player.h:2256
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9538
bool ModifierTreeSatisfied(uint32 modifierTreeId) const
Definition Player.cpp:27554
TeamId GetTeamId() const
Definition Player.h:2407
bool HasExploredZone(uint32 areaId) const
Definition Player.cpp:6307
bool IsGameMaster() const
Definition Player.h:1293
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15929
static bool IsValidGender(uint8 Gender)
Definition Player.h:1859
ReputationRank GetReputationRank(uint32 faction_id) const
Definition Player.cpp:6415
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9577
bool HasSpell(uint32 spell) const override
Definition Player.cpp:3626
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2781
int32 GetQuestSlotObjectiveData(uint16 slot, QuestObjective const &objective) const
Definition Player.cpp:16385
ChrSpecializationEntry const * GetPrimarySpecializationEntry() const
Definition Player.cpp:30736
ReputationMgr & GetReputationMgr()
Definition Player.h:2422
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition Player.cpp:831
uint32 GetCurrencyQuantity(uint32 id) const
Definition Player.cpp:7274
QuestObjectives const & GetObjectives() const
Definition QuestDef.h:677
ReputationRank const * GetForcedRankIfAny(FactionTemplateEntry const *factionTemplateEntry) const
bool IsAura() const
::Difficulty const Difficulty
Definition SpellInfo.h:329
uint32 Dispel
Definition SpellInfo.h:331
SpellSchoolMask GetSchoolMask() const
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:590
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:589
size_t GetThreatListSize() const
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition Unit.h:647
uint32 GetChannelSpellId() const
Definition Unit.h:1443
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1362
float GetHealthPct() const
Definition Unit.h:808
ThreatManager & GetThreatManager()
Definition Unit.h:1093
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4845
uint8 GetClass() const
Definition Unit.h:776
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition Unit.h:1524
uint32 GetClassMask() const
Definition Unit.h:778
uint32 GetMountDisplayId() const
Definition Unit.h:928
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1211
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:860
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1231
MovementFlags GetUnitMovementFlags() const
Definition Unit.h:1762
float GetCombatReach() const override
Definition Unit.h:717
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10105
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1236
virtual bool HasSpell(uint32) const
Definition Unit.h:1099
ObjectGuid GetCreatorGUID() const override
Definition Unit.h:1213
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:12201
Gender GetGender() const
Definition Unit.h:779
uint32 GetCreatureType() const
Definition Unit.cpp:9478
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4881
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:14505
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4806
bool IsHovering() const
Definition Unit.h:1166
ObjectGuid GetMinionGUID() const
Definition Unit.h:1215
uint64 GetHealth() const
Definition Unit.h:800
AttackerSet const & getAttackers() const
Definition Unit.h:736
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4832
ObjectGuid GetCritterGUID() const
Definition Unit.h:1219
int32 GetPower(Powers power) const
Definition Unit.cpp:10096
uint8 GetEffectiveLevel() const
Definition Unit.h:770
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12272
float GetPowerPct(Powers power) const
Definition Unit.h:832
bool HasUnitMovementFlag(MovementFlags f) const
Definition Unit.h:1761
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4822
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1228
bool IsFlying() const
Definition Unit.h:1823
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4664
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12253
ObjectGuid GetTarget() const
Definition Unit.h:1847
uint8 GetLevel() const
Definition Unit.h:769
uint8 GetRace() const
Definition Unit.h:773
bool IsInCombat() const
Definition Unit.h:1073
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1490
constexpr uint32 GetMapId() const
Definition Position.h:216
Map * GetMap() const
Definition Object.h:411
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2329
ReputationRank GetReactionTo(WorldObject const *target) const
Definition Object.cpp:2033
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2487
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:430
uint32 GetAreaId() const
Definition Object.h:333
uint32 GetZoneId() const
Definition Object.h:332
CollectionMgr * GetCollectionMgr() const
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:919
WeatherState
Definition Weather.h:47
@ CONFIG_EXPANSION
Definition World.h:306
static constexpr ObjectData creatureData[]
@ DEFAULT_MAX_BATTLE_PETS_PER_SPECIES
WowTime const * GetWowTime()
Definition GameTime.cpp:106
tm const * GetDateAndTime()
Definition GameTime.cpp:96
time_t GetGameTime()
Definition GameTime.cpp:52
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
constexpr TypeMask ConvertLegacyTypeMask(uint32 legacyTypeMask)
Definition ObjectGuid.h:507
constexpr ::TypeID ConvertLegacyTypeID(TypeID legacyTypeID)
Definition ObjectGuid.h:476
TC_GAME_API WorldStateTemplate const * GetWorldStateTemplate(int32 worldStateId)
TC_GAME_API int32 GetValue(int32 worldStateId, Map const *map)
EnumFlag< AreaFlags > GetFlags() const
EnumFlag< ChrSpecializationFlag > GetFlags() const
ChrSpecializationRole GetRole() const
std::size_t GetHash() const
uint32 SourceGroup
uint32 SourceId
int32 SourceEntry
ConditionSourceInfo(WorldObject const *target0, WorldObject const *target1=nullptr, WorldObject const *target2=nullptr)
Condition const * mLastFailedCondition
std::array< WorldObject const *, MAX_CONDITION_TARGETS > mConditionTargets
Map const * mConditionMap
uint32 SourceGroup
ConditionTypes ConditionType
std::string ConditionStringValue1
uint32 GetSearcherTypeMaskForCondition() const
uint32 ErrorType
uint32 SourceId
int32 SourceEntry
uint32 ElseGroup
uint32 ScriptId
bool NegativeCondition
ConditionSourceType SourceType
uint32 ConditionValue2
uint8 ConditionTarget
uint32 ReferenceId
uint32 ErrorTextId
uint32 ConditionValue3
uint32 GetMaxAvailableConditionTargets() const
uint32 ConditionValue1
bool Meets(ConditionSourceInfo &sourceInfo) const
uint32 GetSubClass() const
PlayerChoiceResponse const * GetResponse(int32 responseId) const
std::array< uint32, 4 > ItemCount
std::array< uint16, 4 > MaxSkill
std::array< int32, 4 > CurrentCompletedQuestID
std::array< int32, 4 > PrevQuestID
std::array< int32, 4 > CurrQuestID
std::array< uint16, 4 > SkillID
std::array< uint32, 3 > MinFactionID
std::array< uint16, 4 > MinSkill
EnumFlag< PlayerConditionFlags > GetFlags() const
std::array< uint8, 3 > MinReputation
std::array< int32, 4 > ItemID
std::array< int32, 4 > SpellID
Trinity::RaceMask< int32, 2 > RaceMask
float GetExactDist(float x, float y, float z) const
Definition Position.h:129
constexpr float GetExactDistSq(float x, float y, float z) const
Definition Position.h:121
bool IsStoringFlag() const
Definition QuestDef.h:515
uint32 QuestID
Definition QuestDef.h:479
SkillLineAbilityAcquireMethod GetAcquireMethod() const
SpawnGroupFlags flags
Definition SpawnData.h:72
constexpr void UpdateData(std::span< V, Extent > data) noexcept
Definition Hash.h:85
std::array< T, N > RawValue
Definition RaceMask.h:95
constexpr bool HasRace(uint32 raceId) const
Definition RaceMask.h:149
constexpr bool IsEmpty() const
Definition RaceMask.h:167
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:237