TrinityCore
MapScripts.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 "Map.h"
19#include "CellImpl.h"
20#include "GameTime.h"
21#include "GossipDef.h"
22#include "GridNotifiers.h"
23#include "Item.h"
24#include "Log.h"
25#include "MapManager.h"
26#include "MotionMaster.h"
27#include "ObjectAccessor.h"
28#include "ObjectMgr.h"
29#include "Pet.h"
30#include "Transport.h"
31#include "WaypointManager.h"
32
34void Map::ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo>> const& scripts, uint32 id, Object* source, Object* target)
35{
37 ScriptMapMap::const_iterator s = scripts.find(id);
38 if (s == scripts.end())
39 return;
40
41 // prepare static data
42 ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty; //some script commands doesn't have source
43 ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty;
44 ObjectGuid ownerGUID = [&] { if (Item* item = Object::ToItem(source)) return item->GetOwnerGUID(); return ObjectGuid::Empty; }();
45
47 ScriptMap const* s2 = &(s->second);
48 bool immedScript = false;
49 for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
50 {
51 ScriptAction sa;
52 sa.sourceGUID = sourceGUID;
53 sa.targetGUID = targetGUID;
54 sa.ownerGUID = ownerGUID;
55
56 sa.script = &iter->second;
57 m_scriptSchedule.insert(ScriptScheduleMap::value_type(time_t(GameTime::GetGameTime() + iter->first), sa));
58 if (iter->first == 0)
59 immedScript = true;
60
61 sMapMgr->IncreaseScheduledScriptsCount();
62 }
64 if (/*start &&*/ immedScript && !i_scriptLock)
65 {
66 i_scriptLock = true;
68 i_scriptLock = false;
69 }
70}
71
72void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
73{
74 // NOTE: script record _must_ exist until command executed
75
76 // prepare static data
77 ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty;
78 ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty;
79 ObjectGuid ownerGUID = [&] { if (Item* item = Object::ToItem(source)) return item->GetOwnerGUID(); return ObjectGuid::Empty; }();
80
81 ScriptAction sa;
82 sa.sourceGUID = sourceGUID;
83 sa.targetGUID = targetGUID;
84 sa.ownerGUID = ownerGUID;
85
86 sa.script = &script;
87 m_scriptSchedule.insert(ScriptScheduleMap::value_type(time_t(GameTime::GetGameTime() + delay), sa));
88
89 sMapMgr->IncreaseScheduledScriptsCount();
90
92 if (delay == 0 && !i_scriptLock)
93 {
94 i_scriptLock = true;
96 i_scriptLock = false;
97 }
98}
99
100// Helpers for ScriptProcess method.
101inline Player* Map::_GetScriptPlayerSourceOrTarget(Object* source, Object* target, ScriptInfo const* scriptInfo) const
102{
103 Player* player = nullptr;
104 if (!source && !target)
105 TC_LOG_ERROR("scripts", "{} source and target objects are NULL.", scriptInfo->GetDebugInfo());
106 else
107 {
108 // Check target first, then source.
109 if (target)
110 player = target->ToPlayer();
111 if (!player && source)
112 player = source->ToPlayer();
113
114 if (!player)
115 TC_LOG_ERROR("scripts", "{} neither source nor target object is player (source: TypeId: {}, Entry: {}, {}; target: TypeId: {}, Entry: {}, {}), skipping.",
116 scriptInfo->GetDebugInfo().c_str(),
117 source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, (source ? source->GetGUID() : ObjectGuid::Empty).ToString().c_str(),
118 target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, (target ? target->GetGUID() : ObjectGuid::Empty).ToString().c_str());
119 }
120 return player;
121}
122
123inline Creature* Map::_GetScriptCreatureSourceOrTarget(Object* source, Object* target, ScriptInfo const* scriptInfo, bool bReverse) const
124{
125 Creature* creature = nullptr;
126 if (!source && !target)
127 TC_LOG_ERROR("scripts", "{} source and target objects are NULL.", scriptInfo->GetDebugInfo());
128 else
129 {
130 if (bReverse)
131 {
132 // Check target first, then source.
133 if (target)
134 creature = target->ToCreature();
135 if (!creature && source)
136 creature = source->ToCreature();
137 }
138 else
139 {
140 // Check source first, then target.
141 if (source)
142 creature = source->ToCreature();
143 if (!creature && target)
144 creature = target->ToCreature();
145 }
146
147 if (!creature)
148 TC_LOG_ERROR("scripts", "{} neither source nor target are creatures (source: TypeId: {}, Entry: {}, {}; target: TypeId: {}, Entry: {}, {}), skipping.",
149 scriptInfo->GetDebugInfo().c_str(),
150 source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, (source ? source->GetGUID() : ObjectGuid::Empty).ToString().c_str(),
151 target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, (target ? target->GetGUID() : ObjectGuid::Empty).ToString().c_str());
152 }
153 return creature;
154}
155
156inline GameObject* Map::_GetScriptGameObjectSourceOrTarget(Object* source, Object* target, ScriptInfo const* scriptInfo, bool bReverse) const
157{
158 GameObject* gameobject = nullptr;
159 if (!source && !target)
160 TC_LOG_ERROR("scripts", "{} source and target objects are NULL.", scriptInfo->GetDebugInfo());
161 else
162 {
163 if (bReverse)
164 {
165 // Check target first, then source.
166 if (target)
167 gameobject = target->ToGameObject();
168 if (!gameobject && source)
169 gameobject = source->ToGameObject();
170 }
171 else
172 {
173 // Check source first, then target.
174 if (source)
175 gameobject = source->ToGameObject();
176 if (!gameobject && target)
177 gameobject = target->ToGameObject();
178 }
179
180 if (!gameobject)
181 TC_LOG_ERROR("scripts", "{} neither source nor target are gameobjects (source: TypeId: {}, Entry: {}, {}; target: TypeId: {}, Entry: {}, {}), skipping.",
182 scriptInfo->GetDebugInfo().c_str(),
183 source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, (source ? source->GetGUID() : ObjectGuid::Empty).ToString().c_str(),
184 target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, (target ? target->GetGUID() : ObjectGuid::Empty).ToString().c_str());
185 }
186 return gameobject;
187}
188
189inline Unit* Map::_GetScriptUnit(Object* obj, bool isSource, ScriptInfo const* scriptInfo) const
190{
191 Unit* unit = nullptr;
192 if (!obj)
193 TC_LOG_ERROR("scripts", "{} {} object is NULL.", scriptInfo->GetDebugInfo(), isSource ? "source" : "target");
194 else if (!obj->IsUnit())
195 TC_LOG_ERROR("scripts", "{} {} object is not unit {}, skipping.",
196 scriptInfo->GetDebugInfo(), isSource ? "source" : "target", obj->GetGUID().ToString());
197 else
198 {
199 unit = obj->ToUnit();
200 if (!unit)
201 TC_LOG_ERROR("scripts", "{} {} object could not be cast to unit.",
202 scriptInfo->GetDebugInfo(), isSource ? "source" : "target");
203 }
204 return unit;
205}
206
207inline Player* Map::_GetScriptPlayer(Object* obj, bool isSource, ScriptInfo const* scriptInfo) const
208{
209 Player* player = nullptr;
210 if (!obj)
211 TC_LOG_ERROR("scripts", "{} {} object is NULL.", scriptInfo->GetDebugInfo(), isSource ? "source" : "target");
212 else
213 {
214 player = obj->ToPlayer();
215 if (!player)
216 TC_LOG_ERROR("scripts", "{} {} object is not a player {}.",
217 scriptInfo->GetDebugInfo(), isSource ? "source" : "target", obj->GetGUID().ToString());
218 }
219 return player;
220}
221
222inline Creature* Map::_GetScriptCreature(Object* obj, bool isSource, ScriptInfo const* scriptInfo) const
223{
224 Creature* creature = nullptr;
225 if (!obj)
226 TC_LOG_ERROR("scripts", "{} {} object is NULL.", scriptInfo->GetDebugInfo(), isSource ? "source" : "target");
227 else
228 {
229 creature = obj->ToCreature();
230 if (!creature)
231 TC_LOG_ERROR("scripts", "{} {} object is not a creature {}.", scriptInfo->GetDebugInfo(),
232 isSource ? "source" : "target", obj->GetGUID().ToString());
233 }
234 return creature;
235}
236
237inline WorldObject* Map::_GetScriptWorldObject(Object* obj, bool isSource, ScriptInfo const* scriptInfo) const
238{
239 WorldObject* pWorldObject = nullptr;
240 if (!obj)
241 TC_LOG_ERROR("scripts", "{} {} object is NULL.",
242 scriptInfo->GetDebugInfo(), isSource ? "source" : "target");
243 else
244 {
245 pWorldObject = dynamic_cast<WorldObject*>(obj);
246 if (!pWorldObject)
247 TC_LOG_ERROR("scripts", "{} {} object is not a world object {}.",
248 scriptInfo->GetDebugInfo(), isSource ? "source" : "target", obj->GetGUID().ToString());
249 }
250 return pWorldObject;
251}
252
253inline void Map::_ScriptProcessDoor(Object* source, Object* target, ScriptInfo const* scriptInfo) const
254{
255 bool bOpen = false;
256 ObjectGuid::LowType guid = scriptInfo->ToggleDoor.GOGuid;
257 int32 nTimeToToggle = std::max(15, int32(scriptInfo->ToggleDoor.ResetDelay));
258 switch (scriptInfo->command)
259 {
260 case SCRIPT_COMMAND_OPEN_DOOR: bOpen = true; break;
261 case SCRIPT_COMMAND_CLOSE_DOOR: break;
262 default:
263 TC_LOG_ERROR("scripts", "{} unknown command for _ScriptProcessDoor.", scriptInfo->GetDebugInfo());
264 return;
265 }
266 if (!guid)
267 TC_LOG_ERROR("scripts", "{} door guid is not specified.", scriptInfo->GetDebugInfo());
268 else if (!source)
269 TC_LOG_ERROR("scripts", "{} source object is NULL.", scriptInfo->GetDebugInfo());
270 else if (!source->IsUnit())
271 TC_LOG_ERROR("scripts", "{} source object is not unit {}, skipping.", scriptInfo->GetDebugInfo(),
272 source->GetGUID().ToString());
273 else
274 {
275 WorldObject* wSource = dynamic_cast <WorldObject*> (source);
276 if (!wSource)
277 TC_LOG_ERROR("scripts", "{} source object could not be cast to world object {}, skipping.",
278 scriptInfo->GetDebugInfo(), source->GetGUID().ToString());
279 else
280 {
281 GameObject* pDoor = _FindGameObject(wSource, guid);
282 if (!pDoor)
283 TC_LOG_ERROR("scripts", "{} gameobject was not found (guid: {}).", scriptInfo->GetDebugInfo(), guid);
284 else if (pDoor->GetGoType() != GAMEOBJECT_TYPE_DOOR)
285 TC_LOG_ERROR("scripts", "{} gameobject is not a door (GoType: {}, {}).",
286 scriptInfo->GetDebugInfo(), pDoor->GetGoType(), pDoor->GetGUID().ToString());
287 else if (bOpen == (pDoor->GetGoState() == GO_STATE_READY))
288 {
289 pDoor->UseDoorOrButton(nTimeToToggle);
290
291 if (GameObject* goTarget = Object::ToGameObject(target))
292 {
293 if (goTarget && goTarget->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
294 goTarget->UseDoorOrButton(nTimeToToggle);
295 }
296 }
297 }
298 }
299}
300
302{
303 auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
304 if (bounds.first == bounds.second)
305 return nullptr;
306
307 return bounds.first->second;
308}
309
312{
313 if (m_scriptSchedule.empty())
314 return;
315
317 ScriptScheduleMap::iterator iter = m_scriptSchedule.begin();
318 // ok as multimap is a *sorted* associative container
319 while (!m_scriptSchedule.empty() && (iter->first <= GameTime::GetGameTime()))
320 {
321 ScriptAction const& step = iter->second;
322
323 Object* source = nullptr;
324 if (!step.sourceGUID.IsEmpty())
325 {
326 switch (step.sourceGUID.GetHigh())
327 {
328 case HighGuid::Item: // as well as HIGHGUID_CONTAINER
329 if (Player* player = GetPlayer(step.ownerGUID))
330 source = player->GetItemByGuid(step.sourceGUID);
331 break;
334 source = GetCreature(step.sourceGUID);
335 break;
336 case HighGuid::Pet:
337 source = GetPet(step.sourceGUID);
338 break;
339 case HighGuid::Player:
340 source = GetPlayer(step.sourceGUID);
341 break;
344 source = GetGameObject(step.sourceGUID);
345 break;
346 case HighGuid::Corpse:
347 source = GetCorpse(step.sourceGUID);
348 break;
349 default:
350 TC_LOG_ERROR("scripts", "{} source with unsupported high guid {}.",
351 step.script->GetDebugInfo(), step.sourceGUID.ToString());
352 break;
353 }
354 }
355
356 WorldObject* target = nullptr;
357 if (!step.targetGUID.IsEmpty())
358 {
359 switch (step.targetGUID.GetHigh())
360 {
363 target = GetCreature(step.targetGUID);
364 break;
365 case HighGuid::Pet:
366 target = GetPet(step.targetGUID);
367 break;
368 case HighGuid::Player:
369 target = GetPlayer(step.targetGUID);
370 break;
373 target = GetGameObject(step.targetGUID);
374 break;
375 case HighGuid::Corpse:
376 target = GetCorpse(step.targetGUID);
377 break;
378 default:
379 TC_LOG_ERROR("scripts", "{} target with unsupported high guid {}.",
380 step.script->GetDebugInfo(), step.targetGUID.ToString());
381 break;
382 }
383 }
384
385 switch (step.script->command)
386 {
388 {
390 {
391 TC_LOG_ERROR("scripts", "{} invalid chat type ({}) specified, skipping.", step.script->GetDebugInfo(), step.script->Talk.ChatType);
392 break;
393 }
394
396 source = _GetScriptPlayerSourceOrTarget(source, target, step.script);
397 else
398 source = _GetScriptCreatureSourceOrTarget(source, target, step.script);
399
400 if (source)
401 {
402 Unit* sourceUnit = source->ToUnit();
403 if (!sourceUnit)
404 {
405 TC_LOG_ERROR("scripts", "{} source object ({}) is not an unit, skipping.", step.script->GetDebugInfo(), source->GetGUID().ToString());
406 break;
407 }
408
409 switch (step.script->Talk.ChatType)
410 {
411 case CHAT_TYPE_SAY:
412 sourceUnit->Say(step.script->Talk.TextID, target);
413 break;
414 case CHAT_TYPE_YELL:
415 sourceUnit->Yell(step.script->Talk.TextID, target);
416 break;
419 sourceUnit->TextEmote(step.script->Talk.TextID, target, step.script->Talk.ChatType == CHAT_TYPE_BOSS_EMOTE);
420 break;
423 {
424 Player* receiver = target ? target->ToPlayer() : nullptr;
425 if (!receiver)
426 TC_LOG_ERROR("scripts", "{} attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo());
427 else
428 sourceUnit->Whisper(step.script->Talk.TextID, receiver, step.script->Talk.ChatType == CHAT_TYPE_BOSS_WHISPER);
429 break;
430 }
431 default:
432 break; // must be already checked at load
433 }
434 }
435 break;
436 }
437
439 // Source or target must be Creature.
440 if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
441 {
443 cSource->SetEmoteState(Emote(step.script->Emote.EmoteID));
444 else
445 cSource->HandleEmoteCommand(static_cast<Emote>(step.script->Emote.EmoteID));
446 }
447 break;
448
450 // Source or target must be Creature.
451 if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
452 {
453 Unit* unit = (Unit*)cSource;
454 if (step.script->MoveTo.TravelTime != 0)
455 {
456 float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f);
457 unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed);
458 }
459 else
461 }
462 break;
463
466 {
467 // Source or target must be Creature.
468 if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
469 cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation);
470 }
471 else
472 {
473 // Source or target must be Player.
474 if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script))
475 player->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation);
476 }
477 break;
478
480 {
481 if (!source)
482 {
483 TC_LOG_ERROR("scripts", "{} source object is NULL.", step.script->GetDebugInfo());
484 break;
485 }
486 if (!target)
487 {
488 TC_LOG_ERROR("scripts", "{} target object is NULL.", step.script->GetDebugInfo());
489 break;
490 }
491
492 // when script called for item spell casting then target == (unit or GO) and source is player
493 WorldObject* worldObject;
494 Player* player = target->ToPlayer();
495 if (player)
496 {
497 if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER)
498 {
499 TC_LOG_ERROR("scripts", "{} source is not unit, gameobject or player {}, skipping.",
500 step.script->GetDebugInfo(), source->GetGUID().ToString());
501 break;
502 }
503 worldObject = dynamic_cast<WorldObject*>(source);
504 }
505 else
506 {
507 player = source->ToPlayer();
508 if (player)
509 {
510 if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER)
511 {
512 TC_LOG_ERROR("scripts", "{} target is not unit, gameobject or player {}, skipping.",
513 step.script->GetDebugInfo(), target->GetGUID().ToString());
514 break;
515 }
516 worldObject = dynamic_cast<WorldObject*>(target);
517 }
518 else
519 {
520 TC_LOG_ERROR("scripts", "{} neither source nor target is player (source: {}; target: {}), skipping.",
521 step.script->GetDebugInfo().c_str(), source->GetGUID().ToString().c_str(),
522 target->GetGUID().ToString().c_str());
523 break;
524 }
525 }
526
527 ASSERT(worldObject);
528
529 // quest id and flags checked at script loading
530 if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->IsAlive()) &&
531 (step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(player, float(step.script->QuestExplored.Distance))))
533 else
534 player->FailQuest(step.script->QuestExplored.QuestID);
535
536 break;
537 }
538
540 // Source or target must be Player.
541 if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script))
542 {
544 player->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, player);
545 else
546 player->KilledMonsterCredit(step.script->KillCredit.CreatureEntry);
547 }
548 break;
549
552 {
553 TC_LOG_ERROR("scripts", "{} gameobject guid (datalong) is not specified.", step.script->GetDebugInfo());
554 break;
555 }
556
557 // Source or target must be WorldObject.
558 if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
559 {
561 if (!pGO)
562 {
563 TC_LOG_ERROR("scripts", "{} gameobject was not found (guid: {}).", step.script->GetDebugInfo(), step.script->RespawnGameobject.GOGuid);
564 break;
565 }
566
571 {
572 TC_LOG_ERROR("scripts", "{} can not be used with gameobject of type {} (guid: {}).",
574 break;
575 }
576
577 // Check that GO is not spawned
578 if (!pGO->isSpawned())
579 {
580 int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay));
582 pGO->SetRespawnTime(nTimeToDespawn);
583
584 pGO->GetMap()->AddToMap(pGO);
585 }
586 }
587 break;
588
590 {
591 // Source must be WorldObject.
592 if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
593 {
595 TC_LOG_ERROR("scripts", "{} creature entry (datalong) is not specified.", step.script->GetDebugInfo());
596 else
597 {
598 float x = step.script->TempSummonCreature.PosX;
599 float y = step.script->TempSummonCreature.PosY;
600 float z = step.script->TempSummonCreature.PosZ;
601 float o = step.script->TempSummonCreature.Orientation;
602
604 TC_LOG_ERROR("scripts", "{} creature was not spawned (entry: {}).", step.script->GetDebugInfo(), step.script->TempSummonCreature.CreatureEntry);
605 }
606 }
607 break;
608 }
609
612 _ScriptProcessDoor(source, target, step.script);
613 break;
614
616 // Source must be Unit.
617 if (Unit* unit = _GetScriptUnit(source, true, step.script))
618 {
619 // Target must be GameObject.
620 if (!target)
621 {
622 TC_LOG_ERROR("scripts", "{} target object is NULL.", step.script->GetDebugInfo());
623 break;
624 }
625
626 if (target->GetTypeId() != TYPEID_GAMEOBJECT)
627 {
628 TC_LOG_ERROR("scripts", "{} target object is not gameobject {}, skipping.",
629 step.script->GetDebugInfo(), target->GetGUID().ToString());
630 break;
631 }
632
633 if (GameObject* pGO = target->ToGameObject())
634 pGO->Use(unit);
635 }
636 break;
637
639 {
640 // Source (datalong2 != 0) or target (datalong2 == 0) must be Unit.
641 bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE;
642 if (Unit* unit = _GetScriptUnit(bReverse ? source : target, bReverse, step.script))
643 unit->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID);
644 break;
645 }
646
648 {
649 if (!source && !target)
650 {
651 TC_LOG_ERROR("scripts", "{} source and target objects are NULL.", step.script->GetDebugInfo());
652 break;
653 }
654
655 WorldObject* uSource = nullptr;
656 WorldObject* uTarget = nullptr;
657 // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s)
658 switch (step.script->CastSpell.Flags)
659 {
660 case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target
661 uSource = dynamic_cast<WorldObject*>(source);
662 uTarget = target;
663 break;
664 case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source
665 uSource = dynamic_cast<WorldObject*>(source);
666 uTarget = uSource;
667 break;
668 case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target
669 uSource = target;
670 uTarget = uSource;
671 break;
672 case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source
673 uSource = target;
674 uTarget = dynamic_cast<WorldObject*>(source);
675 break;
676 case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry
677 uSource = dynamic_cast<WorldObject*>(source);
678 uTarget = uSource ? uSource->FindNearestCreature(abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius) : nullptr;
679 break;
680 }
681
682 if (!uSource)
683 {
684 TC_LOG_ERROR("scripts", "{} no source worldobject found for spell {}", step.script->GetDebugInfo(), step.script->CastSpell.SpellID);
685 break;
686 }
687
688 if (!uTarget)
689 {
690 TC_LOG_ERROR("scripts", "{} no target worldobject found for spell {}", step.script->GetDebugInfo(), step.script->CastSpell.SpellID);
691 break;
692 }
693
694 bool triggered = (step.script->CastSpell.Flags != 4) ?
697 uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered);
698 break;
699 }
700
702 // Source must be WorldObject.
703 if (WorldObject* object = _GetScriptWorldObject(source, true, step.script))
704 {
705 // PlaySound.Flags bitmask: 0/1=anyone/target
706 Player* player = nullptr;
708 {
709 // Target must be Player.
710 player = _GetScriptPlayer(target, false, step.script);
711 if (!target)
712 break;
713 }
714
715 // PlaySound.Flags bitmask: 0/2=without/with distance dependent
717 object->PlayDistanceSound(step.script->PlaySound.SoundID, player);
718 else
719 object->PlayDirectSound(step.script->PlaySound.SoundID, player);
720 }
721 break;
722
724 // Target or source must be Player.
725 if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script))
726 {
727 ItemPosCountVec dest;
728 InventoryResult msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount);
729 if (msg == EQUIP_ERR_OK)
730 {
731 if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true))
732 pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true);
733 }
734 else
735 pReceiver->SendEquipError(msg, nullptr, nullptr, step.script->CreateItem.ItemEntry);
736 }
737 break;
738
740 // First try with target or source creature, then with target or source gameobject
741 if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
742 cSource->DespawnOrUnsummon(Milliseconds(step.script->DespawnSelf.DespawnDelay));
743 else if (GameObject* goSource = _GetScriptGameObjectSourceOrTarget(source, target, step.script, true))
744 goSource->DespawnOrUnsummon(Milliseconds(step.script->DespawnSelf.DespawnDelay));
745 break;
746
748 // Source must be Unit.
749 if (Unit* unit = _GetScriptUnit(source, true, step.script))
750 {
751 if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID))
752 TC_LOG_ERROR("scripts", "{} source object has an invalid path ({}), skipping.", step.script->GetDebugInfo(), step.script->LoadPath.PathID);
753 else
754 unit->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable != 0);
755 }
756 break;
757
759 {
761 {
762 TC_LOG_ERROR("scripts", "{} creature entry is not specified, skipping.", step.script->GetDebugInfo());
763 break;
764 }
765 if (!step.script->CallScript.ScriptID)
766 {
767 TC_LOG_ERROR("scripts", "{} script id is not specified, skipping.", step.script->GetDebugInfo());
768 break;
769 }
770
771 Creature* cTarget = nullptr;
772 auto creatureBounds = _creatureBySpawnIdStore.equal_range(step.script->CallScript.CreatureEntry);
773 if (creatureBounds.first != creatureBounds.second)
774 {
775 // Prefer alive (last respawned) creature
776 auto creatureItr = std::find_if(creatureBounds.first, creatureBounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
777 {
778 return pair.second->IsAlive();
779 });
780
781 cTarget = creatureItr != creatureBounds.second ? creatureItr->second : creatureBounds.first->second;
782 }
783
784 if (!cTarget)
785 {
786 TC_LOG_ERROR("scripts", "{} target was not found (entry: {})", step.script->GetDebugInfo(), step.script->CallScript.CreatureEntry);
787 break;
788 }
789
790 //Lets choose our ScriptMap map
792 //if no scriptmap present...
793 if (!datamap)
794 {
795 TC_LOG_ERROR("scripts", "{} unknown scriptmap ({}) specified, skipping.", step.script->GetDebugInfo(), step.script->CallScript.ScriptType);
796 break;
797 }
798
799 // Insert script into schedule but do not start it
800 ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, nullptr);
801 break;
802 }
803
805 // Source or target must be Creature.
806 if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
807 {
808 if (cSource->isDead())
809 TC_LOG_ERROR("scripts", "{} creature is already dead {}",
810 step.script->GetDebugInfo(), cSource->GetGUID().ToString());
811 else
812 {
813 cSource->setDeathState(JUST_DIED);
814 if (step.script->Kill.RemoveCorpse == 1)
815 cSource->RemoveCorpse();
816 }
817 }
818 break;
819
821 // Source must be Unit.
822 if (Unit* sourceUnit = _GetScriptUnit(source, true, step.script))
823 {
825 {
826 // Target must be Unit.
827 Unit* targetUnit = _GetScriptUnit(target, false, step.script);
828 if (!targetUnit)
829 break;
830
831 sourceUnit->SetFacingToObject(targetUnit);
832 }
833 else
834 sourceUnit->SetFacingTo(step.script->Orientation.Orientation);
835 }
836 break;
837
839 // Source must be Creature.
840 if (Creature* cSource = _GetScriptCreature(source, true, step.script))
841 cSource->LoadEquipment(step.script->Equip.EquipmentID);
842 break;
843
845 // Source must be Creature.
846 if (Creature* cSource = _GetScriptCreature(source, true, step.script))
847 cSource->SetDisplayId(step.script->Model.ModelID);
848 break;
849
851 // Source must be Player.
852 if (Player* player = _GetScriptPlayer(source, true, step.script))
853 player->PlayerTalkClass->SendCloseGossip();
854 break;
855
857 // Source must be Player.
858 if (Player* player = _GetScriptPlayer(source, true, step.script))
859 player->SendMovieStart(step.script->PlayMovie.MovieID);
860 break;
861
863 // Source must be Creature.
864 if (Creature* cSource = _GetScriptCreature(source, true, step.script))
865 {
866 if (!cSource->IsAlive())
867 return;
868
869 cSource->GetMotionMaster()->MoveIdle();
870
871 switch (step.script->Movement.MovementType)
872 {
874 cSource->GetMotionMaster()->MoveRandom((float)step.script->Movement.MovementDistance);
875 break;
877 cSource->GetMotionMaster()->MovePath(step.script->Movement.Path, false);
878 break;
879 }
880 }
881 break;
882
884 // Source must be Creature.
885 if (Creature* cSource = _GetScriptCreature(source, true, step.script))
886 cSource->PlayOneShotAnimKitId(step.script->PlayAnimKit.AnimKitID);
887 break;
888
889 default:
890 TC_LOG_ERROR("scripts", "Unknown script command {}.", step.script->GetDebugInfo());
891 break;
892 }
893
894 m_scriptSchedule.erase(iter);
895 iter = m_scriptSchedule.begin();
896 sMapMgr->DecreaseScheduledScriptCount();
897 }
898}
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ASSERT
Definition: Errors.h:68
@ GO_READY
Definition: GameObject.h:157
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sMapMgr
Definition: MapManager.h:184
@ WAYPOINT_MOTION_TYPE
@ RANDOM_MOTION_TYPE
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
Definition: ObjectDefines.h:63
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
ScriptMapMap * GetScriptsMapByType(ScriptsType type)
Definition: ObjectMgr.cpp:93
@ SF_CASTSPELL_SOURCE_TO_SOURCE
Definition: ObjectMgr.h:204
@ SF_CASTSPELL_SOURCE_TO_TARGET
Definition: ObjectMgr.h:203
@ SF_CASTSPELL_TRIGGERED
Definition: ObjectMgr.h:208
@ SF_CASTSPELL_TARGET_TO_SOURCE
Definition: ObjectMgr.h:206
@ SF_REMOVEAURA_REVERSE
Definition: ObjectMgr.h:200
@ SF_PLAYSOUND_DISTANCE_SOUND
Definition: ObjectMgr.h:212
@ SF_TALK_USE_PLAYER
Definition: ObjectMgr.h:188
@ SF_TELEPORT_USE_CREATURE
Definition: ObjectMgr.h:194
@ SF_KILLCREDIT_REWARD_GROUP
Definition: ObjectMgr.h:197
@ SF_PLAYSOUND_TARGET_PLAYER
Definition: ObjectMgr.h:211
@ SF_CASTSPELL_TARGET_TO_TARGET
Definition: ObjectMgr.h:205
@ SF_EMOTE_USE_STATE
Definition: ObjectMgr.h:191
@ SF_CASTSPELL_SEARCH_CREATURE
Definition: ObjectMgr.h:207
@ SF_ORIENTATION_FACE_TARGET
Definition: ObjectMgr.h:215
std::multimap< uint32, ScriptInfo > ScriptMap
Definition: ObjectMgr.h:418
@ SCRIPT_COMMAND_EMOTE
Definition: ObjectMgr.h:106
@ SCRIPT_COMMAND_CREATE_ITEM
Definition: ObjectMgr.h:122
@ SCRIPT_COMMAND_DESPAWN_SELF
Definition: ObjectMgr.h:123
@ SCRIPT_COMMAND_CLOSE_DOOR
Definition: ObjectMgr.h:117
@ SCRIPT_COMMAND_CAST_SPELL
Definition: ObjectMgr.h:120
@ SCRIPT_COMMAND_RESPAWN_GAMEOBJECT
Definition: ObjectMgr.h:114
@ SCRIPT_COMMAND_QUEST_EXPLORED
Definition: ObjectMgr.h:112
@ SCRIPT_COMMAND_ACTIVATE_OBJECT
Definition: ObjectMgr.h:118
@ SCRIPT_COMMAND_TALK
Definition: ObjectMgr.h:105
@ SCRIPT_COMMAND_OPEN_DOOR
Definition: ObjectMgr.h:116
@ SCRIPT_COMMAND_EQUIP
Definition: ObjectMgr.h:131
@ SCRIPT_COMMAND_PLAYMOVIE
Definition: ObjectMgr.h:134
@ SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT
Definition: ObjectMgr.h:126
@ SCRIPT_COMMAND_PLAY_ANIMKIT
Definition: ObjectMgr.h:136
@ SCRIPT_COMMAND_TELEPORT_TO
Definition: ObjectMgr.h:111
@ SCRIPT_COMMAND_MOVE_TO
Definition: ObjectMgr.h:108
@ SCRIPT_COMMAND_TEMP_SUMMON_CREATURE
Definition: ObjectMgr.h:115
@ SCRIPT_COMMAND_MOVEMENT
Definition: ObjectMgr.h:135
@ SCRIPT_COMMAND_KILL_CREDIT
Definition: ObjectMgr.h:113
@ SCRIPT_COMMAND_KILL
Definition: ObjectMgr.h:127
@ SCRIPT_COMMAND_LOAD_PATH
Definition: ObjectMgr.h:125
@ SCRIPT_COMMAND_ORIENTATION
Definition: ObjectMgr.h:130
@ SCRIPT_COMMAND_PLAY_SOUND
Definition: ObjectMgr.h:121
@ SCRIPT_COMMAND_MODEL
Definition: ObjectMgr.h:132
@ SCRIPT_COMMAND_CLOSE_GOSSIP
Definition: ObjectMgr.h:133
@ SCRIPT_COMMAND_REMOVE_AURA
Definition: ObjectMgr.h:119
@ CHAT_TYPE_SAY
Definition: ObjectMgr.h:141
@ CHAT_TYPE_BOSS_WHISPER
Definition: ObjectMgr.h:146
@ CHAT_TYPE_TEXT_EMOTE
Definition: ObjectMgr.h:143
@ CHAT_TYPE_BOSS_EMOTE
Definition: ObjectMgr.h:144
@ CHAT_TYPE_WHISPER
Definition: ObjectMgr.h:145
@ CHAT_TYPE_YELL
Definition: ObjectMgr.h:142
std::map< uint32, ScriptMap > ScriptMapMap
Definition: ObjectMgr.h:419
ScriptsType
Definition: ObjectMgr.h:175
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ GAMEOBJECT_TYPE_BUTTON
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_FISHINGNODE
@ GAMEOBJECT_TYPE_DOOR
Emote
@ GO_STATE_READY
@ JUST_DIED
Definition: Unit.h:247
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
#define sWaypointMgr
void UseDoorOrButton(uint32 time_to_restore=0, bool alternative=false, Unit *user=nullptr)
GOState GetGoState() const
Definition: GameObject.h:281
bool isSpawned() const
Definition: GameObject.h:256
void SetLootState(LootState s, Unit *unit=nullptr)
void SetRespawnTime(int32 respawn)
GameobjectTypes GetGoType() const
Definition: GameObject.h:279
Definition: Item.h:170
Player * _GetScriptPlayer(Object *obj, bool isSource, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:207
void ScriptsStart(std::map< uint32, std::multimap< uint32, ScriptInfo > > const &scripts, uint32 id, Object *source, Object *target)
Put scripts in the execution queue.
Definition: MapScripts.cpp:34
Pet * GetPet(ObjectGuid const &guid)
Definition: Map.cpp:3494
bool AddToMap(T *)
Definition: Map.cpp:550
GameObject * _FindGameObject(WorldObject *pWorldObject, ObjectGuid::LowType guid) const
Definition: MapScripts.cpp:301
Player * GetPlayer(ObjectGuid const &guid)
Definition: Map.cpp:3469
Creature * _GetScriptCreature(Object *obj, bool isSource, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:222
GameObject * _GetScriptGameObjectSourceOrTarget(Object *source, Object *target, ScriptInfo const *scriptInfo, bool bReverse=false) const
Definition: MapScripts.cpp:156
void ScriptsProcess()
Process queued scripts.
Definition: MapScripts.cpp:311
ScriptScheduleMap m_scriptSchedule
Definition: Map.h:661
void ScriptCommandStart(ScriptInfo const &script, uint32 delay, Object *source, Object *target)
Definition: MapScripts.cpp:72
void _ScriptProcessDoor(Object *source, Object *target, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:253
bool i_scriptLock
Definition: Map.h:655
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
WorldObject * _GetScriptWorldObject(Object *obj, bool isSource, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:237
Corpse * GetCorpse(ObjectGuid const &guid)
Definition: Map.cpp:3474
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition: Map.h:429
Player * _GetScriptPlayerSourceOrTarget(Object *source, Object *target, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:101
Unit * _GetScriptUnit(Object *obj, bool isSource, ScriptInfo const *scriptInfo) const
Definition: MapScripts.cpp:189
CreatureBySpawnIdContainer _creatureBySpawnIdStore
Definition: Map.h:799
Creature * GetCreature(ObjectGuid const &guid)
Definition: Map.cpp:3479
Creature * _GetScriptCreatureSourceOrTarget(Object *source, Object *target, ScriptInfo const *scriptInfo, bool bReverse=false) const
Definition: MapScripts.cpp:123
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
HighGuid GetHigh() const
Definition: ObjectGuid.h:288
Definition: Object.h:150
static Creature * ToCreature(Object *o)
Definition: Object.h:219
static Unit * ToUnit(Object *o)
Definition: Object.h:225
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
bool IsUnit() const
Definition: Object.h:224
TypeID GetTypeId() const
Definition: Object.h:173
GameObject * ToGameObject()
Definition: Object.h:233
uint32 GetEntry() const
Definition: Object.h:161
Item * ToItem()
Definition: Object.h:209
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
void AreaExploredOrEventHappens(uint32 questId)
Definition: Player.cpp:16577
void FailQuest(uint32 quest_id)
Definition: Player.cpp:15446
Definition: Unit.h:627
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13562
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13567
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition: Unit.cpp:13572
void NearTeleportTo(Position const &pos, bool casting=false)
Definition: Unit.cpp:12327
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition: Unit.cpp:13577
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition: Unit.cpp:506
Map * GetMap() const
Definition: Object.h:624
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition: Object.cpp:2148
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1078
time_t GetGameTime()
Definition: GameTime.cpp:44
constexpr float GetOrientation() const
Definition: Position.h:79
ObjectGuid targetGUID
Definition: Map.h:128
ObjectGuid ownerGUID
Definition: Map.h:129
ObjectGuid sourceGUID
Definition: Map.h:127
ScriptInfo const * script
‍owner of source if source is item
Definition: Map.h:130
float Orientation
Definition: ObjectMgr.h:279
uint32 Flags
Definition: ObjectMgr.h:236
struct ScriptInfo::@284::@303 LoadPath
struct ScriptInfo::@284::@296 TempSummonCreature
uint32 QuestID
Definition: ObjectMgr.h:284
float SearchRadius
Definition: ObjectMgr.h:333
struct ScriptInfo::@284::@290 MoveTo
int32 TextID
Definition: ObjectMgr.h:237
struct ScriptInfo::@284::@311 PlayAnimKit
struct ScriptInfo::@284::@295 RespawnGameobject
uint32 MovementType
Definition: ObjectMgr.h:404
uint32 MovementDistance
Definition: ObjectMgr.h:405
struct ScriptInfo::@284::@300 PlaySound
float DestX
Definition: ObjectMgr.h:258
uint32 ItemEntry
Definition: ObjectMgr.h:344
uint32 ChatType
Definition: ObjectMgr.h:235
struct ScriptInfo::@284::@310 Movement
uint32 SoundID
Definition: ObjectMgr.h:338
struct ScriptInfo::@284::@292 TeleportTo
struct ScriptInfo::@284::@305 Kill
uint32 ScriptID
Definition: ObjectMgr.h:362
struct ScriptInfo::@284::@307 Equip
uint32 ModelID
Definition: ObjectMgr.h:392
struct ScriptInfo::@284::@308 Model
float PosY
Definition: ObjectMgr.h:307
ScriptCommands command
Definition: ObjectMgr.h:223
float DestY
Definition: ObjectMgr.h:259
uint32 PathID
Definition: ObjectMgr.h:355
struct ScriptInfo::@284::@297 ToggleDoor
uint32 AnimKitID
Definition: ObjectMgr.h:411
uint32 MapID
Definition: ObjectMgr.h:272
uint32 IsRepeatable
Definition: ObjectMgr.h:356
int32 Path
Definition: ObjectMgr.h:406
int32 RemoveCorpse
Definition: ObjectMgr.h:370
float PosZ
Definition: ObjectMgr.h:308
struct ScriptInfo::@284::@301 CreateItem
uint32 ScriptType
Definition: ObjectMgr.h:363
struct ScriptInfo::@284::@288 Emote
uint32 ResetDelay
Definition: ObjectMgr.h:316
struct ScriptInfo::@284::@294 KillCredit
uint32 DespawnDelay
Definition: ObjectMgr.h:297
float PosX
Definition: ObjectMgr.h:306
struct ScriptInfo::@284::@299 CastSpell
uint32 TravelTime
Definition: ObjectMgr.h:255
uint32 Distance
Definition: ObjectMgr.h:285
uint32 SpellID
Definition: ObjectMgr.h:323
std::string GetDebugInfo() const
Definition: ObjectMgr.cpp:149
struct ScriptInfo::@284::@304 CallScript
float DestZ
Definition: ObjectMgr.h:260
uint32 MovieID
Definition: ObjectMgr.h:399
struct ScriptInfo::@284::@287 Talk
uint32 EquipmentID
Definition: ObjectMgr.h:387
struct ScriptInfo::@284::@293 QuestExplored
uint32 GOGuid
Definition: ObjectMgr.h:296
struct ScriptInfo::@284::@298 RemoveAura
uint32 CreatureEntry
Definition: ObjectMgr.h:290
uint32 Amount
Definition: ObjectMgr.h:345
struct ScriptInfo::@284::@309 PlayMovie
uint32 EmoteID
Definition: ObjectMgr.h:242
struct ScriptInfo::@284::@302 DespawnSelf