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};
165
166ConditionSourceInfo::ConditionSourceInfo(WorldObject const* target0, WorldObject const* target1, WorldObject const* target2) :
167 mConditionTargets({ target0, target1, target2 }),
168 mConditionMap(nullptr),
169 mLastFailedCondition(nullptr)
170{
171 if (WorldObject const* target = Coalesce<WorldObject const>(target0, target1, target2))
172 mConditionMap = target->GetMap();
173}
174
176 mConditionTargets(),
177 mConditionMap(map),
178 mLastFailedCondition(nullptr)
179{
180}
181
182std::size_t ConditionId::GetHash() const
183{
187 hash.UpdateData(SourceId);
188 return hash.Value;
189}
190
191// Checks if object meets the condition
192// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI)
194{
196
197 Map const* map = sourceInfo.mConditionMap;
198 bool condMeets = false;
199 bool needsObject = false;
200 switch (ConditionType)
201 {
202 case CONDITION_NONE:
203 condMeets = true; // empty condition, always met
204 break;
206 condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1);
207 break;
209 {
210 if (InstanceMap const* instanceMap = map->ToInstanceMap())
211 {
212 if (InstanceScript const* instance = instanceMap->GetInstanceScript())
213 {
214 switch (ConditionValue3)
215 {
217 condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
218 break;
220 condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
221 break;
223 condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
224 break;
225 default:
226 condMeets = false;
227 break;
228 }
229 }
230 }
231 else if (BattlegroundMap const* bgMap = map->ToBattlegroundMap())
232 {
233 ZoneScript const* zoneScript = bgMap->GetBattlegroundScript();
234 switch (ConditionValue3)
235 {
237 condMeets = zoneScript->GetData(ConditionValue1) == ConditionValue2;
238 break;
240 condMeets = zoneScript->GetData64(ConditionValue1) == ConditionValue2;
241 break;
242 default:
243 condMeets = false;
244 break;
245 }
246 }
247 break;
248 }
249 case CONDITION_MAPID:
250 condMeets = map->GetId() == ConditionValue1;
251 break;
253 {
255 break;
256 }
258 {
259 AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
260 if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
261 condMeets = true;
262 break;
263 }
265 {
266 condMeets = map->GetDifficultyID() == int32(ConditionValue1);
267 break;
268 }
270 {
271 if (InstanceMap const* instanceMap = map->ToInstanceMap())
272 if (Scenario const* scenario = instanceMap->GetInstanceScenario())
273 if (ScenarioStepEntry const* step = scenario->GetStep())
274 condMeets = step->ID == ConditionValue1;
275 break;
276 }
277 default:
278 needsObject = true;
279 break;
280 }
281
282 WorldObject const* object = sourceInfo.mConditionTargets[ConditionTarget];
283 // object not present, return false
284 if (needsObject && !object)
285 {
286 TC_LOG_DEBUG("condition", "Condition object not found for {}", *this);
287 return false;
288 }
289 switch (ConditionType)
290 {
291 case CONDITION_AURA:
292 {
293 if (Unit const* unit = object->ToUnit())
294 condMeets = unit->HasAuraEffect(ConditionValue1, ConditionValue2);
295 break;
296 }
297 case CONDITION_ITEM:
298 {
299 if (Player const* player = object->ToPlayer())
300 {
301 // don't allow 0 items (it's checked during table load)
303 bool checkBank = ConditionValue3 ? true : false;
304 condMeets = player->HasItemCount(ConditionValue1, ConditionValue2, checkBank);
305 }
306 break;
307 }
309 {
310 if (Player const* player = object->ToPlayer())
311 condMeets = player->HasItemOrGemWithIdEquipped(ConditionValue1, 1);
312 break;
313 }
314 case CONDITION_ZONEID:
315 condMeets = object->GetZoneId() == ConditionValue1;
316 break;
318 {
319 if (Player const* player = object->ToPlayer())
320 {
321 if (FactionEntry const* faction = sFactionStore.LookupEntry(ConditionValue1))
322 condMeets = (ConditionValue2 & (1 << player->GetReputationMgr().GetRank(faction))) != 0;
323 }
324 break;
325 }
327 {
328 if (Player const* player = object->ToPlayer())
329 condMeets = player->HasAchieved(ConditionValue1);
330 break;
331 }
332 case CONDITION_TEAM:
333 {
334 if (Player const* player = object->ToPlayer())
335 condMeets = player->GetTeam() == Team(ConditionValue1);
336 break;
337 }
338 case CONDITION_CLASS:
339 {
340 if (Unit const* unit = object->ToUnit())
341 condMeets = (unit->GetClassMask() & ConditionValue1) != 0;
342 break;
343 }
344 case CONDITION_RACE:
345 {
346 if (Unit const* unit = object->ToUnit())
347 condMeets = Trinity::RaceMask<uint32>{ ConditionValue1 }.HasRace(unit->GetRace());
348 break;
349 }
350 case CONDITION_GENDER:
351 {
352 if (Player const* player = object->ToPlayer())
353 condMeets = player->GetNativeGender() == Gender(ConditionValue1);
354 break;
355 }
356 case CONDITION_SKILL:
357 {
358 if (Player const* player = object->ToPlayer())
359 condMeets = player->HasSkill(ConditionValue1) && player->GetBaseSkillValue(ConditionValue1) >= ConditionValue2;
360 break;
361 }
363 {
364 if (Player const* player = object->ToPlayer())
365 condMeets = player->GetQuestRewardStatus(ConditionValue1);
366 break;
367 }
369 {
370 if (Player const* player = object->ToPlayer())
371 {
372 QuestStatus status = player->GetQuestStatus(ConditionValue1);
373 condMeets = (status == QUEST_STATUS_INCOMPLETE);
374 }
375 break;
376 }
378 {
379 if (Player const* player = object->ToPlayer())
380 {
381 QuestStatus status = player->GetQuestStatus(ConditionValue1);
382 condMeets = (status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(ConditionValue1));
383 }
384 break;
385 }
387 {
388 if (Player const* player = object->ToPlayer())
389 {
390 QuestStatus status = player->GetQuestStatus(ConditionValue1);
391 condMeets = (status == QUEST_STATUS_NONE);
392 }
393 break;
394 }
395 case CONDITION_AREAID:
396 condMeets = DB2Manager::IsInArea(object->GetAreaId(), ConditionValue1);
397 break;
398 case CONDITION_SPELL:
399 {
400 if (Player const* player = object->ToPlayer())
401 condMeets = player->HasSpell(ConditionValue1);
402 break;
403 }
404 case CONDITION_LEVEL:
405 {
406 if (Unit const* unit = object->ToUnit())
407 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), static_cast<uint32>(unit->GetLevel()), ConditionValue1);
408 break;
409 }
411 {
412 if (Player const* player = object->ToPlayer())
413 condMeets = (uint32)Player::GetDrunkenstateByValue(player->GetDrunkValue()) >= ConditionValue1;
414 break;
415 }
417 {
418 condMeets = object->FindNearestCreature(ConditionValue1, (float)ConditionValue2, bool(!ConditionValue3)) != nullptr;
419 break;
420 }
422 {
423 condMeets = object->FindNearestGameObject(ConditionValue1, (float)ConditionValue2) != nullptr;
424 break;
425 }
427 {
428 if (uint32(object->GetTypeId()) == ConditionValue1)
429 {
430 condMeets = !ConditionValue2 || (object->GetEntry() == ConditionValue2);
431
432 if (ConditionValue3)
433 {
434 switch (object->GetTypeId())
435 {
436 case TYPEID_UNIT:
437 condMeets &= object->ToCreature()->GetSpawnId() == ConditionValue3;
438 break;
440 condMeets &= object->ToGameObject()->GetSpawnId() == ConditionValue3;
441 break;
442 default:
443 break;
444 }
445 }
446 }
447 break;
448 }
450 {
451 condMeets = object->isType(TypeMask(ConditionValue1));
452 break;
453 }
455 {
456 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
457 {
458 Unit const* toUnit = toObject->ToUnit();
459 Unit const* unit = object->ToUnit();
460 if (toUnit && unit)
461 {
462 switch (static_cast<RelationType>(ConditionValue2))
463 {
464 case RELATION_SELF:
465 condMeets = unit == toUnit;
466 break;
468 condMeets = unit->IsInPartyWith(toUnit);
469 break;
471 condMeets = unit->IsInRaidWith(toUnit);
472 break;
474 condMeets = unit->GetOwnerGUID() == toUnit->GetGUID();
475 break;
477 condMeets = unit->IsOnVehicle(toUnit);
478 break;
480 condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
481 break;
482 default:
483 break;
484 }
485 }
486 }
487 break;
488 }
490 {
491 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
492 {
493 Unit const* toUnit = toObject->ToUnit();
494 Unit const* unit = object->ToUnit();
495 if (toUnit && unit)
496 condMeets = ((1 << unit->GetReactionTo(toUnit)) & ConditionValue2) != 0;
497 }
498 break;
499 }
501 {
502 if (WorldObject const* toObject = sourceInfo.mConditionTargets[ConditionValue1])
503 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3), object->GetDistance(toObject), static_cast<float>(ConditionValue2));
504 break;
505 }
506 case CONDITION_ALIVE:
507 {
508 if (Unit const* unit = object->ToUnit())
509 condMeets = unit->IsAlive();
510 break;
511 }
512 case CONDITION_HP_VAL:
513 {
514 if (Unit const* unit = object->ToUnit())
515 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealth(), static_cast<uint64>(ConditionValue1));
516 break;
517 }
518 case CONDITION_HP_PCT:
519 {
520 if (Unit const* unit = object->ToUnit())
521 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealthPct(), static_cast<float>(ConditionValue1));
522 break;
523 }
525 {
526 condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
527 break;
528 }
529 case CONDITION_TITLE:
530 {
531 if (Player const* player = object->ToPlayer())
532 condMeets = player->HasTitle(ConditionValue1);
533 break;
534 }
536 {
537 if (Unit const* unit = object->ToUnit())
538 condMeets = unit->HasUnitState(ConditionValue1);
539 break;
540 }
542 {
543 if (Creature const* creature = object->ToCreature())
544 condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
545 break;
546 }
548 {
549 if (Unit const* unit = object->ToUnit())
550 condMeets = unit->IsInWater();
551 break;
552 }
554 {
555 condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1);
556 break;
557 }
559 {
560 if (Unit const* unit = object->ToUnit())
561 {
562 if (ConditionValue1 == 0)
563 condMeets = (unit->GetStandState() == UnitStandStateType(ConditionValue2));
564 else if (ConditionValue2 == 0)
565 condMeets = unit->IsStandState();
566 else if (ConditionValue2 == 1)
567 condMeets = unit->IsSitState();
568 }
569 break;
570 }
572 {
573 if (Player const* player = object->ToPlayer())
574 condMeets = player->IsDailyQuestDone(ConditionValue1);
575 break;
576 }
578 {
579 if (Unit const* unit = object->ToUnit())
580 condMeets = unit->IsCharmed();
581 break;
582 }
584 {
585 if (Player const* player = object->ToPlayer())
586 if (Pet const* pet = player->GetPet())
587 condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0);
588 break;
589 }
590 case CONDITION_TAXI:
591 {
592 if (Player const* player = object->ToPlayer())
593 condMeets = player->IsInFlight();
594 break;
595 }
597 {
598 if (Player const* player = object->ToPlayer())
599 {
600 if (
601 ((ConditionValue2 & (1 << QUEST_STATUS_NONE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_NONE)) ||
602 ((ConditionValue2 & (1 << QUEST_STATUS_COMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_COMPLETE)) ||
603 ((ConditionValue2 & (1 << QUEST_STATUS_INCOMPLETE)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_INCOMPLETE)) ||
604 ((ConditionValue2 & (1 << QUEST_STATUS_FAILED)) && (player->GetQuestStatus(ConditionValue1) == QUEST_STATUS_FAILED)) ||
605 ((ConditionValue2 & (1 << QUEST_STATUS_REWARDED)) && player->GetQuestRewardStatus(ConditionValue1))
606 )
607 condMeets = true;
608 }
609 break;
610 }
612 {
613 if (Player const* player = object->ToPlayer())
614 {
615 QuestObjective const* obj = sObjectMgr->GetQuestObjective(ConditionValue1);
616 if (!obj)
617 break;
618
619 Quest const* quest = sObjectMgr->GetQuestTemplate(obj->QuestID);
620 if (!quest)
621 break;
622
623 uint16 slot = player->FindQuestSlot(obj->QuestID);
624 if (slot >= MAX_QUEST_LOG_SIZE)
625 break;
626
627 condMeets = player->GetQuestSlotObjectiveData(slot, *obj) == int32(ConditionValue3);
628 }
629 break;
630 }
632 {
633 if (Player const* player = object->ToPlayer())
634 {
635 if (ConditionValue1 == 1)
636 condMeets = player->CanBeGameMaster();
637 else
638 condMeets = player->IsGameMaster();
639 }
640 break;
641 }
643 {
644 if (Player const* player = object->ToPlayer())
645 condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue3),
646 player->GetSession()->GetBattlePetMgr()->GetPetCount(sBattlePetSpeciesStore.AssertEntry(ConditionValue1), player->GetGUID()),
647 static_cast<uint8>(ConditionValue2));
648 break;
649 }
651 {
652 if (Player const* player = object->ToPlayer())
653 condMeets = player->GetSceneMgr().GetActiveSceneCount(ConditionValue1) > 0;
654 break;
655 }
657 {
658 if (Player const* player = object->ToPlayer())
660 break;
661 }
663 {
664 condMeets = !object->GetPrivateObjectOwner().IsEmpty();
665 break;
666 }
668 {
669 if (Creature const* creature = object->ToCreature())
670 condMeets = creature->HasStringId(ConditionStringValue1);
671 else if (GameObject const* go = object->ToGameObject())
672 condMeets = go->HasStringId(ConditionStringValue1);
673 break;
674 }
675 case CONDITION_LABEL:
676 {
677 if (Creature const* creature = object->ToCreature())
678 condMeets = creature->HasLabel(ConditionValue1);
679 else if (GameObject const* go = object->ToGameObject())
680 condMeets = go->HasLabel(ConditionValue1);
681 break;
682 }
683 default:
684 break;
685 }
686
688 condMeets = !condMeets;
689
690 if (!condMeets)
691 sourceInfo.mLastFailedCondition = this;
692
693 return condMeets && sScriptMgr->OnConditionCheck(this, sourceInfo); // Returns true by default.;
694}
695
697{
698 // build mask of types for which condition can return true
699 // this is used for speeding up gridsearches
701 return (GRID_MAP_TYPE_MASK_ALL);
702 uint32 mask = 0;
703 switch (ConditionType)
704 {
705 case CONDITION_NONE:
707 break;
708 case CONDITION_AURA:
710 break;
711 case CONDITION_ITEM:
713 break;
716 break;
717 case CONDITION_ZONEID:
719 break;
722 break;
725 break;
726 case CONDITION_TEAM:
728 break;
729 case CONDITION_CLASS:
731 break;
732 case CONDITION_RACE:
734 break;
735 case CONDITION_SKILL:
737 break;
740 break;
743 break;
746 break;
749 break;
752 break;
755 break;
756 case CONDITION_MAPID:
758 break;
759 case CONDITION_AREAID:
761 break;
762 case CONDITION_SPELL:
764 break;
765 case CONDITION_LEVEL:
767 break;
770 break;
773 break;
776 break;
778 switch (ConditionValue1)
779 {
780 case TYPEID_UNIT:
782 break;
783 case TYPEID_PLAYER:
785 break;
788 break;
789 case TYPEID_CORPSE:
791 break;
794 break;
795 default:
796 break;
797 }
798 break;
810 break;
813 break;
816 break;
819 break;
820 case CONDITION_ALIVE:
822 break;
823 case CONDITION_HP_VAL:
825 break;
826 case CONDITION_HP_PCT:
828 break;
831 break;
834 break;
835 case CONDITION_TITLE:
837 break;
838 case CONDITION_GENDER:
840 break;
843 break;
846 break;
849 break;
852 break;
855 break;
858 break;
861 break;
864 break;
867 break;
868 case CONDITION_TAXI:
870 break;
873 break;
876 break;
879 break;
882 break;
885 break;
888 break;
891 break;
894 break;
896 mask |= GRID_MAP_TYPE_MASK_ALL & ~GRID_MAP_TYPE_MASK_PLAYER;
897 break;
900 break;
901 case CONDITION_LABEL:
903 break;
904 default:
905 ABORT_MSG("Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
906 break;
907 }
908 return mask;
909}
910
932
933template <typename FormatContext>
934auto fmt::formatter<Condition>::format(Condition const& condition, FormatContext& ctx) -> decltype(ctx.out())
935{
936 ctx.advance_to(std::ranges::copy("[Condition SourceType: ("sv, ctx.out()).out);
937 if (condition.SourceType < CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED)
938 ctx.advance_to(std::ranges::copy(ConditionMgr::StaticSourceTypeData[condition.SourceType], CStringSentinel, ctx.out()).out);
939 else if (condition.SourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION)
940 ctx.advance_to(std::ranges::copy("Reference"sv, ctx.out()).out);
941 else
942 ctx.advance_to(std::ranges::copy("Unknown"sv, ctx.out()).out);
943
944 *ctx.out() = ')';
945
946 std::array<char, 20> buf;
947
948 if (ConditionMgr::CanHaveSourceGroupSet(condition.SourceType))
949 {
950 ctx.advance_to(std::ranges::copy(", SourceGroup: "sv, ctx.out()).out);
951 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceGroup).ptr, ctx.out()).out);
952 }
953
954 ctx.advance_to(std::ranges::copy(", SourceEntry: "sv, ctx.out()).out);
955 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceEntry).ptr, ctx.out()).out);
956
957 if (ConditionMgr::CanHaveSourceIdSet(condition.SourceType))
958 {
959 ctx.advance_to(std::ranges::copy(", SourceId: "sv, ctx.out()).out);
960 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), condition.SourceId).ptr, ctx.out()).out);
961 }
962
963 ctx.advance_to(std::ranges::copy(", ConditionType: "sv, ctx.out()).out);
964 ctx.advance_to(std::ranges::copy(buf.data(), std::to_chars(buf.data(), buf.data() + buf.size(), int32(condition.ConditionType)).ptr, ctx.out()).out);
965 ctx.advance_to(std::ranges::copy(" ("sv, ctx.out()).out);
966 if (condition.ConditionType < CONDITION_MAX)
967 ctx.advance_to(std::ranges::copy(ConditionMgr::StaticConditionTypeData[condition.ConditionType].Name, CStringSentinel, ctx.out()).out);
968 else
969 ctx.advance_to(std::ranges::copy("Unknown"sv, ctx.out()).out);
970
971 ctx.advance_to(std::ranges::copy(")]"sv, ctx.out()).out);
972
973 return ctx.out();
974}
975
977
982
984{
985 if (conditions.empty())
987 // groupId, typeMask
988 std::map<uint32, uint32> elseGroupSearcherTypeMasks;
989 for (ConditionContainer::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
990 {
991 // no point of having not loaded conditions in list
992 ASSERT(i->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
993 // group not filled yet, fill with widest mask possible
994 auto itr = elseGroupSearcherTypeMasks.try_emplace(i->ElseGroup, GRID_MAP_TYPE_MASK_ALL).first;
995 // no point of checking anymore, empty mask
996 if (!itr->second)
997 continue;
998
999 if (i->ReferenceId) // handle reference
1000 {
1001 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ i->ReferenceId, 0, 0 });
1002 ASSERT(ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
1003 itr->second &= GetSearcherTypeMaskForConditionList(*(ref->second));
1004 }
1005 else // handle normal condition
1006 {
1007 // object will match conditions in one ElseGroupStore only when it matches all of them
1008 // so, let's find a smallest possible mask which satisfies all conditions
1009 itr->second &= i->GetSearcherTypeMaskForCondition();
1010 }
1011 }
1012 // object will match condition when one of the checks in ElseGroupStore is matching
1013 // so, let's include all possible masks
1014 uint32 mask = 0;
1015 for (std::map<uint32, uint32>::const_iterator i = elseGroupSearcherTypeMasks.begin(); i != elseGroupSearcherTypeMasks.end(); ++i)
1016 mask |= i->second;
1017
1018 return mask;
1019}
1020
1022{
1023 // groupId, groupCheckPassed
1024 std::map<uint32, bool> elseGroupStore;
1025 for (Condition const& condition : conditions)
1026 {
1027 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition, condition.ConditionValue1);
1028 if (condition.isLoaded())
1029 {
1031 std::map<uint32, bool>::iterator itr = elseGroupStore.try_emplace(condition.ElseGroup, true).first;
1032 if (!itr->second)
1033 continue;
1034
1035 if (condition.ReferenceId)//handle reference
1036 {
1037 auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1039 {
1040 bool condMeets = IsObjectMeetToConditionList(sourceInfo, *ref->second);
1041 if (condition.NegativeCondition)
1042 condMeets = !condMeets;
1043
1044 if (!condMeets)
1045 itr->second = false;
1046 }
1047 else
1048 {
1049 TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} Reference template -{} not found",
1050 condition, condition.ReferenceId); // checked at loading, should never happen
1051 }
1052
1053 }
1054 else //handle normal condition
1055 {
1056 if (!condition.Meets(sourceInfo))
1057 itr->second = false;
1058 }
1059 }
1060 }
1061 for (std::map<uint32, bool>::const_iterator i = elseGroupStore.begin(); i != elseGroupStore.end(); ++i)
1062 if (i->second)
1063 return true;
1064
1065 return false;
1066}
1067
1069{
1070 ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
1071 return IsObjectMeetToConditions(srcInfo, conditions);
1072}
1073
1074bool ConditionMgr::IsObjectMeetToConditions(WorldObject const* object1, WorldObject const* object2, ConditionContainer const& conditions) const
1075{
1076 ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2);
1077 return IsObjectMeetToConditions(srcInfo, conditions);
1078}
1079
1081{
1082 if (conditions.empty())
1083 return true;
1084
1085 TC_LOG_DEBUG("condition", "ConditionMgr::IsObjectMeetToConditions");
1086 return IsObjectMeetToConditionList(sourceInfo, conditions);
1087}
1088
1090{
1091 return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
1103 sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
1108 sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT ||
1109 sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR ||
1110 sourceType == CONDITION_SOURCE_TYPE_PHASE ||
1111 sourceType == CONDITION_SOURCE_TYPE_GRAVEYARD ||
1112 sourceType == CONDITION_SOURCE_TYPE_AREATRIGGER ||
1117}
1118
1120{
1121 return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
1122}
1123
1125{
1126 switch (sourceType)
1127 {
1129 switch (conditionType)
1130 {
1131 case CONDITION_NONE:
1134 case CONDITION_MAPID:
1139 return true;
1140 default:
1141 return false;
1142 }
1143 break;
1144 default:
1145 break;
1146 }
1147 return true;
1148}
1149
1151{
1152 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1153 {
1154 auto i = ConditionStore[sourceType].find({ 0, int32(entry), 0 });
1155 if (i != ConditionStore[sourceType].end())
1156 {
1157 TC_LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type {} and entry {}", uint32(sourceType), entry);
1158 return IsObjectMeetToConditions(sourceInfo, *i->second);
1159 }
1160 }
1161
1162 return true;
1163}
1164
1165bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, WorldObject const* target0, WorldObject const* target1 /*= nullptr*/, WorldObject const* target2 /*= nullptr*/) const
1166{
1167 ConditionSourceInfo conditionSource(target0, target1, target2);
1168 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1169}
1170
1172{
1173 ConditionSourceInfo conditionSource(map);
1174 return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
1175}
1176
1178{
1179 if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
1180 return ConditionStore[sourceType].contains({ 0, int32(entry), 0 });
1181
1182 return false;
1183}
1184
1185bool ConditionMgr::IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const
1186{
1187 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1189 {
1190 TC_LOG_DEBUG("condition", "IsObjectMeetingSpellClickConditions: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1191 ConditionSourceInfo sourceInfo(clicker, target);
1192 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1193 }
1194 return true;
1195}
1196
1198{
1199 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 });
1201 {
1202 TC_LOG_DEBUG("condition", "HasConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId);
1203 return true;
1204 }
1205 return false;
1206}
1207
1208bool ConditionMgr::IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const
1209{
1210 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].find({ creatureId, int32(spellId), 0 });
1212 {
1213 TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId);
1214 ConditionSourceInfo sourceInfo(player, vehicle);
1215 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1216 }
1217 return true;
1218}
1219
1220bool ConditionMgr::IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const
1221{
1222 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].find({ eventId + 1, int32(entryOrGuid), sourceType });
1224 {
1225 TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId);
1226 ConditionSourceInfo sourceInfo(unit, baseObject);
1227 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1228 }
1229 return true;
1230}
1231
1232bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const
1233{
1234 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ creatureId, int32(itemId), 0 });
1236 {
1237 TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId);
1238 ConditionSourceInfo sourceInfo(player, vendor);
1239 return IsObjectMeetToConditions(sourceInfo, *itr->second);
1240 }
1241 return true;
1242}
1243
1244bool ConditionMgr::IsObjectMeetingPlayerChoiceResponseConditions(uint32 playerChoiceId, int32 playerChoiceResponseId, Player const* player) const
1245{
1246 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_PLAYER_CHOICE_RESPONSE].find({ .SourceGroup = playerChoiceId, .SourceEntry = playerChoiceResponseId, .SourceId = 0 });
1248 {
1249 TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", playerChoiceId, playerChoiceResponseId);
1250 return IsObjectMeetToConditions(player, *itr->second);
1251 }
1252 return true;
1253}
1254
1259
1260ConditionContainer const* ConditionMgr::GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const
1261{
1262 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].find({ areaTriggerId, isServerSide ? 1 : 0, 0 });
1264 return itr->second.get();
1265 return nullptr;
1266}
1267
1269{
1270 auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ trainerId, int32(spellId), 0 });
1272 {
1273 TC_LOG_DEBUG("condition", "IsObjectMeetingTrainerSpellConditions: found conditions for trainer id {} spell {}", trainerId, spellId);
1274 return IsObjectMeetToConditions(player, *itr->second);
1275 }
1276 return true;
1277}
1278
1280{
1283 {
1284 TC_LOG_DEBUG("condition", "IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {} entry {} guid {}", obj->GetTypeId(), obj->GetEntry(), obj->GetGUID());
1285 return IsObjectMeetToConditions(seer, obj, *itr->second);
1286 }
1287 return true;
1288}
1289
1291{
1292 static ConditionMgr instance;
1293 return &instance;
1294}
1295
1297{
1298 uint32 oldMSTime = getMSTime();
1299
1300 Clean();
1301
1302 //must clear all custom handled cases (groupped types) before reload
1303 if (isReload)
1304 {
1305 sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
1306
1307 sObjectMgr->UnloadPhaseConditions();
1308 }
1309
1310 QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
1311 "ConditionValue1, ConditionValue2, ConditionValue3, ConditionStringValue1, "
1312 "NegativeCondition, ErrorType, ErrorTextId, ScriptName FROM conditions");
1313
1314 if (!result)
1315 {
1316 TC_LOG_INFO("server.loading", ">> Loaded 0 conditions. DB table `conditions` is empty!");
1317 return;
1318 }
1319
1320 uint32 count = 0;
1321
1322 auto getOrInitConditions = [this](ConditionSourceType sourceType, ConditionId const& id)
1323 {
1324 auto [itr, inserted] = ConditionStore[sourceType].try_emplace(id, nullptr);
1325 if (inserted)
1326 itr->second = std::make_shared<std::vector<Condition>>();
1327 return itr->second;
1328 };
1329
1330 do
1331 {
1332 Field* fields = result->Fetch();
1333
1334 Condition cond;
1335 int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
1336 cond.SourceGroup = fields[1].GetUInt32();
1337 cond.SourceEntry = fields[2].GetInt32();
1338 cond.SourceId = fields[3].GetInt32();
1339 cond.ElseGroup = fields[4].GetUInt32();
1340 int32 iConditionTypeOrReference = fields[5].GetInt32();
1341 cond.ConditionTarget = fields[6].GetUInt8();
1342 cond.ConditionValue1 = fields[7].GetUInt32();
1343 cond.ConditionValue2 = fields[8].GetUInt32();
1344 cond.ConditionValue3 = fields[9].GetUInt32();
1345 cond.ConditionStringValue1 = fields[10].GetString();
1346 cond.NegativeCondition = fields[11].GetBool();
1347 cond.ErrorType = fields[12].GetUInt32();
1348 cond.ErrorTextId = fields[13].GetUInt32();
1349 cond.ScriptId = sObjectMgr->GetScriptId(fields[14].GetStringView());
1350
1351 if (iConditionTypeOrReference >= 0)
1352 cond.ConditionType = ConditionTypes(iConditionTypeOrReference);
1353
1354 if (iSourceTypeOrReferenceId >= 0)
1355 cond.SourceType = ConditionSourceType(iSourceTypeOrReferenceId);
1356
1357 if (iConditionTypeOrReference < 0)//it has a reference
1358 {
1359 if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip
1360 {
1361 TC_LOG_ERROR("sql.sql", "Condition reference {} is referencing self, skipped", iSourceTypeOrReferenceId);
1362 continue;
1363 }
1364
1365 cond.ReferenceId = uint32(-iConditionTypeOrReference);
1366
1367 char const* rowType = "reference template";
1368 if (iSourceTypeOrReferenceId >= 0)
1369 rowType = "reference";
1370 //check for useless data
1371 if (cond.ConditionTarget)
1372 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionTarget);
1373 if (cond.ConditionValue1)
1374 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue1);
1375 if (cond.ConditionValue2)
1376 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue2);
1377 if (cond.ConditionValue3)
1378 TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3);
1379 }
1380 else if (!isConditionTypeValid(&cond))//doesn't have reference, validate ConditionType
1381 continue;
1382
1383 if (iSourceTypeOrReferenceId < 0)//it is a reference template
1384 {
1385 if (cond.SourceGroup)
1386 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceGroup ({})!", iSourceTypeOrReferenceId, cond.SourceGroup);
1387 if (cond.SourceEntry)
1388 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceEntry ({})!", iSourceTypeOrReferenceId, cond.SourceEntry);
1389 if (cond.SourceId)
1390 TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceId ({})!", iSourceTypeOrReferenceId, cond.SourceId);
1391
1393 cond.SourceGroup = -iSourceTypeOrReferenceId;
1394 }
1395 else if (!isSourceTypeValid(&cond)) //if not a reference and SourceType is invalid, skip
1396 continue;
1397
1398 //Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
1399 if (cond.SourceGroup && !CanHaveSourceGroupSet(cond.SourceType))
1400 {
1401 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond, cond.SourceGroup);
1402 continue;
1403 }
1404 if (cond.SourceId && !CanHaveSourceIdSet(cond.SourceType))
1405 {
1406 TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond, cond.SourceId);
1407 continue;
1408 }
1409
1411 {
1412 TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond, cond.ErrorType);
1413 cond.ErrorType = 0;
1414 }
1415
1416 if (cond.ErrorTextId && !cond.ErrorType)
1417 {
1418 TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond, cond.ErrorTextId);
1419 cond.ErrorTextId = 0;
1420 }
1421
1422 getOrInitConditions(cond.SourceType, { cond.SourceGroup, cond.SourceEntry, cond.SourceId })->emplace_back(std::move(cond));
1423 ++count;
1424 }
1425 while (result->NextRow());
1426
1427 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE])
1428 addToLootTemplate(id, conditions, LootTemplates_Creature.GetLootForConditionFill(id.SourceGroup));
1429
1430 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE])
1432
1433 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE])
1434 addToLootTemplate(id, conditions, LootTemplates_Fishing.GetLootForConditionFill(id.SourceGroup));
1435
1436 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE])
1438
1439 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE])
1440 addToLootTemplate(id, conditions, LootTemplates_Item.GetLootForConditionFill(id.SourceGroup));
1441
1442 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE])
1443 addToLootTemplate(id, conditions, LootTemplates_Mail.GetLootForConditionFill(id.SourceGroup));
1444
1445 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE])
1446 addToLootTemplate(id, conditions, LootTemplates_Milling.GetLootForConditionFill(id.SourceGroup));
1447
1450
1453
1454 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE])
1455 addToLootTemplate(id, conditions, LootTemplates_Reference.GetLootForConditionFill(id.SourceGroup));
1456
1457 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE])
1458 addToLootTemplate(id, conditions, LootTemplates_Skinning.GetLootForConditionFill(id.SourceGroup));
1459
1460 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE])
1461 addToLootTemplate(id, conditions, LootTemplates_Spell.GetLootForConditionFill(id.SourceGroup));
1462
1463 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU])
1464 addToGossipMenus(id, conditions);
1465
1466 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION])
1467 addToGossipMenuItems(id, conditions);
1468
1470 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT])
1471 for (Condition const& condition : *conditions)
1472 if (condition.ConditionType == CONDITION_AURA)
1473 SpellsUsedInSpellClickConditions.insert(condition.ConditionValue1);
1474
1475 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET])
1476 for (Condition const& condition : *conditions)
1478
1479 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PHASE])
1480 addToPhases(id, conditions);
1481
1482 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GRAVEYARD])
1483 addToGraveyardData(id, conditions);
1484
1485 struct
1486 {
1487 bool operator()(uint32 playerConditionId, std::vector<Condition> const& conditions, ConditionEntriesByTypeArray const& store) const
1488 {
1489 return std::ranges::any_of(conditions, [&](Condition const& condition)
1490 {
1492 {
1493 if (condition.ConditionValue1 == playerConditionId)
1494 return true;
1495 auto playerCondItr = store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].find({ 0, int32(condition.ConditionValue1), 0 });
1496 if (playerCondItr != store[CONDITION_SOURCE_TYPE_PLAYER_CONDITION].end())
1497 if (operator()(playerConditionId, *playerCondItr->second, store))
1498 return true;
1499 }
1500 else if (condition.ReferenceId)
1501 {
1502 auto refItr = store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 });
1503 if (refItr != store[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end())
1504 if (operator()(playerConditionId, *refItr->second, store))
1505 return true;
1506 }
1507 return false;
1508 });
1509 }
1510 } isPlayerConditionIdUsedByCondition;
1511
1512 for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PLAYER_CONDITION])
1513 {
1514 if (isPlayerConditionIdUsedByCondition(id.SourceEntry, *conditions, ConditionStore))
1515 {
1516 TC_LOG_ERROR("sql.sql", "[Condition SourceType: CONDITION_SOURCE_TYPE_PLAYER_CONDITION, SourceGroup: {}, SourceEntry: {}, SourceId: {}] "
1517 "has a circular reference to player condition id {}, removed all conditions for this SourceEntry!",
1518 id.SourceGroup, id.SourceEntry, id.SourceId, id.SourceEntry);
1519 conditions->clear();
1520 }
1521 }
1522
1523 TC_LOG_INFO("server.loading", ">> Loaded {} conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1524}
1525
1526void ConditionMgr::addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const
1527{
1528 if (!loot)
1529 {
1530 for (Condition const& condition : *conditions)
1531 TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", condition, id.SourceGroup);
1532 return;
1533 }
1534
1535 if (loot->LinkConditions(id, ConditionsReference{ conditions }))
1536 return;
1537
1538 for (Condition const& condition : *conditions)
1539 TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", condition, id.SourceEntry, id.SourceGroup);
1540}
1541
1542void ConditionMgr::addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1543{
1544 GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(id.SourceGroup);
1545
1546 if (pMenuBounds.first != pMenuBounds.second)
1547 {
1548 for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
1549 if (itr->second.MenuID == id.SourceGroup && (itr->second.TextID == uint32(id.SourceEntry) || id.SourceEntry == 0))
1550 itr->second.Conditions = { conditions };
1551
1552 return;
1553 }
1554
1555 for (Condition const& condition : *conditions)
1556 TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", condition, id.SourceGroup);
1557}
1558
1559void ConditionMgr::addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1560{
1561 Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(id.SourceGroup);
1562 for (auto& [_, gossipMenuItem] : pMenuItemBounds)
1563 {
1564 if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == uint32(id.SourceEntry))
1565 {
1566 gossipMenuItem.Conditions = { conditions };
1567 return;
1568 }
1569 }
1570
1571 for (Condition const& condition : *conditions)
1572 TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", condition, id.SourceGroup, id.SourceEntry);
1573}
1574
1576{
1577 sSpellMgr->ForEachSpellInfoDifficulty(cond.SourceEntry, [&](SpellInfo const* spellInfo)
1578 {
1579 uint32 conditionEffMask = cond.SourceGroup;
1580 std::list<uint32> sharedMasks;
1581 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1582 {
1583 // additional checks by condition type
1584 if (conditionEffMask & (1 << spellEffectInfo.EffectIndex))
1585 {
1586 switch (cond.ConditionType)
1587 {
1588 case CONDITION_OBJECT_ENTRY_GUID:
1589 {
1590 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
1591 if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond.ConditionValue1 != TYPEID_UNIT && cond.ConditionValue1 != TYPEID_PLAYER)
1592 {
1593 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1594 "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER));
1595 return;
1596 }
1597
1598 if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond.ConditionValue1 != TYPEID_GAMEOBJECT)
1599 {
1600 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1601 "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT));
1602 return;
1603 }
1604
1605 if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond.ConditionValue1 != TYPEID_CORPSE)
1606 {
1607 TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - "
1608 "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond, spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE));
1609 return;
1610 }
1611 break;
1612 }
1613 default:
1614 break;
1615 }
1616 }
1617
1618 // check if effect is already a part of some shared mask
1619 auto itr = std::find_if(sharedMasks.begin(), sharedMasks.end(), [&](uint32 mask) { return !!(mask & (1 << spellEffectInfo.EffectIndex)); });
1620 if (itr != sharedMasks.end())
1621 continue;
1622
1623 // build new shared mask with found effect
1624 uint32 sharedMask = 1 << spellEffectInfo.EffectIndex;
1625 for (size_t effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo->GetEffects().size(); ++effIndex)
1626 if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions)
1627 sharedMask |= 1 << effIndex;
1628
1629 sharedMasks.push_back(sharedMask);
1630 }
1631
1632 for (uint32 effectMask : sharedMasks)
1633 {
1634 // some effect indexes should have same data
1635 if (uint32 commonMask = effectMask & conditionEffMask)
1636 {
1637 size_t firstEffIndex = 0;
1638 for (; firstEffIndex < spellInfo->GetEffects().size(); ++firstEffIndex)
1639 if ((1 << firstEffIndex) & effectMask)
1640 break;
1641
1642 if (firstEffIndex >= spellInfo->GetEffects().size())
1643 return;
1644
1645 // get shared data
1646 std::shared_ptr<ConditionContainer> sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions;
1647
1648 // there's already data entry for that sharedMask
1649 if (sharedList)
1650 {
1651 // we have overlapping masks in db
1652 if (conditionEffMask != effectMask)
1653 {
1654 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup {} (spell effectMask) set - "
1655 "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty {}).",
1656 cond, cond.SourceGroup, uint32(spellInfo->Difficulty));
1657 return;
1658 }
1659 }
1660 // no data for shared mask, we can create new submask
1661 else
1662 {
1663 // add new list, create new shared mask
1664 sharedList = std::make_shared<ConditionContainer>();
1665 bool assigned = false;
1666 for (size_t i = firstEffIndex; i < spellInfo->GetEffects().size(); ++i)
1667 {
1668 if ((1 << i) & commonMask)
1669 {
1670 const_cast<SpellEffectInfo&>(spellInfo->GetEffect(SpellEffIndex(i))).ImplicitTargetConditions = sharedList;
1671 assigned = true;
1672 }
1673 }
1674
1675 if (!assigned)
1676 break;
1677 }
1678 sharedList->push_back(cond);
1679 break;
1680 }
1681 }
1682 });
1683}
1684
1685void ConditionMgr::addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1686{
1687 if (!id.SourceEntry)
1688 {
1689 if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(id.SourceGroup))
1690 {
1691 bool found = false;
1692 for (uint32 areaId : phaseInfo->Areas)
1693 {
1694 if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(areaId)))
1695 {
1696 for (PhaseAreaInfo& phase : *phases)
1697 {
1698 if (phase.PhaseInfo->Id == id.SourceGroup)
1699 {
1700 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1701 found = true;
1702 }
1703 }
1704 }
1705 }
1706
1707 if (found)
1708 return;
1709 }
1710 }
1711 else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(id.SourceEntry)))
1712 {
1713 for (PhaseAreaInfo& phase : *phases)
1714 {
1715 if (phase.PhaseInfo->Id == id.SourceGroup)
1716 {
1717 phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end());
1718 return;
1719 }
1720 }
1721 }
1722
1723 for (Condition const& condition : *conditions)
1724 TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", condition, id.SourceEntry, id.SourceGroup);
1725}
1726
1727void ConditionMgr::addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const
1728{
1729 if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(id.SourceEntry, id.SourceGroup)))
1730 {
1731 graveyard->Conditions = { conditions };
1732 return;
1733 }
1734
1735 for (Condition const& condition : *conditions)
1736 TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", condition, id.SourceEntry, id.SourceGroup);
1737}
1738
1740{
1741 switch (cond->SourceType)
1742 {
1744 {
1746 {
1747 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_loot_template`, ignoring.", *cond);
1748 return false;
1749 }
1750 break;
1751 }
1753 {
1755 {
1756 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", *cond);
1757 return false;
1758 }
1759 break;
1760 }
1762 {
1764 {
1765 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `fishing_loot_template`, ignoring.", *cond);
1766 return false;
1767 }
1768 break;
1769 }
1771 {
1773 {
1774 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", *cond);
1775 return false;
1776 }
1777 break;
1778 }
1780 {
1782 {
1783 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `item_loot_template`, ignoring.", *cond);
1784 return false;
1785 }
1786 break;
1787 }
1789 {
1791 {
1792 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `mail_loot_template`, ignoring.", *cond);
1793 return false;
1794 }
1795 break;
1796 }
1798 {
1800 {
1801 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `milling_loot_template`, ignoring.", *cond);
1802 return false;
1803 }
1804 break;
1805 }
1807 {
1809 {
1810 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", *cond);
1811 return false;
1812 }
1813 break;
1814 }
1816 {
1818 {
1819 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", *cond);
1820 return false;
1821 }
1822 break;
1823 }
1825 {
1827 {
1828 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `reference_loot_template`, ignoring.", *cond);
1829 return false;
1830 }
1831 break;
1832 }
1834 {
1836 {
1837 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `skinning_loot_template`, ignoring.", *cond);
1838 return false;
1839 }
1840 break;
1841 }
1843 {
1845 {
1846 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `spell_loot_template`, ignoring.", *cond);
1847 return false;
1848 }
1849 break;
1850 }
1852 {
1853 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1854 if (!spellInfo)
1855 {
1856 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1857 return false;
1858 }
1859
1860 if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup)
1861 {
1862 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup (spell effectMask) set, ignoring.", *cond);
1863 return false;
1864 }
1865
1866 uint32 origGroup = cond->SourceGroup;
1867
1868 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1869 {
1870 if (!((1 << spellEffectInfo.EffectIndex) & cond->SourceGroup))
1871 continue;
1872
1873 if (spellEffectInfo.ChainTargets > 0)
1874 continue;
1875
1876 switch (spellEffectInfo.TargetA.GetSelectionCategory())
1877 {
1883 continue;
1884 default:
1885 break;
1886 }
1887
1888 switch (spellEffectInfo.TargetB.GetSelectionCategory())
1889 {
1895 continue;
1896 default:
1897 break;
1898 }
1899
1900 switch (spellEffectInfo.Effect)
1901 {
1912 continue;
1913 default:
1914 break;
1915 }
1916
1917 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));
1918 cond->SourceGroup &= ~(1 << spellEffectInfo.EffectIndex);
1919 }
1920 // all effects were removed, no need to add the condition at all
1921 if (!cond->SourceGroup)
1922 return false;
1923 break;
1924 }
1926 {
1927 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
1928 {
1929 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1930 return false;
1931 }
1932 break;
1933 }
1936 {
1937 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE);
1938 if (!spellProto)
1939 {
1940 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1941 return false;
1942 }
1943 break;
1944 }
1946 if (!sObjectMgr->GetQuestTemplate(cond->SourceEntry))
1947 {
1948 TC_LOG_ERROR("sql.sql", "{} SourceEntry specifies non-existing quest, skipped.", *cond);
1949 return false;
1950 }
1951 break;
1953 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1954 {
1955 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1956 return false;
1957 }
1958
1959 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
1960 {
1961 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1962 return false;
1963 }
1964 break;
1966 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1967 {
1968 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1969 return false;
1970 }
1971
1972 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
1973 {
1974 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
1975 return false;
1976 }
1977 break;
1979 {
1980 if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
1981 {
1982 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
1983 return false;
1984 }
1985 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(cond->SourceEntry);
1986 if (!itemTemplate)
1987 {
1988 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, item does not exist, ignoring.", *cond);
1989 return false;
1990 }
1991 break;
1992 }
1994 {
1995 if (!sMapStore.LookupEntry(cond->SourceEntry))
1996 {
1997 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in Map.db2, ignoring.", *cond);
1998 return false;
1999 }
2000 break;
2001 }
2003 {
2004 if (cond->SourceEntry && !sAreaTableStore.LookupEntry(cond->SourceEntry))
2005 {
2006 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in AreaTable.db2, ignoring.", *cond);
2007 return false;
2008 }
2009 break;
2010 }
2012 if (!sObjectMgr->FindGraveyardData(cond->SourceEntry, cond->SourceGroup))
2013 {
2014 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `graveyard_zone`, ignoring.", *cond);
2015 return false;
2016 }
2017 break;
2019 if (cond->SourceEntry != 0 && cond->SourceEntry != 1)
2020 {
2021 TC_LOG_ERROR("sql.sql", "{} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring.", *cond);
2022 return false;
2023 }
2024 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), cond->SourceEntry == 1 }))
2025 {
2026 TC_LOG_ERROR("sql.sql", "{} in `condition` table, does not exist in `areatrigger_template`, ignoring.", *cond);
2027 return false;
2028 }
2029 break;
2031 if (!sConversationDataStore->GetConversationLineTemplate(cond->SourceEntry))
2032 {
2033 TC_LOG_ERROR("sql.sql", "{} does not exist in `conversation_line_template`, ignoring.", *cond);
2034 return false;
2035 }
2036 break;
2038 if (!sAreaTriggerStore.LookupEntry(cond->SourceEntry))
2039 {
2040 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exists in AreaTrigger.db2, ignoring.", *cond);
2041 return false;
2042 }
2043 break;
2045 {
2046 if (!sObjectMgr->GetTrainer(cond->SourceGroup))
2047 {
2048 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `trainer`, ignoring.", *cond);
2049 return false;
2050 }
2051 if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE))
2052 {
2053 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table does not exist in `Spell.db2`, ignoring.", *cond);
2054 return false;
2055 }
2056 break;
2057 }
2059 {
2060 if (cond->SourceGroup <= 0 || cond->SourceGroup >= NUM_CLIENT_OBJECT_TYPES)
2061 {
2062 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, is no valid object type, ignoring.", *cond);
2063 return false;
2064 }
2065
2066 if (cond->SourceGroup == TYPEID_UNIT)
2067 {
2068 if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
2069 {
2070 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring.", *cond);
2071 return false;
2072 }
2073 }
2074 else if (cond->SourceGroup == TYPEID_GAMEOBJECT)
2075 {
2076 if (!sObjectMgr->GetGameObjectTemplate(cond->SourceEntry))
2077 {
2078 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `gameobject_template`, ignoring.", *cond);
2079 return false;
2080 }
2081 }
2082 else
2083 {
2084 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, uses unchecked type id, ignoring.", *cond);
2085 return false;
2086 }
2087 break;
2088 }
2090 {
2091 SpawnGroupTemplateData const* spawnGroup = sObjectMgr->GetSpawnGroupData(cond->SourceEntry);
2092 if (!spawnGroup)
2093 {
2094 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `spawn_group_template`, ignoring.", *cond);
2095 return false;
2096 }
2097 if (spawnGroup->flags & (SPAWNGROUP_FLAG_SYSTEM))
2098 {
2099 TC_LOG_ERROR("sql.sql", "{} in `spawn_group_template` table cannot have SPAWNGROUP_FLAG_SYSTEM flags, ignoring.", *cond);
2100 return false;
2101 }
2102 break;
2103 }
2105 {
2106 SkillLineAbilityEntry const* skillLineAbility = sSkillLineAbilityStore.LookupEntry(cond->SourceEntry);
2107 if (!skillLineAbility)
2108 {
2109 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in SkillLineAbility.db2, ignoring.", *cond);
2110 return false;
2111 }
2113 {
2114 TC_LOG_ERROR("sql.sql", "{} in SkillLineAbility.db2 does not have AcquireMethod = {} (LearnedOrAutomaticCharLevel), ignoring.",
2116 return false;
2117 }
2118 break;
2119 }
2121 {
2122 PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(cond->SourceGroup);
2123 if (!playerChoice)
2124 {
2125 TC_LOG_ERROR("sql.sql", "{} SourceGroup in `condition` table, does not exist in `playerchoice`, ignoring.", *cond);
2126 return false;
2127 }
2128 if (!playerChoice->GetResponse(cond->SourceEntry))
2129 {
2130 TC_LOG_ERROR("sql.sql", "{} SourceEntry in `condition` table, does not exist in `playerchoice_response`, ignoring.", *cond);
2131 return false;
2132 }
2133 break;
2134 }
2139 break;
2140 default:
2141 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionSourceType in `condition` table, ignoring.", *cond);
2142 return false;
2143 }
2144
2145 return true;
2146}
2147
2149{
2150 switch (cond->ConditionType)
2151 {
2152 case CONDITION_NONE:
2153 {
2154 if (!cond->NegativeCondition && !cond->ScriptId)
2155 {
2156 TC_LOG_ERROR("sql.sql", "{} must have `NegativeCondition` or `ScriptName` in `condition` table, ignoring.", *cond);
2157 return false;
2158 }
2159 break;
2160 }
2161 case CONDITION_AURA:
2162 {
2163 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE);
2164 if (!spellInfo)
2165 {
2166 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped.", *cond, cond->ConditionValue1);
2167 return false;
2168 }
2169
2170 if (cond->ConditionValue2 >= spellInfo->GetEffects().size())
2171 {
2172 TC_LOG_ERROR("sql.sql", "{} spell {} has non existing effect index ({}) (must be 0..{}), skipped.",
2173 *cond, cond->ConditionValue1, cond->ConditionValue2, spellInfo->GetEffects().size() - 1);
2174 return false;
2175 }
2176
2177 if (!spellInfo->GetEffect(SpellEffIndex(cond->ConditionValue2)).IsAura())
2178 {
2179 TC_LOG_ERROR("sql.sql", "{} spell {} effect index {} is not an aura, skipped.",
2180 *cond, cond->ConditionValue1, cond->ConditionValue2);
2181 return false;
2182 }
2183 break;
2184 }
2185 case CONDITION_ITEM:
2186 {
2187 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2188 if (!proto)
2189 {
2190 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2191 return false;
2192 }
2193
2194 if (!cond->ConditionValue2)
2195 {
2196 TC_LOG_ERROR("sql.sql", "{} Zero item count in ConditionValue2, skipped.", *cond);
2197 return false;
2198 }
2199 break;
2200 }
2202 {
2203 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(cond->ConditionValue1);
2204 if (!proto)
2205 {
2206 TC_LOG_ERROR("sql.sql", "{} Item ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2207 return false;
2208 }
2209 break;
2210 }
2211 case CONDITION_ZONEID:
2212 {
2213 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
2214 if (!areaEntry)
2215 {
2216 TC_LOG_ERROR("sql.sql", "{} Area ({}) does not exist, skipped.", *cond, cond->ConditionValue1);
2217 return false;
2218 }
2219
2220 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2221 {
2222 TC_LOG_ERROR("sql.sql", "{} requires to be in area ({}) which is a subzone but zone expected, skipped.", *cond, cond->ConditionValue1);
2223 return false;
2224 }
2225 break;
2226 }
2228 {
2229 FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->ConditionValue1);
2230 if (!factionEntry)
2231 {
2232 TC_LOG_ERROR("sql.sql", "{} has non existing faction ({}), skipped.", *cond, cond->ConditionValue1);
2233 return false;
2234 }
2235 break;
2236 }
2237 case CONDITION_TEAM:
2238 {
2239 if (cond->ConditionValue1 != ALLIANCE && cond->ConditionValue1 != HORDE)
2240 {
2241 TC_LOG_ERROR("sql.sql", "{} specifies unknown team ({}), skipped.", *cond, cond->ConditionValue1);
2242 return false;
2243 }
2244 break;
2245 }
2246 case CONDITION_SKILL:
2247 {
2248 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(cond->ConditionValue1);
2249 if (!pSkill)
2250 {
2251 TC_LOG_ERROR("sql.sql", "{} specifies non-existing skill ({}), skipped.", *cond, cond->ConditionValue1);
2252 return false;
2253 }
2254
2255 if (cond->ConditionValue2 < 1 || cond->ConditionValue2 > sWorld->GetConfigMaxSkillValue())
2256 {
2257 TC_LOG_ERROR("sql.sql", "{} specifies skill ({}) with invalid value ({}), skipped.", *cond, cond->ConditionValue1, cond->ConditionValue2);
2258 return false;
2259 }
2260 break;
2261 }
2263 if (cond->ConditionValue2 >= (1 << MAX_QUEST_STATUS))
2264 {
2265 TC_LOG_ERROR("sql.sql", "{} has invalid state mask ({}), skipped.", *cond, cond->ConditionValue2);
2266 return false;
2267 }
2268 [[fallthrough]];
2274 {
2275 if (!sObjectMgr->GetQuestTemplate(cond->ConditionValue1))
2276 {
2277 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest ({}), skipped.", *cond, cond->ConditionValue1);
2278 return false;
2279 }
2280 break;
2281 }
2283 {
2284 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2285 if (cond->ConditionValue1 >= events.size() || !events[cond->ConditionValue1].isValid())
2286 {
2287 TC_LOG_ERROR("sql.sql", "{} has non existing event id ({}), skipped.", *cond, cond->ConditionValue1);
2288 return false;
2289 }
2290 break;
2291 }
2293 {
2294 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2295 if (!achievement)
2296 {
2297 TC_LOG_ERROR("sql.sql", "{} has non existing achivement id ({}), skipped.", *cond, cond->ConditionValue1);
2298 return false;
2299 }
2300 break;
2301 }
2302 case CONDITION_CLASS:
2303 {
2305 {
2306 TC_LOG_ERROR("sql.sql", "{} has non existing classmask ({}), skipped.", *cond, cond->ConditionValue1 & ~CLASSMASK_ALL_PLAYABLE);
2307 return false;
2308 }
2309 break;
2310 }
2311 case CONDITION_RACE:
2312 {
2313 Trinity::RaceMask<uint64> invalidRaceMask = Trinity::RaceMask<uint64>{ cond->ConditionValue1 } & ~RACEMASK_ALL_PLAYABLE;
2314 if (!invalidRaceMask.IsEmpty()) // uint32 works thanks to weird index remapping in racemask
2315 {
2316 TC_LOG_ERROR("sql.sql", "{} has non existing racemask ({}), skipped.", *cond, invalidRaceMask.RawValue);
2317 return false;
2318 }
2319 break;
2320 }
2321 case CONDITION_GENDER:
2322 {
2324 {
2325 TC_LOG_ERROR("sql.sql", "{} has invalid gender ({}), skipped.", *cond, cond->ConditionValue1);
2326 return false;
2327 }
2328 break;
2329 }
2330 case CONDITION_MAPID:
2331 {
2332 MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1);
2333 if (!me)
2334 {
2335 TC_LOG_ERROR("sql.sql", "{} has non existing map ({}), skipped", *cond, cond->ConditionValue1);
2336 return false;
2337 }
2338 break;
2339 }
2340 case CONDITION_SPELL:
2341 {
2342 if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE))
2343 {
2344 TC_LOG_ERROR("sql.sql", "{} has non existing spell (Id: {}), skipped", *cond, cond->ConditionValue1);
2345 return false;
2346 }
2347 break;
2348 }
2349 case CONDITION_LEVEL:
2350 {
2351 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2352 {
2353 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2354 return false;
2355 }
2356 break;
2357 }
2359 {
2360 if (cond->ConditionValue1 > DRUNKEN_SMASHED)
2361 {
2362 TC_LOG_ERROR("sql.sql", "{} has invalid state ({}), skipped.", *cond, cond->ConditionValue1);
2363 return false;
2364 }
2365 break;
2366 }
2368 {
2369 if (!sObjectMgr->GetCreatureTemplate(cond->ConditionValue1))
2370 {
2371 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped", *cond, cond->ConditionValue1);
2372 return false;
2373 }
2374 break;
2375 }
2377 {
2378 if (!sObjectMgr->GetGameObjectTemplate(cond->ConditionValue1))
2379 {
2380 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", *cond, cond->ConditionValue1);
2381 return false;
2382 }
2383 break;
2384 }
2388 [[fallthrough]];
2390 {
2391 switch (cond->ConditionValue1)
2392 {
2393 case TYPEID_UNIT:
2394 if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2))
2395 {
2396 TC_LOG_ERROR("sql.sql", "{} has non existing creature template entry ({}), skipped.", *cond, cond->ConditionValue2);
2397 return false;
2398 }
2399 if (cond->ConditionValue3)
2400 {
2401 if (CreatureData const* creatureData = sObjectMgr->GetCreatureData(cond->ConditionValue3))
2402 {
2403 if (cond->ConditionValue2 && creatureData->id != cond->ConditionValue2)
2404 {
2405 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match creature entry ({}), skipped.", *cond, cond->ConditionValue3, cond->ConditionValue2);
2406 return false;
2407 }
2408 }
2409 else
2410 {
2411 TC_LOG_ERROR("sql.sql", "{} has non existing creature guid ({}), skipped.", *cond, cond->ConditionValue3);
2412 return false;
2413 }
2414 }
2415 break;
2416 case TYPEID_GAMEOBJECT:
2417 if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2))
2418 {
2419 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject template entry ({}), skipped.", *cond, cond->ConditionValue2);
2420 return false;
2421 }
2422 if (cond->ConditionValue3)
2423 {
2424 if (GameObjectData const* goData = sObjectMgr->GetGameObjectData(cond->ConditionValue3))
2425 {
2426 if (cond->ConditionValue2 && goData->id != cond->ConditionValue2)
2427 {
2428 TC_LOG_ERROR("sql.sql", "{} has guid {} set but does not match gameobject entry ({}), skipped.", *cond, cond->ConditionValue3, cond->ConditionValue2);
2429 return false;
2430 }
2431 }
2432 else
2433 {
2434 TC_LOG_ERROR("sql.sql", "{} has non existing gameobject guid ({}), skipped.", *cond, cond->ConditionValue3);
2435 return false;
2436 }
2437 }
2438 break;
2439 case TYPEID_PLAYER:
2440 case TYPEID_CORPSE:
2441 if (cond->ConditionValue2)
2443 if (cond->ConditionValue3)
2445 break;
2446 default:
2447 TC_LOG_ERROR("sql.sql", "{} has wrong typeid set ({}), skipped", *cond, cond->ConditionValue1);
2448 return false;
2449 }
2450 break;
2451 }
2455 [[fallthrough]];
2457 {
2459 {
2460 TC_LOG_ERROR("sql.sql", "{} has invalid typemask set ({}), skipped.", *cond, cond->ConditionValue2);
2461 return false;
2462 }
2463 break;
2464 }
2466 {
2468 {
2469 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2470 return false;
2471 }
2472 if (cond->ConditionValue1 == cond->ConditionTarget)
2473 {
2474 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2475 return false;
2476 }
2477 if (cond->ConditionValue2 >= RELATION_MAX)
2478 {
2479 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(RelationType) ({}), skipped.", *cond, cond->ConditionValue2);
2480 return false;
2481 }
2482 break;
2483 }
2485 {
2487 {
2488 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2489 return false;
2490 }
2491 if (cond->ConditionValue1 == cond->ConditionTarget)
2492 {
2493 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2494 return false;
2495 }
2496 if (!cond->ConditionValue2)
2497 {
2498 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue2(rankMask) ({}), skipped.", *cond, cond->ConditionValue2);
2499 return false;
2500 }
2501 break;
2502 }
2504 {
2506 {
2507 TC_LOG_ERROR("sql.sql", "{} has invalid ConditionValue1(ConditionTarget selection) ({}), skipped.", *cond, cond->ConditionValue1);
2508 return false;
2509 }
2510 if (cond->ConditionValue1 == cond->ConditionTarget)
2511 {
2512 TC_LOG_ERROR("sql.sql", "{} has ConditionValue1(ConditionTarget selection) set to self ({}), skipped.", *cond, cond->ConditionValue1);
2513 return false;
2514 }
2515 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2516 {
2517 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue3);
2518 return false;
2519 }
2520 break;
2521 }
2522 case CONDITION_HP_VAL:
2523 {
2524 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2525 {
2526 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2527 return false;
2528 }
2529 break;
2530 }
2531 case CONDITION_HP_PCT:
2532 {
2533 if (cond->ConditionValue1 > 100)
2534 {
2535 TC_LOG_ERROR("sql.sql", "{} has too big percent value ({}), skipped.", *cond, cond->ConditionValue1);
2536 return false;
2537 }
2538 if (cond->ConditionValue2 >= COMP_TYPE_MAX)
2539 {
2540 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue2);
2541 return false;
2542 }
2543 break;
2544 }
2546 {
2548 {
2549 TC_LOG_ERROR("sql.sql", "{} has non existing world state in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2550 return false;
2551 }
2552 break;
2553 }
2554 case CONDITION_PHASEID:
2555 {
2556 if (!sPhaseStore.LookupEntry(cond->ConditionValue1))
2557 {
2558 TC_LOG_ERROR("sql.sql", "{} has nonexistent phaseid in value1 ({}), skipped", *cond, cond->ConditionValue1);
2559 return false;
2560 }
2561 break;
2562 }
2563 case CONDITION_TITLE:
2564 {
2565 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1);
2566 if (!titleEntry)
2567 {
2568 TC_LOG_ERROR("sql.sql", "{} has non existing title in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2569 return false;
2570 }
2571 break;
2572 }
2574 {
2575 TC_LOG_ERROR("sql.sql", "{} using deprecated condition type CONDITION_SPAWNMASK.", *cond);
2576 return false;
2577 }
2579 {
2581 {
2582 TC_LOG_ERROR("sql.sql", "{} has non existing UnitState in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2583 return false;
2584 }
2585 break;
2586 }
2588 {
2590 {
2591 TC_LOG_ERROR("sql.sql", "{} has non existing CreatureType in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2592 return false;
2593 }
2594 break;
2595 }
2597 {
2598 AchievementEntry const* achievement = sAchievementStore.LookupEntry(cond->ConditionValue1);
2599 if (!achievement)
2600 {
2601 TC_LOG_ERROR("sql.sql", "{} has non existing realm first achivement id ({}), skipped.", *cond, cond->ConditionValue1);
2602 return false;
2603 }
2604 break;
2605 }
2607 {
2608 bool valid = false;
2609 switch (cond->ConditionValue1)
2610 {
2611 case 0:
2613 break;
2614 case 1:
2615 valid = cond->ConditionValue2 <= 1;
2616 break;
2617 default:
2618 valid = false;
2619 break;
2620 }
2621 if (!valid)
2622 {
2623 TC_LOG_ERROR("sql.sql", "{} has non-existing stand state ({},{}), skipped.", *cond, cond->ConditionValue1, cond->ConditionValue2);
2624 return false;
2625 }
2626 break;
2627 }
2629 {
2630 QuestObjective const* obj = sObjectMgr->GetQuestObjective(cond->ConditionValue1);
2631 if (!obj)
2632 {
2633 TC_LOG_ERROR("sql.sql", "{} points to non-existing quest objective ({}), skipped.", *cond, cond->ConditionValue1);
2634 return false;
2635 }
2636 int32 limit = obj->IsStoringFlag() ? 1 : obj->Amount;
2637 if (int32(cond->ConditionValue3) > limit)
2638 {
2639 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);
2640 return false;
2641 }
2642 break;
2643 }
2644 case CONDITION_PET_TYPE:
2645 if (cond->ConditionValue1 >= (1 << MAX_PET_TYPE))
2646 {
2647 TC_LOG_ERROR("sql.sql", "{} has non-existing pet type {}, skipped.", *cond, cond->ConditionValue1);
2648 return false;
2649 }
2650 break;
2653 {
2654 TC_LOG_ERROR("sql.sql", "{} has unsupported ConditionValue3 {} (INSTANCE_INFO_GUID_DATA), skipped.", *cond, cond->ConditionValue3);
2655 return false;
2656 }
2657 break;
2658 case CONDITION_AREAID:
2659 case CONDITION_ALIVE:
2660 case CONDITION_IN_WATER:
2662 case CONDITION_CHARMED:
2663 case CONDITION_TAXI:
2667 case CONDITION_LABEL:
2668 break;
2670 if (!sDifficultyStore.LookupEntry(cond->ConditionValue1))
2671 {
2672 TC_LOG_ERROR("sql.sql", "{} has non existing difficulty in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2673 return false;
2674 }
2675 break;
2677 if (!sBattlePetSpeciesStore.LookupEntry(cond->ConditionValue1))
2678 {
2679 TC_LOG_ERROR("sql.sql", "{} has non existing BattlePet SpeciesId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2680 return false;
2681 }
2683 {
2684 TC_LOG_ERROR("sql.sql", "{} has invalid (greater than {}) value2 ({}), skipped.", *cond,
2686 return false;
2687 }
2688 if (cond->ConditionValue3 >= COMP_TYPE_MAX)
2689 {
2690 TC_LOG_ERROR("sql.sql", "{} has invalid ComparisionType ({}), skipped.", *cond, cond->ConditionValue3);
2691 return false;
2692 }
2693 break;
2695 {
2696 if (!sScenarioStepStore.LookupEntry(cond->ConditionValue1))
2697 {
2698 TC_LOG_ERROR("sql.sql", "{} has non existing ScenarioStep in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2699 return false;
2700 }
2701 break;
2702 }
2704 {
2705 if (!sSceneScriptPackageStore.LookupEntry(cond->ConditionValue1))
2706 {
2707 TC_LOG_ERROR("sql.sql", "{} has non existing SceneScriptPackageId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2708 return false;
2709 }
2710 break;
2711 }
2713 {
2714 if (!sPlayerConditionStore.LookupEntry(cond->ConditionValue1))
2715 {
2716 TC_LOG_ERROR("sql.sql", "{} has non existing PlayerConditionId in value1 ({}), skipped.", *cond, cond->ConditionValue1);
2717 return false;
2718 }
2719 break;
2720 }
2721 default:
2722 TC_LOG_ERROR("sql.sql", "{} Invalid ConditionType in `condition` table, ignoring.", *cond);
2723 return false;
2724 }
2725
2727 {
2728 TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect ConditionTarget set, ignoring.", *cond);
2729 return false;
2730 }
2731
2740
2741 return true;
2742}
2743
2745{
2746 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionValue{} ({})!", *cond, index, value);
2747}
2748
2749void ConditionMgr::LogUselessConditionValue(Condition const* cond, uint8 index, std::string const& value)
2750{
2751 TC_LOG_ERROR("sql.sql", "{} has useless data in ConditionStringValue{} ({})!", *cond, index, value);
2752}
2753
2755{
2756 for (std::unordered_map<ConditionId, std::shared_ptr<std::vector<Condition>>>& conditionsMap : ConditionStore)
2757 conditionsMap.clear();
2758
2760}
2761
2762inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
2763{
2764 switch (comparisonType)
2765 {
2766 case 1:
2767 return value1 == value2;
2768 case 2:
2769 return value1 != value2;
2770 case 3:
2771 return value1 > value2;
2772 case 4:
2773 return value1 >= value2;
2774 case 5:
2775 return value1 < value2;
2776 case 6:
2777 return value1 <= value2;
2778 default:
2779 break;
2780 }
2781 return false;
2782}
2783
2784template <std::size_t N>
2785inline bool PlayerConditionLogic(uint32 logic, std::bitset<N>& results)
2786{
2787 static_assert(N < 8, "Logic array size must be equal to or less than 8");
2788
2789 uint32 resultsMask = results.to_ulong() ^ (logic >> 16);
2790 uint32 result = resultsMask & 1;
2791 for (std::size_t i = 1; i < results.size(); ++i)
2792 {
2793 switch ((logic >> (2 * (i - 1))) & 3)
2794 {
2795 case 1:
2796 result &= (resultsMask >> i) & 1;
2797 break;
2798 case 2:
2799 result |= (resultsMask >> i) & 1;
2800 break;
2801 default:
2802 break;
2803 }
2804 }
2805
2806 return result != 0;
2807}
2808
2809template <typename T, std::size_t N, typename... ExtraParams, Trinity::invocable_r<bool, Player const*, T, typename ExtraParams::value_type...> Predicate>
2810inline static std::bitset<N> GetPlayerConditionSingleResult(Predicate predicate, Player const* player, std::array<T, N> const& conditions, ExtraParams const&... params)
2811{
2812 static_assert(((std::tuple_size_v<ExtraParams> == N) && ...));
2813 std::bitset<N> results;
2814
2815 for (std::size_t i = 0; i < N; ++i)
2816 if (predicate(player, conditions[i], params[i]...))
2817 results[i] = true;
2818
2819 return results;
2820}
2821
2823{
2824 Group const* group = player->GetGroup();
2825 if (!group)
2826 return 0;
2827
2828 switch (status)
2829 {
2831 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) ? 1 : 0;
2833 return sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()) &&
2834 sLFGMgr->selectedRandomLfgDungeon(player->GetGUID()) ? 1 : 0;
2836 {
2837 if (!sLFGMgr->inLfgDungeonMap(player->GetGUID(), player->GetMapId(), player->GetMap()->GetDifficultyID()))
2838 return 0;
2839
2840 uint32 selectedRandomDungeon = sLFGMgr->GetSelectedRandomDungeon(player->GetGUID());
2841 if (!selectedRandomDungeon)
2842 return 0;
2843
2844 if (lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(selectedRandomDungeon, player->GetLevel()))
2845 if (Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest))
2846 if (player->CanRewardQuest(quest, false))
2847 return 1;
2848 return 0;
2849 }
2851 break;
2853 break;
2855 break;
2857 break;
2859 break;
2860 default:
2861 break;
2862 }
2863
2864 return 0;
2865}
2866
2868{
2869 if (!conditionId)
2870 return true;
2871
2872 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_PLAYER_CONDITION, conditionId, player))
2873 return false;
2874
2875 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
2876 return IsPlayerMeetingCondition(player, playerCondition) != playerCondition->GetFlags().HasFlag(PlayerConditionFlags::Invert);
2877
2878 return true;
2879}
2880
2882{
2883 if (condition->GetFlags().HasFlag(PlayerConditionFlags::Disabled))
2884 return true;
2885
2886 if (condition->GetFlags().HasFlag(PlayerConditionFlags::IsAtMaxExpansionLevel))
2887 {
2888 uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
2889 if (level < GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION)))
2890 return false;
2891 }
2892
2893 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(condition->ContentTuningID, player->m_playerData->CtrOptions->ConditionalFlags))
2894 {
2895 uint8 level = condition->GetFlags().HasFlag(PlayerConditionFlags::UseEffectiveLevel) ? player->GetEffectiveLevel() : player->GetLevel();
2896 uint8 minLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MinLevelWithDelta : levels->MinLevel;
2897 uint8 maxLevel = 0;
2898 if (!condition->GetFlags().HasFlag(PlayerConditionFlags::WithinOrAboveRecord))
2899 maxLevel = condition->GetFlags().HasFlag(PlayerConditionFlags::IncludeLevelDelta) ? levels->MaxLevelWithDelta : levels->MaxLevel;
2900
2901 if (condition->GetFlags().HasFlag(PlayerConditionFlags::InvertContentTuning))
2902 {
2903 if (minLevel && level >= minLevel && (!maxLevel || level <= maxLevel))
2904 return false;
2905
2906 if (maxLevel && level <= maxLevel && (!minLevel || level >= minLevel))
2907 return false;
2908 }
2909 else
2910 {
2911 if (minLevel && level < minLevel)
2912 return false;
2913
2914 if (maxLevel && level > maxLevel)
2915 return false;
2916 }
2917 }
2918
2919 if (!condition->RaceMask.IsEmpty() && !condition->RaceMask.HasRace(player->GetRace()))
2920 return false;
2921
2922 if (condition->ClassMask && !(player->GetClassMask() & condition->ClassMask))
2923 return false;
2924
2925 if (condition->Gender >= 0 && player->GetGender() != condition->Gender)
2926 return false;
2927
2928 if (condition->NativeGender >= 0 && player->GetNativeGender() != condition->NativeGender)
2929 return false;
2930
2931 if (condition->PowerType != -1 && condition->PowerTypeComp)
2932 {
2933 int32 requiredPowerValue = condition->GetFlags().HasFlag(PlayerConditionFlags::ComparePowerToMax) ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
2934 if (!PlayerConditionCompare(condition->PowerTypeComp, player->GetPower(Powers(condition->PowerType)), requiredPowerValue))
2935 return false;
2936 }
2937
2938 if (condition->ChrSpecializationIndex >= 0 || condition->ChrSpecializationRole >= 0)
2939 {
2941 {
2942 if (condition->ChrSpecializationIndex >= 0 && spec->OrderIndex != condition->ChrSpecializationIndex)
2943 return false;
2944
2945 if (condition->ChrSpecializationRole >= 0 && spec->Role != condition->ChrSpecializationRole)
2946 return false;
2947 }
2948 }
2949
2950 if (std::ranges::any_of(condition->SkillID, [](uint32 skillId) { return skillId != 0; }))
2951 {
2952 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 skillId, uint32 minSkill, uint32 maxSkill)
2953 {
2954 if (!skillId)
2955 return true;
2956
2957 uint16 skillValue = player->GetSkillValue(skillId);
2958 return skillValue != 0 && skillValue > minSkill && skillValue < maxSkill;
2959 }, player, condition->SkillID, condition->MinSkill, condition->MaxSkill);
2960
2961 if (!PlayerConditionLogic(condition->SkillLogic, results))
2962 return false;
2963 }
2964
2965 if (condition->LanguageID)
2966 {
2967 int32 languageSkill = 0;
2969 languageSkill = 300;
2970 else
2971 {
2972 for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(Language(condition->LanguageID)))
2973 languageSkill = std::max<int32>(languageSkill, player->GetSkillValue(languageDesc.second.SkillId));
2974 }
2975
2976 if (condition->MinLanguage && languageSkill < int32(condition->MinLanguage))
2977 return false;
2978
2979 if (condition->MaxLanguage && languageSkill > condition->MaxLanguage)
2980 return false;
2981 }
2982
2983 if (condition->MinFactionID[0] || condition->MinFactionID[1] || condition->MinFactionID[2] || condition->MaxFactionID)
2984 {
2985 auto isMinFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 minReputationRank)
2986 {
2987 if (!sFactionStore.HasRecord(factionId))
2988 return true;
2989
2990 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
2991 return *forcedRank >= ReputationRank(minReputationRank);
2992
2993 return player->GetReputationRank(factionId) >= ReputationRank(minReputationRank);
2994 };
2995
2996 auto isMaxFactionConditionSatisfied = [](Player const* player, uint32 factionId, uint8 maxReputationRank)
2997 {
2998 if (!sFactionStore.HasRecord(factionId))
2999 return true;
3000
3001 if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(factionId))
3002 return *forcedRank <= ReputationRank(maxReputationRank);
3003
3004 return player->GetReputationRank(factionId) <= ReputationRank(maxReputationRank);
3005 };
3006
3007 if (!condition->MinFactionID[0] && !condition->MinFactionID[1] && !condition->MinFactionID[2])
3008 {
3009 if (!isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
3010 return false;
3011 }
3012 else
3013 {
3014 auto minFactionResults = GetPlayerConditionSingleResult(isMinFactionConditionSatisfied, player, condition->MinFactionID, condition->MinReputation);
3015 std::bitset<minFactionResults.size() + 1> results(minFactionResults.to_ulong());
3016 if (isMaxFactionConditionSatisfied(player, condition->MaxFactionID, condition->MaxReputation))
3017 results[3] = true;
3018
3019 if (!PlayerConditionLogic(condition->ReputationLogic, results))
3020 return false;
3021 }
3022 }
3023
3024 if (condition->CurrentPvpFaction)
3025 {
3026 int8 team;
3027 if (player->GetMap()->IsBattlegroundOrArena())
3028 team = player->m_playerData->ArenaFaction;
3029 else
3030 team = player->GetTeamId() == TEAM_ALLIANCE ? 1 : 0;
3031
3032 if (condition->CurrentPvpFaction - 1 != team)
3033 return false;
3034 }
3035
3036 if (condition->PvpMedal && !((1 << (condition->PvpMedal - 1)) & *player->m_activePlayerData->PvpMedals))
3037 return false;
3038
3039 if (condition->LifetimeMaxPVPRank && player->m_activePlayerData->LifetimeMaxRank != condition->LifetimeMaxPVPRank)
3040 return false;
3041
3042 if (condition->MovementFlags[0] && !(player->GetUnitMovementFlags() & condition->MovementFlags[0]))
3043 return false;
3044
3045 if (condition->MovementFlags[1] && !(player->GetExtraUnitMovementFlags() & condition->MovementFlags[1]))
3046 return false;
3047
3048 if (condition->WeaponSubclassMask)
3049 {
3051 if (!mainHand || !((1 << mainHand->GetTemplate()->GetSubClass()) & condition->WeaponSubclassMask))
3052 return false;
3053 }
3054
3055 if (condition->PartyStatus)
3056 {
3057 Group const* group = player->GetGroup();
3058 switch (condition->PartyStatus)
3059 {
3060 case 1:
3061 if (group)
3062 return false;
3063 break;
3064 case 2:
3065 if (!group)
3066 return false;
3067 break;
3068 case 3:
3069 if (!group || group->isRaidGroup())
3070 return false;
3071 break;
3072 case 4:
3073 if (!group || !group->isRaidGroup())
3074 return false;
3075 break;
3076 case 5:
3077 if (group && group->isRaidGroup())
3078 return false;
3079 break;
3080 default:
3081 break;
3082 }
3083 }
3084
3085 if (condition->PrevQuestID[0])
3086 {
3087 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3088 {
3089 return !questId || player->IsQuestCompletedBitSet(questId);
3090 }, player, condition->PrevQuestID);
3091
3092 if (!PlayerConditionLogic(condition->PrevQuestLogic, results))
3093 return false;
3094 }
3095
3096 if (condition->CurrQuestID[0])
3097 {
3098 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3099 {
3100 return !questId || player->FindQuestSlot(questId) != MAX_QUEST_LOG_SIZE;
3101 }, player, condition->CurrQuestID);
3102
3103 if (!PlayerConditionLogic(condition->CurrQuestLogic, results))
3104 return false;
3105 }
3106
3107 if (condition->CurrentCompletedQuestID[0])
3108 {
3109 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 questId)
3110 {
3111 return !questId || player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE;
3112 }, player, condition->CurrentCompletedQuestID);
3113
3114 if (!PlayerConditionLogic(condition->CurrentCompletedQuestLogic, results))
3115 return false;
3116 }
3117
3118 if (condition->SpellID[0])
3119 {
3120 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId)
3121 {
3122 return !spellId || player->HasSpell(spellId);
3123 }, player, condition->SpellID);
3124
3125 if (!PlayerConditionLogic(condition->SpellLogic, results))
3126 return false;
3127 }
3128
3129 if (condition->ItemID[0])
3130 {
3131 auto results = GetPlayerConditionSingleResult([itemFlags = condition->ItemFlags](Player const* player, uint32 itemId, uint32 itemCount)
3132 {
3133 if (!itemId)
3134 return true;
3135
3136 EnumFlag<ItemSearchLocation> where = ItemSearchLocation::Equipment;
3137 if ((itemFlags & 1) != 0) // include banks
3138 where |= ItemSearchLocation::Bank | ItemSearchLocation::ReagentBank | ItemSearchLocation::AccountBank;
3139 if ((itemFlags & 2) == 0) // ignore inventory
3140 where |= ItemSearchLocation::Inventory;
3141
3142 uint32 foundCount = 0;
3143 bool foundItemCount = !player->ForEachItem(where, [&](Item const* item)
3144 {
3145 if (item->GetEntry() == uint32(itemId))
3146 {
3147 foundCount += item->GetCount();
3148 if (foundCount >= itemCount)
3149 return ItemSearchCallbackResult::Stop;
3150 }
3151
3152 return ItemSearchCallbackResult::Continue;
3153 });
3154
3155 if (foundItemCount)
3156 return true;
3157
3158 if (itemCount == 1 && sDB2Manager.IsToyItem(itemId) && player->GetSession()->GetCollectionMgr()->HasToy(itemId))
3159 return true;
3160
3161 return false;
3162 }, player, condition->ItemID, condition->ItemCount);
3163
3164 if (!PlayerConditionLogic(condition->ItemLogic, results))
3165 return false;
3166 }
3167
3168 if (condition->CurrencyID[0])
3169 {
3170 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 currencyId, uint32 count)
3171 {
3172 return !currencyId || player->GetCurrencyQuantity(currencyId) >= count;
3173 }, player, condition->CurrencyID, condition->CurrencyCount);
3174
3175 if (!PlayerConditionLogic(condition->CurrencyLogic, results))
3176 return false;
3177 }
3178
3179 if (condition->Explored[0] || condition->Explored[1])
3180 {
3181 for (std::size_t i = 0; i < condition->Explored.size(); ++i)
3182 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(condition->Explored[i]))
3183 if (!player->HasExploredZone(area->ID))
3184 return false;
3185 }
3186
3187 if (condition->AuraSpellID[0])
3188 {
3189 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 spellId, uint32 count)
3190 {
3191 if (!spellId)
3192 return true;
3193
3194 if (count)
3195 return player->GetAuraCount(spellId) >= count;
3196
3197 return player->HasAura(spellId);
3198 }, player, condition->AuraSpellID, condition->AuraStacks);
3199
3200 if (!PlayerConditionLogic(condition->AuraSpellLogic, results))
3201 return false;
3202 }
3203
3204 if (condition->Time[0])
3205 {
3206 WowTime time0;
3207 time0.SetPackedTime(condition->Time[0]);
3208
3209 if (condition->Time[1])
3210 {
3211 WowTime time1;
3212 time1.SetPackedTime(condition->Time[1]);
3213
3214 if (!GameTime::GetWowTime()->IsInRange(time0, time1))
3215 return false;
3216 }
3217 else if (*GameTime::GetWowTime() != time0)
3218 return false;
3219 }
3220
3221 if (condition->WorldStateExpressionID)
3222 {
3223 WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(condition->WorldStateExpressionID);
3224 if (!worldStateExpression)
3225 return false;
3226
3227 if (!IsMeetingWorldStateExpression(player->GetMap(), worldStateExpression))
3228 return false;
3229 }
3230
3231 if (condition->WeatherID)
3232 if (player->GetMap()->GetZoneWeather(player->GetZoneId()) != WeatherState(condition->WeatherID))
3233 return false;
3234
3235 if (condition->Achievement[0])
3236 {
3237 auto results = GetPlayerConditionSingleResult([flags = condition->GetFlags()](Player const* player, uint32 achievementId)
3238 {
3239 if (!achievementId)
3240 return true;
3241 (void)flags;
3242 // if (flags.HasFlag(PlayerConditionFlags::CheckAchievementsOnAllChars)) { any character on account completed it } else { current character only }
3243 // TODO: part of accountwide achievements
3244 return player->HasAchieved(achievementId);
3245 }, player, condition->Achievement);
3246
3247 if (!PlayerConditionLogic(condition->AchievementLogic, results))
3248 return false;
3249 }
3250
3251 if (condition->LfgStatus[0])
3252 {
3253 auto results = GetPlayerConditionSingleResult([](Player const* player, uint8 status, uint8 compare, uint32 value)
3254 {
3255 return !status || PlayerConditionCompare(compare, GetPlayerConditionLfgValue(player, PlayerConditionLfgStatus(status)), value);
3256 }, player, condition->LfgStatus, condition->LfgCompare, condition->LfgValue);
3257
3258 if (!PlayerConditionLogic(condition->LfgLogic, results))
3259 return false;
3260 }
3261
3262 if (condition->AreaID[0])
3263 {
3264 auto results = GetPlayerConditionSingleResult([](Player const* player, uint32 areaId)
3265 {
3266 return !areaId || DB2Manager::IsInArea(player->GetAreaId(), areaId);
3267 }, player, condition->AreaID);
3268
3269 if (!PlayerConditionLogic(condition->AreaLogic, results))
3270 return false;
3271 }
3272
3273 if (condition->MinExpansionLevel != -1 && player->GetSession()->GetExpansion() < condition->MinExpansionLevel)
3274 return false;
3275
3276 if (condition->MaxExpansionLevel != -1 && player->GetSession()->GetExpansion() > condition->MaxExpansionLevel)
3277 return false;
3278
3279 if (condition->MinExpansionLevel != -1 && condition->MinExpansionTier != -1 && !player->IsGameMaster()
3280 && ((condition->MinExpansionLevel == int32(sWorld->getIntConfig(CONFIG_EXPANSION)) && condition->MinExpansionTier > 0) /*TODO: implement tier*/
3281 || condition->MinExpansionLevel > int32(sWorld->getIntConfig(CONFIG_EXPANSION))))
3282 return false;
3283
3284 if (condition->PhaseID || condition->PhaseGroupID || condition->PhaseUseFlags)
3285 if (!PhasingHandler::InDbPhaseShift(player, condition->PhaseUseFlags, condition->PhaseID, condition->PhaseGroupID))
3286 return false;
3287
3288 if (condition->QuestKillID)
3289 {
3290 Quest const* quest = sObjectMgr->GetQuestTemplate(condition->QuestKillID);
3291 uint16 questSlot = player->FindQuestSlot(condition->QuestKillID);
3292 if (quest && player->GetQuestStatus(condition->QuestKillID) != QUEST_STATUS_COMPLETE && questSlot < MAX_QUEST_LOG_SIZE)
3293 {
3294 auto results = GetPlayerConditionSingleResult([questSlot, quest](Player const* player, uint32 creatureId)
3295 {
3296 if (!creatureId)
3297 return true;
3298
3299 auto objectiveItr = std::ranges::find_if(quest->GetObjectives(), [creatureId](QuestObjective const& objective) -> bool
3300 {
3301 return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == creatureId;
3302 });
3303 return objectiveItr == quest->GetObjectives().end() || player->GetQuestSlotObjectiveData(questSlot, *objectiveItr) >= objectiveItr->Amount;
3304 }, player, condition->QuestKillMonster);
3305
3306 if (!PlayerConditionLogic(condition->QuestKillLogic, results))
3307 return false;
3308 }
3309 }
3310
3311 if (condition->MinAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) < condition->MinAvgItemLevel)
3312 return false;
3313
3314 if (condition->MaxAvgItemLevel && int32(std::floor(player->m_playerData->AvgItemLevel[0])) > condition->MaxAvgItemLevel)
3315 return false;
3316
3317 if (condition->MinAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) < condition->MinAvgEquippedItemLevel)
3318 return false;
3319
3320 if (condition->MaxAvgEquippedItemLevel && uint32(std::floor(player->m_playerData->AvgItemLevel[1])) > condition->MaxAvgEquippedItemLevel)
3321 return false;
3322
3323 if (condition->ModifierTreeID && player->ModifierTreeSatisfied(condition->ModifierTreeID) == condition->GetFlags().HasFlag(PlayerConditionFlags::InvertModifierTree))
3324 return false;
3325
3326 if (condition->CovenantID && player->m_playerData->CovenantID != condition->CovenantID)
3327 return false;
3328
3329 if (std::ranges::any_of(condition->TraitNodeEntryID, [](int32 traitNodeEntryId) { return traitNodeEntryId != 0; }))
3330 {
3331 auto results = GetPlayerConditionSingleResult([](Player const* player, int32 traitNodeEntryId, uint16 minRank, uint16 maxRank)
3332 {
3333 if (!traitNodeEntryId)
3334 return true;
3335
3336 Optional<uint16> rank = [&]() -> Optional<uint16>
3337 {
3338 for (auto const& [_, traitConfig] : player->m_activePlayerData->TraitConfigs)
3339 {
3340 if (TraitConfigType(*traitConfig.value.Type) == TraitConfigType::Combat)
3341 {
3342 if (int32(*player->m_activePlayerData->ActiveCombatTraitConfigID) != *traitConfig.value.ID
3343 || !EnumFlag(TraitCombatConfigFlags(*traitConfig.value.CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::ActiveForSpec))
3344 continue;
3345 }
3346
3347 for (UF::TraitEntry const& traitEntry : traitConfig.value.Entries)
3348 if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
3349 return traitEntry.Rank;
3350 }
3351 return {};
3352 }();
3353
3354 return rank
3355 && (!minRank || *rank >= minRank)
3356 && (!maxRank || *rank <= maxRank);
3357 }, player, condition->TraitNodeEntryID, condition->TraitNodeEntryMinRank, condition->TraitNodeEntryMaxRank);
3358
3359 if (!PlayerConditionLogic(condition->TraitNodeEntryLogic, results))
3360 return false;
3361 }
3362
3363 return true;
3364}
3365
3367{
3368 // WSE_FUNCTION_NONE
3369 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3370 {
3371 return 0;
3372 },
3373
3374 // WSE_FUNCTION_RANDOM
3375 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3376 {
3377 return irand(std::min(arg1, arg2), std::max(arg1, arg2));
3378 },
3379
3380 // WSE_FUNCTION_MONTH
3381 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3382 {
3383 return GameTime::GetDateAndTime()->tm_mon + 1;
3384 },
3385
3386 // WSE_FUNCTION_DAY
3387 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3388 {
3389 return GameTime::GetDateAndTime()->tm_mday + 1;
3390 },
3391
3392 // WSE_FUNCTION_TIME_OF_DAY
3393 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3394 {
3395 tm const* localTime = GameTime::GetDateAndTime();
3396 return localTime->tm_hour * MINUTE + localTime->tm_min;
3397 },
3398
3399 // WSE_FUNCTION_REGION
3400 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3401 {
3402 return sRealmList->GetCurrentRealmId().Region;
3403 },
3404
3405 // WSE_FUNCTION_CLOCK_HOUR
3406 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3407 {
3408 int32 currentHour = GameTime::GetDateAndTime()->tm_hour + 1;
3409 return currentHour <= 12 ? (currentHour ? currentHour : 12) : currentHour - 12;
3410 },
3411
3412 // WSE_FUNCTION_OLD_DIFFICULTY_ID
3413 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3414 {
3415 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(map->GetDifficultyID()))
3416 return difficulty->OldEnumValue;
3417
3418 return -1;
3419 },
3420
3421 // WSE_FUNCTION_HOLIDAY_START
3422 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3423 {
3424 return 0;
3425 },
3426
3427 // WSE_FUNCTION_HOLIDAY_LEFT
3428 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3429 {
3430 return 0;
3431 },
3432
3433 // WSE_FUNCTION_HOLIDAY_ACTIVE
3434 [](Map const* /*map*/, uint32 arg1, uint32 /*arg2*/) -> int32
3435 {
3436 return int32(IsHolidayActive(HolidayIds(arg1)));
3437 },
3438
3439 // WSE_FUNCTION_TIMER_CURRENT_TIME
3440 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3441 {
3442 return GameTime::GetGameTime();
3443 },
3444
3445 // WSE_FUNCTION_WEEK_NUMBER
3446 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3447 {
3448 time_t now = GameTime::GetGameTime();
3449 uint32 raidOrigin = 1135695600;
3450 if (Cfg_RegionsEntry const* region = sCfgRegionsStore.LookupEntry(sRealmList->GetCurrentRealmId().Region))
3451 raidOrigin = region->Raidorigin;
3452
3453 return (now - raidOrigin) / WEEK;
3454 },
3455
3456 // WSE_FUNCTION_UNK13
3457 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3458 {
3459 return 0;
3460 },
3461
3462 // WSE_FUNCTION_UNK14
3463 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3464 {
3465 return 0;
3466 },
3467
3468 // WSE_FUNCTION_DIFFICULTY_ID
3469 [](Map const* map, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3470 {
3471 return map->GetDifficultyID();
3472 },
3473
3474 // WSE_FUNCTION_WAR_MODE_ACTIVE
3475 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3476 {
3477 // check if current zone/map is bound to war mode
3478 return 0;
3479 },
3480
3481 // WSE_FUNCTION_UNK17
3482 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3483 {
3484 return 0;
3485 },
3486
3487 // WSE_FUNCTION_UNK18
3488 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3489 {
3490 return 0;
3491 },
3492
3493 // WSE_FUNCTION_UNK19
3494 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3495 {
3496 return 0;
3497 },
3498
3499 // WSE_FUNCTION_UNK20
3500 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3501 {
3502 return 0;
3503 },
3504
3505 // WSE_FUNCTION_UNK21
3506 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3507 {
3508 return 0;
3509 },
3510
3511 // WSE_FUNCTION_WORLD_STATE_EXPRESSION
3512 [](Map const* map, uint32 arg1, uint32 /*arg2*/) -> int32
3513 {
3514 if (WorldStateExpressionEntry const* worldStateExpression = sWorldStateExpressionStore.LookupEntry(arg1))
3515 return ConditionMgr::IsMeetingWorldStateExpression(map, worldStateExpression);
3516
3517 return 0;
3518 },
3519
3520 // WSE_FUNCTION_KEYSTONE_AFFIX
3521 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3522 {
3523 return 0;
3524 },
3525
3526 // WSE_FUNCTION_UNK24
3527 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3528 {
3529 return 0;
3530 },
3531
3532 // WSE_FUNCTION_UNK25
3533 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3534 {
3535 return 0;
3536 },
3537
3538 // WSE_FUNCTION_UNK26
3539 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3540 {
3541 return 0;
3542 },
3543
3544 // WSE_FUNCTION_UNK27
3545 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3546 {
3547 return 0;
3548 },
3549
3550 // WSE_FUNCTION_KEYSTONE_LEVEL
3551 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3552 {
3553 return 0;
3554 },
3555
3556 // WSE_FUNCTION_UNK29
3557 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3558 {
3559 return 0;
3560 },
3561
3562 // WSE_FUNCTION_UNK30
3563 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3564 {
3565 return 0;
3566 },
3567
3568 // WSE_FUNCTION_UNK31
3569 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3570 {
3571 return 0;
3572 },
3573
3574 // WSE_FUNCTION_UNK32
3575 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3576 {
3577 return 0;
3578 },
3579
3580 // WSE_FUNCTION_MERSENNE_RANDOM
3581 [](Map const* /*map*/, uint32 arg1, uint32 arg2) -> int32
3582 {
3583 if (arg1 == 1)
3584 return 1;
3585
3586 // init with predetermined seed
3587 std::mt19937 mt(arg2 ? arg2 : 1);
3588 return mt() % arg1 + 1;
3589 },
3590
3591 // WSE_FUNCTION_UNK34
3592 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3593 {
3594 return 0;
3595 },
3596
3597 // WSE_FUNCTION_UNK35
3598 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3599 {
3600 return 0;
3601 },
3602
3603 // WSE_FUNCTION_UNK36
3604 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3605 {
3606 return 0;
3607 },
3608
3609 // WSE_FUNCTION_UI_WIDGET_DATA
3610 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3611 {
3612 return 0;
3613 },
3614
3615 // WSE_FUNCTION_TIME_EVENT_PASSED
3616 [](Map const* /*map*/, uint32 /*arg1*/, uint32 /*arg2*/) -> int32
3617 {
3618 return 0;
3619 },
3620};
3621
3623{
3625 int32 value = 0;
3626
3627 switch (valueType)
3628 {
3630 {
3631 value = buffer.read<int32>();
3632 break;
3633 }
3635 {
3636 int32 worldStateId = buffer.read<int32>();
3637 value = WorldStateMgr::GetValue(worldStateId, map);
3638 break;
3639 }
3641 {
3642 uint32 functionType = buffer.read<uint32>();
3643 int32 arg1 = EvalSingleValue(buffer, map);
3644 int32 arg2 = EvalSingleValue(buffer, map);
3645
3646 if (functionType >= WSE_FUNCTION_MAX)
3647 return 0;
3648
3649 value = WorldStateExpressionFunctions[functionType](map, arg1, arg2);
3650 break;
3651 }
3652 default:
3653 break;
3654 }
3655
3656 return value;
3657}
3658
3659int32 EvalValue(ByteBuffer& buffer, Map const* map)
3660{
3661 int32 leftValue = EvalSingleValue(buffer, map);
3662
3664 if (operatorType == WorldStateExpressionOperatorType::None)
3665 return leftValue;
3666
3667 int32 rightValue = EvalSingleValue(buffer, map);
3668
3669 switch (operatorType)
3670 {
3671 case WorldStateExpressionOperatorType::Sum: return leftValue + rightValue;
3672 case WorldStateExpressionOperatorType::Substraction: return leftValue - rightValue;
3673 case WorldStateExpressionOperatorType::Multiplication: return leftValue * rightValue;
3674 case WorldStateExpressionOperatorType::Division: return !rightValue ? 0 : leftValue / rightValue;
3675 case WorldStateExpressionOperatorType::Remainder: return !rightValue ? 0 : leftValue % rightValue;
3676 default:
3677 break;
3678 }
3679
3680 return leftValue;
3681}
3682
3683bool EvalRelOp(ByteBuffer& buffer, Map const* map)
3684{
3685 int32 leftValue = EvalValue(buffer, map);
3686
3688 if (compareLogic == WorldStateExpressionComparisonType::None)
3689 return leftValue != 0;
3690
3691 int32 rightValue = EvalValue(buffer, map);
3692
3693 switch (compareLogic)
3694 {
3695 case WorldStateExpressionComparisonType::Equal: return leftValue == rightValue;
3696 case WorldStateExpressionComparisonType::NotEqual: return leftValue != rightValue;
3697 case WorldStateExpressionComparisonType::Less: return leftValue < rightValue;
3698 case WorldStateExpressionComparisonType::LessOrEqual: return leftValue <= rightValue;
3699 case WorldStateExpressionComparisonType::Greater: return leftValue > rightValue;
3700 case WorldStateExpressionComparisonType::GreaterOrEqual: return leftValue >= rightValue;
3701 default:
3702 break;
3703 }
3704
3705 return false;
3706}
3707
3709{
3710 ByteBuffer buffer(HexStrToByteVector(expression->Expression));
3711 if (buffer.empty())
3712 return false;
3713
3714 uint8 enabled = buffer.read<uint8>();
3715 if (!enabled)
3716 return false;
3717
3718 bool finalResult = EvalRelOp(buffer, map);
3719
3720 do
3721 {
3723 if (resultLogic == WorldStateExpressionLogic::None)
3724 break;
3725
3726 bool secondResult = EvalRelOp(buffer, map);
3727
3728 switch (resultLogic)
3729 {
3730 case WorldStateExpressionLogic::And: finalResult = finalResult && secondResult; break;
3731 case WorldStateExpressionLogic::Or: finalResult = finalResult || secondResult; break;
3732 case WorldStateExpressionLogic::Xor: finalResult = finalResult != secondResult; break;
3733 default:
3734 break;
3735 }
3736 } while (buffer.rpos() < buffer.size());
3737
3738 return finalResult;
3739}
3740catch (std::exception const& e)
3741{
3742 TC_LOG_ERROR("condition", "Failed to parse WorldStateExpression {}: {}", expression->ID, e.what());
3743 return false;
3744}
3745
3746int32 GetUnitConditionVariable(Unit const* unit, Unit const* otherUnit, UnitConditionVariable variable, int32 value)
3747{
3748 switch (variable)
3749 {
3751 return unit->GetRace();
3753 return unit->GetClass();
3755 return unit->GetLevel();
3757 return unit == otherUnit;
3759 return otherUnit && unit->GetCharmerOrOwnerGUID() == otherUnit->GetGUID();
3761 return otherUnit && otherUnit->GetCharmerOrOwnerGUID() == unit->GetGUID();
3763 return otherUnit && otherUnit->GetTarget() == unit->GetGUID();
3765 return otherUnit && unit->IsValidAssistTarget(otherUnit);
3767 return otherUnit && unit->IsValidAttackTarget(otherUnit);
3769 return !unit->GetCharmedGUID().IsEmpty() || !unit->GetMinionGUID().IsEmpty();
3771 if (Player const* player = unit->ToPlayer())
3772 return player->GetWeaponForAttack(BASE_ATTACK) || player->GetWeaponForAttack(OFF_ATTACK);
3773 return unit->GetVirtualItemId(0) || unit->GetVirtualItemId(1);
3775 return unit->GetHealthPct();
3777 return unit->GetPowerPct(POWER_MANA);
3779 return unit->GetPowerPct(POWER_RAGE);
3781 return unit->GetPowerPct(POWER_ENERGY);
3783 return unit->GetPower(POWER_COMBO_POINTS);
3785 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3786 {
3787 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0;
3788 }) != nullptr ? value : 0;
3790 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3791 {
3792 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3793 }) != nullptr ? value : 0;
3795 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3796 {
3797 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3798 }) != nullptr ? value : 0;
3800 return unit->GetAuraApplication(value, [](AuraApplication const* aurApp)
3801 {
3802 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0;
3803 }) != nullptr ? value : 0;
3805 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3806 {
3807 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value;
3808 }) != nullptr ? value : 0;
3810 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3811 {
3812 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (UI64LIT(1) << value)) != 0;
3813 }) != nullptr ? value : 0;
3815 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
3816 {
3817 return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
3818 }) != nullptr ? value : 0;
3820 break;
3822 break;
3824 break;
3826 break;
3828 break;
3830 break;
3832 break;
3834 return unit->IsInCombat();
3838 case UnitConditionVariable::IsCastingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3839 return unit->GetCurrentSpell(CURRENT_GENERIC_SPELL) != nullptr;
3841 case UnitConditionVariable::IsChannelingSpell: // this is supposed to return spell id by client code but data always has 0 or 1
3842 return unit->GetChannelSpellId() != 0;
3844 return std::ranges::count_if(unit->getAttackers(), [unit](Unit const* attacker)
3845 {
3846 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3847 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3848 distance += 1.0f;
3849 return unit->GetExactDistSq(attacker) < distance * distance;
3850 });
3852 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
3854 return otherUnit ? int32(unit->GetExactDist(otherUnit)) : 0;
3856 if (otherUnit)
3857 {
3858 float distance = std::max(unit->GetCombatReach() + otherUnit->GetCombatReach() + 1.3333334f, 5.0f);
3860 distance += 1.0f;
3861 return unit->GetExactDistSq(otherUnit) < distance * distance;
3862 }
3863 return 0;
3865 break;
3871 return unit->GetThreatManager().GetThreatListSize();
3873 break;
3875 break;
3877 break;
3879 break;
3881 break;
3883 break;
3885 break;
3887 break;
3889 break;
3891 return unit->getAttackers().size();
3893 return std::ranges::count_if(unit->getAttackers(), [unit](Unit const* attacker)
3894 {
3895 float distance = std::max(unit->GetCombatReach() + attacker->GetCombatReach() + 1.3333334f, 5.0f);
3896 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || attacker->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3897 distance += 1.0f;
3898 return unit->GetExactDistSq(attacker) >= distance * distance;
3899 });
3901 return unit->GetCreatureType();
3903 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3904 {
3905 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3906 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3907 distance += 1.0f;
3908 return unit->GetExactDistSq(target) < distance * distance;
3909 }
3910 return 0;
3912 if (Unit const* target = ObjectAccessor::GetUnit(*unit, unit->GetTarget()))
3913 {
3914 float distance = std::max(unit->GetCombatReach() + target->GetCombatReach() + 1.3333334f, 5.0f);
3915 if (unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) || target->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3916 distance += 1.0f;
3917 return unit->GetExactDistSq(target) >= distance * distance;
3918 }
3919 return 0;
3921 return unit->GetHealth();
3923 return unit->HasSpell(value) ? value : 0;
3925 return value >= 0 && value < int32(TOTAL_AURAS) && std::find_if(unit->GetAuraEffectsByType(AuraType(value)).begin(), unit->GetAuraEffectsByType(AuraType(value)).end(), [unit](AuraEffect const* aurEff)
3926 {
3927 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) != 0;
3928 }) != unit->GetAuraEffectsByType(AuraType(value)).end();
3930 break;
3932 return unit->IsPlayer();
3934 break;
3936 break;
3938 break;
3940 break;
3942 return !unit->GetCritterGUID().IsEmpty();
3944 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM].IsEmpty();
3946 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_2].IsEmpty();
3948 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_3].IsEmpty();
3950 return !unit->m_SummonSlot[SUMMON_SLOT_TOTEM_4].IsEmpty();
3952 break;
3954 return unit->GetEntry();
3956 break;
3958 return unit->HasAura(value) ? value : 0;
3960 return otherUnit && unit->GetReactionTo(otherUnit) <= REP_HOSTILE;
3962 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3965 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3968 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3971 return unit->IsPlayer() && unit->ToPlayer()->GetPrimarySpecializationEntry()
3974 return unit->IsCreature() && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED);
3976 return unit->GetHealth() == 0;
3978 break;
3980 return unit->GetMountDisplayId() != 0;
3982 return unit->IsCreature() && unit->ToCreature()->HasLabel(value) ? value : 0;
3984 return otherUnit && (otherUnit->GetCharmerGUID() == unit->GetGUID() || otherUnit->GetCreatorGUID() == unit->GetGUID());
3986 return otherUnit && (unit->GetCharmerGUID() == otherUnit->GetGUID() || unit->GetCreatorGUID() == otherUnit->GetGUID());
3988 return otherUnit && unit->GetTarget() == otherUnit->GetGUID();
3990 return unit->GetGender();
3992 if (Optional<ContentTuningLevels> levelRange = sDB2Manager.GetContentTuningData(value, {}))
3993 return unit->GetLevel() >= levelRange->MinLevel && unit->GetLevel() <= levelRange->MaxLevel ? value : 0;
3994 return 0;
3996 return unit->IsFlying();
3998 return unit->IsHovering();
4000 return value >= 0 && value < int32(TOTAL_AURAS) && std::ranges::any_of(unit->GetAuraEffectsByType(AuraType(value)), [unit](AuraEffect const* aurEff)
4001 {
4002 return (aurEff->GetBase()->GetApplicationOfTarget(unit->GetGUID())->GetFlags() & AFLAG_NEGATIVE) == 0;
4003 });
4005 return unit->GetAuraApplication([value](AuraApplication const* aurApp)
4006 {
4007 return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0;
4008 }) != nullptr ? value : 0;
4009 default:
4010 break;
4011 }
4012
4013 return 0;
4014}
4015
4016bool ConditionMgr::IsUnitMeetingCondition(Unit const* unit, Unit const* otherUnit, UnitConditionEntry const* condition)
4017{
4018 for (size_t i = 0; i < MAX_UNIT_CONDITION_VALUES; ++i)
4019 {
4020 if (!condition->Variable[i])
4021 break;
4022
4023 int32 unitValue = GetUnitConditionVariable(unit, otherUnit, UnitConditionVariable(condition->Variable[i]), condition->Value[i]);
4024 bool meets = false;
4025 switch (UnitConditionOp(condition->Op[i]))
4026 {
4028 meets = unitValue == condition->Value[i];
4029 break;
4031 meets = unitValue != condition->Value[i];
4032 break;
4034 meets = unitValue < condition->Value[i];
4035 break;
4037 meets = unitValue <= condition->Value[i];
4038 break;
4040 meets = unitValue > condition->Value[i];
4041 break;
4043 meets = unitValue >= condition->Value[i];
4044 break;
4045 default:
4046 break;
4047 }
4048
4049 if (condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr))
4050 {
4051 if (meets)
4052 return true;
4053 }
4054 else if (!meets)
4055 return false;
4056 }
4057
4058 return !condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr);
4059}
#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)
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
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_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:569
#define MAX_UNIT_CONDITION_VALUES
TraitConfigType
Definition DBCEnums.h:2851
PlayerConditionLfgStatus
Definition DBCEnums.h:2193
#define MAX_EFFECT_MASK
Definition DBCEnums.h:2431
TraitCombatConfigFlags
Definition DBCEnums.h:2821
UnitConditionVariable
Definition DBCEnums.h:2990
WorldStateExpressionFunctions
Definition DBCEnums.h:3236
@ WSE_FUNCTION_MAX
Definition DBCEnums.h:3277
WorldStateExpressionValueType
Definition DBCEnums.h:3200
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
UnitConditionOp
Definition DBCEnums.h:2980
WorldStateExpressionComparisonType
Definition DBCEnums.h:3215
WorldStateExpressionLogic
Definition DBCEnums.h:3207
WorldStateExpressionOperatorType
Definition DBCEnums.h:3226
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:88
#define ASSERT
Definition Errors.h:80
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:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false)
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true)
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
LootStore LootTemplates_Item("item_loot_template", "item entry", true)
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true)
LootStore LootTemplates_Reference("reference_loot_template", "reference id", false)
LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true)
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true)
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true)
LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false)
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true)
@ TYPEID_AREATRIGGER
Definition ObjectGuid.h: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:1885
std::pair< GossipMenusContainer::iterator, GossipMenusContainer::iterator > GossipMenusMapBoundsNonConst
Definition ObjectMgr.h:778
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:744
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
@ DRUNKEN_SMASHED
Definition Player.h:513
#define MAX_QUEST_LOG_SIZE
Definition QuestDef.h:46
QuestStatus
Definition QuestDef.h:146
@ QUEST_STATUS_REWARDED
Definition QuestDef.h:153
@ QUEST_STATUS_FAILED
Definition QuestDef.h:152
@ QUEST_STATUS_INCOMPLETE
Definition QuestDef.h:150
@ QUEST_STATUS_NONE
Definition QuestDef.h:147
@ MAX_QUEST_STATUS
Definition QuestDef.h:154
@ QUEST_STATUS_COMPLETE
Definition QuestDef.h:148
int32 irand(int32 min, int32 max)
Definition Random.cpp:35
#define sRealmList
Definition RealmList.h:93
#define sScriptMgr
Definition ScriptMgr.h:1449
SpellEffIndex
Language
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
Gender
@ CREATURE_TYPE_GAS_CLOUD
@ TEAM_ALLIANCE
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY
@ SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY_NONRANDOM
@ SPELL_EFFECT_APPLY_AURA_ON_PET
@ SPELL_EFFECT_APPLY_AREA_AURA_PET
@ SPELL_EFFECT_APPLY_AREA_AURA_RAID
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
@ SPELL_EFFECT_APPLY_AREA_AURA_SUMMONS
@ SPELL_EFFECT_APPLY_AREA_AURA_OWNER
@ SUMMON_SLOT_TOTEM
@ SUMMON_SLOT_TOTEM_4
@ SUMMON_SLOT_TOTEM_3
@ SUMMON_SLOT_TOTEM_2
@ OFF_ATTACK
@ BASE_ATTACK
@ 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
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_STRAFE_LEFT
@ MOVEMENTFLAG_BACKWARD
@ MOVEMENTFLAG_STRAFE_RIGHT
@ UNIT_FLAG_PLAYER_CONTROLLED
@ CURRENT_GENERIC_SPELL
Definition Unit.h:598
@ UNIT_STATE_ALL_STATE_SUPPORTED
Definition Unit.h:292
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:448
size_t size() const
Definition ByteBuffer.h:568
bool empty() const
Definition ByteBuffer.h:569
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:205
bool isRaidGroup() const
Definition Group.cpp:1628
Definition Item.h:179
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:986
Definition Map.h:225
bool IsBattlegroundOrArena() const
Definition Map.cpp:3369
BattlegroundMap * ToBattlegroundMap()
Definition Map.h:493
Difficulty GetDifficultyID() const
Definition Map.h:360
uint32 GetId() const
Definition Map.cpp:3257
InstanceMap * ToInstanceMap()
Definition Map.h:490
WeatherState GetZoneWeather(uint32 zoneId) const
Definition Map.cpp:4010
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:2008
UF::UpdateField< UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER > m_playerData
Definition Player.h:3061
Gender GetNativeGender() const override
Definition Player.h:1350
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:6010
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3062
uint16 FindQuestSlot(uint32 quest_id) const
Definition Player.cpp:16383
bool IsQuestCompletedBitSet(uint32 questId) const
Definition Player.cpp:16517
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition Player.cpp:14619
WorldSession * GetSession() const
Definition Player.h:2272
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9630
bool ModifierTreeSatisfied(uint32 modifierTreeId) const
Definition Player.cpp:27610
TeamId GetTeamId() const
Definition Player.h:2424
bool HasExploredZone(uint32 areaId) const
Definition Player.cpp:6397
bool IsGameMaster() const
Definition Player.h:1309
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15962
static bool IsValidGender(uint8 Gender)
Definition Player.h:1874
ReputationRank GetReputationRank(uint32 faction_id) const
Definition Player.cpp:6505
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9669
bool HasSpell(uint32 spell) const override
Definition Player.cpp:3735
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2796
int32 GetQuestSlotObjectiveData(uint16 slot, QuestObjective const &objective) const
Definition Player.cpp:16418
ChrSpecializationEntry const * GetPrimarySpecializationEntry() const
Definition Player.cpp:30819
ReputationMgr & GetReputationMgr()
Definition Player.h:2439
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition Player.cpp:869
uint32 GetCurrencyQuantity(uint32 id) const
Definition Player.cpp:7384
QuestObjectives const & GetObjectives() const
Definition QuestDef.h:681
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:588
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:587
size_t GetThreatListSize() const
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition Unit.h:635
uint32 GetChannelSpellId() const
Definition Unit.h:1423
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1342
float GetHealthPct() const
Definition Unit.h:796
uint32 GetUnitMovementFlags() const
Definition Unit.h:1735
ThreatManager & GetThreatManager()
Definition Unit.h:1078
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4827
uint8 GetClass() const
Definition Unit.h:764
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition Unit.h:1501
uint32 GetClassMask() const
Definition Unit.h:766
uint32 GetMountDisplayId() const
Definition Unit.h:913
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1191
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:845
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1211
float GetCombatReach() const override
Definition Unit.h:705
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10037
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1216
virtual bool HasSpell(uint32) const
Definition Unit.h:1084
ObjectGuid GetCreatorGUID() const override
Definition Unit.h:1193
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:12106
Gender GetGender() const
Definition Unit.h:767
uint32 GetCreatureType() const
Definition Unit.cpp:9451
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4863
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:14358
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4788
bool IsHovering() const
Definition Unit.h:1151
ObjectGuid GetMinionGUID() const
Definition Unit.h:1195
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1734
uint64 GetHealth() const
Definition Unit.h:788
AttackerSet const & getAttackers() const
Definition Unit.h:724
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4814
ObjectGuid GetCritterGUID() const
Definition Unit.h:1199
uint32 GetExtraUnitMovementFlags() const
Definition Unit.h:1741
int32 GetPower(Powers power) const
Definition Unit.cpp:10028
uint8 GetEffectiveLevel() const
Definition Unit.h:758
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12177
float GetPowerPct(Powers power) const
Definition Unit.h:820
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1208
bool IsFlying() const
Definition Unit.h:1807
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4646
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12158
ObjectGuid GetTarget() const
Definition Unit.h:1831
uint8 GetLevel() const
Definition Unit.h:757
uint8 GetRace() const
Definition Unit.h:761
bool IsInCombat() const
Definition Unit.h:1058
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1466
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:2324
ReputationRank GetReactionTo(WorldObject const *target) const
Definition Object.cpp:2028
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2482
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:432
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:916
WeatherState
Definition Weather.h:46
@ 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< int32, 2 > MovementFlags
std::array< uint32, 3 > MinFactionID
std::array< uint16, 4 > MinSkill
EnumFlag< PlayerConditionFlags > GetFlags() const
std::array< uint8, 3 > MinReputation
std::array< int32, 4 > ItemID
Trinity::RaceMask< int64 > RaceMask
std::array< int32, 4 > SpellID
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:519
uint32 QuestID
Definition QuestDef.h:483
SkillLineAbilityAcquireMethod GetAcquireMethod() const
SpawnGroupFlags flags
Definition SpawnData.h:72
constexpr void UpdateData(std::span< V, Extent > data) noexcept
Definition Hash.h:85
constexpr bool IsEmpty() const
Definition RaceMask.h:161
constexpr bool HasRace(uint32 raceId) const
Definition RaceMask.h:96
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