TrinityCore
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 "GameEventSender.h"
27#include "GameObject.h"
28#include "GossipDef.h"
29#include "GridNotifiersImpl.h"
30#include "Group.h"
31#include "InstanceScript.h"
32#include "Language.h"
33#include "Log.h"
34#include "Map.h"
35#include "MotionMaster.h"
36#include "MovementTypedefs.h"
37#include "ObjectAccessor.h"
38#include "ObjectMgr.h"
39#include "PhasingHandler.h"
40#include "Random.h"
41#include "SmartAI.h"
42#include "SpellAuras.h"
43#include "TemporarySummon.h"
44#include "Vehicle.h"
45#include "WaypointDefines.h"
46#include "WaypointManager.h"
47
49{
50 go = nullptr;
51 me = nullptr;
52 player = nullptr;
53 trigger = nullptr;
54 areaTrigger = nullptr;
55 sceneTemplate = nullptr;
56 quest = nullptr;
57 event = 0;
58 mEventPhase = 0;
59 mPathId = 0;
60 mTextTimer = 0;
61 mLastTextID = 0;
62 mUseTextTimer = false;
63 mTalkerEntry = 0;
70}
71
73{
74}
75
76bool SmartScript::IsSmart(Creature* c, bool silent) const
77{
78 if (!c)
79 return false;
80
81 bool smart = true;
82 if (!dynamic_cast<SmartAI*>(c->AI()))
83 smart = false;
84
85 if (!smart && !silent)
86 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(), uint64(me ? me->GetSpawnId() : UI64LIT(0)), me ? me->GetEntry() : 0);
87
88 return smart;
89}
90
91bool SmartScript::IsSmart(GameObject* g, bool silent) const
92{
93 if (!g)
94 return false;
95
96 bool smart = true;
97 if (!dynamic_cast<SmartGameObjectAI*>(g->AI()))
98 smart = false;
99
100 if (!smart && !silent)
101 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(), uint64(go ? go->GetSpawnId() : UI64LIT(0)), go ? go->GetEntry() : 0);
102
103 return smart;
104}
105
106bool SmartScript::IsSmart(bool silent) const
107{
108 if (me)
109 return IsSmart(me, silent);
110 if (go)
111 return IsSmart(go, silent);
112 return false;
113}
114
116{
117 // insert or replace
118 _storedTargets.erase(id);
119 _storedTargets.emplace(id, ObjectGuidVector(targets));
120}
121
123{
124 auto [itr, inserted] = _storedTargets.try_emplace(id, targets);
125 if (!inserted)
126 for (WorldObject* obj : targets)
127 itr->second.AddGuid(obj->GetGUID());
128}
129
131{
132 auto itr = _storedTargets.find(id);
133 if (itr != _storedTargets.end())
134 return itr->second.GetObjectVector(ref);
135 return nullptr;
136}
137
139{
140 CounterMap::iterator itr = mCounterList.find(id);
141 if (itr != mCounterList.end())
142 {
143 if (reset == 0)
144 itr->second += value;
145 else
146 itr->second = value;
147 }
148 else
149 mCounterList.insert(std::make_pair(id, value));
150
152}
153
155{
156 CounterMap::const_iterator itr = mCounterList.find(id);
157 if (itr != mCounterList.end())
158 return itr->second;
159 return 0;
160}
161
163{
164 auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
165 if (bounds.first == bounds.second)
166 return nullptr;
167
168 return bounds.first->second;
169}
170
172{
173 auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
174 if (bounds.first == bounds.second)
175 return nullptr;
176
177 auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
178 {
179 return pair.second->IsAlive();
180 });
181
182 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
183}
184
186{
189 {
190 if (!(event.event.event_flags & SMART_EVENT_FLAG_DONT_RESET))
191 {
193 event.runOnce = false;
194 }
195
197 {
200 }
201 }
204}
205
207{
208 WorldObject* lookupRoot = me;
209 if (!lookupRoot)
210 lookupRoot = go;
211
212 if (lookupRoot)
213 {
214 if (!meOrigGUID.IsEmpty())
215 {
216 if (Creature* m = ObjectAccessor::GetCreature(*lookupRoot, meOrigGUID))
217 {
218 me = m;
219 go = nullptr;
220 areaTrigger = nullptr;
221 player = nullptr;
222 }
223 }
224
225 if (!goOrigGUID.IsEmpty())
226 {
228 {
229 me = nullptr;
230 go = o;
231 areaTrigger = nullptr;
232 player = nullptr;
233 }
234 }
235 }
238}
239
240void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob, std::string const& varString)
241{
243
244 // Allow only a fixed number of nested ProcessEventsFor calls
246 {
247 TC_LOG_WARN("scripts.ai", "SmartScript::ProcessEventsFor: reached the limit of max allowed nested ProcessEventsFor() calls with event {}, skipping!\n{}", e, GetBaseObject()->GetDebugInfo());
248 }
249 else
250 {
252 {
253 SMART_EVENT eventType = SMART_EVENT(event.GetEventType());
254 if (eventType == SMART_EVENT_LINK)//special handling
255 continue;
256
257 if (eventType == e)
258 if (sConditionMgr->IsObjectMeetingSmartEventConditions(event.entryOrGuid, event.event_id, event.source_type, unit, GetBaseObject()))
259 ProcessEvent(event, unit, var0, var1, bvar, spell, gob, varString);
260 }
261 }
262
264}
265
266void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob, std::string const& varString)
267{
268 e.runOnce = true; //used for repeat check
269
270 // calc random
272 {
274 return;
275 }
276
277 // Remove SMART_EVENT_FLAG_TEMP_IGNORE_CHANCE_ROLL flag after processing roll chances as it's not needed anymore
278 e.event.event_flags &= ~SMART_EVENT_FLAG_TEMP_IGNORE_CHANCE_ROLL;
279
280 if (unit)
281 mLastInvoker = unit->GetGUID();
282
283 if (Unit* tempInvoker = GetLastInvoker())
284 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: Invoker: {} {}", tempInvoker->GetName(), tempInvoker->GetGUID().ToString());
285
286 ObjectVector targets;
287 GetTargets(targets, e, Coalesce<WorldObject>(unit, gob));
288
289 switch (e.GetActionType())
290 {
292 {
293 Creature* talker = e.target.type == 0 ? me : nullptr;
294 Unit* talkTarget = nullptr;
295
296 for (WorldObject* target : targets)
297 {
298 if (IsCreature(target) && !target->ToCreature()->IsPet()) // Prevented sending text to pets.
299 {
301 {
302 talker = me;
303 talkTarget = target->ToCreature();
304 }
305 else
306 talker = target->ToCreature();
307 break;
308 }
309 else if (IsPlayer(target))
310 {
311 talker = me;
312 talkTarget = target->ToPlayer();
313 break;
314 }
315 }
316
317 if (!talkTarget)
318 talkTarget = GetLastInvoker();
319
320 if (!talker)
321 break;
322
323 mTalkerEntry = talker->GetEntry();
326 mUseTextTimer = true;
327 sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), talkTarget);
328 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: {} {}, textGuid: {}",
329 talker->GetName(), talker->GetGUID().ToString(), talkTarget ? talkTarget->GetGUID().ToString().c_str() : "Empty");
330 break;
331 }
333 {
334 for (WorldObject* target : targets)
335 {
336 if (IsCreature(target))
337 sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : nullptr);
338 else if (IsPlayer(target) && me)
339 {
340 Unit* templastInvoker = GetLastInvoker();
341 sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, SoundKitPlayType::Normal, TEAM_OTHER, false, target->ToPlayer());
342 }
343 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: {} {}, textGroupId: {}",
344 target->GetName(), target->GetGUID().ToString(), uint8(e.action.simpleTalk.textGroupID));
345 }
346 break;
347 }
349 {
350 for (WorldObject* target : targets)
351 {
352 if (IsUnit(target))
353 {
354 target->ToUnit()->HandleEmoteCommand(static_cast<Emote>(e.action.emote.emote));
355 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: {} {}, emote: {}",
356 target->GetName(), target->GetGUID().ToString(), e.action.emote.emote);
357 }
358 }
359 break;
360 }
362 {
363 for (WorldObject* target : targets)
364 {
365 if (IsUnit(target))
366 {
367 if (e.action.sound.distance == 1)
368 target->PlayDistanceSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr);
369 else
370 target->PlayDirectSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr, e.action.sound.keyBroadcastTextId);
371
372 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: {} {}, sound: {}, onlyself: {}",
373 target->GetName(), target->GetGUID().ToString(), e.action.sound.sound, e.action.sound.onlySelf);
374 }
375 }
376 break;
377 }
379 {
380 for (WorldObject* target : targets)
381 {
382 if (IsCreature(target))
383 {
385 {
386 target->ToCreature()->SetFaction(e.action.faction.factionID);
387 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature {} set faction to {}",
388 target->GetGUID().ToString(), e.action.faction.factionID);
389 }
390 else
391 {
392 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->ToCreature()->GetEntry()))
393 {
394 if (target->ToCreature()->GetFaction() != ci->faction)
395 {
396 target->ToCreature()->SetFaction(ci->faction);
397 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature {} set faction to {}",
398 target->GetGUID().ToString(), ci->faction);
399 }
400 }
401 }
402 }
403 }
404 break;
405 }
407 {
408 for (WorldObject* target : targets)
409 {
410 if (!IsCreature(target))
411 continue;
412
414 {
415 //set model based on entry from creature_template
417 {
418 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
419 {
420 CreatureModel const* model = ObjectMgr::ChooseDisplayId(ci);
421 target->ToCreature()->SetDisplayId(model->CreatureDisplayID);
422 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} set displayid to {}",
423 target->GetGUID().ToString(), model->CreatureDisplayID);
424 }
425 }
426 //if no param1, then use value from param2 (modelId)
427 else
428 {
429 target->ToCreature()->SetDisplayId(e.action.morphOrMount.model);
430 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} set displayid to {}",
431 target->GetGUID().ToString(), e.action.morphOrMount.model);
432 }
433 }
434 else
435 {
436 target->ToCreature()->DeMorph();
437 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature {} demorphs.",
438 target->GetGUID().ToString());
439 }
440 }
441 break;
442 }
444 {
445 for (WorldObject* target : targets)
446 {
447 if (IsPlayer(target))
448 {
449 target->ToPlayer()->FailQuest(e.action.quest.quest);
450 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player {} fails quest {}",
451 target->GetGUID().ToString(), e.action.quest.quest);
452 }
453 }
454 break;
455 }
457 {
458 for (WorldObject* target : targets)
459 {
460 if (Player* player = target->ToPlayer())
461 {
462 if (Quest const* q = sObjectMgr->GetQuestTemplate(e.action.questOffer.questID))
463 {
464 if (me && e.action.questOffer.directAdd == 0)
465 {
466 if (player->CanTakeQuest(q, true))
467 {
468 if (WorldSession* session = player->GetSession())
469 {
470 PlayerMenu menu(session);
471 menu.SendQuestGiverQuestDetails(q, me->GetGUID(), true, false);
472 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {} - offering quest {}", player->GetGUID().ToString(), e.action.questOffer.questID);
473 }
474 }
475 }
476 else
477 {
479 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {} - quest {} added",
481 }
482 }
483 }
484 }
485 break;
486 }
488 {
489 for (WorldObject* target : targets)
490 {
491 if (!IsCreature(target))
492 continue;
493
494 target->ToCreature()->SetReactState(ReactStates(e.action.react.state));
495 }
496 break;
497 }
499 {
500 std::vector<uint32> emotes;
501 std::copy_if(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes),
502 std::back_inserter(emotes), [](uint32 emote) { return emote != 0; });
503
504 for (WorldObject* target : targets)
505 {
506 if (IsUnit(target))
507 {
509 target->ToUnit()->HandleEmoteCommand(emote);
510 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature {} handle random emote {}",
511 target->GetGUID().ToString(), emote);
512 }
513 }
514 break;
515 }
517 {
518 if (!me)
519 break;
520
521 for (auto* ref : me->GetThreatManager().GetModifiableThreatList())
522 {
523 ref->ModifyThreatByPercent(std::max<int32>(-100,int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC)));
524 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature {} modify threat for unit {}, value {}",
525 me->GetGUID().ToString(), ref->GetVictim()->GetGUID().ToString(), int32(e.action.threatPCT.threatINC)-int32(e.action.threatPCT.threatDEC));
526 }
527 break;
528 }
530 {
531 if (!me)
532 break;
533
534 for (WorldObject* target : targets)
535 {
536 if (IsUnit(target))
537 {
538 me->GetThreatManager().ModifyThreatByPercent(target->ToUnit(), std::max<int32>(-100, int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC)));
539 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature {} modify threat for unit {}, value {}",
540 me->GetGUID().ToString(), target->GetGUID().ToString(), int32(e.action.threatPCT.threatINC) - int32(e.action.threatPCT.threatDEC));
541 }
542 }
543 break;
544 }
546 {
547 for (WorldObject* target : targets)
548 {
549 // Special handling for vehicles
550 if (IsUnit(target))
551 if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
552 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
553 if (Player* player = ObjectAccessor::GetPlayer(*target, seat.second.Passenger.Guid))
555
556 if (IsPlayer(target))
557 {
558 target->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest);
559
560 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player {} credited quest {}",
561 target->GetGUID().ToString(), e.action.quest.quest);
562 }
563 }
564 break;
565 }
567 {
568 if (targets.empty())
569 break;
570
571 if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit)
573
574 bool failedSpellCast = false, successfulSpellCast = false;
575
576 for (WorldObject* target : targets)
577 {
578 // may be nullptr
579 if (go)
580 go->CastSpell(target->ToUnit(), e.action.cast.spell);
581
582 if (!IsUnit(target))
583 continue;
584
585 if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
586 {
587 TriggerCastFlags triggerFlag = TRIGGERED_NONE;
589 {
591 triggerFlag = TriggerCastFlags(e.action.cast.triggerFlags);
592 else
593 triggerFlag = TRIGGERED_FULL_MASK;
594 }
595
596 if (me)
597 {
600
601 SpellCastResult result = me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
602 bool spellCastFailed = (result != SPELL_CAST_OK && result != SPELL_FAILED_SPELL_IN_PROGRESS);
603
605 {
606 // 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.
607 ENSURE_AI(SmartAI, me->AI())->SetCombatMove(spellCastFailed, true);
608 }
609
610 if (spellCastFailed)
611 failedSpellCast = true;
612 else
613 successfulSpellCast = true;
614 }
615 else if (go)
616 go->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
617
618 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: {} casts spell {} on target {} with castflags {}",
619 me ? me->GetGUID().ToString() : go->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
620 }
621 else
622 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());
623 }
624
625 // If there is at least 1 failed cast and no successful casts at all, retry again on next loop
626 if (failedSpellCast && !successfulSpellCast)
627 {
628 RetryLater(e, true);
629 // Don't execute linked events
630 return;
631 }
632 break;
633 }
635 {
636 if (targets.empty())
637 break;
638
641
642 TriggerCastFlags triggerFlags = TRIGGERED_NONE;
644 {
646 triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
647 else
648 triggerFlags = TRIGGERED_FULL_MASK;
649 }
650
651 for (WorldObject* target : targets)
652 {
653 Unit* uTarget = target->ToUnit();
654 if (!uTarget)
655 continue;
656
658 {
660 uTarget->InterruptNonMeleeSpells(false);
661
662 uTarget->CastSpell(uTarget, e.action.cast.spell, triggerFlags);
663 }
664 }
665 break;
666 }
668 {
669 Unit* tempLastInvoker = GetLastInvoker(unit);
670 if (!tempLastInvoker)
671 break;
672
673 if (targets.empty())
674 break;
675
678
679 for (WorldObject* target : targets)
680 {
681 if (!IsUnit(target))
682 continue;
683
684 if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
685 {
687 tempLastInvoker->InterruptNonMeleeSpells(false);
688
689 TriggerCastFlags triggerFlag = TRIGGERED_NONE;
691 {
693 triggerFlag = TriggerCastFlags(e.action.cast.triggerFlags);
694 else
695 triggerFlag = TRIGGERED_FULL_MASK;
696 }
697
698 tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag);
699 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {} casts spell {} on target {} with castflags {}",
700 tempLastInvoker->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
701 }
702 else
703 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());
704 }
705 break;
706 }
708 {
709 for (WorldObject* target : targets)
710 {
711 if (IsGameObject(target))
712 {
713 // Activate
714 target->ToGameObject()->SetLootState(GO_READY);
715 target->ToGameObject()->UseDoorOrButton(0, false, unit);
716 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated",
717 target->GetGUID().ToString());
718 }
719 }
720 break;
721 }
723 {
724 for (WorldObject* target : targets)
725 {
726 if (IsGameObject(target))
727 {
728 target->ToGameObject()->ResetDoorOrButton();
729 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject {} reset",
730 target->GetGUID().ToString());
731 }
732 }
733 break;
734 }
736 {
737 for (WorldObject* target : targets)
738 {
739 if (IsUnit(target))
740 {
741 target->ToUnit()->SetEmoteState(Emote(e.action.emote.emote));
742 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit {} set emotestate to {}",
743 target->GetGUID().ToString(), e.action.emote.emote);
744 }
745 }
746 break;
747 }
749 {
751 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: {} bool on = {}",
753 break;
754 }
756 {
757 if (!IsSmart())
758 break;
759
760 bool move = e.action.combatMove.move != 0;
761 ENSURE_AI(SmartAI, me->AI())->SetCombatMove(move);
762 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}",
764 break;
765 }
767 {
768 if (!GetBaseObject())
769 break;
770
772 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature {} set event phase {}",
774 break;
775 }
777 {
778 if (!GetBaseObject())
779 break;
780
783 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature {} inc event phase by {}, "
784 "decrease by {}", GetBaseObject()->GetGUID().ToString(), e.action.incEventPhase.inc, e.action.incEventPhase.dec);
785 break;
786 }
788 {
789 if (!me)
790 break;
791
792 // Reset home position to respawn position if specified in the parameters
793 if (e.action.evade.toRespawnPosition == 0)
794 {
795 float homeX, homeY, homeZ, homeO;
796 me->GetRespawnPosition(homeX, homeY, homeZ, &homeO);
797 me->SetHomePosition(homeX, homeY, homeZ, homeO);
798 }
799
800 me->AI()->EnterEvadeMode();
801 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_EVADE: Creature {} EnterEvadeMode", me->GetGUID().ToString());
802 break;
803 }
805 {
806 if (!me)
807 break;
808
810
812 {
815 }
816 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString());
817 break;
818 }
820 {
821 if (!unit)
822 break;
823
824 // If invoker was pet or charm
825 Player* playerCharmed = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
826 if (playerCharmed && GetBaseObject())
827 {
828 playerCharmed->GroupEventHappens(e.action.quest.quest, GetBaseObject());
829 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}",
830 unit->GetGUID().ToString(), e.action.quest.quest);
831 }
832
833 // Special handling for vehicles
834 if (Vehicle* vehicle = unit->GetVehicleKit())
835 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
836 if (Player* passenger = ObjectAccessor::GetPlayer(*unit, seat.second.Passenger.Guid))
837 passenger->GroupEventHappens(e.action.quest.quest, GetBaseObject());
838 break;
839 }
841 {
842 if (!me)
843 break;
844
845 me->CombatStop(true);
846 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_COMBAT_STOP: {} CombatStop", me->GetGUID().ToString());
847 break;
848 }
850 {
851 for (WorldObject* target : targets)
852 {
853 if (!IsUnit(target))
854 continue;
855
856 if (e.action.removeAura.spell)
857 {
858 ObjectGuid casterGUID;
860 {
861 if (!me)
862 break;
863 casterGUID = me->GetGUID();
864 }
865
867 {
868 if (Aura* aur = target->ToUnit()->GetAura(e.action.removeAura.spell, casterGUID))
869 aur->ModCharges(-static_cast<int32>(e.action.removeAura.charges), AURA_REMOVE_BY_EXPIRE);
870 }
871 else
872 target->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell, casterGUID);
873 }
874 else
875 target->ToUnit()->RemoveAllAuras();
876
877 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit {}, spell {}",
878 target->GetGUID().ToString(), e.action.removeAura.spell);
879 }
880 break;
881 }
883 {
884 if (!IsSmart())
885 break;
886
887 if (targets.empty())
888 {
889 ENSURE_AI(SmartAI, me->AI())->StopFollow(false);
890 break;
891 }
892
893 for (WorldObject* target : targets)
894 {
895 if (IsUnit(target))
896 {
897 float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle;
898 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);
899 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}",
900 me->GetGUID().ToString(), target->GetGUID().ToString());
901 break;
902 }
903 }
904 break;
905 }
907 {
908 if (!GetBaseObject())
909 break;
910
911 std::vector<uint32> phases;
912 std::copy_if(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases),
913 std::back_inserter(phases), [](uint32 phase) { return phase != 0; });
914
916 SetPhase(phase);
917 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature {} sets event phase to {}",
918 GetBaseObject()->GetGUID().ToString(), phase);
919 break;
920 }
922 {
923 if (!GetBaseObject())
924 break;
925
927 SetPhase(phase);
928 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature {} sets event phase to {}",
929 GetBaseObject()->GetGUID().ToString(), phase);
930 break;
931 }
933 {
934 if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) // Loot recipient and his group members
935 {
936 if (!me)
937 break;
938
939 for (ObjectGuid tapperGuid : me->GetTapList())
940 {
941 if (Player* tapper = ObjectAccessor::GetPlayer(*me, tapperGuid))
942 {
943 tapper->KilledMonsterCredit(e.action.killedMonster.creature, me->GetGUID());
944 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
945 tapper->GetGUID().ToString(), e.action.killedMonster.creature);
946 }
947 }
948 }
949 else // Specific target type
950 {
951 for (WorldObject* target : targets)
952 {
953 if (IsPlayer(target))
954 {
955 target->ToPlayer()->KilledMonsterCredit(e.action.killedMonster.creature);
956 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
957 target->GetGUID().ToString(), e.action.killedMonster.creature);
958 }
959 else if (IsUnit(target)) // Special handling for vehicles
960 if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
961 for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
962 if (Player* player = ObjectAccessor::GetPlayer(*target, seat.second.Passenger.Guid))
964 }
965 }
966 break;
967 }
969 {
970 WorldObject* obj = GetBaseObject();
971 if (!obj)
972 obj = unit;
973
974 if (!obj)
975 break;
976
977 InstanceScript* instance = obj->GetInstanceScript();
978 if (!instance)
979 {
980 TC_LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
981 break;
982 }
983
984 switch (e.action.setInstanceData.type)
985 {
986 case 0:
988 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetData Field: {}, data: {}",
990 break;
991 case 1:
993 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: {}, State: {} ({})",
995 break;
996 default: // Static analysis
997 break;
998 }
999 break;
1000 }
1002 {
1003 WorldObject* obj = GetBaseObject();
1004 if (!obj)
1005 obj = unit;
1006
1007 if (!obj)
1008 break;
1009
1010 InstanceScript* instance = obj->GetInstanceScript();
1011 if (!instance)
1012 {
1013 TC_LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
1014 break;
1015 }
1016
1017 if (targets.empty())
1018 break;
1019
1020 instance->SetGuidData(e.action.setInstanceData64.field, targets.front()->GetGUID());
1021 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: {}, data: {}",
1022 e.action.setInstanceData64.field, targets.front()->GetGUID().ToString());
1023 break;
1024 }
1026 {
1027 for (WorldObject* target : targets)
1028 if (IsCreature(target))
1029 target->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, nullptr, e.action.updateTemplate.updateLevel != 0);
1030 break;
1031 }
1032 case SMART_ACTION_DIE:
1033 {
1034 if (me && !me->isDead())
1035 {
1036 me->KillSelf();
1037 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());
1038 }
1039 break;
1040 }
1042 {
1043 if (me && me->IsAIEnabled())
1044 {
1045 me->AI()->DoZoneInCombat();
1046 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {}", me->GetGUID().ToString());
1047 }
1048 break;
1049 }
1051 {
1052 if (me)
1053 {
1054 me->CallForHelp(float(e.action.callHelp.range));
1056 {
1058 sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE);
1059 }
1060 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {}", me->GetGUID().ToString());
1061 }
1062 break;
1063 }
1065 {
1066 if (me)
1067 {
1069 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature {}, State: {}",
1071 }
1072 break;
1073 }
1075 {
1076 // there should be at least a world update tick before despawn, to avoid breaking linked actions
1077 Milliseconds despawnDelay(e.action.forceDespawn.delay);
1078 if (despawnDelay <= 0ms)
1079 despawnDelay = 1ms;
1080
1081 Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer);
1082
1083 for (WorldObject* target : targets)
1084 {
1085 if (Creature* creature = target->ToCreature())
1086 creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1087 else if (GameObject* goTarget = target->ToGameObject())
1088 goTarget->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1089 }
1090 break;
1091 }
1093 {
1094 for (WorldObject* target : targets)
1095 {
1096 if (e.action.ingamePhaseId.apply == 1)
1098 else
1100 }
1101 break;
1102 }
1104 {
1105 for (WorldObject* target : targets)
1106 {
1107 if (e.action.ingamePhaseGroup.apply == 1)
1109 else
1111 }
1112 break;
1113 }
1115 {
1116 for (WorldObject* target : targets)
1117 {
1118 if (!IsUnit(target))
1119 continue;
1120
1122 {
1123 if (e.action.morphOrMount.creature > 0)
1124 {
1125 if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1126 target->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)->CreatureDisplayID);
1127 }
1128 else
1129 target->ToUnit()->Mount(e.action.morphOrMount.model);
1130 }
1131 else
1132 target->ToUnit()->Dismount();
1133 }
1134 break;
1135 }
1137 {
1138 for (WorldObject* target : targets)
1139 {
1140 if (IsCreature(target))
1141 {
1142 SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI());
1143 if (!ai)
1144 continue;
1145
1146 if (e.action.invincHP.percent)
1147 ai->SetInvincibilityHpLevel(target->ToCreature()->CountPctFromMaxHealth(e.action.invincHP.percent));
1148 else
1150 }
1151 }
1152 break;
1153 }
1155 {
1156 for (WorldObject* target : targets)
1157 {
1158 if (Creature* cTarget = target->ToCreature())
1159 {
1160 CreatureAI* ai = cTarget->AI();
1161 if (IsSmart(cTarget, true))
1162 ENSURE_AI(SmartAI, ai)->SetData(e.action.setData.field, e.action.setData.data, me);
1163 else
1165 }
1166 else if (GameObject* oTarget = target->ToGameObject())
1167 {
1168 GameObjectAI* ai = oTarget->AI();
1169 if (IsSmart(oTarget, true))
1171 else
1173 }
1174 }
1175 break;
1176 }
1178 {
1179 for (WorldObject* target : targets)
1180 if (Unit* unitTarget = target->ToUnit())
1181 unitTarget->AttackStop();
1182 break;
1183 }
1185 {
1186 for (WorldObject* target : targets)
1187 {
1188 if (!IsCreature(target))
1189 continue;
1190
1192 continue;
1193
1194 Position pos = target->GetPosition();
1195
1196 // Use forward/backward/left/right cartesian plane movement
1197 float x, y, z, o;
1198 o = pos.GetOrientation();
1199 x = pos.GetPositionX() + (std::cos(o - (M_PI / 2))*e.target.x) + (std::cos(o)*e.target.y);
1200 y = pos.GetPositionY() + (std::sin(o - (M_PI / 2))*e.target.x) + (std::sin(o)*e.target.y);
1201 z = pos.GetPositionZ() + e.target.z;
1202 target->ToCreature()->GetMotionMaster()->MovePoint(e.action.moveOffset.PointId, x, y, z);
1203 }
1204 break;
1205 }
1207 {
1208 for (WorldObject* target : targets)
1209 if (IsUnit(target))
1210 target->ToUnit()->SetVisible(e.action.visibility.state ? true : false);
1211 break;
1212 }
1214 {
1215 for (WorldObject* target : targets)
1216 target->setActive(e.action.active.state ? true : false);
1217 break;
1218 }
1220 {
1221 if (!me)
1222 break;
1223
1224 if (targets.empty())
1225 break;
1226
1227 // attack random target
1228 if (Unit * target = Trinity::Containers::SelectRandomContainerElement(targets)->ToUnit())
1229 me->AI()->AttackStart(target);
1230 break;
1231 }
1233 {
1235 bool preferUnit = flags.HasFlag(SmartActionSummonCreatureFlags::PreferUnit);
1236 WorldObject* summoner = preferUnit ? unit : GetBaseObjectOrUnitInvoker(unit);
1237 if (!summoner)
1238 break;
1239
1240 ObjectGuid privateObjectOwner;
1242 privateObjectOwner = summoner->IsPrivateObject() ? summoner->GetPrivateObjectOwner() : summoner->GetGUID();
1243 uint32 spawnsCount = std::max(e.action.summonCreature.count, 1u);
1244
1245 float x, y, z, o;
1246 for (WorldObject* target : targets)
1247 {
1248 target->GetPosition(x, y, z, o);
1249 x += e.target.x;
1250 y += e.target.y;
1251 z += e.target.z;
1252 o += e.target.o;
1253 for (uint32 counter = 0; counter < spawnsCount; counter++)
1254 {
1255 if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, Milliseconds(e.action.summonCreature.duration), privateObjectOwner))
1257 summon->AI()->AttackStart(target->ToUnit());
1258 }
1259 }
1260
1262 break;
1263
1264 for (uint32 counter = 0; counter < spawnsCount; counter++)
1265 {
1267 if (unit && e.action.summonCreature.attackInvoker)
1268 summon->AI()->AttackStart(unit);
1269 }
1270 break;
1271 }
1273 {
1274 WorldObject* summoner = GetBaseObjectOrUnitInvoker(unit);
1275 if (!summoner)
1276 break;
1277
1278 for (WorldObject* target : targets)
1279 {
1280 Position pos = target->GetPositionWithOffset(Position(e.target.x, e.target.y, e.target.z, e.target.o));
1283 }
1284
1286 break;
1287
1290 break;
1291 }
1293 {
1294 for (WorldObject* target : targets)
1295 {
1296 if (!IsUnit(target))
1297 continue;
1298
1299 target->ToUnit()->KillSelf();
1300 }
1301 break;
1302 }
1304 {
1305 for (WorldObject* target : targets)
1306 {
1307 if (!IsPlayer(target))
1308 continue;
1309
1310 target->ToPlayer()->AddItem(e.action.item.entry, e.action.item.count);
1311 }
1312 break;
1313 }
1315 {
1316 for (WorldObject* target : targets)
1317 {
1318 if (!IsPlayer(target))
1319 continue;
1320
1321 target->ToPlayer()->DestroyItemCount(e.action.item.entry, e.action.item.count, true);
1322 }
1323 break;
1324 }
1326 {
1328 break;
1329 }
1331 {
1332 for (WorldObject* target : targets)
1333 {
1334 if (IsPlayer(target))
1335 target->ToPlayer()->TeleportTo(e.action.teleport.mapID, e.target.x, e.target.y, e.target.z, e.target.o);
1336 else if (IsCreature(target))
1337 target->ToCreature()->NearTeleportTo(e.target.x, e.target.y, e.target.z, e.target.o);
1338 }
1339 break;
1340 }
1342 {
1343 if (!IsSmart())
1344 break;
1345
1346 ENSURE_AI(SmartAI, me->AI())->SetDisableGravity(e.action.setDisableGravity.disable != 0);
1347 break;
1348 }
1350 {
1351 if (!IsSmart())
1352 break;
1353
1354 ENSURE_AI(SmartAI, me->AI())->SetRun(e.action.setRun.run != 0);
1355 break;
1356 }
1358 {
1359 if (!targets.empty())
1360 {
1361 for (WorldObject* target : targets)
1362 {
1363 if (IsCreature(target))
1364 {
1365 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
1366 ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
1367 else
1368 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping");
1369 }
1370 else if (IsGameObject(target))
1371 {
1372 if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI()))
1373 ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
1374 else
1375 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping");
1376 }
1377 }
1378 }
1379 else
1381 break;
1382 }
1384 {
1385 if (!IsSmart())
1386 break;
1387
1388 uint32 entry = e.action.wpStart.pathID;
1389 bool repeat = e.action.wpStart.repeat != 0;
1390
1391 for (WorldObject* target : targets)
1392 {
1393 if (IsPlayer(target))
1394 {
1396 break;
1397 }
1398 }
1399
1400 ENSURE_AI(SmartAI, me->AI())->StartPath(entry, repeat, unit);
1401
1403 uint32 DespawnTime = e.action.wpStart.despawnTime;
1404 ENSURE_AI(SmartAI, me->AI())->SetEscortQuest(quest);
1405 ENSURE_AI(SmartAI, me->AI())->SetDespawnTime(DespawnTime);
1406 break;
1407 }
1409 {
1410 if (!IsSmart())
1411 break;
1412
1413 uint32 delay = e.action.wpPause.delay;
1414 ENSURE_AI(SmartAI, me->AI())->PausePath(delay, true);
1415 break;
1416 }
1418 {
1419 if (!IsSmart())
1420 break;
1421
1422 uint32 DespawnTime = e.action.wpStop.despawnTime;
1424 bool fail = e.action.wpStop.fail != 0;
1425 ENSURE_AI(SmartAI, me->AI())->StopPath(DespawnTime, quest, fail);
1426 break;
1427 }
1429 {
1430 if (!IsSmart())
1431 break;
1432
1433 // Set the timer to 1 ms so the path will be resumed on next update loop
1434 if (ENSURE_AI(SmartAI, me->AI())->CanResumePath())
1435 ENSURE_AI(SmartAI, me->AI())->SetWPPauseTimer(1);
1436 break;
1437 }
1439 {
1440 if (!me)
1441 break;
1442
1444 me->SetFacingTo((me->GetTransport() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation());
1445 else if (e.GetTargetType() == SMART_TARGET_POSITION)
1446 me->SetFacingTo(e.target.o);
1447 else if (!targets.empty())
1448 me->SetFacingToObject(targets.front());
1449 break;
1450 }
1452 {
1453 for (WorldObject* target : targets)
1454 {
1455 if (!IsPlayer(target))
1456 continue;
1457
1458 target->ToPlayer()->SendMovieStart(e.action.movie.entry);
1459 }
1460 break;
1461 }
1463 {
1464 if (!IsSmart())
1465 break;
1466
1467 WorldObject* target = nullptr;
1468
1469 // we want to move to random element
1470 if (!targets.empty())
1472
1473 if (target)
1474 {
1475 float x, y, z;
1476 target->GetPosition(x, y, z);
1478 target->GetContactPoint(me, x, y, z, e.action.moveToPos.ContactDistance);
1480 }
1481
1483 break;
1484
1485 Position dest(e.target.x, e.target.y, e.target.z);
1487 if (TransportBase* trans = me->GetDirectTransport())
1488 trans->CalculatePassengerPosition(dest.m_positionX, dest.m_positionY, dest.m_positionZ);
1489
1491 break;
1492 }
1494 {
1495 for (WorldObject* target : targets)
1496 {
1497 if (IsCreature(target))
1498 TC_LOG_WARN("sql.sql", "Invalid creature target '{}' (entry {}, spawnId {}) specified for SMART_ACTION_ENABLE_TEMP_GOBJ", target->GetName(), target->GetEntry(), target->ToCreature()->GetSpawnId());
1499 else if (IsGameObject(target))
1500 {
1501 if (target->ToGameObject()->isSpawnedByDefault())
1502 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());
1503 else
1504 target->ToGameObject()->SetRespawnTime(e.action.enableTempGO.duration);
1505 }
1506 }
1507 break;
1508 }
1510 {
1511 for (WorldObject* target : targets)
1512 if (IsPlayer(target))
1513 target->ToPlayer()->PlayerTalkClass->SendCloseGossip();
1514 break;
1515 }
1516 case SMART_ACTION_EQUIP:
1517 {
1518 for (WorldObject* target : targets)
1519 {
1520 if (Creature* npc = target->ToCreature())
1521 {
1522 std::array<EquipmentItem, MAX_EQUIPMENT_ITEMS> slot;
1523 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
1524 {
1525 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId);
1526 if (!eInfo)
1527 {
1528 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}", equipId, npc->GetEntry());
1529 break;
1530 }
1531
1532 npc->SetCurrentEquipmentId(equipId);
1533
1534 std::copy(std::begin(eInfo->Items), std::end(eInfo->Items), std::begin(slot));
1535 }
1536 else
1537 {
1538 slot[0].ItemId = e.action.equip.slot1;
1539 slot[1].ItemId = e.action.equip.slot2;
1540 slot[2].ItemId = e.action.equip.slot3;
1541 }
1542
1543 for (uint32 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1544 if (!e.action.equip.mask || (e.action.equip.mask & (1 << i)))
1545 npc->SetVirtualItem(i, slot[i].ItemId, slot[i].AppearanceModId, slot[i].ItemVisual);
1546 }
1547 }
1548 break;
1549 }
1551 {
1552 SmartEvent ne = SmartEvent();
1555 if (!ne.event_chance) ne.event_chance = 100;
1556
1561
1562 ne.event_flags = 0;
1565
1566 SmartAction ac = SmartAction();
1569
1571 ev.event = ne;
1572 ev.event_id = e.action.timeEvent.id;
1573 ev.target = e.target;
1574 ev.action = ac;
1575 InitTimer(ev);
1576 mStoredEvents.push_back(ev);
1577 break;
1578 }
1580 {
1582
1583 // remove this event if not repeatable
1585 mRemIDs.push_back(e.action.timeEvent.id);
1586 break;
1587 }
1589 {
1590 mRemIDs.push_back(e.action.timeEvent.id);
1591 break;
1592 }
1594 {
1595 SetPhase(0);
1596 OnReset();
1597 break;
1598 }
1600 {
1601 if (!IsSmart())
1602 break;
1603
1604 float attackDistance = float(e.action.setRangedMovement.distance);
1605 float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * float(M_PI);
1606
1607 for (WorldObject* target : targets)
1608 {
1609 if (Creature* creature = target->ToCreature())
1610 if (IsSmart(creature) && creature->GetVictim())
1611 if (ENSURE_AI(SmartAI, creature->AI())->CanCombatMove())
1612 creature->StartDefaultCombatMovement(creature->GetVictim(), attackDistance, attackAngle);
1613 }
1614
1615 break;
1616 }
1618 {
1620 {
1621 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());
1622 break;
1623 }
1624
1625 for (WorldObject* target : targets)
1626 {
1627 if (Creature* creature = target->ToCreature())
1628 {
1629 if (IsSmart(creature))
1630 ENSURE_AI(SmartAI, creature->AI())->SetTimedActionList(e, e.action.timedActionList.id, GetLastInvoker());
1631 }
1632 else if (GameObject* goTarget = target->ToGameObject())
1633 {
1634 if (IsSmart(goTarget))
1635 ENSURE_AI(SmartGameObjectAI, goTarget->AI())->SetTimedActionList(e, e.action.timedActionList.id, GetLastInvoker());
1636 }
1637 else if (AreaTrigger* areaTriggerTarget = target->ToAreaTrigger())
1638 if (SmartAreaTriggerAI* atSAI = CAST_AI(SmartAreaTriggerAI, areaTriggerTarget->AI()))
1639 atSAI->SetTimedActionList(e, e.action.timedActionList.id, GetLastInvoker());
1640 }
1641 break;
1642 }
1644 {
1645 for (WorldObject* target : targets)
1646 if (IsCreature(target))
1647 target->ToUnit()->ReplaceAllNpcFlags(NPCFlags(e.action.flag.flag));
1648 break;
1649 }
1651 {
1652 for (WorldObject* target : targets)
1653 if (IsCreature(target))
1654 target->ToUnit()->SetNpcFlag(NPCFlags(e.action.flag.flag));
1655 break;
1656 }
1658 {
1659 for (WorldObject* target : targets)
1660 if (IsCreature(target))
1661 target->ToUnit()->RemoveNpcFlag(NPCFlags(e.action.flag.flag));
1662 break;
1663 }
1665 {
1666 if (targets.empty())
1667 break;
1668
1669 ObjectVector casters;
1671
1672 for (WorldObject* caster : casters)
1673 {
1674 if (!IsUnit(caster))
1675 continue;
1676
1677 Unit* casterUnit = caster->ToUnit();
1678
1679 bool interruptedSpell = false;
1680
1681 for (WorldObject* target : targets)
1682 {
1683 if (!IsUnit(target))
1684 continue;
1685
1686 if (!(e.action.crossCast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.crossCast.spell))
1687 {
1688 if (!interruptedSpell && e.action.crossCast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
1689 {
1690 casterUnit->InterruptNonMeleeSpells(false);
1691 interruptedSpell = true;
1692 }
1693
1694 casterUnit->CastSpell(target->ToUnit(), e.action.crossCast.spell, (e.action.crossCast.castFlags & SMARTCAST_TRIGGERED) != 0);
1695 }
1696 else
1697 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());
1698 }
1699 }
1700 break;
1701 }
1703 {
1704 std::vector<uint32> actionLists;
1705 std::copy_if(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists),
1706 std::back_inserter(actionLists), [](uint32 actionList) { return actionList != 0; });
1707
1710 {
1711 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());
1712 break;
1713 }
1714
1715 for (WorldObject* target : targets)
1716 {
1717 if (Creature* creature = target->ToCreature())
1718 {
1719 if (IsSmart(creature))
1720 ENSURE_AI(SmartAI, creature->AI())->SetTimedActionList(e, id, GetLastInvoker());
1721 }
1722 else if (GameObject* goTarget = target->ToGameObject())
1723 {
1724 if (IsSmart(goTarget))
1725 ENSURE_AI(SmartGameObjectAI, goTarget->AI())->SetTimedActionList(e, id, GetLastInvoker());
1726 }
1727 else if (AreaTrigger* areaTriggerTarget = target->ToAreaTrigger())
1728 if (SmartAreaTriggerAI* atSAI = CAST_AI(SmartAreaTriggerAI, areaTriggerTarget->AI()))
1729 atSAI->SetTimedActionList(e, id, GetLastInvoker());
1730 }
1731 break;
1732 }
1734 {
1737 {
1738 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());
1739 break;
1740 }
1741
1742 for (WorldObject* target : targets)
1743 {
1744 if (Creature* creature = target->ToCreature())
1745 {
1746 if (IsSmart(creature))
1747 ENSURE_AI(SmartAI, creature->AI())->SetTimedActionList(e, id, GetLastInvoker());
1748 }
1749 else if (GameObject* goTarget = target->ToGameObject())
1750 {
1751 if (IsSmart(goTarget))
1752 ENSURE_AI(SmartGameObjectAI, goTarget->AI())->SetTimedActionList(e, id, GetLastInvoker());
1753 }
1754 else if (AreaTrigger* areaTriggerTarget = target->ToAreaTrigger())
1755 if (SmartAreaTriggerAI* atSAI = CAST_AI(SmartAreaTriggerAI, areaTriggerTarget->AI()))
1756 atSAI->SetTimedActionList(e, id, GetLastInvoker());
1757 }
1758 break;
1759 }
1761 {
1762 for (WorldObject* target : targets)
1763 if (IsPlayer(target))
1764 target->ToPlayer()->ActivateTaxiPathTo(e.action.taxi.id);
1765 break;
1766 }
1768 {
1769 bool foundTarget = false;
1770
1771 for (WorldObject* target : targets)
1772 {
1773 if (IsCreature((target)))
1774 {
1775 foundTarget = true;
1776
1778 target->ToCreature()->GetMotionMaster()->MoveRandom(float(e.action.moveRandom.distance));
1779 else
1780 target->ToCreature()->GetMotionMaster()->MoveIdle();
1781 }
1782 }
1783
1784 if (!foundTarget && me && IsCreature(me))
1785 {
1788 else
1790 }
1791 break;
1792 }
1794 {
1795 for (WorldObject* target : targets)
1796 if (IsUnit(target))
1797 {
1798 switch (e.action.setunitByte.type)
1799 {
1800 case 0:
1801 target->ToUnit()->SetStandState(UnitStandStateType(e.action.setunitByte.byte1));
1802 break;
1803 case 1:
1804 // pet talent points
1805 break;
1806 case 2:
1807 target->ToUnit()->SetVisFlag(UnitVisFlags(e.action.setunitByte.byte1));
1808 break;
1809 case 3:
1810 target->ToUnit()->SetAnimTier(AnimTier(e.action.setunitByte.byte1));
1811 break;
1812 }
1813 }
1814 break;
1815 }
1817 {
1818 for (WorldObject* target : targets)
1819 if (IsUnit(target))
1820 {
1821 switch (e.action.setunitByte.type)
1822 {
1823 case 0:
1824 target->ToUnit()->SetStandState(UNIT_STAND_STATE_STAND);
1825 break;
1826 case 1:
1827 // pet talent points
1828 break;
1829 case 2:
1830 target->ToUnit()->RemoveVisFlag(UnitVisFlags(e.action.setunitByte.byte1));
1831 break;
1832 case 3:
1833 target->ToUnit()->SetAnimTier(AnimTier::Ground);
1834 break;
1835 }
1836 }
1837 break;
1838 }
1840 {
1841 for (WorldObject* target : targets)
1842 if (IsUnit(target))
1843 target->ToUnit()->InterruptNonMeleeSpells(e.action.interruptSpellCasting.withDelayed != 0, e.action.interruptSpellCasting.spell_id, e.action.interruptSpellCasting.withInstant != 0);
1844 break;
1845 }
1847 {
1848 WorldObject* target = nullptr;
1849
1850 if (!targets.empty())
1852
1853 Position pos(e.target.x, e.target.y, e.target.z);
1854 if (target)
1855 {
1856 float x, y, z;
1857 target->GetPosition(x, y, z);
1858 if (e.action.jump.ContactDistance > 0)
1859 target->GetContactPoint(me, x, y, z, e.action.jump.ContactDistance);
1860 pos = Position(x + e.target.x, y + e.target.y, z + e.target.z);
1861 }
1862 else if (e.GetTargetType() != SMART_TARGET_POSITION)
1863 break;
1864
1866 {
1869 }
1870 else
1871 me->GetMotionMaster()->MoveJump(pos, float(e.action.jump.SpeedXY), float(e.action.jump.SpeedZ), e.action.jump.PointId);
1872
1873 break;
1874 }
1876 {
1877 for (WorldObject* target : targets)
1878 if (IsGameObject(target))
1879 target->ToGameObject()->SetLootState((LootState)e.action.setGoLootState.state);
1880 break;
1881 }
1883 {
1884 for (WorldObject* target : targets)
1885 if (IsGameObject(target))
1886 target->ToGameObject()->SetGoState((GOState)e.action.goState.state);
1887 break;
1888 }
1890 {
1891 WorldObject* ref = GetBaseObject();
1892 if (!ref)
1893 ref = unit;
1894
1895 if (!ref)
1896 break;
1897
1898 ObjectVector const* storedTargets = GetStoredTargetVector(e.action.sendTargetToTarget.id, *ref);
1899 if (!storedTargets)
1900 break;
1901
1902 for (WorldObject* target : targets)
1903 {
1904 if (IsCreature(target))
1905 {
1906 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
1907 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
1908 else
1909 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping");
1910 }
1911 else if (IsGameObject(target))
1912 {
1913 if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI()))
1914 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
1915 else
1916 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping");
1917 }
1918 }
1919 break;
1920 }
1922 {
1923 if (!GetBaseObject() || !IsSmart())
1924 break;
1925
1926 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {}, gossipNpcTextId {}",
1928
1929 // override default gossip
1930 if (me)
1931 ENSURE_AI(SmartAI, me->AI())->SetGossipReturn(true);
1932 else if (go)
1933 ENSURE_AI(SmartGameObjectAI, go->AI())->SetGossipReturn(true);
1934
1935 for (WorldObject* target : targets)
1936 {
1937 if (Player* player = target->ToPlayer())
1938 {
1941 else
1942 player->PlayerTalkClass->ClearMenus();
1943
1944 uint32 gossipNpcTextId = e.action.sendGossipMenu.gossipNpcTextId;
1945 if (!gossipNpcTextId)
1947
1948 player->PlayerTalkClass->SendGossipMenu(gossipNpcTextId, GetBaseObject()->GetGUID());
1949 }
1950 }
1951 break;
1952 }
1954 {
1955 for (WorldObject* target : targets)
1956 {
1957 if (IsCreature(target))
1958 {
1960 target->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
1961 else if (e.GetTargetType() == SMART_TARGET_POSITION)
1962 target->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o);
1970 {
1971 target->ToCreature()->SetHomePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
1972 }
1973 else
1974 TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is invalid, skipping");
1975 }
1976 }
1977 break;
1978 }
1980 {
1981 for (WorldObject* target : targets)
1982 if (IsCreature(target))
1983 target->ToCreature()->SetRegenerateHealth(e.action.setHealthRegen.regenHealth != 0);
1984 break;
1985 }
1987 {
1988 for (WorldObject* target : targets)
1989 if (IsCreature(target))
1990 target->ToCreature()->SetControlled(e.action.setRoot.root != 0, UNIT_STATE_ROOT);
1991 break;
1992 }
1994 {
1995 std::list<TempSummon*> summonList;
1997
1998 for (TempSummon* summon : summonList)
1999 if (unit && e.action.creatureGroup.attackInvoker)
2000 summon->AI()->AttackStart(unit);
2001 break;
2002 }
2004 {
2005 for (WorldObject* target : targets)
2006 if (IsUnit(target))
2007 target->ToUnit()->SetPower(Powers(e.action.power.powerType), e.action.power.newPower);
2008 break;
2009 }
2011 {
2012 for (WorldObject* target : targets)
2013 if (IsUnit(target))
2014 target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) + e.action.power.newPower);
2015 break;
2016 }
2018 {
2019 for (WorldObject* target : targets)
2020 if (IsUnit(target))
2021 target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) - e.action.power.newPower);
2022 break;
2023 }
2025 {
2026 uint32 eventId = e.action.gameEventStop.id;
2027 if (!sGameEventMgr->IsActiveEvent(eventId))
2028 {
2029 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: {})", eventId);
2030 break;
2031 }
2032 sGameEventMgr->StopEvent(eventId, true);
2033 break;
2034 }
2036 {
2037 uint32 eventId = e.action.gameEventStart.id;
2038 if (sGameEventMgr->IsActiveEvent(eventId))
2039 {
2040 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: {})", eventId);
2041 break;
2042 }
2043 sGameEventMgr->StartEvent(eventId, true);
2044 break;
2045 }
2047 {
2048 std::vector<uint32> waypoints;
2049 std::copy_if(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps),
2050 std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
2051
2052 float distanceToClosest = std::numeric_limits<float>::max();
2053 std::pair<uint32, uint32> closest = { 0, 0 };
2054
2055 for (WorldObject* target : targets)
2056 {
2057 if (Creature* creature = target->ToCreature())
2058 {
2059 if (IsSmart(creature))
2060 {
2061 for (uint32 pathId : waypoints)
2062 {
2063 WaypointPath const* path = sWaypointMgr->GetPath(pathId);
2064 if (!path || path->Nodes.empty())
2065 continue;
2066
2067 for (WaypointNode const& waypoint : path->Nodes)
2068 {
2069 float distanceToThisNode = creature->GetDistance(waypoint.X, waypoint.Y, waypoint.Z);
2070 if (distanceToThisNode < distanceToClosest)
2071 {
2072 distanceToClosest = distanceToThisNode;
2073 closest.first = pathId;
2074 closest.second = waypoint.Id;
2075 }
2076 }
2077 }
2078
2079 if (closest.first != 0)
2080 ENSURE_AI(SmartAI, creature->AI())->StartPath(closest.first, true, nullptr, closest.second);
2081 }
2082 }
2083 }
2084 break;
2085 }
2087 {
2088 std::vector<uint32> sounds;
2089 std::copy_if(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds),
2090 std::back_inserter(sounds), [](uint32 sound) { return sound != 0; });
2091
2092 bool onlySelf = e.action.randomSound.onlySelf != 0;
2093 for (WorldObject* const target : targets)
2094 {
2095 if (IsUnit(target))
2096 {
2098
2099 if (e.action.randomSound.distance == 1)
2100 target->PlayDistanceSound(sound, onlySelf ? target->ToPlayer() : nullptr);
2101 else
2102 target->PlayDirectSound(sound, onlySelf ? target->ToPlayer() : nullptr);
2103
2104 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: {} ({}), sound: {}, onlyself: {}",
2105 target->GetName(), target->GetGUID().ToString(), sound, onlySelf ? "true" : "false");
2106 }
2107 }
2108 break;
2109 }
2111 {
2112 for (WorldObject* const target : targets)
2113 {
2114 if (IsCreature(target))
2115 target->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer, !e.action.corpseDelay.includeDecayRatio);
2116 }
2117
2118 break;
2119 }
2121 {
2122 if (e.action.groupSpawn.minDelay == 0 && e.action.groupSpawn.maxDelay == 0)
2123 {
2126
2127 // Instant spawn
2128 GetBaseObject()->GetMap()->SpawnGroupSpawn(e.action.groupSpawn.groupId, ignoreRespawn, force);
2129 }
2130 else
2131 {
2132 // Delayed spawn (use values from parameter to schedule event to call us back
2133 SmartEvent ne = SmartEvent();
2135 ne.event_chance = 100;
2136
2139 ne.minMaxRepeat.repeatMin = 0;
2140 ne.minMaxRepeat.repeatMax = 0;
2141
2142 ne.event_flags = 0;
2144
2145 SmartAction ac = SmartAction();
2148 ac.groupSpawn.minDelay = 0;
2149 ac.groupSpawn.maxDelay = 0;
2152
2154 ev.event = ne;
2155 ev.event_id = e.event_id;
2156 ev.target = e.target;
2157 ev.action = ac;
2158 InitTimer(ev);
2159 mStoredEvents.push_back(ev);
2160 }
2161 break;
2162 }
2164 {
2165 if (e.action.groupSpawn.minDelay == 0 && e.action.groupSpawn.maxDelay == 0)
2166 {
2167 bool const deleteRespawnTimes = ((e.action.groupSpawn.spawnflags & SMARTAI_SPAWN_FLAGS::SMARTAI_SPAWN_FLAG_NOSAVE_RESPAWN) != 0);
2168
2169 // Instant spawn
2170 GetBaseObject()->GetMap()->SpawnGroupDespawn(e.action.groupSpawn.groupId, deleteRespawnTimes);
2171 }
2172 else
2173 {
2174 // Delayed spawn (use values from parameter to schedule event to call us back
2175 SmartEvent ne = SmartEvent();
2177 ne.event_chance = 100;
2178
2181 ne.minMaxRepeat.repeatMin = 0;
2182 ne.minMaxRepeat.repeatMax = 0;
2183
2184 ne.event_flags = 0;
2186
2187 SmartAction ac = SmartAction();
2190 ac.groupSpawn.minDelay = 0;
2191 ac.groupSpawn.maxDelay = 0;
2194
2196 ev.event = ne;
2197 ev.event_id = e.event_id;
2198 ev.target = e.target;
2199 ev.action = ac;
2200 InitTimer(ev);
2201 mStoredEvents.push_back(ev);
2202 }
2203 break;
2204 }
2206 {
2207 if (!IsSmart())
2208 break;
2209
2210 ENSURE_AI(SmartAI, me->AI())->SetEvadeDisabled(e.action.disableEvade.disable != 0);
2211 break;
2212 }
2214 {
2215 if (!me->CanHaveThreatList())
2216 break;
2217 for (WorldObject* const target : targets)
2218 if (IsUnit(target))
2219 me->GetThreatManager().AddThreat(target->ToUnit(), float(e.action.threat.threatINC) - float(e.action.threat.threatDEC), nullptr, true, true);
2220 break;
2221 }
2223 {
2224 for (WorldObject* const target : targets)
2225 if (IsCreature(target))
2226 target->ToCreature()->LoadEquipment(e.action.loadEquipment.id, e.action.loadEquipment.force != 0);
2227 break;
2228 }
2230 {
2233 break;
2234 }
2236 {
2237 for (WorldObject* const target : targets)
2238 if (IsUnit(target))
2239 target->ToUnit()->PauseMovement(e.action.pauseMovement.pauseTimer, e.action.pauseMovement.movementSlot, e.action.pauseMovement.force);
2240 break;
2241 }
2243 {
2244 Map* map = nullptr;
2245 if (WorldObject* obj = GetBaseObject())
2246 map = obj->GetMap();
2247 else if (!targets.empty())
2248 map = targets.front()->GetMap();
2249
2250 if (map)
2252 else
2253 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);
2254 break;
2255 }
2257 {
2258 for (WorldObject* const target : targets)
2259 {
2260 if (IsCreature(target))
2261 {
2262 if (e.action.animKit.type == 0)
2263 target->ToCreature()->PlayOneShotAnimKitId(e.action.animKit.animKit);
2264 else if (e.action.animKit.type == 1)
2265 target->ToCreature()->SetAIAnimKitId(e.action.animKit.animKit);
2266 else if (e.action.animKit.type == 2)
2267 target->ToCreature()->SetMeleeAnimKitId(e.action.animKit.animKit);
2268 else if (e.action.animKit.type == 3)
2269 target->ToCreature()->SetMovementAnimKitId(e.action.animKit.animKit);
2270
2271 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_ANIMKIT: target: {} ({}), AnimKit: {}, Type: {}",
2272 target->GetName(), target->GetGUID().ToString(), e.action.animKit.animKit, e.action.animKit.type);
2273 }
2274 else if (IsGameObject(target))
2275 {
2276 switch (e.action.animKit.type)
2277 {
2278 case 0:
2279 target->ToGameObject()->SetAnimKitId(e.action.animKit.animKit, true);
2280 break;
2281 case 1:
2282 target->ToGameObject()->SetAnimKitId(e.action.animKit.animKit, false);
2283 break;
2284 default:
2285 break;
2286 }
2287
2288 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_ANIMKIT: target: {} ({}), AnimKit: {}, Type: {}",
2289 target->GetName(), target->GetGUID().ToString(), e.action.animKit.animKit, e.action.animKit.type);
2290 }
2291 }
2292
2293 break;
2294 }
2296 {
2297 for (WorldObject* const target : targets)
2298 if (Player* playerTarget = target->ToPlayer())
2299 playerTarget->GetSceneMgr().PlayScene(e.action.scene.sceneId);
2300
2301 break;
2302 }
2304 {
2305 for (WorldObject* const target : targets)
2306 if (Player* playerTarget = target->ToPlayer())
2307 playerTarget->GetSceneMgr().CancelSceneBySceneId(e.action.scene.sceneId);
2308
2309 break;
2310 }
2312 {
2313 for (WorldObject* target : targets)
2314 {
2315 if (!IsPlayer(target))
2316 continue;
2317
2318 target->ToPlayer()->SendCinematicStart(e.action.cinematic.entry);
2319 }
2320 break;
2321 }
2323 {
2324 uint32 speedInteger = e.action.movementSpeed.speedInteger;
2325 uint32 speedFraction = e.action.movementSpeed.speedFraction;
2326 float speed = float(speedInteger) + float(speedFraction) / std::pow(10, std::floor(std::log10(float(speedFraction ? speedFraction : 1)) + 1));
2327
2328 for (WorldObject* const target : targets)
2329 if (IsCreature(target))
2330 target->ToCreature()->SetSpeed(UnitMoveType(e.action.movementSpeed.movementType), speed);
2331
2332 break;
2333 }
2335 {
2336 for (WorldObject* const target : targets)
2337 {
2338 if (IsUnit(target))
2339 {
2340 target->ToUnit()->SendPlaySpellVisualKit(e.action.spellVisualKit.spellVisualKitId, e.action.spellVisualKit.kitType,
2342
2343 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_SPELL_VISUAL_KIT: target: {} ({}), SpellVisualKit: {}",
2344 target->GetName(), target->GetGUID().ToString(), e.action.spellVisualKit.spellVisualKitId);
2345 }
2346 }
2347
2348 break;
2349 }
2351 {
2352 if (WorldObject* obj = GetBaseObject())
2353 {
2355 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_OVERRIDE_LIGHT: {} sets zone override light (zoneId: {}, areaLightId: {}, overrideLightId: {}, transitionMilliseconds: {})",
2357 }
2358 break;
2359 }
2361 {
2362 if (WorldObject* obj = GetBaseObject())
2363 {
2365 TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_OVERRIDE_WEATHER: {} sets zone weather (zoneId: {}, weatherId: {}, intensity: {})",
2367 }
2368 break;
2369 }
2371 {
2372 for (WorldObject* target : targets)
2373 if (IsUnit(target))
2374 target->ToUnit()->SetHover(e.action.setHover.enable != 0);
2375 break;
2376 }
2378 {
2379 for (WorldObject* target : targets)
2380 if (Unit* targetUnit = target->ToUnit())
2381 targetUnit->SetHealth(targetUnit->CountPctFromMaxHealth(e.action.setHealthPct.percent));
2382 break;
2383 }
2385 {
2386 WorldObject* baseObject = GetBaseObject();
2387
2388 for (WorldObject* const target : targets)
2389 {
2390 if (Player* playerTarget = target->ToPlayer())
2391 {
2392 Conversation* conversation = Conversation::CreateConversation(e.action.conversation.id, playerTarget,
2393 *playerTarget, playerTarget->GetGUID(), nullptr);
2394 if (!conversation)
2395 TC_LOG_WARN("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CREATE_CONVERSATION: id {}, baseObject {}, target {} - failed to create conversation",
2396 e.action.conversation.id, !baseObject ? "" : baseObject->GetName().c_str(), playerTarget->GetName());
2397 }
2398 }
2399
2400 break;
2401 }
2403 {
2404 for (WorldObject* target : targets)
2405 {
2406 if (IsUnit(target))
2407 {
2409 target->ToUnit()->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
2410 else
2411 target->ToUnit()->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
2412 }
2413 }
2414 break;
2415 }
2417 {
2418 for (WorldObject* target : targets)
2419 {
2420 if (IsUnit(target))
2421 {
2423 target->ToUnit()->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
2424 else
2425 target->ToUnit()->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
2426 }
2427 }
2428 break;
2429 }
2431 {
2432 for (WorldObject* target : targets)
2433 {
2434 if (IsUnit(target))
2435 {
2436 target->ToUnit()->SetUninteractible(e.action.setUninteractible.uninteractible != 0);
2437 }
2438 }
2439 break;
2440 }
2442 {
2443 for (WorldObject* target : targets)
2444 {
2445 if (GameObject* targetGo = target->ToGameObject())
2446 {
2448 }
2449 }
2450 break;
2451 }
2453 {
2454 if (!targets.empty())
2456 else
2457 {
2458 WorldObject* baseObject = GetBaseObject();
2459 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",
2460 e.action.addToStoredTargets.id, !baseObject ? "" : baseObject->GetName().c_str(), e.event_id);
2461 }
2462 break;
2463 }
2465 {
2466 WorldObject* baseObject = GetBaseObject();
2467
2468 auto doCreatePersonalClone = [&](Position const& position, Player* privateObjectOwner)
2469 {
2471 if (IsSmart(summon))
2472 ENSURE_AI(SmartAI, summon->AI())->SetTimedActionList(e, e.entryOrGuid, privateObjectOwner, e.event_id + 1);
2473 };
2474
2475 // if target is position then targets container was empty
2477 {
2478 for (WorldObject* target : targets)
2479 if (Player* playerTarget = Object::ToPlayer(target))
2480 doCreatePersonalClone(baseObject->GetPosition(), playerTarget);
2481 }
2482 else
2483 {
2484 if (Player* invoker = Object::ToPlayer(GetLastInvoker()))
2485 doCreatePersonalClone({ e.target.x, e.target.y, e.target.z, e.target.o }, invoker);
2486 }
2487
2488 // action list will continue on personal clones
2489 Trinity::Containers::EraseIf(mTimedActionList, [e](SmartScriptHolder const& script) { return script.event_id > e.event_id; });
2490 break;
2491 }
2493 {
2494 WorldObject* sourceObject = GetBaseObjectOrUnitInvoker(unit);
2495 for (WorldObject* target : targets)
2496 {
2498 GameEvents::Trigger(e.action.triggerGameEvent.eventId, target, sourceObject);
2499 else
2500 GameEvents::Trigger(e.action.triggerGameEvent.eventId, sourceObject, target);
2501 }
2502
2503 break;
2504 }
2506 {
2507 for (WorldObject* target : targets)
2508 {
2509 if (Unit* unitTarget = Object::ToUnit(target))
2510 {
2511 if (unitTarget->GetAI())
2512 unitTarget->GetAI()->DoAction(e.action.doAction.actionId);
2513 }
2514 else if (GameObject* goTarget = Object::ToGameObject(target))
2515 {
2516 if (goTarget->AI())
2517 goTarget->AI()->DoAction(e.action.doAction.actionId);
2518 }
2519 }
2520
2521 break;
2522 }
2523 default:
2524 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2525 break;
2526 }
2527
2528 if (e.link && e.link != e.event_id)
2529 {
2531 if (linked)
2532 ProcessEvent(linked, unit, var0, var1, bvar, spell, gob, varString);
2533 else
2534 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);
2535 }
2536}
2537
2538void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob, std::string const& varString)
2539{
2540 // 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
2541 if (sConditionMgr->IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
2542 {
2543 RecalcTimer(e, min, max);
2544 ProcessAction(e, unit, var0, var1, bvar, spell, gob, varString);
2545 }
2546 else
2547 RecalcTimer(e, std::min<uint32>(min, 5000), std::min<uint32>(min, 5000));
2548}
2549
2550SmartScriptHolder 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, uint32 action_param7, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
2551{
2552 SmartScriptHolder script;
2553 script.event.type = e;
2554 script.event.raw.param1 = event_param1;
2555 script.event.raw.param2 = event_param2;
2556 script.event.raw.param3 = event_param3;
2557 script.event.raw.param4 = event_param4;
2558 script.event.raw.param5 = event_param5;
2559 script.event.event_phase_mask = phaseMask;
2560 script.event.event_flags = event_flags;
2561 script.event.event_chance = 100;
2562
2563 script.action.type = action;
2564 script.action.raw.param1 = action_param1;
2565 script.action.raw.param2 = action_param2;
2566 script.action.raw.param3 = action_param3;
2567 script.action.raw.param4 = action_param4;
2568 script.action.raw.param5 = action_param5;
2569 script.action.raw.param6 = action_param6;
2570 script.action.raw.param7 = action_param7;
2571
2572 script.target.type = t;
2573 script.target.raw.param1 = target_param1;
2574 script.target.raw.param2 = target_param2;
2575 script.target.raw.param3 = target_param3;
2576 script.target.raw.param4 = target_param4;
2577
2579 InitTimer(script);
2580 return script;
2581}
2582
2583void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, WorldObject* invoker /*= nullptr*/) const
2584{
2585 WorldObject* scriptTrigger = nullptr;
2586 if (invoker)
2587 scriptTrigger = invoker;
2588 else if (Unit* tempLastInvoker = GetLastInvoker())
2589 scriptTrigger = tempLastInvoker;
2590
2591 WorldObject* baseObject = GetBaseObject();
2592 switch (e.GetTargetType())
2593 {
2594 case SMART_TARGET_SELF:
2595 if (baseObject)
2596 targets.push_back(baseObject);
2597 break;
2599 if (me)
2600 if (Unit* victim = me->GetVictim())
2601 targets.push_back(victim);
2602 break;
2604 if (me)
2605 {
2607 {
2609 targets.push_back(u);
2610 }
2612 targets.push_back(u);
2613 }
2614 break;
2616 if (me)
2617 {
2619 {
2621 targets.push_back(u);
2622 }
2624 targets.push_back(u);
2625 }
2626 break;
2628 if (me)
2629 {
2631 {
2633 targets.push_back(u);
2634 }
2636 targets.push_back(u);
2637 }
2638 break;
2640 if (me)
2641 {
2643 {
2645 targets.push_back(u);
2646 }
2648 targets.push_back(u);
2649 }
2650 break;
2652 if (me)
2653 {
2655 targets.push_back(u);
2656 }
2657 break;
2659 if (scriptTrigger)
2660 targets.push_back(scriptTrigger);
2661 break;
2663 if (scriptTrigger && scriptTrigger->ToUnit() && scriptTrigger->ToUnit()->GetVehicle() && scriptTrigger->ToUnit()->GetVehicle()->GetBase())
2664 targets.push_back(scriptTrigger->ToUnit()->GetVehicle()->GetBase());
2665 break;
2667 if (scriptTrigger)
2668 {
2669 if (Player* player = scriptTrigger->ToPlayer())
2670 {
2671 if (Group* group = player->GetGroup())
2672 {
2673 for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
2674 if (Player* member = groupRef->GetSource())
2675 if (member->IsInMap(player))
2676 targets.push_back(member);
2677 }
2678 // We still add the player to the list if there is no group. If we do
2679 // this even if there is a group (thus the else-check), it will add the
2680 // same player to the list twice. We don't want that to happen.
2681 else
2682 targets.push_back(scriptTrigger);
2683 }
2684 }
2685 break;
2687 {
2688 WorldObject* ref = baseObject;
2689 if (!ref)
2690 ref = scriptTrigger;
2691
2692 if (!ref)
2693 {
2694 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CREATURE_RANGE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2696 break;
2697 }
2698
2699 ObjectVector units;
2700 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitRange.maxDist));
2701
2702 for (WorldObject* unit : units)
2703 {
2704 if (!IsCreature(unit))
2705 continue;
2706
2707 if (me && me->GetGUID() == unit->GetGUID())
2708 continue;
2709
2710 if ((!e.target.unitRange.creature || unit->ToCreature()->GetEntry() == e.target.unitRange.creature) && ref->IsInRange(unit, float(e.target.unitRange.minDist), float(e.target.unitRange.maxDist)))
2711 targets.push_back(unit);
2712 }
2713
2714 if (e.target.unitRange.maxSize)
2716 break;
2717 }
2719 {
2720 ObjectVector units;
2721 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitDistance.dist));
2722
2723 for (WorldObject* unit : units)
2724 {
2725 if (!IsCreature(unit))
2726 continue;
2727
2728 if (me && me->GetGUID() == unit->GetGUID())
2729 continue;
2730
2731 if (!e.target.unitDistance.creature || unit->ToCreature()->GetEntry() == e.target.unitDistance.creature)
2732 targets.push_back(unit);
2733 }
2734
2737 break;
2738 }
2740 {
2741 ObjectVector units;
2742 GetWorldObjectsInDist(units, static_cast<float>(e.target.goDistance.dist));
2743
2744 for (WorldObject* unit : units)
2745 {
2746 if (!IsGameObject(unit))
2747 continue;
2748
2749 if (go && go->GetGUID() == unit->GetGUID())
2750 continue;
2751
2752 if (!e.target.goDistance.entry || unit->ToGameObject()->GetEntry() == e.target.goDistance.entry)
2753 targets.push_back(unit);
2754 }
2755
2758 break;
2759 }
2761 {
2762 WorldObject* ref = baseObject;
2763 if (!ref)
2764 ref = scriptTrigger;
2765
2766 if (!ref)
2767 {
2768 TC_LOG_ERROR("sql.sql", "SMART_TARGET_GAMEOBJECT_RANGE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2770 break;
2771 }
2772
2773 ObjectVector units;
2774 GetWorldObjectsInDist(units, static_cast<float>(e.target.goRange.maxDist));
2775
2776 for (WorldObject* unit : units)
2777 {
2778 if (!IsGameObject(unit))
2779 continue;
2780
2781 if (go && go->GetGUID() == unit->GetGUID())
2782 continue;
2783
2784 if ((!e.target.goRange.entry || unit->ToGameObject()->GetEntry() == e.target.goRange.entry) && ref->IsInRange(unit, float(e.target.goRange.minDist), float(e.target.goRange.maxDist)))
2785 targets.push_back(unit);
2786 }
2787
2788 if (e.target.goRange.maxSize)
2790 break;
2791 }
2793 {
2794 if (!scriptTrigger && !baseObject)
2795 {
2796 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CREATURE_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2798 break;
2799 }
2800
2801 if (Creature* target = FindCreatureNear(scriptTrigger ? scriptTrigger : baseObject, e.target.unitGUID.dbGuid))
2802 if (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry)
2803 targets.push_back(target);
2804 break;
2805 }
2807 {
2808 if (!scriptTrigger && !baseObject)
2809 {
2810 TC_LOG_ERROR("sql.sql", "SMART_TARGET_GAMEOBJECT_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2812 break;
2813 }
2814
2815 if (GameObject* target = FindGameObjectNear(scriptTrigger ? scriptTrigger : baseObject, e.target.goGUID.dbGuid))
2816 if (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry)
2817 targets.push_back(target);
2818 break;
2819 }
2821 {
2822 ObjectVector units;
2823 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerRange.maxDist));
2824
2825 if (!units.empty() && baseObject)
2826 for (WorldObject* unit : units)
2827 if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
2828 targets.push_back(unit);
2829 break;
2830 }
2832 {
2833 ObjectVector units;
2834 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerDistance.dist));
2835
2836 for (WorldObject* unit : units)
2837 if (IsPlayer(unit))
2838 targets.push_back(unit);
2839 break;
2840 }
2842 {
2843 WorldObject* ref = baseObject;
2844 if (!ref)
2845 ref = scriptTrigger;
2846
2847 if (!ref)
2848 {
2849 TC_LOG_ERROR("sql.sql", "SMART_TARGET_STORED: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2851 break;
2852 }
2853
2854 if (ObjectVector const* stored = GetStoredTargetVector(e.target.stored.id, *ref))
2855 targets.assign(stored->begin(), stored->end());
2856 break;
2857 }
2859 {
2860 WorldObject* ref = baseObject;
2861 if (!ref)
2862 ref = scriptTrigger;
2863
2864 if (!ref)
2865 {
2866 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CLOSEST_CREATURE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2868 break;
2869 }
2870
2872 targets.push_back(target);
2873 break;
2874 }
2876 {
2877 WorldObject* ref = baseObject;
2878 if (!ref)
2879 ref = scriptTrigger;
2880
2881 if (!ref)
2882 {
2883 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CLOSEST_GAMEOBJECT: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2885 break;
2886 }
2887
2889 targets.push_back(target);
2890 break;
2891 }
2893 {
2894 WorldObject* ref = baseObject;
2895 if (!ref)
2896 ref = scriptTrigger;
2897
2898 if (!ref)
2899 {
2900 TC_LOG_ERROR("sql.sql", "SMART_TARGET_CLOSEST_PLAYER: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
2902 break;
2903 }
2904
2905 if (Player* target = ref->SelectNearestPlayer(float(e.target.playerDistance.dist)))
2906 targets.push_back(target);
2907 break;
2908 }
2910 {
2911 if (me)
2912 {
2913 ObjectGuid charmerOrOwnerGuid = me->GetCharmerOrOwnerGUID();
2914
2915 if (!charmerOrOwnerGuid)
2916 if (TempSummon* tempSummon = me->ToTempSummon())
2917 if (WorldObject* summoner = tempSummon->GetSummoner())
2918 charmerOrOwnerGuid = summoner->GetGUID();
2919
2920 if (!charmerOrOwnerGuid)
2921 charmerOrOwnerGuid = me->GetCreatorGUID();
2922
2923 if (WorldObject* owner = ObjectAccessor::GetWorldObject(*me, charmerOrOwnerGuid))
2924 targets.push_back(owner);
2925 }
2926 else if (go)
2927 {
2928 if (Unit* owner = ObjectAccessor::GetUnit(*go, go->GetOwnerGUID()))
2929 targets.push_back(owner);
2930 }
2931
2932 // Get owner of owner
2933 if (e.target.owner.useCharmerOrOwner && !targets.empty())
2934 {
2935 WorldObject* owner = targets.front();
2936 targets.clear();
2937
2938 if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->GetCharmerOrOwnerGUID()))
2939 targets.push_back(base);
2940 }
2941 break;
2942 }
2944 {
2945 if (me && me->CanHaveThreatList())
2946 for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
2947 if (!e.target.threatList.maxDist || me->IsWithinCombatRange(ref->GetVictim(), float(e.target.threatList.maxDist)))
2948 targets.push_back(ref->GetVictim());
2949 break;
2950 }
2952 {
2953 if (me)
2955 targets.push_back(target);
2956 break;
2957 }
2959 {
2960 if (me)
2962 targets.push_back(target);
2963 break;
2964 }
2966 {
2967 if (me)
2968 for (ObjectGuid tapperGuid : me->GetTapList())
2969 if (Player* tapper = ObjectAccessor::GetPlayer(*me, tapperGuid))
2970 targets.push_back(tapper);
2971
2972 break;
2973 }
2975 {
2976 if (me && me->IsVehicle())
2977 for (std::pair<int8 const, VehicleSeat>& seat : me->GetVehicleKit()->Seats)
2978 if (!e.target.vehicle.seatMask || (e.target.vehicle.seatMask & (1 << seat.first)))
2979 if (Unit* u = ObjectAccessor::GetUnit(*me, seat.second.Passenger.Guid))
2980 targets.push_back(u);
2981 break;
2982 }
2984 {
2985 if (GameObject* target = baseObject->FindNearestUnspawnedGameObject(e.target.goClosest.entry, float(e.target.goClosest.dist ? e.target.goClosest.dist : 100)))
2986 targets.push_back(target);
2987 break;
2988 }
2990 case SMART_TARGET_NONE:
2991 default:
2992 break;
2993 }
2994}
2995
2996void SmartScript::GetWorldObjectsInDist(ObjectVector& targets, float dist) const
2997{
2998 WorldObject* obj = GetBaseObject();
2999 if (!obj)
3000 return;
3001
3002 Trinity::AllWorldObjectsInRange u_check(obj, dist);
3004 Cell::VisitAllObjects(obj, searcher, dist);
3005}
3006
3007void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob, std::string const& varString)
3008{
3009 if (!e.active && e.GetEventType() != SMART_EVENT_LINK)
3010 return;
3011
3013 return;
3014
3016 return;
3017
3018 switch (e.GetEventType())
3019 {
3020 case SMART_EVENT_LINK://special handling
3021 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
3022 break;
3023 //called from Update tick
3024 case SMART_EVENT_UPDATE:
3026 break;
3028 if (me && me->IsEngaged())
3029 return;
3031 break;
3033 if (!me || !me->IsEngaged())
3034 return;
3036 break;
3038 {
3039 if (!me || !me->IsEngaged() || !me->GetMaxHealth())
3040 return;
3041 uint32 perc = (uint32)me->GetHealthPct();
3042 if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
3043 return;
3045 break;
3046 }
3048 {
3049 if (!me || !me->IsEngaged() || !me->GetMaxPower(POWER_MANA))
3050 return;
3052 if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
3053 return;
3055 break;
3056 }
3057 case SMART_EVENT_RANGE:
3058 {
3059 if (!me || !me->IsEngaged() || !me->GetVictim())
3060 return;
3061
3062 if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
3064 else // make it predictable
3065 RecalcTimer(e, 500, 500);
3066 break;
3067 }
3069 {
3070 if (!me || !me->IsEngaged())
3071 return;
3072
3073 Unit* victim = me->GetVictim();
3074
3075 if (!victim || !victim->IsNonMeleeSpellCast(false, false, true))
3076 return;
3077
3078 if (e.event.targetCasting.spellId > 0)
3079 if (Spell* currSpell = victim->GetCurrentSpell(CURRENT_GENERIC_SPELL))
3080 if (currSpell->m_spellInfo->Id != e.event.targetCasting.spellId)
3081 return;
3082
3084 break;
3085 }
3087 {
3088 if (!me || !me->IsEngaged())
3089 return;
3090
3091 std::vector<Creature*> creatures;
3092 DoFindFriendlyCC(creatures, float(e.event.friendlyCC.radius));
3093 if (creatures.empty())
3094 {
3095 // if there are at least two same npcs, they will perform the same action immediately even if this is useless...
3096 RecalcTimer(e, 1000, 3000);
3097 return;
3098 }
3100 break;
3101 }
3103 {
3104 std::vector<Creature*> creatures;
3106
3107 if (creatures.empty())
3108 return;
3109
3111 break;
3112 }
3114 {
3115 if (!me)
3116 return;
3117 uint32 count = me->GetAuraCount(e.event.aura.spell);
3118 if ((!e.event.aura.count && !count) || (e.event.aura.count && count >= e.event.aura.count))
3120 break;
3121 }
3123 {
3124 if (!me || !me->GetVictim())
3125 return;
3127 if (count < e.event.aura.count)
3128 return;
3130 break;
3131 }
3133 {
3134 if (bvar == (e.event.charm.onRemove != 1))
3135 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
3136 break;
3137 }
3142 {
3143 ProcessAction(e, unit);
3144 break;
3145 }
3147 {
3148 if (var0 == (e.event.questObjective.id))
3149 ProcessAction(e, unit);
3150 break;
3151 }
3152 //no params
3153 case SMART_EVENT_AGGRO:
3154 case SMART_EVENT_DEATH:
3155 case SMART_EVENT_EVADE:
3162 case SMART_EVENT_RESET:
3168 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
3169 break;
3171 switch (e.event.gossipHello.filter)
3172 {
3173 case 0:
3174 // no filter set, always execute action
3175 break;
3176 case 1:
3177 // OnGossipHello only filter set, skip action if OnReportUse
3178 if (var0)
3179 return;
3180 break;
3181 case 2:
3182 // OnReportUse only filter set, skip action if OnGossipHello
3183 if (!var0)
3184 return;
3185 break;
3186 default:
3187 // Ignore any other value
3188 break;
3189 }
3190
3191 ProcessAction(e, unit, var0, var1, bvar, spell, gob);
3192 break;
3194 if (e.event.emote.emote == var0)
3195 {
3196 RecalcTimer(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax);
3197 ProcessAction(e, unit);
3198 }
3199 break;
3200 case SMART_EVENT_KILL:
3201 {
3202 if (!me || !unit)
3203 return;
3204 if (e.event.kill.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
3205 return;
3206 if (e.event.kill.creature && unit->GetEntry() != e.event.kill.creature)
3207 return;
3209 ProcessAction(e, unit);
3210 break;
3211 }
3214 {
3215 if (!spell)
3216 return;
3217 if ((!e.event.spellHit.spell || spell->Id == e.event.spellHit.spell) &&
3218 (!e.event.spellHit.school || (spell->SchoolMask & e.event.spellHit.school)))
3219 {
3221 ProcessAction(e, unit, 0, 0, bvar, spell, gob);
3222 }
3223 break;
3224 }
3228 {
3229 if (!spell)
3230 return;
3231
3232 if (spell->Id != e.event.spellCast.spell)
3233 return;
3234
3236 ProcessAction(e, nullptr, 0, 0, bvar, spell);
3237 break;
3238 }
3240 {
3241 if (!me || me->IsEngaged())
3242 return;
3243 //can trigger if closer than fMaxAllowedRange
3244 float range = (float)e.event.los.maxDist;
3245
3246 //if range is ok and we are actually in LOS
3247 if (me->IsWithinDistInMap(unit, range) && me->IsWithinLOSInMap(unit))
3248 {
3250 //if friendly event&&who is not hostile OR hostile event&&who is hostile
3251 if ((hostilityMode == SmartEvent::LOSHostilityMode::Any) ||
3252 (hostilityMode == SmartEvent::LOSHostilityMode::NotHostile && !me->IsHostileTo(unit)) ||
3253 (hostilityMode == SmartEvent::LOSHostilityMode::Hostile && me->IsHostileTo(unit)))
3254 {
3255 if (e.event.los.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
3256 return;
3258 ProcessAction(e, unit);
3259 }
3260 }
3261 break;
3262 }
3263 case SMART_EVENT_IC_LOS:
3264 {
3265 if (!me || !me->IsEngaged())
3266 return;
3267 //can trigger if closer than fMaxAllowedRange
3268 float range = (float)e.event.los.maxDist;
3269
3270 //if range is ok and we are actually in LOS
3271 if (me->IsWithinDistInMap(unit, range) && me->IsWithinLOSInMap(unit))
3272 {
3274 //if friendly event&&who is not hostile OR hostile event&&who is hostile
3275 if ((hostilityMode == SmartEvent::LOSHostilityMode::Any) ||
3276 (hostilityMode == SmartEvent::LOSHostilityMode::NotHostile && !me->IsHostileTo(unit)) ||
3277 (hostilityMode == SmartEvent::LOSHostilityMode::Hostile && me->IsHostileTo(unit)))
3278 {
3279 if (e.event.los.playerOnly && unit->GetTypeId() != TYPEID_PLAYER)
3280 return;
3282 ProcessAction(e, unit);
3283 }
3284 }
3285 break;
3286 }
3288 {
3289 if (!GetBaseObject())
3290 return;
3292 return;
3294 return;
3295 ProcessAction(e);
3296 break;
3297 }
3300 {
3301 if (!IsCreature(unit))
3302 return;
3303 if (e.event.summoned.creature && unit->GetEntry() != e.event.summoned.creature)
3304 return;
3306 ProcessAction(e, unit);
3307 break;
3308 }
3312 {
3313 if (var0 > e.event.minMaxRepeat.max || var0 < e.event.minMaxRepeat.min)
3314 return;
3316 ProcessAction(e, unit);
3317 break;
3318 }
3320 {
3321 if ((e.event.movementInform.type && var0 != e.event.movementInform.type) || (e.event.movementInform.id != 0xFFFFFFFF && var1 != e.event.movementInform.id))
3322 return;
3323 ProcessAction(e, unit, var0, var1);
3324 break;
3325 }
3327 {
3329 return;
3330 ProcessAction(e, unit, var0);
3331 break;
3332 }
3338 {
3339 if (!me || (e.event.waypoint.pointID != 0xFFFFFFFF && var0 != e.event.waypoint.pointID) || (e.event.waypoint.pathID && var1 != e.event.waypoint.pathID))
3340 return;
3341 ProcessAction(e, unit);
3342 break;
3343 }
3345 {
3346 if (e.event.summoned.creature && e.event.summoned.creature != var0)
3347 return;
3349 ProcessAction(e, unit, var0);
3350 break;
3351 }
3353 {
3355 return;
3357 ProcessAction(e, unit, var0);
3358 break;
3359 }
3362 {
3363 if (e.event.quest.quest && var0 != e.event.quest.quest)
3364 return;
3365 RecalcTimer(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax);
3366 ProcessAction(e, unit, var0);
3367 break;
3368 }
3370 {
3372 return;
3373 ProcessAction(e, unit, var0);
3374 break;
3375 }
3377 {
3378 if (e.event.areatrigger.id && var0 != e.event.areatrigger.id)
3379 return;
3380 ProcessAction(e, unit, var0);
3381 break;
3382 }
3384 {
3386 return;
3387 ProcessAction(e, unit, var0);
3388 break;
3389 }
3391 {
3392 if (e.event.dataSet.id != var0 || e.event.dataSet.value != var1)
3393 return;
3395 ProcessAction(e, unit, var0, var1);
3396 break;
3397 }
3400 {
3401 if (!unit)
3402 return;
3404 ProcessAction(e, unit);
3405 break;
3406 }
3408 {
3409 if (e.event.timedEvent.id == var0)
3410 ProcessAction(e, unit);
3411 break;
3412 }
3414 {
3415 TC_LOG_DEBUG("scripts.ai", "SmartScript: Gossip Select: menu {} action {}", var0, var1);//little help for scripters
3416 if (e.event.gossip.sender != var0 || e.event.gossip.action != var1)
3417 return;
3418 ProcessAction(e, unit, var0, var1);
3419 break;
3420 }
3423 {
3424 if (e.event.gameEvent.gameEventId != var0)
3425 return;
3426 ProcessAction(e, nullptr, var0);
3427 break;
3428 }
3430 {
3431 if (e.event.goLootStateChanged.lootState != var0)
3432 return;
3433 ProcessAction(e, unit, var0, var1);
3434 break;
3435 }
3437 {
3438 if (e.event.eventInform.eventId != var0)
3439 return;
3440 ProcessAction(e, nullptr, var0);
3441 break;
3442 }
3444 {
3445 if (e.event.doAction.eventId != var0)
3446 return;
3447 ProcessAction(e, unit, var0);
3448 break;
3449 }
3451 {
3452 if (!me || !me->IsEngaged())
3453 return;
3454
3455 Unit* unitTarget = nullptr;
3456 switch (e.GetTargetType())
3457 {
3465 {
3466 ObjectVector targets;
3467 GetTargets(targets, e);
3468
3469 for (WorldObject* target : targets)
3470 {
3471 if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat())
3472 {
3473 uint32 healthPct = uint32(target->ToUnit()->GetHealthPct());
3474 if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct)
3475 continue;
3476
3477 unitTarget = target->ToUnit();
3478 break;
3479 }
3480 }
3481 break;
3482 }
3485 break;
3486 default:
3487 return;
3488 }
3489
3490 if (!unitTarget)
3491 return;
3492
3494 break;
3495 }
3497 {
3498 if (!me)
3499 return;
3500
3501 Creature* creature = nullptr;
3502
3503 if (e.event.distance.guid != 0)
3504 {
3505 creature = FindCreatureNear(me, e.event.distance.guid);
3506 if (!creature)
3507 return;
3508
3509 if (!me->IsInRange(creature, 0, static_cast<float>(e.event.distance.dist)))
3510 return;
3511 }
3512 else if (e.event.distance.entry != 0)
3513 {
3514 std::list<Creature*> list;
3515 me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, static_cast<float>(e.event.distance.dist));
3516
3517 if (!list.empty())
3518 creature = list.front();
3519 }
3520
3521 if (creature)
3523
3524 break;
3525 }
3527 {
3528 if (!me)
3529 return;
3530
3531 GameObject* gameobject = nullptr;
3532
3533 if (e.event.distance.guid != 0)
3534 {
3535 gameobject = FindGameObjectNear(me, e.event.distance.guid);
3536 if (!gameobject)
3537 return;
3538
3539 if (!me->IsInRange(gameobject, 0, static_cast<float>(e.event.distance.dist)))
3540 return;
3541 }
3542 else if (e.event.distance.entry != 0)
3543 {
3544 std::list<GameObject*> list;
3545 me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, static_cast<float>(e.event.distance.dist));
3546
3547 if (!list.empty())
3548 gameobject = list.front();
3549 }
3550
3551 if (gameobject)
3552 ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat, nullptr, 0, 0, false, nullptr, gameobject);
3553
3554 break;
3555 }
3557 if (e.event.counter.id != var0 || GetCounterValue(e.event.counter.id) != e.event.counter.value)
3558 return;
3559
3561 break;
3565 {
3566 ProcessAction(e, unit);
3567 break;
3568 }
3570 {
3571 if (e.event.param_string != varString)
3572 return;
3573
3574 ProcessAction(e, unit, var0, 0, false, nullptr, nullptr, varString);
3575 break;
3576 }
3577 default:
3578 TC_LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type {}", e.GetEventType());
3579 break;
3580 }
3581}
3582
3584{
3585 switch (e.GetEventType())
3586 {
3587 //set only events which have initial timers
3588 case SMART_EVENT_UPDATE:
3592 break;
3596 break;
3597 default:
3598 e.active = true;
3599 break;
3600 }
3601}
3603{
3604 // min/max was checked at loading!
3605 e.timer = urand(min, max);
3606 e.active = e.timer ? false : true;
3607}
3608
3610{
3611 if (e.GetEventType() == SMART_EVENT_LINK)
3612 return;
3613
3615 return;
3616
3617 if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsEngaged()))
3618 return;
3619
3620 if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsEngaged())) //can be used with me=nullptr (go script)
3621 return;
3622
3623 if (e.timer < diff)
3624 {
3625 // delay spell cast event if another spell is being cast
3627 {
3629 {
3631 {
3632 RaisePriority(e);
3633 return;
3634 }
3635 }
3636 }
3637
3638 // Delay flee for assist event if stunned or rooted
3640 {
3642 {
3643 e.timer = 1;
3644 return;
3645 }
3646 }
3647
3648 e.active = true;//activate events with cooldown
3649
3650 switch (e.GetEventType())//process ONLY timed events
3651 {
3652 case SMART_EVENT_UPDATE:
3657 case SMART_EVENT_RANGE:
3666 {
3668 {
3669 Unit* invoker = nullptr;
3672 ProcessEvent(e, invoker);
3673 e.enableTimed = false;//disable event if it is in an ActionList and was processed once
3674 for (SmartScriptHolder& scriptholder : mTimedActionList)
3675 {
3676 //find the first event which is not the current one and enable it
3677 if (scriptholder.event_id > e.event_id)
3678 {
3679 scriptholder.enableTimed = true;
3680 break;
3681 }
3682 }
3683 }
3684 else
3685 ProcessEvent(e);
3686 break;
3687 }
3688 }
3689
3691 {
3692 // Reset priority to default one only if the event hasn't been rescheduled again to next loop
3693 if (e.timer > 1)
3694 {
3695 // Re-sort events if this was moved to the top of the queue
3696 mEventSortingRequired = true;
3697 // Reset priority to default one
3699 }
3700 }
3701 }
3702 else
3703 e.timer -= diff;
3704}
3705
3707{
3708 return e.active;
3709}
3710
3712{
3713 if (!mInstallEvents.empty())
3714 {
3715 for (SmartScriptHolder& installevent : mInstallEvents)
3716 mEvents.push_back(installevent);//must be before UpdateTimers
3717
3718 mInstallEvents.clear();
3719 }
3720}
3721
3723{
3724 if (!mStoredEvents.empty())
3725 {
3726 for (auto i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
3727 {
3728 if (i->event_id == id)
3729 {
3730 mStoredEvents.erase(i);
3731 return;
3732 }
3733 }
3734 }
3735}
3736
3738{
3739 WorldObject* obj = nullptr;
3740 if (me)
3741 obj = me;
3742 else if (go)
3743 obj = go;
3744 else if (areaTrigger)
3745 obj = areaTrigger;
3746 else if (player)
3747 obj = player;
3748 return obj;
3749}
3750
3752{
3753 return Coalesce<WorldObject>(GetBaseObject(), invoker);
3754}
3755
3757{
3758 return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
3759}
3760
3762{
3763 return obj && obj->GetTypeId() == TYPEID_PLAYER;
3764}
3765
3767{
3768 return obj && obj->GetTypeId() == TYPEID_UNIT;
3769}
3770
3772{
3773 if (!obj)
3774 return false;
3775
3776 if (Creature* creatureObj = obj->ToCreature())
3777 return creatureObj->IsCharmed();
3778
3779 return false;
3780}
3781
3783{
3784 return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
3785}
3786
3788{
3793 && !GetBaseObject())
3794 return;
3795
3796 // Don't run any action while evading
3797 if (me && me->IsInEvadeMode())
3798 {
3799 // Check if the timed action list finished and clear it if so.
3800 // This is required by SMART_ACTION_CALL_TIMED_ACTIONLIST failing if mTimedActionList is not empty.
3801 if (!mTimedActionList.empty())
3802 {
3803 bool needCleanup = true;
3804 for (SmartScriptHolder& scriptholder : mTimedActionList)
3805 {
3806 if (scriptholder.enableTimed)
3807 needCleanup = false;
3808 }
3809
3810 if (needCleanup)
3811 mTimedActionList.clear();
3812 }
3813
3814 return;
3815 }
3816
3817 InstallEvents();//before UpdateTimers
3818
3820 {
3822 mEventSortingRequired = false;
3823 }
3824
3825 for (SmartScriptHolder& mEvent : mEvents)
3826 UpdateTimer(mEvent, diff);
3827
3828 if (!mStoredEvents.empty())
3829 {
3830 SmartAIEventStoredList::iterator i, icurr;
3831 for (i = mStoredEvents.begin(); i != mStoredEvents.end();)
3832 {
3833 icurr = i++;
3834 UpdateTimer(*icurr, diff);
3835 }
3836 }
3837
3838 bool needCleanup = true;
3839 if (!mTimedActionList.empty())
3840 {
3842
3843 for (size_t i = 0; i < mTimedActionList.size(); ++i)
3844 {
3845 SmartScriptHolder& scriptHolder = mTimedActionList[i];
3846 if (scriptHolder.enableTimed)
3847 {
3848 UpdateTimer(scriptHolder, diff);
3849 needCleanup = false;
3850 }
3851 }
3852
3854 }
3855
3856 if (needCleanup)
3857 mTimedActionList.clear();
3858
3859 if (!mRemIDs.empty())
3860 {
3861 for (auto i : mRemIDs)
3863
3864 mRemIDs.clear();
3865 }
3866
3867 if (mUseTextTimer && me)
3868 {
3869 if (mTextTimer < diff)
3870 {
3871 uint32 textID = mLastTextID;
3872 mLastTextID = 0;
3873 uint32 entry = mTalkerEntry;
3874 mTalkerEntry = 0;
3875 mTextTimer = 0;
3876 mUseTextTimer = false;
3877 ProcessEventsFor(SMART_EVENT_TEXT_OVER, nullptr, textID, entry);
3878 } else mTextTimer -= diff;
3879 }
3880}
3881
3883{
3884 std::sort(events.begin(), events.end());
3885}
3886
3888{
3889 e.timer = 1;
3890 // Change priority only if it's set to default, otherwise keep the current order of events
3892 {
3894 mEventSortingRequired = true;
3895 }
3896}
3897
3898void SmartScript::RetryLater(SmartScriptHolder& e, bool ignoreChanceRoll)
3899{
3900 RaisePriority(e);
3901
3902 // This allows to retry the action later without rolling again the chance roll (which might fail and end up not executing the action)
3903 if (ignoreChanceRoll)
3905
3906 e.runOnce = false;
3907}
3908
3909void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* quest, uint32 event)
3910{
3911 if (e.empty())
3912 {
3913 if (obj)
3914 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Entry {} is empty but is using SmartScript.", obj->GetEntry());
3915 if (at)
3916 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for AreaTrigger {} is empty but is using SmartScript.", at->ID);
3917 if (scene)
3918 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for SceneId {} is empty but is using SmartScript.", scene->SceneId);
3919 if (quest)
3920 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Quest {} is empty but is using SmartScript.", quest->GetQuestId());
3921 if (event)
3922 TC_LOG_DEBUG("scripts.ai", "SmartScript: EventMap for Event {} is empty but is using SmartScript.", event);
3923 return;
3924 }
3925 for (SmartScriptHolder& scriptholder : e)
3926 {
3927 #ifndef TRINITY_DEBUG
3928 if (scriptholder.event.event_flags & SMART_EVENT_FLAG_DEBUG_ONLY)
3929 continue;
3930 #endif
3931
3932 if (obj && scriptholder.Difficulties.size())
3933 {
3934 bool foundValidDifficulty = false;
3935 for (Difficulty difficulty : scriptholder.Difficulties)
3936 {
3937 if (difficulty == obj->GetMap()->GetDifficultyID())
3938 {
3939 foundValidDifficulty = true;
3940 break;
3941 }
3942 }
3943
3944 if (!foundValidDifficulty)
3945 continue;
3946 }
3947
3948 mAllEventFlags |= scriptholder.event.event_flags;
3949 mEvents.push_back(scriptholder);
3950 }
3951}
3952
3954{
3956
3957 // We must use script type to avoid ambiguities
3958 switch (mScriptType)
3959 {
3961 e = sSmartScriptMgr->GetScript(-((int32)me->GetSpawnId()), mScriptType);
3962 if (e.empty())
3963 e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType);
3964 FillScript(std::move(e), me, nullptr, nullptr, nullptr, 0);
3965 break;
3967 e = sSmartScriptMgr->GetScript(-((int32)go->GetSpawnId()), mScriptType);
3968 if (e.empty())
3969 e = sSmartScriptMgr->GetScript((int32)go->GetEntry(), mScriptType);
3970 FillScript(std::move(e), go, nullptr, nullptr, nullptr, 0);
3971 break;
3975 FillScript(std::move(e), areaTrigger, nullptr, nullptr, nullptr, 0);
3976 break;
3978 e = sSmartScriptMgr->GetScript((int32)trigger->ID, mScriptType);
3979 FillScript(std::move(e), nullptr, trigger, nullptr, nullptr, 0);
3980 break;
3983 FillScript(std::move(e), nullptr, nullptr, sceneTemplate, nullptr, 0);
3984 break;
3986 e = sSmartScriptMgr->GetScript(quest->GetQuestId(), mScriptType);
3987 FillScript(std::move(e), nullptr, nullptr, nullptr, quest, 0);
3988 break;
3990 e = sSmartScriptMgr->GetScript((int32)event, mScriptType);
3991 FillScript(std::move(e), nullptr, nullptr, nullptr, nullptr, event);
3992 break;
3993 default:
3994 break;
3995 }
3996}
3997
3998void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at, SceneTemplate const* scene, Quest const* qst, uint32 evnt)
3999{
4000 if (at)
4001 {
4003 trigger = at;
4004 player = obj->ToPlayer();
4005
4006 if (!player)
4007 {
4008 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: source is AreaTrigger with id {}, missing trigger player", trigger->ID);
4009 return;
4010 }
4011
4012 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is AreaTrigger with id {}, triggered by player {}", trigger->ID, player->GetGUID().ToString());
4013 }
4014 else if (scene)
4015 {
4017 sceneTemplate = scene;
4018 player = obj->ToPlayer();
4019
4020 if (!player)
4021 {
4022 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: source is Scene with id {}, missing trigger player", scene->SceneId);
4023 return;
4024 }
4025
4026 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Scene with id {}, triggered by player {}", scene->SceneId, player->GetGUID().ToString());
4027 }
4028 else if (qst)
4029 {
4031 quest = qst;
4032 player = obj->ToPlayer();
4033
4034 if (!player)
4035 {
4036 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: source is Quest with id {}, missing trigger player", qst->GetQuestId());
4037 return;
4038 }
4039
4040 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Quest with id {}, triggered by player {}", qst->GetQuestId(), player->GetGUID().ToString());
4041 }
4042 else if (evnt)
4043 {
4045 event = evnt;
4046
4047 if (obj->IsPlayer())
4048 {
4049 player = obj->ToPlayer();
4050 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by player {}", event, player->GetGUID().ToString());
4051 }
4052 else if (obj->IsCreature())
4053 {
4054 me = obj->ToCreature();
4055 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by creature {}", event, me->GetEntry());
4056 }
4057 else if (obj->IsGameObject())
4058 {
4059 go = obj->ToGameObject();
4060 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Event {}, triggered by gameobject {}", event, go->GetEntry());
4061 }
4062 else
4063 {
4064 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: source is Event {}, missing trigger WorldObject", event);
4065 return;
4066 }
4067 }
4068 else if (obj) // Handle object based scripts
4069 {
4070 switch (obj->GetTypeId())
4071 {
4072 case TYPEID_UNIT:
4074 me = obj->ToCreature();
4075 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is Creature {}", me->GetEntry());
4076 break;
4077 case TYPEID_GAMEOBJECT:
4079 go = obj->ToGameObject();
4080 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is GameObject {}", go->GetEntry());
4081 break;
4082 case TYPEID_AREATRIGGER:
4083 areaTrigger = obj->ToAreaTrigger();
4085 TC_LOG_DEBUG("scripts.ai", "SmartScript::OnInitialize: source is AreaTrigger {}, IsCustom {}", areaTrigger->GetEntry(), uint32(areaTrigger->IsCustom()));
4086 break;
4087 default:
4088 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: Unhandled TypeID !WARNING!");
4089 return;
4090 }
4091 }
4092 else
4093 {
4094 TC_LOG_ERROR("misc", "SmartScript::OnInitialize: !WARNING! Initialized objects are NULL.");
4095 return;
4096 }
4097
4098 GetScript();//load copy of script
4099
4101 InitTimer(event);//calculate timers for first time use
4102
4104 InstallEvents();
4106 mCounterList.clear();
4107}
4108
4110{
4111 if (!me)
4112 return;
4113
4115}
4116// SmartScript end
4117
4119{
4120 if (!me)
4121 return nullptr;
4122
4123 Unit* unit = nullptr;
4124
4125 Trinity::MostHPMissingInRange u_check(me, range, MinHPDiff);
4127 Cell::VisitGridObjects(me, searcher, range);
4128 return unit;
4129}
4130
4132{
4133 if (!me)
4134 return nullptr;
4135
4136 Unit* unit = nullptr;
4137 Trinity::MostHPPercentMissingInRange u_check(me, range, minHpPct, maxHpPct);
4139 Cell::VisitGridObjects(me, searcher, range);
4140 return unit;
4141}
4142
4143void SmartScript::DoFindFriendlyCC(std::vector<Creature*>& creatures, float range) const
4144{
4145 if (!me)
4146 return;
4147
4148 Trinity::FriendlyCCedInRange u_check(me, range);
4150 Cell::VisitGridObjects(me, searcher, range);
4151}
4152
4153void SmartScript::DoFindFriendlyMissingBuff(std::vector<Creature*>& creatures, float range, uint32 spellid) const
4154{
4155 if (!me)
4156 return;
4157
4158 Trinity::FriendlyMissingBuffInRange u_check(me, range, spellid);
4160 Cell::VisitGridObjects(me, searcher, range);
4161}
4162
4163Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) const
4164{
4165 if (!me)
4166 return nullptr;
4167
4168 Unit* unit = nullptr;
4169 Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range, playerOnly);
4171 Cell::VisitAllObjects(me, searcher, range);
4172 return unit;
4173}
4174
4175void SmartScript::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker, uint32 startFromEventId)
4176{
4177 //do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete
4178 // any SmartScriptHolder contained like the "e" parameter passed to this function
4180 {
4181 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());
4182 return;
4183 }
4184
4185 // 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
4187 return;
4188
4189 mTimedActionList.clear();
4191 if (mTimedActionList.empty())
4192 return;
4193
4194 Trinity::Containers::EraseIf(mTimedActionList, [startFromEventId](SmartScriptHolder const& script) { return script.event_id < startFromEventId; });
4195
4196 mTimedActionListInvoker = invoker ? invoker->GetGUID() : ObjectGuid::Empty;
4197 for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i)
4198 {
4199 i->enableTimed = i == mTimedActionList.begin();//enable processing only for the first action
4200
4201 if (e.action.timedActionList.timerType == 0)
4202 i->event.type = SMART_EVENT_UPDATE_OOC;
4203 else if (e.action.timedActionList.timerType == 1)
4204 i->event.type = SMART_EVENT_UPDATE_IC;
4205 else if (e.action.timedActionList.timerType > 1)
4206 i->event.type = SMART_EVENT_UPDATE;
4207
4208 InitTimer((*i));
4209 }
4210}
4211
4213{
4214 // Look for invoker only on map of base object... Prevents multithreaded crashes
4215 if (WorldObject* baseObject = GetBaseObject())
4216 return ObjectAccessor::GetUnit(*baseObject, mLastInvoker);
4217 // used for area triggers invoker cast
4218 else if (invoker)
4219 return ObjectAccessor::GetUnit(*invoker, mLastInvoker);
4220
4221 return nullptr;
4222}
4223
4225{
4226 // protect phase from overflowing
4227 SetPhase(std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p));
4228}
4229
4231{
4232 if (p >= mEventPhase)
4233 SetPhase(0);
4234 else
4235 SetPhase(mEventPhase - p);
4236}
4237
4239{
4240 mEventPhase = p;
4241}
4242
4244{
4245 if (mEventPhase == 0)
4246 return false;
4247 return ((1 << (mEventPhase - 1)) & p) != 0;
4248}
#define M_PI
Definition: Common.h:115
#define sConditionMgr
Definition: ConditionMgr.h:365
#define sCreatureTextMgr
@ TEXT_RANGE_NORMAL
Difficulty
Definition: DBCEnums.h:873
uint8_t uint8
Definition: Define.h:144
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
std::string GetDebugInfo()
Definition: Errors.cpp:157
#define sGameEventMgr
Definition: GameEventMgr.h:177
GameObjectActions
LootState
Definition: GameObject.h:155
@ GO_READY
Definition: GameObject.h:157
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
Definition: ObjectDefines.h:62
GOSummonType
Definition: ObjectDefines.h:82
@ TYPEID_AREATRIGGER
Definition: ObjectGuid.h:46
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
#define sObjectMgr
Definition: ObjectMgr.h:1946
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
bool roll_chance_i(int chance)
Definition: Random.h:59
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
@ LANG_ADDON
Emote
@ TEAM_OTHER
Powers
@ POWER_MANA
SpellCastResult
@ SPELL_CAST_OK
@ SPELL_FAILED_SPELL_IN_PROGRESS
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_ADDON
GOState
@ SMART_SCRIPT_TYPE_TIMED_ACTIONLIST
@ SMART_SCRIPT_TYPE_CREATURE
@ SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_CUSTOM
@ SMART_SCRIPT_TYPE_GAMEOBJECT
@ SMART_SCRIPT_TYPE_AREATRIGGER
@ SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY
@ SMART_SCRIPT_TYPE_EVENT
@ SMART_SCRIPT_TYPE_SCENE
@ SMART_SCRIPT_TYPE_QUEST
std::vector< SmartScriptHolder > SmartAIEventList
@ SMART_EVENT_FLAG_WHILE_CHARMED
@ 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_CREATE_CONVERSATION
@ 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_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_BECOME_PERSONAL_CLONE_FOR_PLAYER
@ SMART_ACTION_CALL_GROUPEVENTHAPPENS
@ SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL
@ SMART_ACTION_INVOKER_CAST
@ SMART_ACTION_SCENE_PLAY
@ 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_SCENE_CANCEL
@ SMART_ACTION_SET_POWER
@ SMART_ACTION_SEND_TARGET_TO_TARGET
@ SMART_ACTION_SET_INGAME_PHASE_ID
@ SMART_ACTION_REMOVE_POWER
@ 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_TRIGGER_GAME_EVENT
@ SMART_ACTION_TALK
@ SMART_ACTION_CALL_SCRIPT_RESET
@ SMART_ACTION_SET_DATA
@ SMART_ACTION_PLAY_SPELL_VISUAL_KIT
@ SMART_ACTION_WP_START
@ SMART_ACTION_COMBAT_STOP
@ SMART_ACTION_SET_INGAME_PHASE_GROUP
@ 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_PLAY_ANIMKIT
@ 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_DO_ACTION
@ 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_SCENE_START
@ SMART_EVENT_RECEIVE_EMOTE
@ SMART_EVENT_FRIENDLY_HEALTH_PCT
@ SMART_EVENT_QUEST_FAIL
@ SMART_EVENT_DATA_SET
@ SMART_EVENT_RECEIVE_HEAL
@ SMART_EVENT_TIMED_EVENT_TRIGGERED
@ SMART_EVENT_SCENE_COMPLETE
@ 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_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_SCENE_CANCEL
@ 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_SCENE_TRIGGER
@ 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_SEND_EVENT_TRIGGER
@ 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_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:33
@ AURA_REMOVE_BY_EXPIRE
TriggerCastFlags
Definition: SpellDefines.h:245
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
@ TRIGGERED_NONE
Not triggered.
Definition: SpellDefines.h:246
#define CAST_AI(a, b)
Definition: UnitAI.h:28
#define ENSURE_AI(a, b)
Definition: UnitAI.h:29
UnitMoveType
Definition: UnitDefines.h:116
ReactStates
Definition: UnitDefines.h:505
UnitStandStateType
Definition: UnitDefines.h:41
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
NPCFlags
Non Player Character flags.
Definition: UnitDefines.h:295
SheathState
Definition: UnitDefines.h:81
#define MAX_EQUIPMENT_ITEMS
Definition: UnitDefines.h:37
AnimTier
Definition: UnitDefines.h:69
UnitVisFlags
Definition: UnitDefines.h:58
@ UNIT_FLAG_IMMUNE_TO_NPC
Definition: UnitDefines.h:153
@ UNIT_FLAG_IMMUNE_TO_PC
Definition: UnitDefines.h:152
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:590
@ UNIT_STATE_LOST_CONTROL
Definition: Unit.h:296
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_CASTING
Definition: Unit.h:270
#define sWaypointMgr
static float waypoint[6][3]
Definition: boss_alar.cpp:54
bool IsCustom() const
Definition: AreaTrigger.h:76
static Conversation * CreateConversation(uint32 conversationEntry, Unit *creator, Position const &pos, ObjectGuid privateObjectOwner, SpellInfo const *spellInfo=nullptr, bool autoStart=true)
void DoZoneInCombat()
Definition: CreatureAI.h:161
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
Definition: CreatureAI.cpp:219
void AttackStart(Unit *victim) override
== Triggered Actions Requested ==================
Definition: CreatureAI.cpp:328
static void SendChatPacket(WorldObject *source, Builder const &builder, ChatMsg msgType, WorldObject const *whisperTarget=nullptr, CreatureTextRange range=TEXT_RANGE_NORMAL, Team team=TEAM_OTHER, bool gmOnly=false)
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
void SetCanMelee(bool canMelee, bool fleeFromMelee=false)
Definition: Creature.cpp:2822
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr, float *dist=nullptr) const
Definition: Creature.cpp:2882
void CallForHelp(float fRadius)
Definition: Creature.cpp:2563
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition: Creature.h:373
void GetTransportHomePosition(float &x, float &y, float &z, float &ori) const
Definition: Creature.h:378
bool IsEngaged() const override
Definition: Creature.cpp:3601
GuidUnorderedSet const & GetTapList() const
Definition: Creature.h:282
void DoFleeToGetAssistance()
Definition: Creature.cpp:1002
ObjectGuid::LowType GetSpawnId() const
Definition: Creature.h:98
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
Definition: Creature.cpp:2493
bool IsInEvadeMode() const
Definition: Creature.h:203
CreatureAI * AI() const
Definition: Creature.h:214
virtual void SetData(uint32, uint32)
Definition: GameObjectAI.h:100
ObjectGuid GetOwnerGUID() const override
Definition: GameObject.h:242
GameObjectAI * AI() const
Definition: GameObject.h:378
ObjectGuid::LowType GetSpawnId() const
Definition: GameObject.h:212
GroupReference * next()
Definition: Group.h:197
virtual bool SetBossState(uint32 id, EncounterState state)
static char const * GetBossStateName(uint8 state)
Definition: Map.h:189
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition: Map.cpp:2348
Difficulty GetDifficultyID() const
Definition: Map.h:324
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition: Map.h:429
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes=false, size_t *count=nullptr)
Definition: Map.cpp:2437
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
Definition: Map.h:425
void Respawn(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition: Map.cpp:2058
void MoveJumpWithGravity(Position const &pos, float speedXY, float gravity, uint32 id=EVENT_JUMP, bool hasOrientation=false, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveRandom(float wanderDistance=0.0f, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_DEFAULT)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
uint64 LowType
Definition: ObjectGuid.h:278
void Clear()
Definition: ObjectGuid.h:286
static CreatureModel const * ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=nullptr)
Definition: ObjectMgr.cpp:1616
static Creature * ToCreature(Object *o)
Definition: Object.h:219
bool IsPlayer() const
Definition: Object.h:212
static Unit * ToUnit(Object *o)
Definition: Object.h:225
Player * ToPlayer()
Definition: Object.h:215
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
TypeID GetTypeId() const
Definition: Object.h:173
bool IsGameObject() const
Definition: Object.h:230
GameObject * ToGameObject()
Definition: Object.h:233
uint32 GetEntry() const
Definition: Object.h:161
bool IsCreature() const
Definition: Object.h:218
static AreaTrigger * ToAreaTrigger(Object *o)
Definition: Object.h:249
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
Unit * ToUnit()
Definition: Object.h:227
static void AddPhase(WorldObject *object, uint32 phaseId, bool updateVisibility)
static void AddPhaseGroup(WorldObject *object, uint32 phaseGroupId, bool updateVisibility)
static void RemovePhaseGroup(WorldObject *object, uint32 phaseGroupId, bool updateVisibility)
static void RemovePhase(WorldObject *object, uint32 phaseId, bool updateVisibility)
void SendQuestGiverQuestDetails(Quest const *quest, ObjectGuid npcGUID, bool autoLaunched, bool displayPopup) const
Definition: GossipDef.cpp:439
void KilledMonsterCredit(uint32 entry, ObjectGuid guid=ObjectGuid::Empty)
Definition: Player.cpp:16680
void GroupEventHappens(uint32 questId, WorldObject const *pEventObject)
Definition: Player.cpp:16598
WorldSession * GetSession() const
Definition: Player.h:2101
void AddQuestAndCheckCompletion(Quest const *quest, Object *questGiver)
Definition: Player.cpp:14774
bool CanTakeQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14620
void AreaExploredOrEventHappens(uint32 questId)
Definition: Player.cpp:16577
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition: Player.cpp:14036
uint32 GetGossipTextId(uint32 menuId, WorldObject *source)
Definition: Player.cpp:14367
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
uint32 GetQuestId() const
Definition: QuestDef.h:587
static SmartScriptHolder & FindLinkedEvent(SmartAIEventList &list, uint32 link)
void SetInvincibilityHpLevel(uint32 level)
Definition: SmartAI.h:196
bool CheckTimer(SmartScriptHolder const &e) const
uint32 mEventPhase
Definition: SmartScript.h:127
static constexpr uint32 MAX_NESTED_EVENTS
Definition: SmartScript.h:143
void DoFindFriendlyMissingBuff(std::vector< Creature * > &creatures, float range, uint32 spellid) const
Creature * me
Definition: SmartScript.h:116
uint32 mPathId
Definition: SmartScript.h:129
ObjectGuid mLastInvoker
Definition: SmartScript.h:95
void OnUpdate(const uint32 diff)
void IncPhase(uint32 p)
void DoFindFriendlyCC(std::vector< Creature * > &creatures, float range) const
SmartScriptType mScriptType
Definition: SmartScript.h:126
void InstallEvents()
void UpdateTimer(SmartScriptHolder &e, uint32 const diff)
CounterMap mCounterList
Definition: SmartScript.h:97
void ProcessEventsFor(SMART_EVENT e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr, std::string const &varString="")
void FillScript(SmartAIEventList e, WorldObject *obj, AreaTriggerEntry const *at, SceneTemplate const *scene, Quest const *quest, uint32 event=0)
bool mUseTextTimer
Definition: SmartScript.h:136
void SortEvents(SmartAIEventList &events)
uint32 mLastTextID
Definition: SmartScript.h:134
SceneTemplate const * sceneTemplate
Definition: SmartScript.h:123
static void RecalcTimer(SmartScriptHolder &e, uint32 min, uint32 max)
void OnInitialize(WorldObject *obj, AreaTriggerEntry const *at=nullptr, SceneTemplate const *scene=nullptr, Quest const *qst=nullptr, uint32 evnt=0)
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)
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, std::string const &varString="")
uint32 mTextTimer
Definition: SmartScript.h:133
void RetryLater(SmartScriptHolder &e, bool ignoreChanceRoll=false)
void GetScript()
SmartAIEventStoredList mStoredEvents
Definition: SmartScript.h:130
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 OnMoveInLineOfSight(Unit *who)
bool IsSmart(Creature *c, bool silent=false) const
Definition: SmartScript.cpp:76
WorldObject * GetBaseObjectOrUnitInvoker(Unit *invoker)
Unit * DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) const
GameObject * go
Definition: SmartScript.h:118
bool IsInPhase(uint32 p) const
SmartAIEventList mInstallEvents
Definition: SmartScript.h:112
static void InitTimer(SmartScriptHolder &e)
AreaTriggerEntry const * trigger
Definition: SmartScript.h:121
Unit * DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const
uint32 mAllEventFlags
Definition: SmartScript.h:140
Player * player
Definition: SmartScript.h:120
AreaTrigger * areaTrigger
Definition: SmartScript.h:122
void ProcessEvent(SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr, std::string const &varString="")
void StoreCounter(uint32 id, uint32 value, uint32 reset)
uint32 mCurrentPriority
Definition: SmartScript.h:137
WorldObject * GetBaseObject() const
void GetWorldObjectsInDist(ObjectVector &objects, float dist) const
uint32 mNestedEventsCounter
Definition: SmartScript.h:139
Creature * FindCreatureNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
uint32 mTalkerEntry
Definition: SmartScript.h:135
static bool IsGameObject(WorldObject *obj)
void ProcessAction(SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr, std::string const &varString="")
uint32 event
Definition: SmartScript.h:125
void GetTargets(ObjectVector &targets, SmartScriptHolder const &e, WorldObject *invoker=nullptr) const
SmartAIEventList mEvents
Definition: SmartScript.h:111
void OnReset()
Quest const * quest
Definition: SmartScript.h:124
bool isProcessingTimedActionList
Definition: SmartScript.h:115
ObjectVector const * GetStoredTargetVector(uint32 id, WorldObject const &ref) const
Unit * DoFindClosestFriendlyInRange(float range, bool playerOnly) const
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, uint32 action_param7, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
ObjectGuid goOrigGUID
Definition: SmartScript.h:119
SmartAIEventList mTimedActionList
Definition: SmartScript.h:113
void DecPhase(uint32 p)
ObjectGuid meOrigGUID
Definition: SmartScript.h:117
ObjectVectorMap _storedTargets
Definition: SmartScript.h:145
bool mEventSortingRequired
Definition: SmartScript.h:138
ObjectGuid mTimedActionListInvoker
Definition: SmartScript.h:114
void RemoveStoredEvent(uint32 id)
void SetTimedActionList(SmartScriptHolder &e, uint32 entry, Unit *invoker, uint32 startFromEventId=0)
std::vector< uint32 > mRemIDs
Definition: SmartScript.h:131
GameObject * FindGameObjectNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
void ResetBaseObject()
uint32 const Id
Definition: SpellInfo.h:325
uint32 SchoolMask
Definition: SpellInfo.h:413
Definition: Spell.h:255
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:74
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:79
Definition: Unit.h:627
bool IsVehicle() const
Definition: Unit.h:743
Vehicle * GetVehicle() const
Definition: Unit.h:1713
float GetHealthPct() const
Definition: Unit.h:784
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5827
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition: Unit.h:1015
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition: Unit.cpp:635
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition: Unit.cpp:12671
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9410
TempSummon * ToTempSummon()
Definition: Unit.h:1756
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1195
ObjectGuid GetCreatorGUID() const override
Definition: Unit.h:1172
void SetSheath(SheathState sheathed)
Definition: Unit.cpp:5630
Gender GetGender() const
Definition: Unit.h:755
Unit * EnsureVictim() const
Definition: Unit.h:717
bool IsAIEnabled() const
Definition: Unit.h:658
uint32 GetAuraCount(uint32 spellId) const
Definition: Unit.cpp:4648
uint64 GetMaxHealth() const
Definition: Unit.h:777
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition: Unit.cpp:11520
Unit * GetVictim() const
Definition: Unit.h:715
void SetFacingTo(float const ori, bool force=true)
Definition: Unit.cpp:12653
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
float GetPowerPct(Powers power) const
Definition: Unit.h:807
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
Vehicle * GetVehicleKit() const
Definition: Unit.h:1711
void KillSelf(bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.h:921
bool isDead() const
Definition: Unit.h:1166
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1442
Unit * GetBase() const
Definition: Vehicle.h:49
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition: Vehicle.h:67
TempSummon * SummonPersonalClone(Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, Player *privateObjectOwner=nullptr)
Definition: Object.cpp:2048
Player * SelectNearestPlayer(float range) const
Definition: Object.cpp:2210
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition: Object.cpp:2170
Map * GetMap() const
Definition: Object.h:624
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition: Object.cpp:3312
ObjectGuid GetPrivateObjectOwner() const
Definition: Object.h:785
void GetGameObjectListWithEntryInGrid(Container &gameObjectContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition: Object.cpp:3292
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool IsHostileTo(WorldObject const *target) const
Definition: Object.cpp:2860
virtual ObjectGuid GetCharmerOrOwnerGUID() const
Definition: Object.h:652
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:2025
TransportBase * GetTransport() const
Definition: Object.h:750
bool IsPrivateObject() const
Definition: Object.h:784
GameObject * SummonGameObject(uint32 entry, Position const &pos, QuaternionData const &rot, Seconds respawnTime, GOSummonType summonType=GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)
Definition: Object.cpp:2065
std::string const & GetName() const
Definition: Object.h:555
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1181
void GetContactPoint(WorldObject const *obj, float &x, float &y, float &z, float distance2d=CONTACT_DISTANCE) const
Definition: Object.cpp:3430
GameObject * FindNearestUnspawnedGameObject(uint32 entry, float range) const
Definition: Object.cpp:2192
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition: Object.cpp:2148
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2252
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition: Object.cpp:1238
void SummonCreatureGroup(uint8 group, std::list< TempSummon * > *list=nullptr)
Definition: Object.cpp:2131
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2865
Player session in the World.
Definition: WorldSession.h:963
virtual void SetData(uint32, uint32)
Definition: ZoneScript.h:92
virtual void SetGuidData(uint32, ObjectGuid)
Definition: ZoneScript.h:84
WeatherState
Definition: Weather.h:46
TC_GAME_API void Trigger(uint32 gameEventId, WorldObject *source, WorldObject *target)
float constexpr gravity
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:109
void EraseIf(Container &c, Predicate p)
Definition: Containers.h:279
void RandomResize(C &container, std::size_t requestedSize)
Definition: Containers.h:67
std::string ToString(Type &&val, Params &&... params)
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:179
uint32 CreatureDisplayID
Definition: CreatureData.h:432
EquipmentItem Items[MAX_EQUIPMENT_ITEMS]
Definition: CreatureData.h:584
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
Position GetPositionWithOffset(Position const &offset) const
Definition: Position.cpp:58
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
Definition: GameObject.cpp:118
uint32 SceneId
Definition: ObjectMgr.h:854
struct SmartAction::@66::@135 setRoot
struct SmartAction::@66::@166 addToStoredTargets
uint32 sounds[4]
uint32 targetParam2
SAIBool UseDefaultGravity
struct SmartAction::@66::@143 randomSound
struct SmartAction::@66::@79 crossCast
struct SmartAction::@66::@95 callHelp
struct SmartAction::@66::@128 enableTempGO
struct SmartAction::@66::@85 setEventPhase
uint32 repeatMax
struct SmartAction::@66::@161 conversation
uint32 targetsLimit
SAIBool transport
struct SmartAction::@66::@144 corpseDelay
struct SmartAction::@66::@160 setHealthPct
uint32 gameObjectAction
SAIBool disable
struct SmartAction::@66::@108 wpPause
struct SmartAction::@66::@92 setInstanceData
struct SmartAction::@66::@131 setGoLootState
struct SmartAction::@66::@130 sendGossipMenu
struct SmartAction::@66::@105 active
struct SmartAction::@66::@115 storeTargets
SAIBool regenHealth
uint32 wps[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@66::@91 killedMonster
struct SmartAction::@66::@111 setRun
SAIBool allowOverride
struct SmartAction::@66::@107 wpStart
struct SmartAction::@66::@137 creatureGroup
uint32 triggerFlags
struct SmartAction::@66::@102 moveRandom
struct SmartAction::@66::@120 setunitByte
struct SmartAction::@66::@142 moveOffset
struct SmartAction::@66::@104 summonGO
uint32 emotes[SMART_ACTION_PARAM_COUNT]
SAIBool withDelayed
struct SmartAction::@66::@106 taxi
struct SmartAction::@66::@146 groupSpawn
SAIBool withInstant
struct SmartAction::@66::@162 setImmunePC
uint32 transitionMilliseconds
struct SmartAction::@66::@81 threatPCT
uint32 targetParam1
struct SmartAction::@66::@118 equip
struct SmartAction::@66::@148 randomTimedEvent
uint32 includeDecayRatio
struct SmartAction::@66::@134 setHealthRegen
struct SmartAction::@66::@96 setSheath
SAIBool toRespawnPosition
struct SmartAction::@66::@70 faction
struct SmartAction::@66::@129 moveToPos
SAIBool attackInvoker
struct SmartAction::@66::@69 simpleTalk
SAIBool useTalkTarget
uint32 areaLightId
struct SmartAction::@66::@88 follow
struct SmartAction::@66::@97 forceDespawn
SAIBool uninteractible
uint32 targetParam3
struct SmartAction::@66::@155 spellVisualKit
struct SmartAction::@66::@77 randomEmote
struct SmartAction::@66::@117 movie
struct SmartAction::@66::@140 gameEventStart
struct SmartAction::@66::@80 summonCreature
struct SmartAction::@66::@167 becomePersonalClone
struct SmartAction::@66::@109 wpStop
struct SmartAction::@66::@75 questOffer
uint32 spellVisualKitId
struct SmartAction::@66::@138 power
struct SmartAction::@66::@123 randTimedActionList
struct SmartAction::@66::@165 activateGameObject
struct SmartAction::@66::@122 timedActionList
struct SmartAction::@66::@101 setData
struct SmartAction::@66::@94 updateTemplate
struct SmartAction::@66::@141 closestWaypointFromList
struct SmartAction::@66::@103 visibility
struct SmartAction::@66::@152 scene
struct SmartAction::@66::@158 setHover
struct SmartAction::@66::@154 movementSpeed
SAIBool immunePC
struct SmartAction::@66::@159 evade
SAIBool updateLevel
uint32 actionLists[SMART_ACTION_PARAM_COUNT]
SMART_ACTION type
struct SmartAction::@66::@86 incEventPhase
struct SmartAction::@66::@125 interruptSpellCasting
uint32 forceRespawnTimer
uint32 targetType
struct SmartAction::@66::@93 setInstanceData64
uint32 phases[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@66::@83 autoAttack
struct SmartAction::@66::@99 ingamePhaseId
struct SmartAction::@66::@113 teleport
struct SmartAction::@66::@153 cinematic
SAIBool onlySelf
struct SmartAction::@66::@112 setDisableGravity
SAIBool attack
uint32 repeatMin
struct SmartAction::@66::@87 removeAura
SAIBool onlyOwnedAuras
uint32 textGroupID
uint32 castFlags
uint32 overrideLightId
struct SmartAction::@66::@145 disableEvade
struct SmartAction::@66::@98 invincHP
struct SmartAction::@66::@100 ingamePhaseGroup
struct SmartAction::@66::@124 randRangeTimedActionList
uint32 gossipMenuId
struct SmartAction::@66::@116 timeEvent
SAIBool repeat
uint32 gossipNpcTextId
SAIBool disablePathfinding
struct SmartAction::@66::@139 gameEventStop
uint32 timerType
struct SmartAction::@66::@156 overrideLight
uint32 ContactDistance
struct SmartAction::@66::@168 triggerGameEvent
struct SmartAction::@66::@136 goState
uint32 counterId
SAIBool withEmote
SAIBool useSaiTargetAsGameEventSource
struct SmartAction::@66::@126 jump
uint32 summonType
struct SmartAction::@66::@133 setRangedMovement
uint32 speedFraction
uint32 movementSlot
struct SmartAction::@66::@164 setUninteractible
SAIBool directAdd
struct SmartAction::@66::@163 setImmuneNPC
uint32 threatINC
struct SmartAction::@66::@76 react
struct SmartAction::@66::@78 cast
uint32 threatDEC
struct SmartAction::@66::@127 fleeAssist
struct SmartAction::@66::@84 combatMove
struct SmartAction::@66::@110 item
struct SmartAction::@66::@169 doAction
uint32 speedInteger
struct SmartAction::@66::@89 randomPhase
uint32 despawnTime
struct SmartAction::@66::@132 sendTargetToTarget
uint32 factionID
struct SmartAction::@66::@68 talk
SAIBool immuneNPC
struct SmartAction::@66::@149 pauseMovement
struct SmartAction::@66::@150 respawnData
uint32 movementType
struct SmartAction::@66::@157 overrideWeather
struct SmartAction::@66::@170 raw
struct SmartAction::@66::@82 threat
struct SmartAction::@66::@71 morphOrMount
struct SmartAction::@66::@90 randomPhaseRange
struct SmartAction::@66::@147 loadEquipment
uint32 creditType
struct SmartAction::@66::@114 setCounter
uint32 event_flags
struct SmartEvent::@29::@36 minMax
uint32 event_phase_mask
struct SmartEvent::@29::@65 raw
struct SmartEvent::@29::@47 dataSet
struct SmartEvent::@29::@46 movementInform
struct SmartEvent::@29::@32 kill
std::string param_string
struct SmartEvent::@29::@48 waypoint
uint32 cooldownMax
struct SmartEvent::@29::@40 summoned
uint32 pointID
struct SmartEvent::@29::@58 goLootStateChanged
uint32 maxDist
struct SmartEvent::@29::@55 gossipHello
struct SmartEvent::@29::@37 targetCasting
struct SmartEvent::@29::@62 distance
uint32 eventId
struct SmartEvent::@29::@60 doAction
uint32 spellId
struct SmartEvent::@29::@59 eventInform
struct SmartEvent::@29::@39 missingBuff
uint32 hostilityMode
Hostility mode of the event. 0: hostile, 1: not hostile, 2: any
uint32 repeatMin
struct SmartEvent::@29::@63 counter
struct SmartEvent::@29::@38 friendlyCC
struct SmartEvent::@29::@34 los
uint32 event_chance
struct SmartEvent::@29::@35 respawn
struct SmartEvent::@29::@56 gossip
SAIBool playerOnly
struct SmartEvent::@29::@61 friendlyHealthPct
struct SmartEvent::@29::@45 charm
uint32 creatureEntry
struct SmartEvent::@29::@52 areatrigger
uint32 lootState
struct SmartEvent::@29::@33 spellHit
struct SmartEvent::@29::@42 questObjective
struct SmartEvent::@29::@50 transportRelocate
uint32 repeatMax
uint32 gameEventId
uint32 textGroupID
uint32 cooldownMin
struct SmartEvent::@29::@54 timedEvent
struct SmartEvent::@29::@64 spellCast
struct SmartEvent::@29::@49 transportAddCreature
uint32 minHpPct
struct SmartEvent::@29::@51 instancePlayerEnter
struct SmartEvent::@29::@57 gameEvent
struct SmartEvent::@29::@44 aura
SAIBool onRemove
uint32 maxHpPct
struct SmartEvent::@29::@31 minMaxRepeat
SMART_EVENT type
uint32 creature
struct SmartEvent::@29::@53 textOver
static constexpr uint32 DEFAULT_PRIORITY
uint32 GetScriptType() const
uint32 GetEventType() const
uint32 GetTargetType() const
SmartScriptType source_type
uint32 GetActionType() const
struct SmartTarget::@171::@178 playerDistance
struct SmartTarget::@171::@175 unitRange
struct SmartTarget::@171::@185 goClosest
struct SmartTarget::@171::@187 closestFriendly
SAIBool useCharmerOrOwner
SAIBool playerOnly
struct SmartTarget::@171::@184 unitClosest
struct SmartTarget::@171::@182 goGUID
struct SmartTarget::@171::@190 threatList
struct SmartTarget::@171::@183 goDistance
struct SmartTarget::@171::@191 raw
struct SmartTarget::@171::@186 closestAttackable
struct SmartTarget::@171::@189 vehicle
struct SmartTarget::@171::@177 unitDistance
struct SmartTarget::@171::@181 goRange
struct SmartTarget::@171::@173 hostilRandom
struct SmartTarget::@171::@176 unitGUID
struct SmartTarget::@171::@188 owner
struct SmartTarget::@171::@174 farthest
SMARTAI_TARGETS type
struct SmartTarget::@171::@179 playerRange
struct SmartTarget::@171::@180 stored
std::vector< WaypointNode > Nodes