TrinityCore
Loading...
Searching...
No Matches
SmartScript.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 "SmartScript.h"
19#include "CellImpl.h"
20#include "ChatTextBuilder.h"
21#include "Containers.h"
22#include "Creature.h"
23#include "CreatureTextMgr.h"
24#include "CreatureTextMgrImpl.h"
25#include "GameEventMgr.h"
26#include "GameObject.h"
27#include "GossipDef.h"
28#include "GridNotifiersImpl.h"
29#include "Group.h"
30#include "InstanceScript.h"
31#include "Language.h"
32#include "Log.h"
33#include "Map.h"
34#include "MotionMaster.h"
35#include "ObjectAccessor.h"
36#include "ObjectMgr.h"
37#include "Random.h"
38#include "SmartAI.h"
39#include "SpellAuras.h"
40#include "SpellMgr.h"
41#include "TemporarySummon.h"
42#include "Vehicle.h"
43#include "WaypointDefines.h"
44#include "WaypointManager.h"
45#include <G3D/Quat.h>
46
48{
49 go = nullptr;
50 me = nullptr;
51 trigger = nullptr;
52 atPlayer = nullptr;
53 mEventPhase = 0;
54 mPathId = 0;
55 mTextTimer = 0;
56 mLastTextID = 0;
57 mUseTextTimer = false;
58 mTalkerEntry = 0;
65}
66
70
71bool SmartScript::IsSmart(Creature* c, bool silent) const
72{
73 if (!c)
74 return false;
75
76 bool smart = true;
77 if (!dynamic_cast<SmartAI*>(c->AI()))
78 smart = false;
79
80 if (!smart && !silent)
81 TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: {} Entry: {}) is not using SmartAI, action called by Creature (GUID: {} Entry: {}) skipped to prevent crash.", c->GetSpawnId(), c->GetEntry(), me ? me->GetSpawnId() : 0, me ? me->GetEntry() : 0);
82
83 return smart;
84}
85
86bool SmartScript::IsSmart(GameObject* g, bool silent) const
87{
88 if (!g)
89 return false;
90
91 bool smart = true;
92 if (!dynamic_cast<SmartGameObjectAI*>(g->AI()))
93 smart = false;
94
95 if (!smart && !silent)
96 TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: {} Entry: {}) is not using SmartGameObjectAI, action called by GameObject (GUID: {} Entry: {}) skipped to prevent crash.", g->GetSpawnId(), g->GetEntry(), go ? go->GetSpawnId() : 0, go ? go->GetEntry() : 0);
97
98 return smart;
99}
100
101bool SmartScript::IsSmart(bool silent) const
102{
103 if (me)
104 return IsSmart(me, silent);
105 if (go)
106 return IsSmart(go, silent);
107 return false;
108}
109
111{
112 // insert or replace
113 _storedTargets.erase(id);
114 _storedTargets.emplace(id, ObjectGuidVector(targets));
115}
116
118{
119 auto [itr, inserted] = _storedTargets.try_emplace(id, targets);
120 if (!inserted)
121 for (WorldObject* obj : targets)
122 itr->second.AddGuid(obj->GetGUID());
123}
124
126{
127 auto itr = _storedTargets.find(id);
128 if (itr != _storedTargets.end())
129 return itr->second.GetObjectVector(ref);
130 return nullptr;
131}
132
134{
135 CounterMap::iterator itr = mCounterList.find(id);
136 if (itr != mCounterList.end())
137 {
138 if (reset == 0)
139 itr->second += value;
140 else
141 itr->second = value;
142 }
143 else
144 mCounterList.insert(std::make_pair(id, value));
145
147}
148
150{
151 CounterMap::const_iterator itr = mCounterList.find(id);
152 if (itr != mCounterList.end())
153 return itr->second;
154 return 0;
155}
156
158{
159 auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
160 if (bounds.first == bounds.second)
161 return nullptr;
162
163 return bounds.first->second;
164}
165
167{
168 auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
169 if (bounds.first == bounds.second)
170 return nullptr;
171
172 auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
173 {
174 return pair.second->IsAlive();
175 });
176
177 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
178}
179
181{
183 for (SmartScriptHolder& event : mEvents)
184 {
185 if (!(event.event.event_flags & SMART_EVENT_FLAG_DONT_RESET))
186 {
187 InitTimer(event);
188 event.runOnce = false;
189 }
190
191 if (event.priority != SmartScriptHolder::DEFAULT_PRIORITY)
192 {
195 }
196 }
199}
200
202{
203 WorldObject* lookupRoot = me;
204 if (!lookupRoot)
205 lookupRoot = go;
206
207 if (lookupRoot)
208 {
209 if (!meOrigGUID.IsEmpty())
210 {
211 if (Creature* m = ObjectAccessor::GetCreature(*lookupRoot, meOrigGUID))
212 {
213 me = m;
214 go = nullptr;
215 }
216 }
217
218 if (!goOrigGUID.IsEmpty())
219 {
221 {
222 me = nullptr;
223 go = o;
224 }
225 }
226 }
229}
230
231void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
232{
234
235 // Allow only a fixed number of nested ProcessEventsFor calls
237 {
238 TC_LOG_WARN("scripts.ai", "SmartScript::ProcessEventsFor: reached the limit of max allowed nested ProcessEventsFor() calls with event {}, skipping!\n{}", e, GetBaseObject()->GetDebugInfo());
239 }
240 else
241 {
242 for (SmartScriptHolder& event : mEvents)
243 {
244 SMART_EVENT eventType = SMART_EVENT(event.GetEventType());
245 if (eventType == SMART_EVENT_LINK)//special handling
246 continue;
247
248 if (eventType == e)
249 if (sConditionMgr->IsObjectMeetingSmartEventConditions(event.entryOrGuid, event.event_id, event.source_type, unit, GetBaseObject()))
250 ProcessEvent(event, unit, var0, var1, bvar, spell, gob);
251 }
252 }
253
255}
256
257void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
258{
259 e.runOnce = true; //used for repeat check
260
261 // calc random
263 {
265 return;
266 }
267
268 // Remove SMART_EVENT_FLAG_TEMP_IGNORE_CHANCE_ROLL flag after processing roll chances as it's not needed anymore
269 e.event.event_flags &= ~SMART_EVENT_FLAG_TEMP_IGNORE_CHANCE_ROLL;
270
271 if (unit)
272 mLastInvoker = unit->GetGUID();
273
274 if (Unit* tempInvoker = GetLastInvoker())
275 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: Invoker: {} {}", tempInvoker->GetName(), tempInvoker->GetGUID().ToString());
276
277 ObjectVector targets;
278 GetTargets(targets, e, Coalesce<WorldObject>(unit, gob));
279
280 switch (e.GetActionType())
281 {
283 {
284 Creature* talker = e.target.type == 0 ? me : nullptr;
285 Unit* talkTarget = nullptr;
286
287 for (WorldObject* target : targets)
288 {
289 if (IsCreature(target) && !target->ToCreature()->IsPet()) // Prevented sending text to pets.
290 {
292 {
293 talker = me;
294 talkTarget = target->ToCreature();
295 }
296 else
297 talker = target->ToCreature();
298 break;
299 }
300 else if (IsPlayer(target))
301 {
302 talker = me;
303 talkTarget = target->ToPlayer();
304 break;
305 }
306 }
307
308 if (!talkTarget)
309 talkTarget = GetLastInvoker();
310
311 if (!talker)
312 break;
313
314 mTalkerEntry = talker->GetEntry();
317 mUseTextTimer = true;
318 sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), talkTarget);
319 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: {} {}, textGuid: {}",
320 talker->GetName(), talker->GetGUID().ToString(), talkTarget ? talkTarget->GetGUID().ToString() : "Empty");
321 break;
322 }
324 {
325 for (WorldObject* target : targets)
326 {
327 if (IsCreature(target))
328 sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : 0);
329 else if (IsPlayer(target) && me)
330 {
331 Unit* templastInvoker = GetLastInvoker();
332 sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_OTHER, false, target->ToPlayer());
333 }
334 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: {} {}, textGroupId: {}",
335 target->GetName(), target->GetGUID().ToString(), uint8(e.action.simpleTalk.textGroupID));
336 }
337 break;
338 }
340 {
341 for (WorldObject* target : targets)
342 {
343 if (IsUnit(target))
344 {
345 target->ToUnit()->HandleEmoteCommand(static_cast<Emote>(e.action.emote.emote));
346 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: {} {}, emote: {}",
347 target->GetName(), target->GetGUID().ToString(), e.action.emote.emote);
348 }
349 }
350 break;
351 }
353 {
354 for (WorldObject* target : targets)
355 {
356 if (IsUnit(target))
357 {
358 if (e.action.sound.distance == 1)
359 target->PlayDistanceSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr);
360 else
361 target->PlayDirectSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr);
362
363 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: {} {}, sound: {}, onlyself: {}",
364 target->GetName(), target->GetGUID().ToString(), e.action.sound.sound, e.action.sound.onlySelf);
365 }
366 }
367 break;
368 }
370 {
371 for (WorldObject* target : targets)
372 {
373 if (IsCreature(target))
374 {
376 {
377 target->ToCreature()->SetFaction(e.action.faction.factionID);
378 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature {} set faction to {}",
379 target->GetGUID().ToString(), e.action.faction.factionID);
380 }
381 else
382 {
383 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->ToCreature()->GetEntry()))
384 {
385 if (target->ToCreature()->GetFaction() != ci->faction)
386 {
387 target->ToCreature()->SetFaction(ci->faction);
388 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature {} set faction to {}",
389 target->GetGUID().ToString(), ci->faction);
390 }
391 }
392 }
393 }
394 }
395 break;
396 }
398 {
399 for (WorldObject* target : targets)
400 {
401 if (!IsCreature(target))
402 continue;
403
405 {
406 //set model based on entry from creature_template
408 {
409 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
410 {
411 uint32 displayId = ObjectMgr::ChooseDisplayId(ci);
412 target->ToCreature()->SetDisplayId(displayId);
413 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} set displayid to {}",
414 target->GetGUID().ToString(), displayId);
415 }
416 }
417 //if no param1, then use value from param2 (modelId)
418 else
419 {
420 target->ToCreature()->SetDisplayId(e.action.morphOrMount.model);
421 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} set displayid to {}",
422 target->GetGUID().ToString(), e.action.morphOrMount.model);
423 }
424 }
425 else
426 {
427 target->ToCreature()->DeMorph();
428 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} demorphs.",
429 target->GetGUID().ToString());
430 }
431 }
432 break;
433 }
435 {
436 for (WorldObject* target : targets)
437 {
438 if (IsPlayer(target))
439 {
440 target->ToPlayer()->FailQuest(e.action.quest.quest);
441 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player {} fails quest {}",
442 target->GetGUID().ToString(), e.action.quest.quest);
443 }
444 }
445 break;
446 }
448 {
449 for (WorldObject* target : targets)
450 {
451 if (Player* player = target->ToPlayer())
452 {
453 if (Quest const* q = sObjectMgr->GetQuestTemplate(e.action.questOffer.questID))
454 {
455 if (me && e.action.questOffer.directAdd == 0)
456 {
457 if (player->CanTakeQuest(q, true))
458 {
459 if (WorldSession* session = player->GetSession())
460 {
461 PlayerMenu menu(session);
462 menu.SendQuestGiverQuestDetails(q, me->GetGUID(), true);
463 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {} - offering quest {}", player->GetGUID().ToString(), e.action.questOffer.questID);
464 }
465 }
466 }
467 else
468 {
469 player->AddQuestAndCheckCompletion(q, nullptr);
470 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {} - quest {} added",
471 player->GetGUID().ToString(), e.action.questOffer.questID);
472 }
473 }
474 }
475 }
476 break;
477 }
479 {
480 for (WorldObject* target : targets)
481 {
482 if (!IsCreature(target))
483 continue;
484
485 target->ToCreature()->SetReactState(ReactStates(e.action.react.state));
486 }
487 break;
488 }
490 {
491 std::vector<uint32> emotes;
492 std::copy_if(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes),
493 std::back_inserter(emotes), [](uint32 emote) { return emote != 0; });
494
495 for (WorldObject* target : targets)
496 {
497 if (IsUnit(target))
498 {
500 target->ToUnit()->HandleEmoteCommand(emote);
501 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature {} handle random emote {}",
502 target->GetGUID().ToString(), emote);
503 }
504 }
505 break;
506 }
508 {
509 if (!me)
510 break;
511
512 for (auto* ref : me->GetThreatManager().GetModifiableThreatList())
513 {
514 ref->ModifyThreatByPercent(std::max<int32>(-100,int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC)));
515 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature {} modify threat for unit {}, value {}",
516 me->GetGUID().ToString(), ref->GetVictim()->GetGUID().ToString(), int32(e.action.threatPCT.threatINC)-int32(e.action.threatPCT.threatDEC));
517 }
518 break;
519 }
521 {
522 if (!me)
523 break;
524
525 for (WorldObject* target : targets)
526 {
527 if (IsUnit(target))
528 {
529 me->GetThreatManager().ModifyThreatByPercent(target->ToUnit(), std::max<int32>(-100, int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC)));
530 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature {} modify threat for unit {}, value {}",
531 me->GetGUID().ToString(), target->GetGUID().ToString(), int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC));
532 }
533 }
534 break;
535 }
537 {
538 for (WorldObject* target : targets)
539 {
540 // Special handling for vehicles
541 if (IsUnit(target))
542 if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
543 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
544 if (Player* player = ObjectAccessor::GetPlayer(*target, seat.second.Passenger.Guid))
545 player->AreaExploredOrEventHappens(e.action.quest.quest);
546
547 if (IsPlayer(target))
548 {
549 target->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest);
550
551 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player {} credited quest {}",
552 target->GetGUID().ToString(), e.action.quest.quest);
553 }
554 }
555 break;
556 }
558 {
559 if (targets.empty())
560 break;
561
562 if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit)
564
565 bool failedSpellCast = false, successfulSpellCast = false;
566
567 for (WorldObject* target : targets)
568 {
569 // may be nullptr
570 if (go)
571 go->CastSpell(target->ToUnit(), e.action.cast.spell);
572
573 if (!IsUnit(target))
574 continue;
575
576 if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
577 {
578 TriggerCastFlags triggerFlag = TRIGGERED_NONE;
580 {
582 triggerFlag = TriggerCastFlags(e.action.cast.triggerFlags);
583 else
584 triggerFlag = TRIGGERED_FULL_MASK;
585 }
586
587 if (me)
588 {
591
592 SpellCastResult result = me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
593 bool spellCastFailed = (result != SPELL_CAST_OK && result != SPELL_FAILED_SPELL_IN_PROGRESS);
594
596 {
597 // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed unless target is outside spell range, out of mana, or LOS.
598 ENSURE_AI(SmartAI, me->AI())->SetCombatMove(spellCastFailed, true);
599 }
600
601 if (spellCastFailed)
602 failedSpellCast = true;
603 else
604 successfulSpellCast = true;
605 }
606 else if (go)
607 go->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
608
609 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: {} casts spell {} on target {} with castflags {}",
610 me ? me->GetGUID().ToString() : go->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
611 }
612 else
613 TC_LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target ({}) already has the aura", e.action.cast.spell, target->GetGUID().ToString());
614 }
615
616 // If there is at least 1 failed cast and no successful casts at all, retry again on next loop
617 if (failedSpellCast && !successfulSpellCast)
618 {
619 RetryLater(e, true);
620 // Don't execute linked events
621 return;
622 }
623 break;
624 }
626 {
627 if (targets.empty())
628 break;
629
632
633 TriggerCastFlags triggerFlags = TRIGGERED_NONE;
635 {
637 triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
638 else
639 triggerFlags = TRIGGERED_FULL_MASK;
640 }
641
642 for (WorldObject* target : targets)
643 {
644 Unit* uTarget = target->ToUnit();
645 if (!uTarget)
646 continue;
647
649 {
651 uTarget->InterruptNonMeleeSpells(false);
652
653 uTarget->CastSpell(uTarget, e.action.cast.spell, triggerFlags);
654 }
655 }
656 break;
657 }
659 {
660 Unit* tempLastInvoker = GetLastInvoker(unit);
661 if (!tempLastInvoker)
662 break;
663
664 if (targets.empty())
665 break;
666
669
670 for (WorldObject* target : targets)
671 {
672 if (!IsUnit(target))
673 continue;
674
675 if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
676 {
678 tempLastInvoker->InterruptNonMeleeSpells(false);
679
680 TriggerCastFlags triggerFlag = TRIGGERED_NONE;
682 {
684 triggerFlag = TriggerCastFlags(e.action.cast.triggerFlags);
685 else
686 triggerFlag = TRIGGERED_FULL_MASK;
687 }
688
689 tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
690 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {} casts spell {} on target {} with castflags {}",
691 tempLastInvoker->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
692 }
693 else
694 TC_LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target ({}) already has the aura", e.action.cast.spell, target->GetGUID().ToString());
695 }
696 break;
697 }
699 {
700 for (WorldObject* target : targets)
701 {
702 if (IsGameObject(target))
703 {
704 // Activate
705 target->ToGameObject()->SetLootState(GO_READY);
706 target->ToGameObject()->UseDoorOrButton(0, false, unit);
707 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated",
708 target->GetGUID().ToString());
709 }
710 }
711 break;
712 }
714 {
715 for (WorldObject* target : targets)
716 {
717 if (IsGameObject(target))
718 {
719 target->ToGameObject()->ResetDoorOrButton();
720 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject {} reset",
721 target->GetGUID().ToString());
722 }
723 }
724 break;
725 }
727 {
728 for (WorldObject* target : targets)
729 {
730 if (IsUnit(target))
731 {
732 target->ToUnit()->SetEmoteState(Emote(e.action.emote.emote));
733 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit {} set emotestate to {}",
734 target->GetGUID().ToString(), e.action.emote.emote);
735 }
736 }
737 break;
738 }
740 {
741 if (!IsSmart())
742 break;
743
744 ENSURE_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack != 0);
745 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: {} bool on = {}",
747 break;
748 }
750 {
751 if (!IsSmart())
752 break;
753
754 bool move = e.action.combatMove.move != 0;
755 ENSURE_AI(SmartAI, me->AI())->SetCombatMove(move);
756 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}",
758 break;
759 }
761 {
762 if (!GetBaseObject())
763 break;
764
766 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature {} set event phase {}",
767 GetBaseObject()->GetGUID().ToString(), e.action.setEventPhase.phase);
768 break;
769 }
771 {
772 if (!GetBaseObject())
773 break;
774
777 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature {} inc event phase by {}, "
778 "decrease by {}", GetBaseObject()->GetGUID().ToString(), e.action.incEventPhase.inc, e.action.incEventPhase.dec);
779 break;
780 }
782 {
783 if (!me)
784 break;
785
786 // Reset home position to respawn position if specified in the parameters
787 if (e.action.evade.toRespawnPosition == 0)
788 {
789 float homeX, homeY, homeZ, homeO;
790 me->GetRespawnPosition(homeX, homeY, homeZ, &homeO);
791 me->SetHomePosition(homeX, homeY, homeZ, homeO);
792 }
793
794 me->AI()->EnterEvadeMode();
795 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_EVADE: Creature {} EnterEvadeMode", me->GetGUID().ToString());
796 break;
797 }
799 {
800 if (!me)
801 break;
802
804
806 {
808 sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE);
809 }
810 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString());
811 break;
812 }
814 {
815 if (!unit)
816 break;
817
818 // If invoker was pet or charm
819 Player* playerCharmed = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
820 if (playerCharmed && GetBaseObject())
821 {
822 playerCharmed->GroupEventHappens(e.action.quest.quest, GetBaseObject());
823 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}",
824 unit->GetGUID().ToString(), e.action.quest.quest);
825 }
826
827 // Special handling for vehicles
828 if (Vehicle* vehicle = unit->GetVehicleKit())
829 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
830 if (Player* passenger = ObjectAccessor::GetPlayer(*unit, seat.second.Passenger.Guid))
831 passenger->GroupEventHappens(e.action.quest.quest, GetBaseObject());
832 break;
833 }
835 {
836 if (!me)
837 break;
838
839 me->CombatStop(true);
840 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_COMBAT_STOP: {} CombatStop", me->GetGUID().ToString());
841 break;
842 }
844 {
845 for (WorldObject* target : targets)
846 {
847 if (!IsUnit(target))
848 continue;
849
850 if (e.action.removeAura.spell)
851 {
852 ObjectGuid casterGUID;
854 {
855 if (!me)
856 break;
857 casterGUID = me->GetGUID();
858 }
859
861 {
862 if (Aura* aur = target->ToUnit()->GetAura(e.action.removeAura.spell, casterGUID))
863 aur->ModCharges(-static_cast<int32>(e.action.removeAura.charges), AURA_REMOVE_BY_EXPIRE);
864 }
865 else
866 target->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell, casterGUID);
867 }
868 else
869 target->ToUnit()->RemoveAllAuras();
870
871 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit {}, spell {}",
872 target->GetGUID().ToString(), e.action.removeAura.spell);
873 }
874 break;
875 }
877 {
878 if (!IsSmart())
879 break;
880
881 if (targets.empty())
882 {
883 ENSURE_AI(SmartAI, me->AI())->StopFollow(false);
884 break;
885 }
886
887 for (WorldObject* target : targets)
888 {
889 if (IsUnit(target))
890 {
891 float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle;
892 ENSURE_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType);
893 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}",
894 me->GetGUID().ToString(), target->GetGUID().ToString());
895 break;
896 }
897 }
898 break;
899 }
901 {
902 if (!GetBaseObject())
903 break;
904
905 std::vector<uint32> phases;
906 std::copy_if(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases),
907 std::back_inserter(phases), [](uint32 phase) { return phase != 0; });
908
910 SetPhase(phase);
911 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature {} sets event phase to {}",
912 GetBaseObject()->GetGUID().ToString(), phase);
913 break;
914 }
916 {
917 if (!GetBaseObject())
918 break;
919
921 SetPhase(phase);
922 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature {} sets event phase to {}",
923 GetBaseObject()->GetGUID().ToString(), phase);
924 break;
925 }
927 {
928 if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) // Loot recipient and his group members
929 {
930 if (!me)
931 break;
932
933 if (Player* player = me->GetLootRecipient())
934 {
935 player->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, player);
936 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
937 player->GetGUID().ToString(), e.action.killedMonster.creature);
938 }
939 }
940 else // Specific target type
941 {
942 for (WorldObject* target : targets)
943 {
944 if (IsPlayer(target))
945 {
946 target->ToPlayer()->KilledMonsterCredit(e.action.killedMonster.creature);
947 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
948 target->GetGUID().ToString(), e.action.killedMonster.creature);
949 }
950 else if (IsUnit(target)) // Special handling for vehicles
951 if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
952 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
953 if (Player* player = ObjectAccessor::GetPlayer(*target, seat.second.Passenger.Guid))
954 player->KilledMonsterCredit(e.action.killedMonster.creature);
955 }
956 }
957 break;
958 }
960 {
961 WorldObject* obj = GetBaseObject();
962 if (!obj)
963 obj = unit;
964
965 if (!obj)
966 break;
967
968 InstanceScript* instance = obj->GetInstanceScript();
969 if (!instance)
970 {
971 TC_LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
972 break;
973 }
974
975 switch (e.action.setInstanceData.type)
976 {
977 case 0:
979 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetData Field: {}, data: {}",
981 break;
982 case 1:
984 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: {}, State: {} ({})",
986 break;
987 default: // Static analysis
988 break;
989 }
990 break;
991 }
993 {
994 WorldObject* obj = GetBaseObject();
995 if (!obj)
996 obj = unit;
997
998 if (!obj)
999 break;
1000
1001 InstanceScript* instance = obj->GetInstanceScript();
1002 if (!instance)
1003 {
1004 TC_LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
1005 break;
1006 }
1007
1008 if (targets.empty())
1009 break;
1010
1011 instance->SetGuidData(e.action.setInstanceData64.field, targets.front()->GetGUID());
1012 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: {}, data: {}",
1013 e.action.setInstanceData64.field, targets.front()->GetGUID().ToString());
1014 break;
1015 }
1017 {
1018 for (WorldObject* target : targets)
1019 if (IsCreature(target))
1020 target->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, nullptr, e.action.updateTemplate.updateLevel != 0);
1021 break;
1022 }
1023 case SMART_ACTION_DIE:
1024 {
1025 if (me && !me->isDead())
1026 {
1027 me->KillSelf();
1028 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());
1029 }
1030 break;
1031 }
1033 {
1034 if (me && me->IsAIEnabled())
1035 {
1036 me->AI()->DoZoneInCombat();
1037 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {}", me->GetGUID().ToString());
1038 }
1039 break;
1040 }
1042 {
1043 if (me)
1044 {
1045 me->CallForHelp(float(e.action.callHelp.range));
1047 {
1049 sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE);
1050 }
1051 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {}", me->GetGUID().ToString());
1052 }
1053 break;
1054 }
1056 {
1057 if (me)
1058 {
1060 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature {}, State: {}",
1062 }
1063 break;
1064 }
1066 {
1067 // there should be at least a world update tick before despawn, to avoid breaking linked actions
1068 Milliseconds despawnDelay(e.action.forceDespawn.delay);
1069 if (despawnDelay <= 0ms)
1070 despawnDelay = 1ms;
1071
1072 Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer);
1073
1074 for (WorldObject* target : targets)
1075 {
1076 if (Creature* creature = target->ToCreature())
1077 creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1078 else if (GameObject* goTarget = target->ToGameObject())
1079 goTarget->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1080 }
1081 break;
1082 }
1084 {
1085 for (WorldObject* target : targets)
1086 {
1087 if (IsUnit(target))
1088 target->ToUnit()->SetPhaseMask(e.action.ingamePhaseMask.mask, true);
1089 else if (IsGameObject(target))
1090 target->ToGameObject()->SetPhaseMask(e.action.ingamePhaseMask.mask, true);
1091 }
1092 break;
1093 }
1095 {
1096 for (WorldObject* target : targets)
1097 {
1098 if (!IsUnit(target))
1099 continue;
1100
1102 {
1103 if (e.action.morphOrMount.creature > 0)
1104 {
1105 if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1106 target->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo));
1107 }
1108 else
1109 target->ToUnit()->Mount(e.action.morphOrMount.model);
1110 }
1111 else
1112 target->ToUnit()->Dismount();
1113 }
1114 break;
1115 }
1117 {
1118 for (WorldObject* target : targets)
1119 {
1120 if (IsCreature(target))
1121 {
1122 SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI());
1123 if (!ai)
1124 continue;
1125
1126 if (e.action.invincHP.percent)
1127 ai->SetInvincibilityHpLevel(target->ToCreature()->CountPctFromMaxHealth(e.action.invincHP.percent));
1128 else
1130 }
1131 }
1132 break;
1133 }
1135 {
1136 for (WorldObject* target : targets)
1137 {
1138 if (Creature* cTarget = target->ToCreature())
1139 {
1140 CreatureAI* ai = cTarget->AI();
1141 if (IsSmart(cTarget, true))
1143 else
1145 }
1146 else if (GameObject* oTarget = target->ToGameObject())
1147 {
1148 GameObjectAI* ai = oTarget->AI();
1149 if (IsSmart(oTarget, true))
1151 else
1153 }
1154 }
1155 break;
1156 }
1158 {
1159 for (WorldObject* target : targets)
1160 if (Unit* unitTarget = target->ToUnit())
1161 unitTarget->AttackStop();
1162 break;
1163 }
1165 {
1166 for (WorldObject* target : targets)
1167 {
1168 if (!IsCreature(target))
1169 continue;
1170
1172 continue;
1173
1174 Position pos = target->GetPosition();
1175
1176 // Use forward/backward/left/right cartesian plane movement
1177 float x, y, z, o;
1178 o = pos.GetOrientation();
1179 x = pos.GetPositionX() + (std::cos(o - (M_PI / 2))*e.target.x) + (std::cos(o)*e.target.y);
1180 y = pos.GetPositionY() + (std::sin(o - (M_PI / 2))*e.target.x) + (std::sin(o)*e.target.y);
1181 z = pos.GetPositionZ() + e.target.z;
1182 target->ToCreature()->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z);
1183 }
1184 break;
1185 }
1187 {
1188 for (WorldObject* target : targets)
1189 if (IsUnit(target))
1190 target->ToUnit()->SetVisible(e.action.visibility.state ? true : false);
1191 break;
1192 }
1194 {
1195 for (WorldObject* target : targets)
1196 target->setActive(e.action.active.state ? true : false);
1197 break;
1198 }
1200 {
1201 if (!me)
1202 break;
1203
1204 if (targets.empty())
1205 break;
1206
1207 // attack random target
1209 me->AI()->AttackStart(target);
1210 break;
1211 }
1213 {
1215 bool preferUnit = flags.HasFlag(SmartActionSummonCreatureFlags::PreferUnit);
1216 WorldObject* summoner = preferUnit ? unit : Coalesce<WorldObject>(GetBaseObjectOrPlayerTrigger(), unit);
1217 if (!summoner)
1218 break;
1219
1220 ObjectGuid privateObjectOwner;
1222 privateObjectOwner = summoner->IsPrivateObject() ? summoner->GetPrivateObjectOwner() : summoner->GetGUID();
1223 uint32 spawnsCount = std::max(e.action.summonCreature.count, 1u);
1224
1225 float x, y, z, o;
1226 for (WorldObject* target : targets)
1227 {
1228 target->GetPosition(x, y, z, o);
1229 x += e.target.x;
1230 y += e.target.y;
1231 z += e.target.z;
1232 o += e.target.o;
1233 for (uint32 counter = 0; counter < spawnsCount; counter++)
1234 {
1235 if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner))
1237 summon->AI()->AttackStart(target->ToUnit());
1238 }
1239 }
1240
1242 break;
1243
1244 for (uint32 counter = 0; counter < spawnsCount; counter++)
1245 {
1247 if (unit && e.action.summonCreature.attackInvoker)
1248 summon->AI()->AttackStart(unit);
1249 }
1250 break;
1251 }
1253 {
1254 if (!GetBaseObject())
1255 break;
1256
1257 for (WorldObject* target : targets)
1258 {
1259 Position pos = target->GetPositionWithOffset(Position(e.target.x, e.target.y, e.target.z, e.target.o));
1262 }
1263
1265 break;
1266
1269 break;
1270 }
1272 {
1273 for (WorldObject* target : targets)
1274 {
1275 if (!IsUnit(target))
1276 continue;
1277
1278 target->ToUnit()->KillSelf();
1279 }
1280 break;
1281 }
1283 {
1284 for (WorldObject* target : targets)
1285 {
1286 if (!IsPlayer(target))
1287 continue;
1288
1289 target->ToPlayer()->AddItem(e.action.item.entry, e.action.item.count);
1290 }
1291 break;
1292 }
1294 {
1295 for (WorldObject* target : targets)
1296 {
1297 if (!IsPlayer(target))
1298 continue;
1299
1300 target->ToPlayer()->DestroyItemCount(e.action.item.entry, e.action.item.count, true);
1301 }
1302 break;
1303 }
1305 {
1307 break;
1308 }
1310 {
1311 for (WorldObject* target : targets)
1312 {
1313 if (IsPlayer(target))
1314 target->ToPlayer()->TeleportTo(e.action.teleport.mapID, e.target.x, e.target.y, e.target.z, e.target.o);
1315 else if (IsCreature(target))
1316 target->ToCreature()->NearTeleportTo(e.target.x, e.target.y, e.target.z, e.target.o);
1317 }
1318 break;
1319 }
1321 {
1322 if (!IsSmart())
1323 break;
1324
1325 ENSURE_AI(SmartAI, me->AI())->SetDisableGravity(e.action.setDisableGravity.disable != 0);
1326 break;
1327 }
1329 {
1330 if (!IsSmart())
1331 break;
1332
1333 ENSURE_AI(SmartAI, me->AI())->SetRun(e.action.setRun.run != 0);
1334 break;
1335 }
1337 {
1338 if (!targets.empty())
1339 {
1340 for (WorldObject* target : targets)
1341 {
1342 if (IsCreature(target))
1343 {
1344 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
1345 ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
1346 else
1347 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping");
1348 }
1349 else if (IsGameObject(target))
1350 {
1351 if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI()))
1352 ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
1353 else
1354 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping");
1355 }
1356 }
1357 }
1358 else
1360 break;
1361 }
1363 {
1364 if (!IsSmart())
1365 break;
1366
1367 uint32 entry = e.action.wpStart.pathID;
1368 bool repeat = e.action.wpStart.repeat != 0;
1369
1370 for (WorldObject* target : targets)
1371 {
1372 if (IsPlayer(target))
1373 {
1375 break;
1376 }
1377 }
1378
1379 ENSURE_AI(SmartAI, me->AI())->StartPath(entry, repeat, unit);
1380
1381 uint32 quest = e.action.wpStart.quest;
1382 uint32 DespawnTime = e.action.wpStart.despawnTime;
1383 ENSURE_AI(SmartAI, me->AI())->SetEscortQuest(quest);
1384 ENSURE_AI(SmartAI, me->AI())->SetDespawnTime(DespawnTime);
1385 break;
1386 }
1388 {
1389 if (!IsSmart())
1390 break;
1391
1392 uint32 delay = e.action.wpPause.delay;
1393 ENSURE_AI(SmartAI, me->AI())->PausePath(delay, true);
1394 break;
1395 }
1397 {
1398 if (!IsSmart())
1399 break;
1400
1401 uint32 DespawnTime = e.action.wpStop.despawnTime;
1402 uint32 quest = e.action.wpStop.quest;
1403 bool fail = e.action.wpStop.fail != 0;
1404 ENSURE_AI(SmartAI, me->AI())->StopPath(DespawnTime, quest, fail);
1405 break;
1406 }
1408 {
1409 if (!IsSmart())
1410 break;
1411
1412 // Set the timer to 1 ms so the path will be resumed on next update loop
1413 if (ENSURE_AI(SmartAI, me->AI())->CanResumePath())
1414 ENSURE_AI(SmartAI, me->AI())->SetWPPauseTimer(1);
1415 break;
1416 }
1418 {
1419 if (!me)
1420 break;
1421
1424 else if (e.GetTargetType() == SMART_TARGET_POSITION)
1425 me->SetFacingTo(e.target.o);
1426 else if (!targets.empty())
1427 me->SetFacingToObject(targets.front());
1428 break;
1429 }
1431 {
1432 for (WorldObject* target : targets)
1433 {
1434 if (!IsPlayer(target))
1435 continue;
1436
1437 target->ToPlayer()->SendMovieStart(e.action.movie.entry);
1438 }
1439 break;
1440 }
1442 {
1443 if (!IsSmart())
1444 break;
1445
1446 WorldObject* target = nullptr;
1447
1448 // we want to move to random element
1449 if (!targets.empty())
1451
1452 if (target)
1453 {
1454 float x, y, z;
1455 target->GetPosition(x, y, z);
1457 target->GetContactPoint(me, x, y, z, e.action.moveToPos.ContactDistance);
1459 }
1460
1462 break;
1463
1464 Position dest(e.target.x, e.target.y, e.target.z);
1466 if (TransportBase* trans = me->GetDirectTransport())
1467 trans->CalculatePassengerPosition(dest.m_positionX, dest.m_positionY, dest.m_positionZ);
1468
1470 break;
1471 }
1473 {
1474 for (WorldObject* target : targets)
1475 {
1476 if (IsCreature(target))
1477 TC_LOG_WARN("sql.sql", "Invalid creature target '{}' (entry {}, spawnId {}) specified for SMART_ACTION_ENABLE_TEMP_GOBJ", target->GetName(), target->GetEntry(), target->ToCreature()->GetSpawnId());
1478 else if (IsGameObject(target))
1479 {
1480 if (target->ToGameObject()->isSpawnedByDefault())
1481 TC_LOG_WARN("sql.sql", "Invalid gameobject target '{}' (entry {}, spawnId {}) for SMART_ACTION_ENABLE_TEMP_GOBJ - the object is spawned by default", target->GetName(), target->GetEntry(), target->ToGameObject()->GetSpawnId());
1482 else
1483 target->ToGameObject()->SetRespawnTime(e.action.enableTempGO.duration);
1484 }
1485 }
1486 break;
1487 }
1489 {
1490 for (WorldObject* target : targets)
1491 if (IsPlayer(target))
1492 target->ToPlayer()->PlayerTalkClass->SendCloseGossip();
1493 break;
1494 }
1495 case SMART_ACTION_EQUIP:
1496 {
1497 for (WorldObject* target : targets)
1498 {
1499 if (Creature* npc = target->ToCreature())
1500 {
1501 std::array<uint32, MAX_EQUIPMENT_ITEMS> slot;
1502 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
1503 {
1504 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId);
1505 if (!eInfo)
1506 {
1507 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}", equipId, npc->GetEntry());
1508 break;
1509 }
1510
1511 npc->SetCurrentEquipmentId(equipId);
1512
1513 std::copy(std::begin(eInfo->ItemEntry), std::end(eInfo->ItemEntry), std::begin(slot));
1514 }
1515 else
1516 {
1517 slot[0] = e.action.equip.slot1;
1518 slot[1] = e.action.equip.slot2;
1519 slot[2] = e.action.equip.slot3;
1520 }
1521
1522 for (uint32 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1523 if (!e.action.equip.mask || (e.action.equip.mask & (1 << i)))
1524 npc->SetVirtualItem(i, slot[i]);
1525 }
1526 }
1527 break;
1528 }
1530 {
1531 SmartEvent ne = SmartEvent();
1534 if (!ne.event_chance) ne.event_chance = 100;
1535
1540
1541 ne.event_flags = 0;
1544
1547
1548 SmartAction ac = SmartAction();
1551
1553 ev.event = ne;
1554 ev.event_id = e.action.timeEvent.id;
1555 ev.target = e.target;
1556 ev.action = ac;
1557 InitTimer(ev);
1558 mStoredEvents.push_back(ev);
1559 break;
1560 }
1562 {
1564
1565 // remove this event if not repeatable
1567 mRemIDs.push_back(e.action.timeEvent.id);
1568 break;
1569 }
1571 {
1572 mRemIDs.push_back(e.action.timeEvent.id);
1573 break;
1574 }
1576 {
1577 SetPhase(0);
1578 OnReset();
1579 break;
1580 }
1582 {
1583 if (!IsSmart())
1584 break;
1585
1586 float attackDistance = float(e.action.setRangedMovement.distance);
1587 float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * float(M_PI);
1588
1589 for (WorldObject* target : targets)
1590 {
1591 if (Creature* creature = target->ToCreature())
1592 if (IsSmart(creature) && creature->GetVictim())
1593 if (ENSURE_AI(SmartAI, creature->AI())->CanCombatMove())
1594 creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle);
1595 }
1596
1597 break;
1598 }
1600 {
1602 {
1603 TC_LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
1604 break;
1605 }
1606
1607 for (WorldObject* target : targets)
1608 {
1609 if (Creature* creature = target->ToCreature())
1610 {
1611 if (IsSmart(creature))
1613 }
1614 else if (GameObject* goTarget = target->ToGameObject())
1615 {
1616 if (IsSmart(goTarget))
1618 }
1619 }
1620 break;
1621 }
1623 {
1624 for (WorldObject* target : targets)
1625 if (IsCreature(target))
1626 target->ToUnit()->ReplaceAllNpcFlags(NPCFlags(e.action.flag.flag));
1627 break;
1628 }
1630 {
1631 for (WorldObject* target : targets)
1632 if (IsCreature(target))
1633 target->ToUnit()->SetNpcFlag(NPCFlags(e.action.flag.flag));
1634 break;
1635 }
1637 {
1638 for (WorldObject* target : targets)
1639 if (IsCreature(target))
1640 target->ToUnit()->RemoveNpcFlag(NPCFlags(e.action.flag.flag));
1641 break;
1642 }
1644 {
1645 if (targets.empty())
1646 break;
1647
1648 ObjectVector casters;
1650
1651 for (WorldObject* caster : casters)
1652 {
1653 if (!IsUnit(caster))
1654 continue;
1655
1656 Unit* casterUnit = caster->ToUnit();
1657
1658 bool interruptedSpell = false;
1659
1660 for (WorldObject* target : targets)
1661 {
1662 if (!IsUnit(target))
1663 continue;
1664
1665 if (!(e.action.crossCast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.crossCast.spell))
1666 {
1667 if (!interruptedSpell && e.action.crossCast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
1668 {
1669 casterUnit->InterruptNonMeleeSpells(false);
1670 interruptedSpell = true;
1671 }
1672
1673 casterUnit->CastSpell(target->ToUnit(), e.action.crossCast.spell, (e.action.crossCast.castFlags & SMARTCAST_TRIGGERED) != 0);
1674 }
1675 else
1676 TC_LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target ({}) already has the aura", e.action.crossCast.spell, target->GetGUID().ToString());
1677 }
1678 }
1679 break;
1680 }
1682 {
1683 std::vector<uint32> actionLists;
1684 std::copy_if(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists),
1685 std::back_inserter(actionLists), [](uint32 actionList) { return actionList != 0; });
1686
1689 {
1690 TC_LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
1691 break;
1692 }
1693
1694 for (WorldObject* target : targets)
1695 {
1696 if (Creature* creature = target->ToCreature())
1697 {
1698 if (IsSmart(creature))
1699 ENSURE_AI(SmartAI, creature->AI())->SetTimedActionList(e, id, GetLastInvoker());
1700 }
1701 else if (GameObject* goTarget = target->ToGameObject())
1702 {
1703 if (IsSmart(goTarget))
1705 }
1706 }
1707 break;
1708 }
1710 {
1713 {
1714 TC_LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
1715 break;
1716 }
1717
1718 for (WorldObject* target : targets)
1719 {
1720 if (Creature* creature = target->ToCreature())
1721 {
1722 if (IsSmart(creature))
1723 ENSURE_AI(SmartAI, creature->AI())->SetTimedActionList(e, id, GetLastInvoker());
1724 }
1725 else if (GameObject* goTarget = target->ToGameObject())
1726 {
1727 if (IsSmart(goTarget))
1729 }
1730 }
1731 break;
1732 }
1734 {
1735 for (WorldObject* target : targets)
1736 if (IsPlayer(target))
1737 target->ToPlayer()->ActivateTaxiPathTo(e.action.taxi.id);
1738 break;
1739 }
1741 {
1742 bool foundTarget = false;
1743
1744 for (WorldObject* target : targets)
1745 {
1746 if (IsCreature((target)))
1747 {
1748 foundTarget = true;
1749
1751 target->ToCreature()->GetMotionMaster()->MoveRandom(float(e.action.moveRandom.distance));
1752 else
1753 target->ToCreature()->GetMotionMaster()->MoveIdle();
1754 }
1755 }
1756
1757 if (!foundTarget && me && IsCreature(me))
1758 {
1761 else
1763 }
1764 break;
1765 }
1767 {
1768 for (WorldObject* target : targets)
1769 {
1770 if (IsUnit(target))
1771 {
1772 switch (e.action.setunitByte.type)
1773 {
1774 case 0:
1775 target->ToUnit()->SetStandState(UnitStandStateType(e.action.setunitByte.byte1));
1776 break;
1777 case 1:
1778 // pet talent points
1779 break;
1780 case 2:
1781 target->ToUnit()->SetVisFlag(UnitVisFlags(e.action.setunitByte.byte1));
1782 break;
1783 case 3:
1784 target->ToUnit()->SetAnimTier(AnimTier(e.action.setunitByte.byte1));
1785 break;
1786 }
1787 }
1788 }
1789 break;
1790 }
1792 {
1793 for (WorldObject* target : targets)
1794 {
1795 if (IsUnit(target))
1796 {
1797 switch (e.action.setunitByte.type)
1798 {
1799 case 0:
1800 target->ToUnit()->SetStandState(UNIT_STAND_STATE_STAND);
1801 break;
1802 case 1:
1803 // pet talent points
1804 break;
1805 case 2:
1806 target->ToUnit()->RemoveVisFlag(UnitVisFlags(e.action.setunitByte.byte1));
1807 break;
1808 case 3:
1809 target->ToUnit()->SetAnimTier(AnimTier::Ground);
1810 break;
1811 }
1812 }
1813 }
1814 break;
1815 }
1817 {
1818 for (WorldObject* target : targets)
1819 if (IsUnit(target))
1820 target->ToUnit()->InterruptNonMeleeSpells(e.action.interruptSpellCasting.withDelayed != 0, e.action.interruptSpellCasting.spell_id, e.action.interruptSpellCasting.withInstant != 0);
1821 break;
1822 }
1824 {
1825 for (WorldObject* target : targets)
1826 if (Creature* creature = target->ToCreature())
1827 creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, 0.0f, float(e.action.jump.speedxy), float(e.action.jump.speedz)); // @todo add optional jump orientation support?
1828 break;
1829 }
1831 {
1832 for (WorldObject* target : targets)
1833 if (IsGameObject(target))
1834 target->ToGameObject()->SetLootState((LootState)e.action.setGoLootState.state);
1835 break;
1836 }
1838 {
1839 for (WorldObject* target : targets)
1840 if (IsGameObject(target))
1841 target->ToGameObject()->SetGoState((GOState)e.action.goState.state);
1842 break;
1843 }
1845 {
1846 WorldObject* ref = GetBaseObject();
1847 if (!ref)
1848 ref = unit;
1849
1850 if (!ref)
1851 break;
1852
1853 ObjectVector const* storedTargets = GetStoredTargetVector(e.action.sendTargetToTarget.id, *ref);
1854 if (!storedTargets)
1855 break;
1856
1857 for (WorldObject* target : targets)
1858 {
1859 if (IsCreature(target))
1860 {
1861 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
1862 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
1863 else
1864 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping");
1865 }
1866 else if (IsGameObject(target))
1867 {
1868 if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI()))
1869 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
1870 else
1871 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping");
1872 }
1873 }
1874 break;
1875 }
1877 {
1878 if (!GetBaseObject() || !IsSmart())
1879 break;
1880
1881 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {}, gossipNpcTextId {}",
1883
1884 // override default gossip
1885 if (me)
1886 ENSURE_AI(SmartAI, me->AI())->SetGossipReturn(true);
1887 else if (go)
1888 ENSURE_AI(SmartGameObjectAI, go->AI())->SetGossipReturn(true);
1889
1890 for (WorldObject* target : targets)
1891 {
1892 if (Player* player = target->ToPlayer())
1893 {
1895 player->PrepareGossipMenu(GetBaseObject(), e.action.sendGossipMenu.gossipMenuId, true);
1896 else
1897 player->PlayerTalkClass->ClearMenus();
1898
1899 player->PlayerTalkClass->SendGossipMenu(e.action.sendGossipMenu.gossipNpcTextId, GetBaseObject()->GetGUID());
1900 }
1901 }
1902 break;
1903 }
1905 {
1906 for (WorldObject* target : targets)
1907 {
1908 if (IsCreature(target))
1909 {
1911 target->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
1912 else if (e.GetTargetType() == SMART_TARGET_POSITION)
1913 target->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o);
1921 {
1922 target->ToCreature()->SetHomePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
1923 }
1924 else
1925 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is invalid, skipping");
1926 }
1927 }
1928 break;
1929 }
1931 {
1932 for (WorldObject* target : targets)
1933 if (IsCreature(target))
1934 target->ToCreature()->SetRegenerateHealth(e.action.setHealthRegen.regenHealth != 0);
1935 break;
1936 }
1938 {
1939 for (WorldObject* target : targets)
1940 if (IsCreature(target))
1941 target->ToCreature()->SetControlled(e.action.setRoot.root != 0, UNIT_STATE_ROOT);
1942 break;
1943 }
1945 {
1946 std::list<TempSummon*> summonList;
1948
1949 for (TempSummon* summon : summonList)
1950 if (unit && e.action.creatureGroup.attackInvoker)
1951 summon->AI()->AttackStart(unit);
1952 break;
1953 }
1955 {
1956 for (WorldObject* target : targets)
1957 if (IsUnit(target))
1958 target->ToUnit()->SetPower(Powers(e.action.power.powerType), e.action.power.newPower);
1959 break;
1960 }
1962 {
1963 for (WorldObject* target : targets)
1964 if (IsUnit(target))
1965 target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) + e.action.power.newPower);
1966 break;
1967 }
1969 {
1970 for (WorldObject* target : targets)
1971 if (IsUnit(target))
1972 target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) - e.action.power.newPower);
1973 break;
1974 }
1976 {
1977 uint32 eventId = e.action.gameEventStop.id;
1978 if (!sGameEventMgr->IsActiveEvent(eventId))
1979 {
1980 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: {})", eventId);
1981 break;
1982 }
1983 sGameEventMgr->StopEvent(eventId, true);
1984 break;
1985 }
1987 {
1988 uint32 eventId = e.action.gameEventStart.id;
1989 if (sGameEventMgr->IsActiveEvent(eventId))
1990 {
1991 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: {})", eventId);
1992 break;
1993 }
1994 sGameEventMgr->StartEvent(eventId, true);
1995 break;
1996 }
1998 {
1999 std::vector<uint32> waypoints;
2000 std::copy_if(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps),
2001 std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
2002
2003 float distanceToClosest = std::numeric_limits<float>::max();
2004 std::pair<uint32, uint32> closest = { 0, 0 };
2005
2006 for (WorldObject* target : targets)
2007 {
2008 if (Creature* creature = target->ToCreature())
2009 {
2010 if (IsSmart(creature))
2011 {
2012 for (uint32 pathId : waypoints)
2013 {
2014 WaypointPath const* path = sWaypointMgr->GetPath(pathId);
2015 if (!path || path->nodes.empty())
2016 continue;
2017
2018 for (WaypointNode const& waypoint : path->nodes)
2019 {
2020 float distamceToThisNode = creature->GetDistance(waypoint.x, waypoint.y, waypoint.z);
2021 if (distamceToThisNode < distanceToClosest)
2022 {
2023 distanceToClosest = distamceToThisNode;
2024 closest.first = pathId;
2025 closest.second = waypoint.id;
2026 }
2027 }
2028 }
2029
2030 if (closest.first != 0)
2031 ENSURE_AI(SmartAI, creature->AI())->StartPath(closest.first, true, nullptr, closest.second);
2032 }
2033 }
2034 }
2035 break;
2036 }
2038 {
2039 std::vector<uint32> sounds;
2040 std::copy_if(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds),
2041 std::back_inserter(sounds), [](uint32 sound) { return sound != 0; });
2042
2043 bool onlySelf = e.action.randomSound.onlySelf != 0;
2044 for (WorldObject* const target : targets)
2045 {
2046 if (IsUnit(target))
2047 {
2049
2050 if (e.action.randomSound.distance == 1)
2051 target->PlayDistanceSound(sound, onlySelf ? target->ToPlayer() : nullptr);
2052 else
2053 target->PlayDirectSound(sound, onlySelf ? target->ToPlayer() : nullptr);
2054
2055 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: {} ({}), sound: {}, onlyself: {}",
2056 target->GetName(), target->GetGUID().ToString(), sound, onlySelf ? "true" : "false");
2057 }
2058 }
2059 break;
2060 }
2062 {
2063 for (WorldObject* const target : targets)
2064 {
2065 if (IsCreature(target))
2066 target->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer, !e.action.corpseDelay.includeDecayRatio);
2067 }
2068
2069 break;
2070 }
2072 {
2073 if (e.action.groupSpawn.minDelay == 0 && e.action.groupSpawn.maxDelay == 0)
2074 {
2077
2078 // Instant spawn
2079 GetBaseObject()->GetMap()->SpawnGroupSpawn(e.action.groupSpawn.groupId, ignoreRespawn, force);
2080 }
2081 else
2082 {
2083 // Delayed spawn (use values from parameter to schedule event to call us back
2084 SmartEvent ne = SmartEvent();
2086 ne.event_chance = 100;
2087
2090 ne.minMaxRepeat.repeatMin = 0;
2091 ne.minMaxRepeat.repeatMax = 0;
2092
2093 ne.event_flags = 0;
2095
2096 SmartAction ac = SmartAction();
2099 ac.groupSpawn.minDelay = 0;
2100 ac.groupSpawn.maxDelay = 0;
2103
2105 ev.event = ne;
2106 ev.event_id = e.event_id;
2107 ev.target = e.target;
2108 ev.action = ac;
2109 InitTimer(ev);
2110 mStoredEvents.push_back(ev);
2111 }
2112 break;
2113 }
2115 {
2116 if (e.action.groupSpawn.minDelay == 0 && e.action.groupSpawn.maxDelay == 0)
2117 {
2118 bool const deleteRespawnTimes = ((e.action.groupSpawn.spawnflags & SMARTAI_SPAWN_FLAGS::SMARTAI_SPAWN_FLAG_NOSAVE_RESPAWN) != 0);
2119
2120 // Instant spawn
2121 GetBaseObject()->GetMap()->SpawnGroupDespawn(e.action.groupSpawn.groupId, deleteRespawnTimes);
2122 }
2123 else
2124 {
2125 // Delayed spawn (use values from parameter to schedule event to call us back
2126 SmartEvent ne = SmartEvent();
2128 ne.event_chance = 100;
2129
2132 ne.minMaxRepeat.repeatMin = 0;
2133 ne.minMaxRepeat.repeatMax = 0;
2134
2135 ne.event_flags = 0;
2137
2138 SmartAction ac = SmartAction();
2141 ac.groupSpawn.minDelay = 0;
2142 ac.groupSpawn.maxDelay = 0;
2145
2147 ev.event = ne;
2148 ev.event_id = e.event_id;
2149 ev.target = e.target;
2150 ev.action = ac;
2151 InitTimer(ev);
2152 mStoredEvents.push_back(ev);
2153 }
2154 break;
2155 }
2157 {
2158 if (!IsSmart())
2159 break;
2160
2161 ENSURE_AI(SmartAI, me->AI())->SetEvadeDisabled(e.action.disableEvade.disable != 0);
2162 break;
2163 }
2165 {
2166 if (!me->CanHaveThreatList())
2167 break;
2168 for (WorldObject* const target : targets)
2169 if (IsUnit(target))
2170 me->GetThreatManager().AddThreat(target->ToUnit(), float(e.action.threat.threatINC) - float(e.action.threat.threatDEC), nullptr, true, true);
2171 break;
2172 }
2174 {
2175 for (WorldObject* const target : targets)
2176 if (IsCreature(target))
2177 target->ToCreature()->LoadEquipment(e.action.loadEquipment.id, e.action.loadEquipment.force != 0);
2178 break;
2179 }
2181 {
2184 break;
2185 }
2187 {
2188 for (WorldObject* const target : targets)
2189 if (IsUnit(target))
2190 target->ToUnit()->PauseMovement(e.action.pauseMovement.pauseTimer, e.action.pauseMovement.movementSlot, e.action.pauseMovement.force);
2191 break;
2192 }
2194 {
2195 Map* map = nullptr;
2196 if (WorldObject* obj = GetBaseObject())
2197 map = obj->GetMap();
2198 else if (!targets.empty())
2199 map = targets.front()->GetMap();
2200
2201 if (map)
2203 else
2204 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {} - tries to respawn by spawnId but does not provide a map", e.entryOrGuid, e.GetScriptType(), e.event_id);
2205 break;
2206 }
2208 {
2209 for (WorldObject* target : targets)
2210 {
2211 if (!IsPlayer(target))
2212 continue;
2213
2214 target->ToPlayer()->SendCinematicStart(e.action.cinematic.entry);
2215 }
2216 break;
2217 }
2219 {
2220 uint32 speedInteger = e.action.movementSpeed.speedInteger;
2221 uint32 speedFraction = e.action.movementSpeed.speedFraction;
2222 float speed = float(speedInteger) + float(speedFraction) / std::pow(10, std::floor(std::log10(float(speedFraction ? speedFraction : 1)) + 1));
2223
2224 for (WorldObject* target : targets)
2225 if (IsCreature(target))
2226 target->ToCreature()->SetSpeed(UnitMoveType(e.action.movementSpeed.movementType), speed);
2227
2228 break;
2229 }
2231 {
2232 if (WorldObject* obj = GetBaseObject())
2233 {
2235 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_OVERRIDE_LIGHT: {} sets zone override light (zoneId: {}, areaLightId: {}, overrideLightId: {}, transitionMilliseconds: {})",
2237 }
2238 break;
2239 }
2241 {
2242 if (WorldObject* obj = GetBaseObject())
2243 {
2245 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_OVERRIDE_WEATHER: {} sets zone weather (zoneId: {}, weatherId: {}, intensity: {})",
2247 }
2248 break;
2249 }
2251 {
2252 for (WorldObject* target : targets)
2253 if (IsUnit(target))
2254 target->ToUnit()->SetHover(e.action.setHover.enable != 0);
2255 break;
2256 }
2258 {
2259 for (WorldObject* target : targets)
2260 if (Unit* targetUnit = target->ToUnit())
2261 targetUnit->SetHealth(targetUnit->CountPctFromMaxHealth(e.action.setHealthPct.percent));
2262 break;
2263 }
2265 {
2266 for (WorldObject* target : targets)
2267 {
2268 if (IsUnit(target))
2269 {
2271 target->ToUnit()->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
2272 else
2273 target->ToUnit()->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
2274 }
2275 }
2276 break;
2277 }
2279 {
2280 for (WorldObject* target : targets)
2281 {
2282 if (IsUnit(target))
2283 {
2285 target->ToUnit()->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
2286 else
2287 target->ToUnit()->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
2288 }
2289 }
2290 break;
2291 }
2293 {
2294 for (WorldObject* target : targets)
2295 {
2296 if (IsUnit(target))
2297 {
2299 target->ToUnit()->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
2300 else
2301 target->ToUnit()->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
2302 }
2303 }
2304 break;
2305 }
2307 {
2308 for (WorldObject* target : targets)
2309 {
2310 if (GameObject* targetGo = target->ToGameObject())
2311 {
2313 }
2314 }
2315 break;
2316 }
2318 {
2319 if (!targets.empty())
2321 else
2322 {
2323 WorldObject* baseObject = GetBaseObject();
2324 TC_LOG_WARN("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ADD_TO_STORED_TARGET_LIST: var {}, baseObject {}, event {} - tried to add no targets to stored target list",
2325 e.action.addToStoredTargets.id, !baseObject ? "" : baseObject->GetName(), e.event_id);
2326 }
2327 break;
2328 }
2330 {
2331 for (WorldObject* const target : targets)
2332 if (IsUnit(target))
2333 target->ToUnit()->ResumeMovement(e.action.resumeMovement.resumeTimer, e.action.resumeMovement.movementSlot);
2334 break;
2335 }
2336 default:
2337 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2338 break;
2339 }
2340
2341 if (e.link && e.link != e.event_id)
2342 {
2344 if (linked)
2345 ProcessEvent(linked, unit, var0, var1, bvar, spell, gob);
2346 else
2347 TC_LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
2348 }
2349}
2350
2351void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
2352{
2353 // We may want to execute action rarely and because of this if condition is not fulfilled the action will be rechecked in a long time
2354 if (sConditionMgr->IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
2355 {
2356 RecalcTimer(e, min, max);
2357 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
2358 }
2359 else
2360 RecalcTimer(e, std::min<uint32>(min, 5000), std::min<uint32>(min, 5000));
2361}
2362
2363SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
2364{
2365 SmartScriptHolder script;
2366 script.event.type = e;
2367 script.event.raw.param1 = event_param1;
2368 script.event.raw.param2 = event_param2;
2369 script.event.raw.param3 = event_param3;
2370 script.event.raw.param4 = event_param4;
2371 script.event.raw.param5 = event_param5;
2372 script.event.event_phase_mask = phaseMask;
2373 script.event.event_flags = event_flags;
2374 script.event.event_chance = 100;
2375
2376 script.action.type = action;
2377 script.action.raw.param1 = action_param1;
2378 script.action.raw.param2 = action_param2;
2379 script.action.raw.param3 = action_param3;
2380 script.action.raw.param4 = action_param4;
2381 script.action.raw.param5 = action_param5;
2382 script.action.raw.param6 = action_param6;
2383
2384 script.target.type = t;
2385 script.target.raw.param1 = target_param1;
2386 script.target.raw.param2 = target_param2;
2387 script.target.raw.param3 = target_param3;
2388 script.target.raw.param4 = target_param4;
2389
2391 InitTimer(script);
2392 return script;
2393}
2394
2395void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, WorldObject* invoker /*= nullptr*/) const
2396{
2397 WorldObject* scriptTrigger = nullptr;
2398 if (invoker)
2399 scriptTrigger = invoker;
2400 else if (Unit* tempLastInvoker = GetLastInvoker())
2401 scriptTrigger = tempLastInvoker;
2402
2404 switch (e.GetTargetType())
2405 {
2406 case SMART_TARGET_SELF:
2407 if (baseObject)
2408 targets.push_back(baseObject);
2409 break;
2411 if (me)
2412 if (Unit* victim = me->GetVictim())
2413 targets.push_back(victim);
2414 break;
2416 if (me)
2417 {
2419 {
2421 targets.push_back(u);
2422 }
2424 targets.push_back(u);
2425 }
2426 break;
2428 if (me)
2429 {
2431 {
2433 targets.push_back(u);
2434 }
2436 targets.push_back(u);
2437 }
2438 break;
2440 if (me)
2441 {
2443 {
2445 targets.push_back(u);
2446 }
2448 targets.push_back(u);
2449 }
2450 break;
2452 if (me)
2453 {
2455 {
2457 targets.push_back(u);
2458 }
2460 targets.push_back(u);
2461 }
2462 break;
2464 if (me)
2465 {
2467 targets.push_back(u);
2468 }
2469 break;
2471 if (scriptTrigger)
2472 targets.push_back(scriptTrigger);
2473 break;
2475 if (scriptTrigger && scriptTrigger->ToUnit() && scriptTrigger->ToUnit()->GetVehicle() && scriptTrigger->ToUnit()->GetVehicle()->GetBase())
2476 targets.push_back(scriptTrigger->ToUnit()->GetVehicle()->GetBase());
2477 break;
2479 if (scriptTrigger)
2480 {
2481 if (Player* player = scriptTrigger->ToPlayer())
2482 {
2483 if (Group* group = player->GetGroup())
2484 {
2485 for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
2486 if (Player* member = groupRef->GetSource())
2487 if (member->IsInMap(player))
2488 targets.push_back(member);
2489 }
2490 // We still add the player to the list if there is no group. If we do
2491 // this even if there is a group (thus the else-check), it will add the
2492 // same player to the list twice. We don't want that to happen.
2493 else
2494 targets.push_back(scriptTrigger);
2495 }
2496 }
2497 break;
2499 {
2500 ObjectVector units;
2501 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitRange.maxDist));
2502
2503 for (WorldObject* unit : units)
2504 {
2505 if (!IsCreature(unit))
2506 continue;
2507
2508 if (me && me->GetGUID() == unit->GetGUID())
2509 continue;
2510
2511 if ((!e.target.unitRange.creature || unit->ToCreature()->GetEntry() == e.target.unitRange.creature) && baseObject->IsInRange(unit, float(e.target.unitRange.minDist), float(e.target.unitRange.maxDist)))
2512 targets.push_back(unit);
2513 }
2514
2515 if (e.target.unitRange.maxSize)
2517 break;
2518 }
2520 {
2521 ObjectVector units;
2522 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitDistance.dist));
2523
2524 for (WorldObject* unit : units)
2525 {
2526 if (!IsCreature(unit))
2527 continue;
2528
2529 if (me && me->GetGUID() == unit->GetGUID())
2530 continue;
2531
2532 if (!e.target.unitDistance.creature || unit->ToCreature()->GetEntry() == e.target.unitDistance.creature)
2533 targets.push_back(unit);
2534 }
2535
2538 break;
2539 }
2541 {
2542 ObjectVector units;
2543 GetWorldObjectsInDist(units, static_cast<float>(e.target.goDistance.dist));
2544
2545 for (WorldObject* unit : units)
2546 {
2547 if (!IsGameObject(unit))
2548 continue;
2549
2550 if (go && go->GetGUID() == unit->GetGUID())
2551 continue;
2552
2553 if (!e.target.goDistance.entry || unit->ToGameObject()->GetEntry() == e.target.goDistance.entry)
2554 targets.push_back(unit);
2555 }
2556
2559 break;
2560 }
2562 {
2563 ObjectVector units;
2564 GetWorldObjectsInDist(units, static_cast<float>(e.target.goRange.maxDist));
2565
2566 for (WorldObject* unit : units)
2567 {
2568 if (!IsGameObject(unit))
2569 continue;
2570
2571 if (go && go->GetGUID() == unit->GetGUID())
2572 continue;
2573
2574 if ((!e.target.goRange.entry || unit->ToGameObject()->GetEntry() == e.target.goRange.entry) && baseObject->IsInRange(unit, float(e.target.goRange.minDist), float(e.target.goRange.maxDist)))
2575 targets.push_back(unit);
2576 }
2577
2578 if (e.target.goRange.maxSize)
2580 break;
2581 }
2583 {
2584 if (!scriptTrigger && !baseObject)
2585 {
2586 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CREATURE_GUID can not be used without invoker");
2587 break;
2588 }
2589
2590 if (Creature* target = FindCreatureNear(scriptTrigger ? scriptTrigger : baseObject, e.target.unitGUID.dbGuid))
2591 if (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry)
2592 targets.push_back(target);
2593 break;
2594 }
2596 {
2597 if (!scriptTrigger && !baseObject)
2598 {
2599 TC_LOG_ERROR("sql.sql", "SMART_TARGET_GAMEOBJECT_GUID can not be used without invoker");
2600 break;
2601 }
2602
2603 if (GameObject* target = FindGameObjectNear(scriptTrigger ? scriptTrigger : baseObject, e.target.goGUID.dbGuid))
2604 if (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry)
2605 targets.push_back(target);
2606 break;
2607 }
2609 {
2610 ObjectVector units;
2611 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerRange.maxDist));
2612
2613 if (!units.empty() && baseObject)
2614 for (WorldObject* unit : units)
2615 if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
2616 targets.push_back(unit);
2617 break;
2618 }
2620 {
2621 ObjectVector units;
2622 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerDistance.dist));
2623
2624 for (WorldObject* unit : units)
2625 if (IsPlayer(unit))
2626 targets.push_back(unit);
2627 break;
2628 }
2630 {
2631 WorldObject* ref = GetBaseObject();
2632 if (!ref)
2633 ref = scriptTrigger;
2634
2635 if (ref)
2636 if (ObjectVector const* stored = GetStoredTargetVector(e.target.stored.id, *ref))
2637 targets.assign(stored->begin(), stored->end());
2638 break;
2639 }
2641 {
2643 targets.push_back(target);
2644 break;
2645 }
2647 {
2648 if (GameObject* target = baseObject->FindNearestGameObject(e.target.goClosest.entry, float(e.target.goClosest.dist ? e.target.goClosest.dist : 100)))
2649 targets.push_back(target);
2650 break;
2651 }
2653 {
2654 if (WorldObject* obj = GetBaseObject())
2655 if (Player* target = obj->SelectNearestPlayer(float(e.target.playerDistance.dist)))
2656 targets.push_back(target);
2657 break;
2658 }
2660 {
2661 if (me)
2662 {
2663 ObjectGuid charmerOrOwnerGuid = me->GetCharmerOrOwnerGUID();
2664
2665 if (!charmerOrOwnerGuid)
2666 if (TempSummon* tempSummon = me->ToTempSummon())
2667 if (WorldObject* summoner = tempSummon->GetSummoner())
2668 charmerOrOwnerGuid = summoner->GetGUID();
2669
2670 if (!charmerOrOwnerGuid)
2671 charmerOrOwnerGuid = me->GetCreatorGUID();
2672
2673 if (WorldObject* owner = ObjectAccessor::GetWorldObject(*me, charmerOrOwnerGuid))
2674 targets.push_back(owner);
2675 }
2676 else if (go)
2677 {
2678 if (Unit* owner = ObjectAccessor::GetUnit(*go, go->GetOwnerGUID()))
2679 targets.push_back(owner);
2680 }
2681
2682 // Get owner of owner
2683 if (e.target.owner.useCharmerOrOwner && !targets.empty())
2684 {
2685 WorldObject* owner = targets.front();
2686 targets.clear();
2687
2688 if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->GetCharmerOrOwnerGUID()))
2689 targets.push_back(base);
2690 }
2691 break;
2692 }
2694 {
2695 if (me && me->CanHaveThreatList())
2696 for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
2697 if (!e.target.threatList.maxDist || me->IsWithinCombatRange(ref->GetVictim(), float(e.target.threatList.maxDist)))
2698 targets.push_back(ref->GetVictim());
2699 break;
2700 }
2702 {
2703 if (me)
2705 targets.push_back(target);
2706 break;
2707 }
2709 {
2710 if (me)
2712 targets.push_back(target);
2713 break;
2714 }
2716 {
2717 if (me)
2718 {
2719 if (Group* lootGroup = me->GetLootRecipientGroup())
2720 {
2721 for (GroupReference* it = lootGroup->GetFirstMember(); it != nullptr; it = it->next())
2722 if (Player* recipient = it->GetSource())
2723 if (recipient->IsInMap(me))
2724 targets.push_back(recipient);
2725 }
2726 else
2727 {
2728 if (Player* recipient = me->GetLootRecipient())
2729 targets.push_back(recipient);
2730 }
2731 }
2732 break;
2733 }
2735 {
2736 if (me && me->IsVehicle())
2737 for (std::pair<int8 const, VehicleSeat>& seat : me->GetVehicleKit()->Seats)
2738 if (!e.target.vehicle.seatMask || (e.target.vehicle.seatMask & (1 << seat.first)))
2739 if (Unit* u = ObjectAccessor::GetUnit(*me, seat.second.Passenger.Guid))
2740 targets.push_back(u);
2741 break;
2742 }
2744 {
2745 if (GameObject* target = baseObject->FindNearestUnspawnedGameObject(e.target.goClosest.entry, float(e.target.goClosest.dist ? e.target.goClosest.dist : 100)))
2746 targets.push_back(target);
2747 break;
2748 }
2750 case SMART_TARGET_NONE:
2751 default:
2752 break;
2753 }
2754}
2755
2756void SmartScript::GetWorldObjectsInDist(ObjectVector& targets, float dist) const
2757{
2759 if (!obj)
2760 return;
2761
2762 Trinity::AllWorldObjectsInRange u_check(obj, dist);
2764 Cell::VisitAllObjects(obj, searcher, dist);
2765}
2766
2767void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob)
2768{
2769 if (!e.active && e.GetEventType() != SMART_EVENT_LINK)
2770 return;
2771
2773 return;
2774
2776 return;
2777
2778 switch (e.GetEventType())
2779 {
2780 case SMART_EVENT_LINK://special handling
2781 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
2782 break;
2783 //called from Update tick
2784 case SMART_EVENT_UPDATE:
2786 break;
2788 if (me && me->IsEngaged())
2789 return;
2791 break;
2793 if (!me || !me->IsEngaged())
2794 return;
2796 break;
2798 {
2799 if (!me || !me->IsEngaged() || !me->GetMaxHealth())
2800 return;
2801 uint32 perc = (uint32)me->GetHealthPct();
2802 if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
2803 return;
2805 break;
2806 }
2808 {
2809 if (!me || !me->IsEngaged() || !me->GetMaxPower(POWER_MANA))
2810 return;
2812 if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
2813 return;
2815 break;
2816 }
2817 case SMART_EVENT_RANGE:
2818 {
2819 if (!me || !me->IsEngaged() || !me->GetVictim())
2820 return;
2821
2822 if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
2824 else // make it predictable
2825 RecalcTimer(e, 500, 500);
2826 break;
2827 }
2829 {
2830 if (!me || !me->IsEngaged())
2831 return;
2832
2833 Unit* victim = me->GetVictim();
2834
2835 if (!victim || !victim->IsNonMeleeSpellCast(false, false, true))
2836 return;
2837
2838 if (e.event.targetCasting.spellId > 0)
2839 if (Spell* currSpell = victim->GetCurrentSpell(CURRENT_GENERIC_SPELL))
2840 if (currSpell->m_spellInfo->Id != e.event.targetCasting.spellId)
2841 return;
2842
2844 break;
2845 }
2847 {
2848 if (!me || !me->IsEngaged())
2849 return;
2850
2851 std::vector<Creature*> creatures;
2852 DoFindFriendlyCC(creatures, float(e.event.friendlyCC.radius));
2853 if (creatures.empty())
2854 {
2855 // if there are at least two same npcs, they will perform the same action immediately even if this is useless...
2856 RecalcTimer(e, 1000, 3000);
2857 return;
2858 }
2860 break;
2861 }
2863 {
2864 std::vector<Creature*> creatures;
2866
2867 if (creatures.empty())
2868 return;
2869
2871 break;
2872 }
2874 {
2875 if (!me)
2876 return;
2877 uint32 count = me->GetAuraCount(e.event.aura.spell);
2878 if ((!e.event.aura.count && !count) || (e.event.aura.count && count >= e.event.aura.count))
2880 break;
2881 }
2883 {
2884 if (!me || !me->GetVictim())
2885 return;
2887 if (count < e.event.aura.count)
2888 return;
2890 break;
2891 }
2893 {
2894 if (bvar == (e.event.charm.onRemove != 1))
2895 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
2896 break;
2897 }
2898 //no params
2899 case SMART_EVENT_AGGRO:
2900 case SMART_EVENT_DEATH:
2901 case SMART_EVENT_EVADE:
2913 case SMART_EVENT_RESET:
2918 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
2919 break;
2921 switch (e.event.gossipHello.filter)
2922 {
2923 case 0:
2924 // no filter set, always execute action
2925 break;
2926 case 1:
2927 // OnGossipHello only filter set, skip action if OnReportUse
2928 if (var0)
2929 return;
2930 break;
2931 case 2:
2932 // OnReportUse only filter set, skip action if OnGossipHello
2933 if (!var0)
2934 return;
2935 break;
2936 default:
2937 // Ignore any other value
2938 break;
2939 }
2940
2941 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
2942 break;
2944 if (e.event.emote.emote == var0)
2945 {
2946 RecalcTimer(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax);
2947 ProcessAction(e, unit);
2948 }
2949 break;
2950 case SMART_EVENT_KILL:
2951 {
2952 if (!me || !unit)
2953 return;
2954 if (e.event.kill.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
2955 return;
2956 if (e.event.kill.creature && unit->GetEntry() != e.event.kill.creature)
2957 return;
2959 ProcessAction(e, unit);
2960 break;
2961 }
2964 {
2965 if (!spell)
2966 return;
2967 if ((!e.event.spellHit.spell || spell->Id == e.event.spellHit.spell) &&
2968 (!e.event.spellHit.school || (spell->SchoolMask & e.event.spellHit.school)))
2969 {
2971 ProcessAction(e, unit, 0, 0, bvar, spell, gob);
2972 }
2973 break;
2974 }
2980 {
2981 if (!spell)
2982 return;
2983
2984 if (spell->Id != e.event.spellCast.spell)
2985 return;
2986
2988 ProcessAction(e, nullptr, 0, 0, bvar, spell);
2989 break;
2990 }
2992 {
2993 if (!me || me->IsEngaged())
2994 return;
2995 //can trigger if closer than fMaxAllowedRange
2996 float range = (float)e.event.los.maxDist;
2997
2998 //if range is ok and we are actually in LOS
2999 if (me->IsWithinDistInMap(unit, range) && me->IsWithinLOSInMap(unit))
3000 {
3002 //if friendly event&&who is not hostile OR hostile event&&who is hostile
3003 if ((hostilityMode == SmartEvent::LOSHostilityMode::Any) ||
3004 (hostilityMode == SmartEvent::LOSHostilityMode::NotHostile && !me->IsHostileTo(unit)) ||
3005 (hostilityMode == SmartEvent::LOSHostilityMode::Hostile && me->IsHostileTo(unit)))
3006 {
3007 if (e.event.los.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
3008 return;
3010 ProcessAction(e, unit);
3011 }
3012 }
3013 break;
3014 }
3015 case SMART_EVENT_IC_LOS:
3016 {
3017 if (!me || !me->IsEngaged())
3018 return;
3019 //can trigger if closer than fMaxAllowedRange
3020 float range = (float)e.event.los.maxDist;
3021
3022 //if range is ok and we are actually in LOS
3023 if (me->IsWithinDistInMap(unit, range) && me->IsWithinLOSInMap(unit))
3024 {
3026 //if friendly event&&who is not hostile OR hostile event&&who is hostile
3027 if ((hostilityMode == SmartEvent::LOSHostilityMode::Any) ||
3028 (hostilityMode == SmartEvent::LOSHostilityMode::NotHostile && !me->IsHostileTo(unit)) ||
3029 (hostilityMode == SmartEvent::LOSHostilityMode::Hostile && me->IsHostileTo(unit)))
3030 {
3031 if (e.event.los.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
3032 return;
3034 ProcessAction(e, unit);
3035 }
3036 }
3037 break;
3038 }
3040 {
3041 if (!GetBaseObject())
3042 return;
3044 return;
3046 return;
3047 ProcessAction(e);
3048 break;
3049 }
3052 {
3053 if (!IsCreature(unit))
3054 return;
3055 if (e.event.summoned.creature && unit->GetEntry() != e.event.summoned.creature)
3056 return;
3058 ProcessAction(e, unit);
3059 break;
3060 }
3064 {
3065 if (var0 > e.event.minMaxRepeat.max || var0 < e.event.minMaxRepeat.min)
3066 return;
3068 ProcessAction(e, unit);
3069 break;
3070 }
3072 {
3073 if ((e.event.movementInform.type && var0 != e.event.movementInform.type) || (e.event.movementInform.id && var1 != e.event.movementInform.id))
3074 return;
3075 ProcessAction(e, unit, var0, var1);
3076 break;
3077 }
3079 {
3081 return;
3082 ProcessAction(e, unit, var0);
3083 break;
3084 }
3090 {
3091 if (!me || (e.event.waypoint.pointID && var0 != e.event.waypoint.pointID) || (e.event.waypoint.pathID && var1 != e.event.waypoint.pathID))
3092 return;
3093 ProcessAction(e, unit);
3094 break;
3095 }
3097 {
3098 if (e.event.summoned.creature && e.event.summoned.creature != var0)
3099 return;
3101 ProcessAction(e, unit, var0);
3102 break;
3103 }
3105 {
3107 return;
3109 ProcessAction(e, unit, var0);
3110 break;
3111 }
3114 {
3115 if (e.event.quest.quest && var0 != e.event.quest.quest)
3116 return;
3117 RecalcTimer(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax);
3118 ProcessAction(e, unit, var0);
3119 break;
3120 }
3122 {
3124 return;
3125 ProcessAction(e, unit, var0);
3126 break;
3127 }
3129 {
3130 if (e.event.areatrigger.id && var0 != e.event.areatrigger.id)
3131 return;
3132 ProcessAction(e, unit, var0);
3133 break;
3134 }
3136 {
3138 return;
3139 ProcessAction(e, unit, var0);
3140 break;
3141 }
3143 {
3144 if (e.event.dataSet.id != var0 || e.event.dataSet.value != var1)
3145 return;
3147 ProcessAction(e, unit, var0, var1);
3148 break;
3149 }
3152 {
3153 if (!unit)
3154 return;
3156 ProcessAction(e, unit);
3157 break;
3158 }
3160 {
3161 if (e.event.timedEvent.id == var0)
3162 ProcessAction(e, unit);
3163 break;
3164 }
3166 {
3167 TC_LOG_DEBUG("scripts.ai", "SmartScript: Gossip Select: menu {} action {}", var0, var1);//little help for scripters
3168 if (e.event.gossip.sender != var0 || e.event.gossip.action != var1)
3169 return;
3170 ProcessAction(e, unit, var0, var1);
3171 break;
3172 }
3175 {
3176 if (e.event.gameEvent.gameEventId != var0)
3177 return;
3178 ProcessAction(e, nullptr, var0);
3179 break;
3180 }
3182 {
3183 if (e.event.goLootStateChanged.lootState != var0)
3184 return;
3185 ProcessAction(e, unit, var0, var1);
3186 break;
3187 }
3189 {
3190 if (e.event.eventInform.eventId != var0)
3191 return;
3192 ProcessAction(e, nullptr, var0);
3193 break;
3194 }
3196 {
3197 if (e.event.doAction.eventId != var0)
3198 return;
3199 ProcessAction(e, unit, var0);
3200 break;
3201 }
3203 {
3204 if (!me || !me->IsEngaged())
3205 return;
3206
3207 Unit* unitTarget = nullptr;
3208 switch (e.GetTargetType())
3209 {
3217 {
3218 ObjectVector targets;
3219 GetTargets(targets, e);
3220
3221 for (WorldObject* target : targets)
3222 {
3223 if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat())
3224 {
3225 uint32 healthPct = uint32(target->ToUnit()->GetHealthPct());
3226 if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct)
3227 continue;
3228
3229 unitTarget = target->ToUnit();
3230 break;
3231 }
3232 }
3233 break;
3234 }
3237 break;
3238 default:
3239 return;
3240 }
3241
3242 if (!unitTarget)
3243 return;
3244
3246 break;
3247 }
3249 {
3250 if (!me)
3251 return;
3252
3253 Creature* creature = nullptr;
3254
3255 if (e.event.distance.guid != 0)
3256 {
3257 creature = FindCreatureNear(me, e.event.distance.guid);
3258 if (!creature)
3259 return;
3260
3261 if (!me->IsInRange(creature, 0, static_cast<float>(e.event.distance.dist)))
3262 return;
3263 }
3264 else if (e.event.distance.entry != 0)
3265 {
3266 std::list<Creature*> list;
3267 me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, static_cast<float>(e.event.distance.dist));
3268
3269 if (!list.empty())
3270 creature = list.front();
3271 }
3272
3273 if (creature)
3275
3276 break;
3277 }
3279 {
3280 if (!me)
3281 return;
3282
3283 GameObject* gameobject = nullptr;
3284
3285 if (e.event.distance.guid != 0)
3286 {
3287 gameobject = FindGameObjectNear(me, e.event.distance.guid);
3288 if (!gameobject)
3289 return;
3290
3291 if (!me->IsInRange(gameobject, 0, static_cast<float>(e.event.distance.dist)))
3292 return;
3293 }
3294 else if (e.event.distance.entry != 0)
3295 {
3296 std::list<GameObject*> list;
3297 me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, static_cast<float>(e.event.distance.dist));
3298
3299 if (!list.empty())
3300 gameobject = list.front();
3301 }
3302
3303 if (gameobject)
3304 ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat, nullptr, 0, 0, false, nullptr, gameobject);
3305
3306 break;
3307 }
3309 if (e.event.counter.id != var0 || GetCounterValue(e.event.counter.id) != e.event.counter.value)
3310 return;
3311
3313 break;
3314 default:
3315 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type {}", e.GetEventType());
3316 break;
3317 }
3318}
3319
3321{
3322 switch (e.GetEventType())
3323 {
3324 //set only events which have initial timers
3325 case SMART_EVENT_UPDATE:
3329 break;
3333 break;
3334 default:
3335 e.active = true;
3336 break;
3337 }
3338}
3340{
3341 // min/max was checked at loading!
3342 e.timer = urand(min, max);
3343 e.active = e.timer ? false : true;
3344}
3345
3347{
3348 if (e.GetEventType() == SMART_EVENT_LINK)
3349 return;
3350
3352 return;
3353
3354 if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsEngaged()))
3355 return;
3356
3357 if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsEngaged())) //can be used with me=nullptr (go script)
3358 return;
3359
3360 if (e.timer < diff)
3361 {
3362 // delay spell cast event if another spell is being cast
3364 {
3366 {
3368 {
3369 RaisePriority(e);
3370 return;
3371 }
3372 }
3373 }
3374
3375 // Delay flee for assist event if stunned or rooted
3377 {
3379 {
3380 e.timer = 1;
3381 return;
3382 }
3383 }
3384
3385 e.active = true;//activate events with cooldown
3386
3387 switch (e.GetEventType())//process ONLY timed events
3388 {
3389 case SMART_EVENT_UPDATE:
3394 case SMART_EVENT_RANGE:
3403 {
3405 {
3406 Unit* invoker = nullptr;
3409 ProcessEvent(e, invoker);
3410 e.enableTimed = false;//disable event if it is in an ActionList and was processed once
3411 for (SmartScriptHolder& scriptholder : mTimedActionList)
3412 {
3413 //find the first event which is not the current one and enable it
3414 if (scriptholder.event_id > e.event_id)
3415 {
3416 scriptholder.enableTimed = true;
3417 break;
3418 }
3419 }
3420 }
3421 else
3422 ProcessEvent(e);
3423 break;
3424 }
3425 }
3426
3428 {
3429 // Reset priority to default one only if the event hasn't been rescheduled again to next loop
3430 if (e.timer > 1)
3431 {
3432 // Re-sort events if this was moved to the top of the queue
3433 mEventSortingRequired = true;
3434 // Reset priority to default one
3436 }
3437 }
3438 }
3439 else
3440 e.timer -= diff;
3441}
3442
3444{
3445 return e.active;
3446}
3447
3449{
3450 if (!mInstallEvents.empty())
3451 {
3452 for (SmartScriptHolder& installevent : mInstallEvents)
3453 mEvents.push_back(installevent);//must be before UpdateTimers
3454
3455 mInstallEvents.clear();
3456 }
3457}
3458
3460{
3461 if (!mStoredEvents.empty())
3462 {
3463 for (auto i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
3464 {
3465 if (i->event_id == id)
3466 {
3467 mStoredEvents.erase(i);
3468 return;
3469 }
3470 }
3471 }
3472}
3473
3475{
3476 WorldObject* obj = nullptr;
3477 if (me)
3478 obj = me;
3479 else if (go)
3480 obj = go;
3481 return obj;
3482}
3483
3488
3490{
3491 return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
3492}
3493
3495{
3496 return obj && obj->GetTypeId() == TYPEID_PLAYER;
3497}
3498
3500{
3501 return obj && obj->GetTypeId() == TYPEID_UNIT;
3502}
3503
3505{
3506 if (!obj)
3507 return false;
3508
3509 if (Creature* creatureObj = obj->ToCreature())
3510 return creatureObj->IsCharmed();
3511
3512 return false;
3513}
3514
3516{
3517 return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
3518}
3519
3521{
3523 return;
3524
3525 // Don't run any action while evading
3526 if (me && me->IsInEvadeMode())
3527 {
3528 // Check if the timed action list finished and clear it if so.
3529 // This is required by SMART_ACTION_CALL_TIMED_ACTIONLIST failing if mTimedActionList is not empty.
3530 if (!mTimedActionList.empty())
3531 {
3532 bool needCleanup = true;
3533 for (SmartScriptHolder& scriptholder : mTimedActionList)
3534 {
3535 if (scriptholder.enableTimed)
3536 needCleanup = false;
3537 }
3538
3539 if (needCleanup)
3540 mTimedActionList.clear();
3541 }
3542
3543 return;
3544 }
3545
3546 InstallEvents();//before UpdateTimers
3547
3549 {
3551 mEventSortingRequired = false;
3552 }
3553
3554 for (SmartScriptHolder& mEvent : mEvents)
3555 UpdateTimer(mEvent, diff);
3556
3557 if (!mStoredEvents.empty())
3558 {
3559 SmartAIEventStoredList::iterator i, icurr;
3560 for (i = mStoredEvents.begin(); i != mStoredEvents.end();)
3561 {
3562 icurr = i++;
3563 UpdateTimer(*icurr, diff);
3564 }
3565 }
3566
3567 bool needCleanup = true;
3568 if (!mTimedActionList.empty())
3569 {
3571 for (SmartScriptHolder& scriptholder : mTimedActionList)
3572 {
3573 if (scriptholder.enableTimed)
3574 {
3575 UpdateTimer(scriptholder, diff);
3576 needCleanup = false;
3577 }
3578 }
3579
3581 }
3582 if (needCleanup)
3583 mTimedActionList.clear();
3584
3585 if (!mRemIDs.empty())
3586 {
3587 for (auto i : mRemIDs)
3589
3590 mRemIDs.clear();
3591 }
3592
3593 if (mUseTextTimer && me)
3594 {
3595 if (mTextTimer < diff)
3596 {
3597 uint32 textID = mLastTextID;
3598 mLastTextID = 0;
3599 uint32 entry = mTalkerEntry;
3600 mTalkerEntry = 0;
3601 mTextTimer = 0;
3602 mUseTextTimer = false;
3603 ProcessEventsFor(SMART_EVENT_TEXT_OVER, nullptr, textID, entry);
3604 } else mTextTimer -= diff;
3605 }
3606}
3607
3609{
3610 std::sort(events.begin(), events.end());
3611}
3612
3614{
3615 e.timer = 1;
3616 // Change priority only if it's set to default, otherwise keep the current order of events
3618 {
3620 mEventSortingRequired = true;
3621 }
3622}
3623
3624void SmartScript::RetryLater(SmartScriptHolder& e, bool ignoreChanceRoll)
3625{
3626 RaisePriority(e);
3627
3628 // This allows to retry the action later without rolling again the chance roll (which might fail and end up not executing the action)
3629 if (ignoreChanceRoll)
3631
3632 e.runOnce = false;
3633}
3634
3636{
3637 if (e.empty())
3638 {
3639 if (obj)
3640 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Entry {} is empty but is using SmartScript.", obj->GetEntry());
3641 if (at)
3642 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for AreaTrigger {} is empty but is using SmartScript.", at->ID);
3643 return;
3644 }
3645 for (SmartScriptHolder& scriptholder : e)
3646 {
3647 #ifndef TRINITY_DEBUG
3648 if (scriptholder.event.event_flags & SMART_EVENT_FLAG_DEBUG_ONLY)
3649 continue;
3650 #endif
3651
3652 if (scriptholder.event.event_flags & SMART_EVENT_FLAG_DIFFICULTY_ALL)//if has instance flag add only if in it
3653 {
3654 if (!(obj && obj->GetMap()->IsDungeon()))
3655 continue;
3656
3657 if (!(1 << (obj->GetMap()->GetSpawnMode() + 1) & scriptholder.event.event_flags))
3658 continue;
3659 }
3660 mAllEventFlags |= scriptholder.event.event_flags;
3661 mEvents.push_back(scriptholder);//NOTE: 'world(0)' events still get processed in ANY instance mode
3662 }
3663}
3664
3666{
3668 if (me)
3669 {
3670 e = sSmartScriptMgr->GetScript(-((int32)me->GetSpawnId()), mScriptType);
3671 if (e.empty())
3672 e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType);
3673 FillScript(e, me, nullptr);
3674 }
3675 else if (go)
3676 {
3677 e = sSmartScriptMgr->GetScript(-((int32)go->GetSpawnId()), mScriptType);
3678 if (e.empty())
3679 e = sSmartScriptMgr->GetScript((int32)go->GetEntry(), mScriptType);
3680 FillScript(e, go, nullptr);
3681 }
3682 else if (trigger)
3683 {
3684 e = sSmartScriptMgr->GetScript((int32)trigger->ID, mScriptType);
3685 FillScript(e, nullptr, trigger);
3686 }
3687}
3688
3690{
3691 if (obj)//handle object based scripts
3692 {
3693 switch (obj->GetTypeId())
3694 {
3695 case TYPEID_UNIT:
3697 me = obj->ToCreature();
3698 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Creature {}", me->GetEntry());
3699 break;
3700 case TYPEID_GAMEOBJECT:
3702 go = obj->ToGameObject();
3703 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is GameObject {}", go->GetEntry());
3704 break;
3705 case TYPEID_PLAYER:
3706 if (at)
3707 {
3709 trigger = at;
3710 atPlayer = obj->ToPlayer();
3711 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is AreaTrigger {}, triggered by player {}", trigger->ID, atPlayer->GetGUID().ToString());
3712 }
3713 else
3714 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: !WARNING! Player TypeID is only allowed for AreaTriggers");
3715 break;
3716 default:
3717 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: Unhandled TypeID !WARNING!");
3718 return;
3719 }
3720 }
3721 else
3722 {
3723 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: !WARNING! Initialized objects are NULL.");
3724 return;
3725 }
3726
3727 GetScript();//load copy of script
3728
3729 for (SmartScriptHolder& event : mEvents)
3730 InitTimer(event);//calculate timers for first time use
3731
3733 InstallEvents();
3735 mCounterList.clear();
3736}
3737
3739{
3740 if (!me)
3741 return;
3742
3744}
3745// SmartScript end
3746
3748{
3749 if (!me)
3750 return nullptr;
3751
3752 Unit* unit = nullptr;
3753 Trinity::MostHPMissingInRange u_check(me, range, MinHPDiff);
3755 Cell::VisitGridObjects(me, searcher, range);
3756 return unit;
3757}
3758
3760{
3761 if (!me)
3762 return nullptr;
3763
3764 Unit* unit = nullptr;
3765 Trinity::MostHPPercentMissingInRange u_check(me, range, minHpPct, maxHpPct);
3767 Cell::VisitGridObjects(me, searcher, range);
3768 return unit;
3769}
3770
3771void SmartScript::DoFindFriendlyCC(std::vector<Creature*>& creatures, float range) const
3772{
3773 if (!me)
3774 return;
3775
3776 Trinity::FriendlyCCedInRange u_check(me, range);
3778 Cell::VisitGridObjects(me, searcher, range);
3779}
3780
3781void SmartScript::DoFindFriendlyMissingBuff(std::vector<Creature*>& creatures, float range, uint32 spellid) const
3782{
3783 if (!me)
3784 return;
3785
3786 Trinity::FriendlyMissingBuffInRange u_check(me, range, spellid);
3788 Cell::VisitGridObjects(me, searcher, range);
3789}
3790
3791Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) const
3792{
3793 if (!me)
3794 return nullptr;
3795
3796 Unit* unit = nullptr;
3797 Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range, playerOnly);
3799 Cell::VisitAllObjects(me, searcher, range);
3800 return unit;
3801}
3802
3804{
3805 //do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete
3806 // any SmartScriptHolder contained like the "e" parameter passed to this function
3808 {
3809 TC_LOG_ERROR("scripts.ai", "Entry {} SourceType {} Event {} Action {} is trying to overwrite timed action list from a timed action, this is not allowed!.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
3810 return;
3811 }
3812
3813 // Do NOT allow to start a new actionlist if a previous one is already running, unless explicitly allowed. We need to always finish the current actionlist
3815 return;
3816
3817 mTimedActionList.clear();
3819 if (mTimedActionList.empty())
3820 return;
3821 mTimedActionListInvoker = invoker ? invoker->GetGUID() : ObjectGuid::Empty;
3822 for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i)
3823 {
3824 i->enableTimed = i == mTimedActionList.begin();//enable processing only for the first action
3825
3826 if (e.action.timedActionList.timerType == 0)
3827 i->event.type = SMART_EVENT_UPDATE_OOC;
3828 else if (e.action.timedActionList.timerType == 1)
3829 i->event.type = SMART_EVENT_UPDATE_IC;
3830 else if (e.action.timedActionList.timerType > 1)
3831 i->event.type = SMART_EVENT_UPDATE;
3832
3833 InitTimer((*i));
3834 }
3835}
3836
3838{
3839 // Look for invoker only on map of base object... Prevents multithreaded crashes
3840 if (WorldObject* baseObject = GetBaseObject())
3841 return ObjectAccessor::GetUnit(*baseObject, mLastInvoker);
3842 // used for area triggers invoker cast
3843 else if (invoker)
3844 return ObjectAccessor::GetUnit(*invoker, mLastInvoker);
3845
3846 return nullptr;
3847}
3848
3850{
3851 // protect phase from overflowing
3852 SetPhase(std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p));
3853}
3854
3856{
3857 if (p >= mEventPhase)
3858 SetPhase(0);
3859 else
3860 SetPhase(mEventPhase - p);
3861}
3862
3864{
3865 mEventPhase = p;
3866}
3867
3869{
3870 if (mEventPhase == 0)
3871 return false;
3872 return ((1 << (mEventPhase - 1)) & p) != 0;
3873}
#define M_PI
Definition Common.h:72
#define sConditionMgr
#define sCreatureTextMgr
@ TEXT_RANGE_NORMAL
uint8_t uint8
Definition Define.h:135
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
uint16 flags
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
std::string GetDebugInfo()
Definition Errors.cpp:155
#define sGameEventMgr
GameObjectActions
LootState
Definition GameObject.h:75
@ GO_READY
Definition GameObject.h:77
EncounterState
@ BROADCAST_TEXT_CALL_FOR_HELP
Definition Language.h:24
@ BROADCAST_TEXT_FLEE_FOR_ASSIST
Definition Language.h:25
#define TC_LOG_WARN(filterType__,...)
Definition Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
TempSummonType
GOSummonType
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:40
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
#define sObjectMgr
Definition ObjectMgr.h:1721
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
bool roll_chance_i(int chance)
Definition Random.h:59
@ LANG_ADDON
@ TEAM_OTHER
Powers
@ POWER_MANA
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_ADDON
SpellCastResult
@ SPELL_CAST_OK
@ SPELL_FAILED_SPELL_IN_PROGRESS
GOState
@ SMART_SCRIPT_TYPE_TIMED_ACTIONLIST
@ SMART_SCRIPT_TYPE_CREATURE
@ SMART_SCRIPT_TYPE_GAMEOBJECT
@ SMART_SCRIPT_TYPE_AREATRIGGER
std::vector< SmartScriptHolder > SmartAIEventList
@ SMART_EVENT_FLAG_WHILE_CHARMED
@ SMART_EVENT_FLAG_DIFFICULTY_ALL
@ SMART_EVENT_FLAG_DONT_RESET
@ SMART_EVENT_FLAG_DEBUG_ONLY
@ SMART_EVENT_FLAG_TEMP_IGNORE_CHANCE_ROLL
@ SMART_EVENT_FLAG_NOT_REPEATABLE
SMARTAI_TARGETS
@ SMART_TARGET_LOOT_RECIPIENTS
@ SMART_TARGET_CLOSEST_CREATURE
@ SMART_TARGET_CREATURE_DISTANCE
@ SMART_TARGET_HOSTILE_RANDOM_NOT_TOP
@ SMART_TARGET_INVOKER_PARTY
@ SMART_TARGET_CLOSEST_FRIENDLY
@ SMART_TARGET_CLOSEST_GAMEOBJECT
@ SMART_TARGET_VEHICLE_PASSENGER
@ SMART_TARGET_GAMEOBJECT_RANGE
@ SMART_TARGET_CREATURE_GUID
@ SMART_TARGET_PLAYER_RANGE
@ SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT
@ SMART_TARGET_VICTIM
@ SMART_TARGET_GAMEOBJECT_DISTANCE
@ SMART_TARGET_CREATURE_RANGE
@ SMART_TARGET_CLOSEST_PLAYER
@ SMART_TARGET_HOSTILE_RANDOM
@ SMART_TARGET_GAMEOBJECT_GUID
@ SMART_TARGET_HOSTILE_SECOND_AGGRO
@ SMART_TARGET_OWNER_OR_SUMMONER
@ SMART_TARGET_SELF
@ SMART_TARGET_ACTION_INVOKER
@ SMART_TARGET_POSITION
@ SMART_TARGET_HOSTILE_LAST_AGGRO
@ SMART_TARGET_ACTION_INVOKER_VEHICLE
@ SMART_TARGET_FARTHEST
@ SMART_TARGET_THREAT_LIST
@ SMART_TARGET_CLOSEST_ENEMY
@ SMART_TARGET_NONE
@ SMART_TARGET_PLAYER_DISTANCE
@ SMART_TARGET_STORED
std::vector< WorldObject * > ObjectVector
@ SMART_SCRIPT_RESPAWN_CONDITION_AREA
@ SMART_SCRIPT_RESPAWN_CONDITION_MAP
#define sSmartScriptMgr
SMART_ACTION
@ SMART_ACTION_REMOVE_TIMED_EVENT
@ SMART_ACTION_NONE
@ SMART_ACTION_WP_RESUME
@ SMART_ACTION_UPDATE_TEMPLATE
@ SMART_ACTION_STORE_TARGET_LIST
@ SMART_ACTION_SET_HEALTH_REGEN
@ SMART_ACTION_ACTIVATE_GOBJECT
@ SMART_ACTION_FORCE_DESPAWN
@ SMART_ACTION_GAME_EVENT_START
@ SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST
@ SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1
@ SMART_ACTION_SET_DISABLE_GRAVITY
@ SMART_ACTION_SET_INST_DATA64
@ SMART_ACTION_SET_FACTION
@ SMART_ACTION_THREAT_SINGLE_PCT
@ SMART_ACTION_OFFER_QUEST
@ SMART_ACTION_OVERRIDE_LIGHT
@ SMART_ACTION_SET_INGAME_PHASE_MASK
@ SMART_ACTION_SET_UNIT_FIELD_BYTES_1
@ SMART_ACTION_CLOSE_GOSSIP
@ SMART_ACTION_DISABLE_EVADE
@ SMART_ACTION_KILL_UNIT
@ SMART_ACTION_LOAD_EQUIPMENT
@ SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS
@ SMART_ACTION_ATTACK_START
@ SMART_ACTION_CALL_GROUPEVENTHAPPENS
@ SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL
@ SMART_ACTION_INVOKER_CAST
@ SMART_ACTION_JUMP_TO_POS
@ SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST
@ SMART_ACTION_SEND_GOSSIP_MENU
@ SMART_ACTION_SET_COUNTER
@ SMART_ACTION_FLEE_FOR_ASSIST
@ SMART_ACTION_EQUIP
@ SMART_ACTION_SET_ROOT
@ SMART_ACTION_ATTACK_STOP
@ SMART_ACTION_SUMMON_GO
@ SMART_ACTION_SET_HOVER
@ SMART_ACTION_WP_PAUSE
@ SMART_ACTION_SIMPLE_TALK
@ SMART_ACTION_CAST
@ SMART_ACTION_SPAWN_SPAWNGROUP
@ SMART_ACTION_ALLOW_COMBAT_MOVEMENT
@ SMART_ACTION_THREAT_ALL_PCT
@ SMART_ACTION_SOUND
@ SMART_ACTION_SET_MOVEMENT_SPEED
@ SMART_ACTION_PLAY_CINEMATIC
@ SMART_ACTION_ADD_NPC_FLAG
@ SMART_ACTION_EVADE
@ SMART_ACTION_FAIL_QUEST
@ SMART_ACTION_INTERRUPT_SPELL
@ SMART_ACTION_ADD_POWER
@ SMART_ACTION_RANDOM_SOUND
@ SMART_ACTION_SET_IMMUNE_PC
@ SMART_ACTION_SET_POWER
@ SMART_ACTION_SEND_TARGET_TO_TARGET
@ SMART_ACTION_REMOVE_POWER
@ SMART_ACTION_RESUME_MOVEMENT
@ SMART_ACTION_GO_SET_GO_STATE
@ SMART_ACTION_MOVE_OFFSET
@ SMART_ACTION_REMOVE_ITEM
@ SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL
@ SMART_ACTION_RANDOM_PHASE
@ SMART_ACTION_SET_EMOTE_STATE
@ SMART_ACTION_CROSS_CAST
@ SMART_ACTION_WP_STOP
@ SMART_ACTION_GAME_EVENT_STOP
@ SMART_ACTION_CALL_KILLEDMONSTER
@ SMART_ACTION_TALK
@ SMART_ACTION_CALL_SCRIPT_RESET
@ SMART_ACTION_SET_DATA
@ SMART_ACTION_WP_START
@ SMART_ACTION_COMBAT_STOP
@ SMART_ACTION_SET_RUN
@ SMART_ACTION_ACTIVATE_GAMEOBJECT
@ SMART_ACTION_ADD_TO_STORED_TARGET_LIST
@ SMART_ACTION_SET_HEALTH_PCT
@ SMART_ACTION_AUTO_ATTACK
@ SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL
@ SMART_ACTION_SET_VISIBILITY
@ SMART_ACTION_RANDOM_PHASE_RANGE
@ SMART_ACTION_GO_SET_LOOT_STATE
@ SMART_ACTION_SELF_CAST
@ SMART_ACTION_SET_INST_DATA
@ SMART_ACTION_CALL_FOR_HELP
@ SMART_ACTION_SET_UNINTERACTIBLE
@ SMART_ACTION_OVERRIDE_WEATHER
@ SMART_ACTION_ADD_THREAT
@ SMART_ACTION_TELEPORT
@ SMART_ACTION_PLAYMOVIE
@ SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT
@ SMART_ACTION_FOLLOW
@ SMART_ACTION_PLAY_EMOTE
@ SMART_ACTION_SET_EVENT_PHASE
@ SMART_ACTION_DESPAWN_SPAWNGROUP
@ SMART_ACTION_SET_CORPSE_DELAY
@ SMART_ACTION_SET_SHEATH
@ SMART_ACTION_SET_ORIENTATION
@ SMART_ACTION_RESPAWN_BY_SPAWNID
@ SMART_ACTION_SET_NPC_FLAG
@ SMART_ACTION_MOVE_TO_POS
@ SMART_ACTION_RANDOM_EMOTE
@ SMART_ACTION_INC_EVENT_PHASE
@ SMART_ACTION_ENABLE_TEMP_GOBJ
@ SMART_ACTION_CREATE_TIMED_EVENT
@ SMART_ACTION_DIE
@ SMART_ACTION_REMOVE_NPC_FLAG
@ SMART_ACTION_SUMMON_CREATURE
@ SMART_ACTION_RESET_GOBJECT
@ SMART_ACTION_CALL_TIMED_ACTIONLIST
@ SMART_ACTION_SET_IN_COMBAT_WITH_ZONE
@ SMART_ACTION_SET_HOME_POS
@ SMART_ACTION_ADD_ITEM
@ SMART_ACTION_SET_ACTIVE
@ SMART_ACTION_SET_RANGED_MOVEMENT
@ SMART_ACTION_ACTIVATE_TAXI
@ SMART_ACTION_START_CLOSEST_WAYPOINT
@ SMART_ACTION_SUMMON_CREATURE_GROUP
@ SMART_ACTION_SET_REACT_STATE
@ SMART_ACTION_RANDOM_MOVE
@ SMART_ACTION_SET_IMMUNE_NPC
@ SMART_ACTION_TRIGGER_TIMED_EVENT
@ SMART_ACTION_REMOVEAURASFROMSPELL
@ SMART_ACTION_PAUSE_MOVEMENT
SMART_EVENT
@ SMART_EVENT_IC_LOS
@ SMART_EVENT_EVADE
@ SMART_EVENT_ACTION_DONE
@ SMART_EVENT_SUMMON_DESPAWNED
@ SMART_EVENT_SPELLHIT
@ SMART_EVENT_RECEIVE_EMOTE
@ SMART_EVENT_FRIENDLY_HEALTH_PCT
@ SMART_EVENT_QUEST_FAIL
@ SMART_EVENT_ON_AURA_APPLIED
@ SMART_EVENT_DATA_SET
@ SMART_EVENT_RECEIVE_HEAL
@ SMART_EVENT_TIMED_EVENT_TRIGGERED
@ SMART_EVENT_QUEST_COMPLETION
@ SMART_EVENT_JUST_CREATED
@ SMART_EVENT_HEALTH_PCT
@ SMART_EVENT_AREATRIGGER_ONTRIGGER
@ SMART_EVENT_DISTANCE_GAMEOBJECT
@ SMART_EVENT_ON_SPELLCLICK
@ SMART_EVENT_MOVEMENTINFORM
@ SMART_EVENT_RANGE
@ SMART_EVENT_MANA_PCT
@ SMART_EVENT_PASSENGER_REMOVED
@ SMART_EVENT_ON_AURA_REMOVED
@ SMART_EVENT_INSTANCE_PLAYER_ENTER
@ SMART_EVENT_LINK
@ SMART_EVENT_WAYPOINT_PAUSED
@ SMART_EVENT_REACHED_HOME
@ SMART_EVENT_TRANSPORT_ADDCREATURE
@ SMART_EVENT_REWARD_QUEST
@ SMART_EVENT_GO_EVENT_INFORM
@ SMART_EVENT_GO_LOOT_STATE_CHANGED
@ SMART_EVENT_UPDATE_IC
@ SMART_EVENT_RESET
@ SMART_EVENT_JUST_SUMMONED
@ SMART_EVENT_CHARMED
@ SMART_EVENT_AI_INIT
@ SMART_EVENT_ON_SPELL_CAST
@ SMART_EVENT_SPELLHIT_TARGET
@ SMART_EVENT_GAME_EVENT_START
@ SMART_EVENT_KILL
@ SMART_EVENT_TRANSPORT_REMOVE_PLAYER
@ SMART_EVENT_GOSSIP_HELLO
@ SMART_EVENT_GOSSIP_SELECT
@ SMART_EVENT_CORPSE_REMOVED
@ SMART_EVENT_PASSENGER_BOARDED
@ SMART_EVENT_UPDATE
@ SMART_EVENT_TRANSPORT_ADDPLAYER
@ SMART_EVENT_WAYPOINT_ENDED
@ SMART_EVENT_UPDATE_OOC
@ SMART_EVENT_ACCEPTED_QUEST
@ SMART_EVENT_COUNTER_SET
@ SMART_EVENT_FRIENDLY_MISSING_BUFF
@ SMART_EVENT_WAYPOINT_RESUMED
@ SMART_EVENT_ON_SPELL_FAILED
@ SMART_EVENT_WAYPOINT_REACHED
@ SMART_EVENT_TARGET_BUFFED
@ SMART_EVENT_RESPAWN
@ SMART_EVENT_QUEST_ACCEPTED
@ SMART_EVENT_QUEST_REWARDED
@ SMART_EVENT_TEXT_OVER
@ SMART_EVENT_DEATH
@ SMART_EVENT_TRANSPORT_RELOCATE
@ SMART_EVENT_GAME_EVENT_END
@ SMART_EVENT_DAMAGED
@ SMART_EVENT_FOLLOW_COMPLETED
@ SMART_EVENT_QUEST_OBJ_COMPLETION
@ SMART_EVENT_DISTANCE_CREATURE
@ SMART_EVENT_WAYPOINT_STOPPED
@ SMART_EVENT_SUMMONED_UNIT_DIES
@ SMART_EVENT_FRIENDLY_IS_CC
@ SMART_EVENT_OOC_LOS
@ SMART_EVENT_ON_SPELL_START
@ SMART_EVENT_ON_DESPAWN
@ SMART_EVENT_AGGRO
@ SMART_EVENT_VICTIM_CASTING
@ SMART_EVENT_DAMAGED_TARGET
@ SMART_EVENT_HAS_AURA
@ SMART_EVENT_SUMMONED_UNIT
SmartActionSummonCreatureFlags
@ SMART_RANDOM_POINT
@ SMART_ESCORT_TARGETS
@ SMARTAI_SPAWN_FLAG_FORCE_SPAWN
@ SMARTAI_SPAWN_FLAG_NOSAVE_RESPAWN
@ SMARTAI_SPAWN_FLAG_IGNORE_RESPAWN
@ SMARTCAST_TRIGGERED
@ SMARTCAST_COMBAT_MOVE
@ SMARTCAST_INTERRUPT_PREVIOUS
@ SMARTCAST_AURA_NOT_PRESENT
@ SMART_EVENT_PHASE_12
SpawnObjectType
Definition SpawnData.h:30
@ AURA_REMOVE_BY_EXPIRE
TriggerCastFlags
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_NONE
#define CAST_AI(a, b)
Definition UnitAI.h:27
#define ENSURE_AI(a, b)
Definition UnitAI.h:28
ReactStates
UnitStandStateType
Definition UnitDefines.h:33
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ MOVEMENTFLAG_ONTRANSPORT
NPCFlags
Non Player Character flags.
SheathState
Definition UnitDefines.h:97
#define MAX_EQUIPMENT_ITEMS
Definition UnitDefines.h:29
AnimTier
Definition UnitDefines.h:85
UnitVisFlags
Definition UnitDefines.h:50
UnitMoveType
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_FLAG_IMMUNE_TO_PC
@ CURRENT_GENERIC_SPELL
Definition Unit.h:607
@ UNIT_STATE_LOST_CONTROL
Definition Unit.h:261
@ UNIT_STATE_ROOT
Definition Unit.h:230
@ UNIT_STATE_CASTING
Definition Unit.h:235
#define sWaypointMgr
void DoZoneInCombat(Creature *creature=nullptr)
virtual void EnterEvadeMode(EvadeReason why=EVADE_REASON_OTHER)
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:293
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr, float *dist=nullptr) const
void CallForHelp(float fRadius)
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:295
void GetTransportHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:300
bool IsEngaged() const override
void DoFleeToGetAssistance()
Definition Creature.cpp:973
Player * GetLootRecipient() const
ObjectGuid::LowType GetSpawnId() const
Definition Creature.h:83
Group * GetLootRecipientGroup() const
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
bool IsInEvadeMode() const
Definition Creature.h:146
CreatureAI * AI() const
Definition Creature.h:154
virtual void SetData(uint32, uint32)
ObjectGuid GetOwnerGUID() const override
Definition GameObject.h:141
GameObjectAI * AI() const
Definition GameObject.h:275
ObjectGuid::LowType GetSpawnId() const
Definition GameObject.h:112
GroupReference * next()
Definition Group.h:165
virtual bool SetBossState(uint32 id, EncounterState state)
static char const * GetBossStateName(uint8 state)
Definition Map.h:281
bool IsDungeon() const
Definition Map.cpp:4236
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition Map.cpp:3382
uint8 GetSpawnMode() const
Definition Map.h:388
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition Map.h:496
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes=false, size_t *count=nullptr)
Definition Map.cpp:3458
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
Definition Map.h:492
void Respawn(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:3105
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={})
void MoveRandom(float wanderDistance=0.0f)
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
std::string ToString() const
uint32 LowType
Definition ObjectGuid.h:142
void Clear()
Definition ObjectGuid.h:150
static uint32 ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=nullptr)
static Creature * ToCreature(Object *o)
Definition Object.h:186
static Unit * ToUnit(Object *o)
Definition Object.h:192
static GameObject * ToGameObject(Object *o)
Definition Object.h:198
TypeID GetTypeId() const
Definition Object.h:93
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
void SendQuestGiverQuestDetails(Quest const *quest, ObjectGuid npcGUID, bool activateAccept) const
void GroupEventHappens(uint32 questId, WorldObject const *pEventObject)
Definition Player.cpp:16032
static SmartScriptHolder & FindLinkedEvent(SmartAIEventList &list, uint32 link)
void SetInvincibilityHpLevel(uint32 level)
Definition SmartAI.h:206
bool CheckTimer(SmartScriptHolder const &e) const
uint32 mEventPhase
static constexpr uint32 MAX_NESTED_EVENTS
void DoFindFriendlyMissingBuff(std::vector< Creature * > &creatures, float range, uint32 spellid) const
Creature * me
uint32 mPathId
ObjectGuid mLastInvoker
Definition SmartScript.h:92
void OnUpdate(const uint32 diff)
void IncPhase(uint32 p)
void ProcessEventsFor(SMART_EVENT e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
void DoFindFriendlyCC(std::vector< Creature * > &creatures, float range) const
SmartScriptType mScriptType
void ProcessAction(SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
void InstallEvents()
void UpdateTimer(SmartScriptHolder &e, uint32 const diff)
CounterMap mCounterList
Definition SmartScript.h:94
bool mUseTextTimer
void SortEvents(SmartAIEventList &events)
uint32 mLastTextID
static void RecalcTimer(SmartScriptHolder &e, uint32 min, uint32 max)
void ProcessEvent(SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
uint32 GetCounterValue(uint32 id) const
static bool IsCharmedCreature(WorldObject *obj)
void StoreTargetList(ObjectVector const &targets, uint32 id)
static bool IsUnit(WorldObject *obj)
void AddToStoredTargetList(ObjectVector const &targets, uint32 id)
uint32 mTextTimer
void RetryLater(SmartScriptHolder &e, bool ignoreChanceRoll=false)
SmartAIEventStoredList mStoredEvents
void SetPhase(uint32 p)
void RaisePriority(SmartScriptHolder &e)
static bool IsPlayer(WorldObject *obj)
Unit * GetLastInvoker(Unit *invoker=nullptr) const
static bool IsCreature(WorldObject *obj)
void FillScript(SmartAIEventList e, WorldObject *obj, AreaTriggerEntry const *at)
Player * atPlayer
void OnMoveInLineOfSight(Unit *who)
bool IsSmart(Creature *c, bool silent=false) const
WorldObject * GetBaseObjectOrPlayerTrigger() const
Unit * DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) const
GameObject * go
bool IsInPhase(uint32 p) const
SmartAIEventList mInstallEvents
static void InitTimer(SmartScriptHolder &e)
AreaTriggerEntry const * trigger
Unit * DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const
uint32 mAllEventFlags
static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
void OnInitialize(WorldObject *obj, AreaTriggerEntry const *at=nullptr)
void StoreCounter(uint32 id, uint32 value, uint32 reset)
uint32 mCurrentPriority
WorldObject * GetBaseObject() const
void GetWorldObjectsInDist(ObjectVector &objects, float dist) const
uint32 mNestedEventsCounter
Creature * FindCreatureNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
uint32 mTalkerEntry
static bool IsGameObject(WorldObject *obj)
void ProcessTimedAction(SmartScriptHolder &e, uint32 const &min, uint32 const &max, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
void GetTargets(ObjectVector &targets, SmartScriptHolder const &e, WorldObject *invoker=nullptr) const
SmartAIEventList mEvents
bool isProcessingTimedActionList
ObjectVector const * GetStoredTargetVector(uint32 id, WorldObject const &ref) const
Unit * DoFindClosestFriendlyInRange(float range, bool playerOnly) const
ObjectGuid goOrigGUID
SmartAIEventList mTimedActionList
void DecPhase(uint32 p)
ObjectGuid meOrigGUID
ObjectVectorMap _storedTargets
void SetTimedActionList(SmartScriptHolder &e, uint32 entry, Unit *invoker)
bool mEventSortingRequired
ObjectGuid mTimedActionListInvoker
void RemoveStoredEvent(uint32 id)
std::vector< uint32 > mRemIDs
GameObject * FindGameObjectNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
void ResetBaseObject()
uint32 Id
Definition SpellInfo.h:289
uint32 SchoolMask
Definition SpellInfo.h:361
Definition Spell.h:152
void ModifyThreatByPercent(Unit *target, int32 percent)
Trinity::IteratorPair< ThreatListIterator, std::nullptr_t > GetUnsortedThreatList() const
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
std::vector< ThreatReference * > GetModifiableThreatList()
virtual void SetData(uint32, uint32)
Definition UnitAI.h:156
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:96
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:30
Definition Unit.h:769
bool IsVehicle() const
Definition Unit.h:887
Vehicle * GetVehicle() const
Definition Unit.h:1737
float GetHealthPct() const
Definition Unit.h:921
void KillSelf(bool durabilityLoss=true)
Definition Unit.h:1023
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1122
ThreatManager & GetThreatManager()
Definition Unit.h:1155
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:603
ObjectGuid GetCreatorGUID() const
Definition Unit.h:1243
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3063
uint32 GetMaxHealth() const
Definition Unit.h:914
TempSummon * ToTempSummon()
Definition Unit.h:1794
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1260
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
Gender GetGender() const
Definition Unit.h:898
Unit * EnsureVictim() const
Definition Unit.h:861
virtual void SetSheath(SheathState sheathed)
Definition Unit.h:970
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13259
bool IsAIEnabled() const
Definition Unit.h:798
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4519
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1678
uint32 GetMaxPower(Powers power) const
Definition Unit.h:936
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition Unit.cpp:11866
Unit * GetVictim() const
Definition Unit.h:859
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11856
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
float GetPowerPct(Powers power) const
Definition Unit.h:937
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13250
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5691
Vehicle * GetVehicleKit() const
Definition Unit.h:1735
bool isDead() const
Definition Unit.h:1236
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1476
Unit * GetBase() const
May be called from scripts.
Definition Vehicle.h:45
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition Vehicle.h:63
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:2121
Map * GetMap() const
Definition Object.h:449
Player * SelectNearestPlayer(float distance) const
Definition Object.cpp:2161
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:3153
ObjectGuid GetPrivateObjectOwner() const
Definition Object.h:595
void GetGameObjectListWithEntryInGrid(Container &gameObjectContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:3133
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
bool IsHostileTo(WorldObject const *target) const
Definition Object.cpp:2796
virtual ObjectGuid GetCharmerOrOwnerGUID() const
Definition Object.h:473
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1992
bool IsPrivateObject() const
Definition Object.h:594
GameObject * SummonGameObject(uint32 entry, Position const &pos, QuaternionData const &rot, Seconds respawnTime, GOSummonType summonType=GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)
Definition Object.cpp:2015
std::string const & GetName() const
Definition Object.h:382
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1226
void GetContactPoint(WorldObject const *obj, float &x, float &y, float &z, float distance2d=CONTACT_DISTANCE) const
Definition Object.cpp:3271
GameObject * FindNearestUnspawnedGameObject(uint32 entry, float range) const
Definition Object.cpp:2143
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:2099
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:2203
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition Object.cpp:1283
void SummonCreatureGroup(uint8 group, std::list< TempSummon * > *list=nullptr)
Definition Object.cpp:2082
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2801
Player session in the World.
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:56
virtual void SetGuidData(uint32, ObjectGuid)
Definition ZoneScript.h:49
WeatherState
Definition Weather.h:47
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition Containers.h:108
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:66
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:192
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:168
uint32 ItemEntry[MAX_EQUIPMENT_ITEMS]
float m_positionZ
Definition Position.h:58
Position GetPositionWithOffset(Position const &offset) const
Definition Position.cpp:60
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
struct SmartAction::@65::@144 loadEquipment
struct SmartAction::@65::@97 invincHP
struct SmartAction::@65::@161 raw
uint32 sounds[4]
uint32 targetParam2
struct SmartAction::@65::@83 combatMove
struct SmartAction::@65::@102 summonGO
struct SmartAction::@65::@70 morphOrMount
struct SmartAction::@65::@146 pauseMovement
uint32 targetsLimit
struct SmartAction::@65::@139 closestWaypointFromList
struct SmartAction::@65::@69 faction
struct SmartAction::@65::@130 sendTargetToTarget
uint32 gameObjectAction
struct SmartAction::@65::@129 setGoLootState
struct SmartAction::@65::@85 incEventPhase
SAIBool regenHealth
struct SmartAction::@65::@106 wpPause
uint32 wps[SMART_ACTION_PARAM_COUNT]
SAIBool allowOverride
struct SmartAction::@65::@111 teleport
struct SmartAction::@65::@99 setData
struct SmartAction::@65::@137 gameEventStop
struct SmartAction::@65::@157 setUninteractible
uint32 triggerFlags
struct SmartAction::@65::@134 goState
struct SmartAction::@65::@155 setImmunePC
uint32 emotes[SMART_ACTION_PARAM_COUNT]
SAIBool withDelayed
SAIBool withInstant
uint32 transitionMilliseconds
struct SmartAction::@65::@92 setInstanceData64
struct SmartAction::@65::@127 moveToPos
struct SmartAction::@65::@152 setHover
struct SmartAction::@65::@118 setunitByte
struct SmartAction::@65::@126 enableTempGO
struct SmartAction::@65::@128 sendGossipMenu
struct SmartAction::@65::@141 corpseDelay
struct SmartAction::@65::@121 randTimedActionList
struct SmartAction::@65::@108 item
struct SmartAction::@65::@140 randomSound
uint32 targetParam1
struct SmartAction::@65::@78 crossCast
struct SmartAction::@65::@138 gameEventStart
uint32 includeDecayRatio
struct SmartAction::@65::@74 questOffer
SAIBool toRespawnPosition
SAIBool attackInvoker
SAIBool useTalkTarget
struct SmartAction::@65::@110 setDisableGravity
struct SmartAction::@65::@160 resumeMovement
SAIBool uninteractible
struct SmartAction::@65::@153 evade
uint32 targetParam3
struct SmartAction::@65::@89 randomPhaseRange
struct SmartAction::@65::@120 timedActionList
struct SmartAction::@65::@115 movie
struct SmartAction::@65::@158 activateGameObject
struct SmartAction::@65::@81 threat
struct SmartAction::@65::@67 talk
struct SmartAction::@65::@114 timeEvent
struct SmartAction::@65::@151 overrideWeather
struct SmartAction::@65::@147 respawnData
struct SmartAction::@65::@100 moveRandom
SAIBool updateLevel
struct SmartAction::@65::@131 setRangedMovement
uint32 actionLists[SMART_ACTION_PARAM_COUNT]
SMART_ACTION type
struct SmartAction::@65::@150 overrideLight
uint32 forceRespawnTimer
struct SmartAction::@65::@156 setImmuneNPC
struct SmartAction::@65::@125 fleeAssist
struct SmartAction::@65::@148 cinematic
uint32 phases[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@65::@104 taxi
struct SmartAction::@65::@154 setHealthPct
struct SmartAction::@65::@132 setHealthRegen
struct SmartAction::@65::@75 react
struct SmartAction::@65::@123 interruptSpellCasting
SAIBool onlyOwnedAuras
uint32 overrideLightId
struct SmartAction::@65::@88 randomPhase
struct SmartAction::@65::@93 updateTemplate
struct SmartAction::@65::@96 forceDespawn
struct SmartAction::@65::@124 jump
struct SmartAction::@65::@136 power
uint32 gossipNpcTextId
struct SmartAction::@65::@86 removeAura
SAIBool disablePathfinding
struct SmartAction::@65::@98 ingamePhaseMask
struct SmartAction::@65::@91 setInstanceData
struct SmartAction::@65::@77 cast
uint32 ContactDistance
struct SmartAction::@65::@68 simpleTalk
struct SmartAction::@65::@133 setRoot
SAIBool withEmote
struct SmartAction::@65::@109 setRun
struct SmartAction::@65::@142 disableEvade
struct SmartAction::@65::@113 storeTargets
struct SmartAction::@65::@76 randomEmote
struct SmartAction::@65::@82 autoAttack
struct SmartAction::@65::@87 follow
SAIBool directAdd
struct SmartAction::@65::@94 callHelp
struct SmartAction::@65::@105 wpStart
struct SmartAction::@65::@101 visibility
struct SmartAction::@65::@116 equip
struct SmartAction::@65::@79 summonCreature
struct SmartAction::@65::@107 wpStop
struct SmartAction::@65::@149 movementSpeed
struct SmartAction::@65::@159 addToStoredTargets
struct SmartAction::@65::@143 groupSpawn
struct SmartAction::@65::@80 threatPCT
struct SmartAction::@65::@103 active
struct SmartAction::@65::@84 setEventPhase
struct SmartAction::@65::@145 randomTimedEvent
struct SmartAction::@65::@112 setCounter
struct SmartAction::@65::@122 randRangeTimedActionList
struct SmartAction::@65::@95 setSheath
struct SmartAction::@65::@90 killedMonster
struct SmartAction::@65::@135 creatureGroup
uint32 event_flags
struct SmartEvent::@29::@62 counter
struct SmartEvent::@29::@36 minMax
struct SmartEvent::@29::@56 gameEvent
struct SmartEvent::@29::@50 instancePlayerEnter
struct SmartEvent::@29::@45 movementInform
uint32 event_phase_mask
struct SmartEvent::@29::@44 charm
struct SmartEvent::@29::@52 textOver
struct SmartEvent::@29::@32 kill
uint32 cooldownMax
struct SmartEvent::@29::@40 summoned
struct SmartEvent::@29::@54 gossipHello
struct SmartEvent::@29::@59 doAction
struct SmartEvent::@29::@37 targetCasting
struct SmartEvent::@29::@48 transportAddCreature
struct SmartEvent::@29::@43 aura
struct SmartEvent::@29::@46 dataSet
struct SmartEvent::@29::@58 eventInform
struct SmartEvent::@29::@39 missingBuff
uint32 hostilityMode
Hostility mode of the event. 0: hostile, 1: not hostile, 2: any.
struct SmartEvent::@29::@49 transportRelocate
struct SmartEvent::@29::@61 distance
struct SmartEvent::@29::@38 friendlyCC
struct SmartEvent::@29::@34 los
uint32 event_chance
struct SmartEvent::@29::@63 spellCast
struct SmartEvent::@29::@35 respawn
struct SmartEvent::@29::@60 friendlyHealthPct
SAIBool playerOnly
uint32 creatureEntry
struct SmartEvent::@29::@57 goLootStateChanged
struct SmartEvent::@29::@33 spellHit
struct SmartEvent::@29::@53 timedEvent
struct SmartEvent::@29::@47 waypoint
uint32 gameEventId
uint32 textGroupID
uint32 cooldownMin
struct SmartEvent::@29::@51 areatrigger
struct SmartEvent::@29::@64 raw
SAIBool onRemove
struct SmartEvent::@29::@55 gossip
struct SmartEvent::@29::@31 minMaxRepeat
SMART_EVENT type
static constexpr uint32 DEFAULT_PRIORITY
uint32 GetScriptType() const
uint32 GetEventType() const
uint32 GetTargetType() const
SmartScriptType source_type
uint32 GetActionType() const
struct SmartTarget::@162::@180 vehicle
struct SmartTarget::@162::@170 playerRange
struct SmartTarget::@162::@166 unitRange
struct SmartTarget::@162::@179 owner
struct SmartTarget::@162::@175 unitClosest
struct SmartTarget::@162::@171 stored
struct SmartTarget::@162::@167 unitGUID
SAIBool useCharmerOrOwner
struct SmartTarget::@162::@173 goGUID
struct SmartTarget::@162::@181 threatList
struct SmartTarget::@162::@178 closestFriendly
struct SmartTarget::@162::@177 closestAttackable
struct SmartTarget::@162::@172 goRange
struct SmartTarget::@162::@168 unitDistance
struct SmartTarget::@162::@174 goDistance
struct SmartTarget::@162::@182 raw
SMARTAI_TARGETS type
struct SmartTarget::@162::@169 playerDistance
struct SmartTarget::@162::@165 farthest
struct SmartTarget::@162::@176 goClosest
struct SmartTarget::@162::@164 hostilRandom
std::vector< WaypointNode > nodes