· 6 years ago · Aug 09, 2019, 04:06 PM
1/*
2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "ScriptMgr.h"
20#include "Chat.h"
21#include "Config.h"
22#include "Creature.h"
23#include "CreatureAIImpl.h"
24#include "DatabaseEnv.h"
25#include "DBCStores.h"
26#include "GossipDef.h"
27#include "InstanceScript.h"
28#include "Item.h"
29#include "LFGScripts.h"
30#include "Log.h"
31#include "MapManager.h"
32#include "ObjectMgr.h"
33#include "OutdoorPvPMgr.h"
34#include "Player.h"
35#include "ScriptReloadMgr.h"
36#include "ScriptSystem.h"
37#include "SmartAI.h"
38#include "SpellInfo.h"
39#include "SpellMgr.h"
40#include "SpellScript.h"
41#include "Transport.h"
42#include "Vehicle.h"
43#include "Weather.h"
44#include "WorldPacket.h"
45#include "WorldSession.h"
46
47// Trait which indicates whether this script type
48// must be assigned in the database.
49template<typename>
50struct is_script_database_bound
51 : std::false_type { };
52
53template<>
54struct is_script_database_bound<SpellScriptLoader>
55 : std::true_type { };
56
57template<>
58struct is_script_database_bound<InstanceMapScript>
59 : std::true_type { };
60
61template<>
62struct is_script_database_bound<ItemScript>
63 : std::true_type { };
64
65template<>
66struct is_script_database_bound<CreatureScript>
67 : std::true_type { };
68
69template<>
70struct is_script_database_bound<GameObjectScript>
71 : std::true_type { };
72
73template<>
74struct is_script_database_bound<VehicleScript>
75 : std::true_type { };
76
77template<>
78struct is_script_database_bound<AreaTriggerScript>
79 : std::true_type { };
80
81template<>
82struct is_script_database_bound<BattlegroundScript>
83 : std::true_type { };
84
85template<>
86struct is_script_database_bound<OutdoorPvPScript>
87 : std::true_type { };
88
89template<>
90struct is_script_database_bound<WeatherScript>
91 : std::true_type { };
92
93template<>
94struct is_script_database_bound<ConditionScript>
95 : std::true_type { };
96
97template<>
98struct is_script_database_bound<TransportScript>
99 : std::true_type { };
100
101template<>
102struct is_script_database_bound<AchievementCriteriaScript>
103 : std::true_type { };
104
105enum Spells
106{
107 SPELL_HOTSWAP_VISUAL_SPELL_EFFECT = 40162 // 59084
108};
109
110class ScriptRegistryInterface
111{
112public:
113 ScriptRegistryInterface() { }
114 virtual ~ScriptRegistryInterface() { }
115
116 ScriptRegistryInterface(ScriptRegistryInterface const&) = delete;
117 ScriptRegistryInterface(ScriptRegistryInterface&&) = delete;
118
119 ScriptRegistryInterface& operator= (ScriptRegistryInterface const&) = delete;
120 ScriptRegistryInterface& operator= (ScriptRegistryInterface&&) = delete;
121
122 /// Removes all scripts associated with the given script context.
123 /// Requires ScriptRegistryBase::SwapContext to be called after all transfers have finished.
124 virtual void ReleaseContext(std::string const& context) = 0;
125
126 /// Injects and updates the changed script objects.
127 virtual void SwapContext(bool initialize) = 0;
128
129 /// Removes the scripts used by this registry from the given container.
130 /// Used to find unused script names.
131 virtual void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) = 0;
132
133 /// Unloads the script registry.
134 virtual void Unload() = 0;
135};
136
137template<class>
138class ScriptRegistry;
139
140class ScriptRegistryCompositum
141 : public ScriptRegistryInterface
142{
143 ScriptRegistryCompositum() { }
144
145 template<class>
146 friend class ScriptRegistry;
147
148 /// Type erasure wrapper for objects
149 class DeleteableObjectBase
150 {
151 public:
152 DeleteableObjectBase() { }
153 virtual ~DeleteableObjectBase() { }
154
155 DeleteableObjectBase(DeleteableObjectBase const&) = delete;
156 DeleteableObjectBase& operator= (DeleteableObjectBase const&) = delete;
157 };
158
159 template<typename T>
160 class DeleteableObject
161 : public DeleteableObjectBase
162 {
163 public:
164 DeleteableObject(T&& object)
165 : _object(std::forward<T>(object)) { }
166
167 private:
168 T _object;
169 };
170
171public:
172 void SetScriptNameInContext(std::string const& scriptname, std::string const& context)
173 {
174 ASSERT(_scriptnames_to_context.find(scriptname) == _scriptnames_to_context.end(),
175 "Scriptname was assigned to this context already!");
176 _scriptnames_to_context.insert(std::make_pair(scriptname, context));
177 }
178
179 std::string const& GetScriptContextOfScriptName(std::string const& scriptname) const
180 {
181 auto itr = _scriptnames_to_context.find(scriptname);
182 ASSERT(itr != _scriptnames_to_context.end() &&
183 "Given scriptname doesn't exist!");
184 return itr->second;
185 }
186
187 void ReleaseContext(std::string const& context) final override
188 {
189 for (auto const registry : _registries)
190 registry->ReleaseContext(context);
191
192 // Clear the script names in context after calling the release hooks
193 // since it's possible that new references to a shared library
194 // are acquired when releasing.
195 for (auto itr = _scriptnames_to_context.begin();
196 itr != _scriptnames_to_context.end();)
197 if (itr->second == context)
198 itr = _scriptnames_to_context.erase(itr);
199 else
200 ++itr;
201 }
202
203 void SwapContext(bool initialize) final override
204 {
205 for (auto const registry : _registries)
206 registry->SwapContext(initialize);
207
208 DoDelayedDelete();
209 }
210
211 void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override
212 {
213 for (auto const registry : _registries)
214 registry->RemoveUsedScriptsFromContainer(scripts);
215 }
216
217 void Unload() final override
218 {
219 for (auto const registry : _registries)
220 registry->Unload();
221 }
222
223 template<typename T>
224 void QueueForDelayedDelete(T&& any)
225 {
226 _delayed_delete_queue.push_back(
227 Trinity::make_unique<
228 DeleteableObject<typename std::decay<T>::type>
229 >(std::forward<T>(any))
230 );
231 }
232
233 static ScriptRegistryCompositum* Instance()
234 {
235 static ScriptRegistryCompositum instance;
236 return &instance;
237 }
238
239private:
240 void Register(ScriptRegistryInterface* registry)
241 {
242 _registries.insert(registry);
243 }
244
245 void DoDelayedDelete()
246 {
247 _delayed_delete_queue.clear();
248 }
249
250 std::unordered_set<ScriptRegistryInterface*> _registries;
251
252 std::vector<std::unique_ptr<DeleteableObjectBase>> _delayed_delete_queue;
253
254 std::unordered_map<
255 std::string /*script name*/,
256 std::string /*context*/
257 > _scriptnames_to_context;
258};
259
260#define sScriptRegistryCompositum ScriptRegistryCompositum::Instance()
261
262template<typename /*ScriptType*/, bool /*IsDatabaseBound*/>
263class SpecializedScriptRegistry;
264
265// This is the global static registry of scripts.
266template<class ScriptType>
267class ScriptRegistry final
268 : public SpecializedScriptRegistry<
269 ScriptType, is_script_database_bound<ScriptType>::value>
270{
271 ScriptRegistry()
272 {
273 sScriptRegistryCompositum->Register(this);
274 }
275
276public:
277 static ScriptRegistry* Instance()
278 {
279 static ScriptRegistry instance;
280 return &instance;
281 }
282
283 void LogDuplicatedScriptPointerError(ScriptType const* first, ScriptType const* second)
284 {
285 // See if the script is using the same memory as another script. If this happens, it means that
286 // someone forgot to allocate new memory for a script.
287 TC_LOG_ERROR("scripts", "Script '%s' has same memory pointer as '%s'.",
288 first->GetName().c_str(), second->GetName().c_str());
289 }
290};
291
292class ScriptRegistrySwapHookBase
293{
294public:
295 ScriptRegistrySwapHookBase() { }
296 virtual ~ScriptRegistrySwapHookBase() { }
297
298 ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase const&) = delete;
299 ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase&&) = delete;
300
301 ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase const&) = delete;
302 ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase&&) = delete;
303
304 /// Called before the actual context release happens
305 virtual void BeforeReleaseContext(std::string const& /*context*/) { }
306
307 /// Called before SwapContext
308 virtual void BeforeSwapContext(bool /*initialize*/) { }
309
310 /// Called before Unload
311 virtual void BeforeUnload() { }
312};
313
314template<typename ScriptType, typename Base>
315class ScriptRegistrySwapHooks
316 : public ScriptRegistrySwapHookBase
317{
318};
319
320/// This hook is responsible for swapping OutdoorPvP's
321template<typename Base>
322class UnsupportedScriptRegistrySwapHooks
323 : public ScriptRegistrySwapHookBase
324{
325public:
326 void BeforeReleaseContext(std::string const& context) final override
327 {
328 auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context);
329 ASSERT(bounds.first == bounds.second);
330 }
331};
332
333/// This hook is responsible for swapping Creature and GameObject AI's
334template<typename ObjectType, typename ScriptType, typename Base>
335class CreatureGameObjectScriptRegistrySwapHooks
336 : public ScriptRegistrySwapHookBase
337{
338 template<typename W>
339 class AIFunctionMapWorker
340 {
341 public:
342 template<typename T>
343 AIFunctionMapWorker(T&& worker)
344 : _worker(std::forward<T>(worker)) { }
345
346 void Visit(std::unordered_map<ObjectGuid, ObjectType*>& objects)
347 {
348 _worker(objects);
349 }
350
351 template<typename O>
352 void Visit(std::unordered_map<ObjectGuid, O*>&) { }
353
354 private:
355 W _worker;
356 };
357
358 class AsyncCastHotswapEffectEvent : public BasicEvent
359 {
360 public:
361 explicit AsyncCastHotswapEffectEvent(Unit* owner) : owner_(owner) { }
362
363 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
364 {
365 owner_->CastSpell(owner_, SPELL_HOTSWAP_VISUAL_SPELL_EFFECT, true);
366 return true;
367 }
368
369 private:
370 Unit* owner_;
371 };
372
373 // Hook which is called before a creature is swapped
374 static void UnloadResetScript(Creature* creature)
375 {
376 // Remove deletable events only,
377 // otherwise it causes crashes with non-deletable spell events.
378 creature->m_Events.KillAllEvents(false);
379
380 if (creature->IsCharmed())
381 creature->RemoveCharmedBy(nullptr);
382
383 ASSERT(!creature->IsCharmed(),
384 "There is a disabled AI which is still loaded.");
385
386 if (creature->IsAlive())
387 creature->AI()->EnterEvadeMode();
388 }
389
390 static void UnloadDestroyScript(Creature* creature)
391 {
392 bool const destroyed = creature->AIM_Destroy();
393 ASSERT(destroyed,
394 "Destroying the AI should never fail here!");
395 (void)destroyed;
396
397 ASSERT(!creature->AI(),
398 "The AI should be null here!");
399 }
400
401 // Hook which is called before a gameobject is swapped
402 static void UnloadResetScript(GameObject* gameobject)
403 {
404 gameobject->AI()->Reset();
405 }
406
407 static void UnloadDestroyScript(GameObject* gameobject)
408 {
409 gameobject->AIM_Destroy();
410
411 ASSERT(!gameobject->AI(),
412 "The AI should be null here!");
413 }
414
415 // Hook which is called after a creature was swapped
416 static void LoadInitializeScript(Creature* creature)
417 {
418 ASSERT(!creature->AI(),
419 "The AI should be null here!");
420
421 if (creature->IsAlive())
422 creature->ClearUnitState(UNIT_STATE_EVADE);
423
424 bool const created = creature->AIM_Create();
425 ASSERT(created,
426 "Creating the AI should never fail here!");
427 (void)created;
428 }
429
430 static void LoadResetScript(Creature* creature)
431 {
432 if (!creature->IsAlive())
433 return;
434
435 creature->AI_InitializeAndEnable();
436 creature->AI()->EnterEvadeMode();
437
438 // Cast a dummy visual spell asynchronously here to signal
439 // that the AI was hot swapped
440 creature->m_Events.AddEvent(new AsyncCastHotswapEffectEvent(creature),
441 creature->m_Events.CalculateTime(0));
442 }
443
444 // Hook which is called after a gameobject was swapped
445 static void LoadInitializeScript(GameObject* gameobject)
446 {
447 ASSERT(!gameobject->AI(),
448 "The AI should be null here!");
449
450 gameobject->AIM_Initialize();
451 }
452
453 static void LoadResetScript(GameObject* gameobject)
454 {
455 gameobject->AI()->Reset();
456 }
457
458 static Creature* GetEntityFromMap(std::common_type<Creature>, Map* map, ObjectGuid const& guid)
459 {
460 return map->GetCreature(guid);
461 }
462
463 static GameObject* GetEntityFromMap(std::common_type<GameObject>, Map* map, ObjectGuid const& guid)
464 {
465 return map->GetGameObject(guid);
466 }
467
468 template<typename T>
469 static void VisitObjectsToSwapOnMap(Map* map, std::unordered_set<uint32> const& idsToRemove, T visitor)
470 {
471 auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects)
472 {
473 for (auto object : objects)
474 {
475 // When the script Id of the script isn't removed in this
476 // context change, do nothing.
477 if (idsToRemove.find(object.second->GetScriptId()) != idsToRemove.end())
478 visitor(object.second);
479 }
480 };
481
482 AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator));
483 TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker);
484
485 containerVisitor.Visit(map->GetObjectsStore());
486 }
487
488 static void DestroyScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove)
489 {
490 // First reset all swapped scripts safe by guid
491 // Skip creatures and gameobjects with an empty guid
492 // (that were not added to the world as of now)
493 sMapMgr->DoForAllMaps([&](Map* map)
494 {
495 std::vector<ObjectGuid> guidsToReset;
496
497 VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
498 {
499 if (object->AI() && !object->GetGUID().IsEmpty())
500 guidsToReset.push_back(object->GetGUID());
501 });
502
503 for (ObjectGuid const& guid : guidsToReset)
504 {
505 if (auto entity = GetEntityFromMap(std::common_type<ObjectType>{}, map, guid))
506 UnloadResetScript(entity);
507 }
508
509 VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
510 {
511 // Destroy the scripts instantly
512 UnloadDestroyScript(object);
513 });
514 });
515 }
516
517 static void InitializeScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove)
518 {
519 sMapMgr->DoForAllMaps([&](Map* map)
520 {
521 std::vector<ObjectGuid> guidsToReset;
522
523 VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
524 {
525 if (!object->AI() && !object->GetGUID().IsEmpty())
526 {
527 // Initialize the script
528 LoadInitializeScript(object);
529 guidsToReset.push_back(object->GetGUID());
530 }
531 });
532
533 for (ObjectGuid const& guid : guidsToReset)
534 {
535 // Reset the script
536 if (auto entity = GetEntityFromMap(std::common_type<ObjectType>{}, map, guid))
537 {
538 if (!entity->AI())
539 LoadInitializeScript(entity);
540
541 LoadResetScript(entity);
542 }
543 }
544 });
545 }
546
547public:
548 void BeforeReleaseContext(std::string const& context) final override
549 {
550 auto idsToRemove = static_cast<Base*>(this)->GetScriptIDsToRemove(context);
551 DestroyScriptIdsFromSet(idsToRemove);
552
553 // Add the new ids which are removed to the global ids to remove set
554 ids_removed_.insert(idsToRemove.begin(), idsToRemove.end());
555 }
556
557 void BeforeSwapContext(bool initialize) override
558 {
559 // Never swap creature or gameobject scripts when initializing
560 if (initialize)
561 return;
562
563 // Add the recently added scripts to the deleted scripts to replace
564 // default AI's with recently added core scripts.
565 ids_removed_.insert(static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().begin(),
566 static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().end());
567
568 DestroyScriptIdsFromSet(ids_removed_);
569 InitializeScriptIdsFromSet(ids_removed_);
570
571 ids_removed_.clear();
572 }
573
574 void BeforeUnload() final override
575 {
576 ASSERT(ids_removed_.empty());
577 }
578
579private:
580 std::unordered_set<uint32> ids_removed_;
581};
582
583// This hook is responsible for swapping CreatureAI's
584template<typename Base>
585class ScriptRegistrySwapHooks<CreatureScript, Base>
586 : public CreatureGameObjectScriptRegistrySwapHooks<
587 Creature, CreatureScript, Base
588 > { };
589
590// This hook is responsible for swapping GameObjectAI's
591template<typename Base>
592class ScriptRegistrySwapHooks<GameObjectScript, Base>
593 : public CreatureGameObjectScriptRegistrySwapHooks<
594 GameObject, GameObjectScript, Base
595 > { };
596
597/// This hook is responsible for swapping BattlegroundScript's
598template<typename Base>
599class ScriptRegistrySwapHooks<BattlegroundScript, Base>
600 : public UnsupportedScriptRegistrySwapHooks<Base> { };
601
602/// This hook is responsible for swapping OutdoorPvP's
603template<typename Base>
604class ScriptRegistrySwapHooks<OutdoorPvPScript, Base>
605 : public ScriptRegistrySwapHookBase
606{
607public:
608 ScriptRegistrySwapHooks() : swapped(false) { }
609
610 void BeforeReleaseContext(std::string const& context) final override
611 {
612 auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context);
613
614 if ((!swapped) && (bounds.first != bounds.second))
615 {
616 swapped = true;
617 sOutdoorPvPMgr->Die();
618 }
619 }
620
621 void BeforeSwapContext(bool initialize) override
622 {
623 // Never swap outdoor pvp scripts when initializing
624 if ((!initialize) && swapped)
625 {
626 sOutdoorPvPMgr->InitOutdoorPvP();
627 swapped = false;
628 }
629 }
630
631 void BeforeUnload() final override
632 {
633 ASSERT(!swapped);
634 }
635
636private:
637 bool swapped;
638};
639
640/// This hook is responsible for swapping InstanceMapScript's
641template<typename Base>
642class ScriptRegistrySwapHooks<InstanceMapScript, Base>
643 : public ScriptRegistrySwapHookBase
644{
645public:
646 ScriptRegistrySwapHooks() : swapped(false) { }
647
648 void BeforeReleaseContext(std::string const& context) final override
649 {
650 auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context);
651 if (bounds.first != bounds.second)
652 swapped = true;
653 }
654
655 void BeforeSwapContext(bool /*initialize*/) override
656 {
657 swapped = false;
658 }
659
660 void BeforeUnload() final override
661 {
662 ASSERT(!swapped);
663 }
664
665private:
666 bool swapped;
667};
668
669/// This hook is responsible for swapping SpellScriptLoader's
670template<typename Base>
671class ScriptRegistrySwapHooks<SpellScriptLoader, Base>
672 : public ScriptRegistrySwapHookBase
673{
674public:
675 ScriptRegistrySwapHooks() : swapped(false) { }
676
677 void BeforeReleaseContext(std::string const& context) final override
678 {
679 auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context);
680
681 if (bounds.first != bounds.second)
682 swapped = true;
683 }
684
685 void BeforeSwapContext(bool /*initialize*/) override
686 {
687 if (swapped)
688 {
689 sObjectMgr->ValidateSpellScripts();
690 swapped = false;
691 }
692 }
693
694 void BeforeUnload() final override
695 {
696 ASSERT(!swapped);
697 }
698
699private:
700 bool swapped;
701};
702
703// Database bound script registry
704template<typename ScriptType>
705class SpecializedScriptRegistry<ScriptType, true>
706 : public ScriptRegistryInterface,
707 public ScriptRegistrySwapHooks<ScriptType, ScriptRegistry<ScriptType>>
708{
709 template<typename>
710 friend class UnsupportedScriptRegistrySwapHooks;
711
712 template<typename, typename>
713 friend class ScriptRegistrySwapHooks;
714
715 template<typename, typename, typename>
716 friend class CreatureGameObjectScriptRegistrySwapHooks;
717
718public:
719 SpecializedScriptRegistry() { }
720
721 typedef std::unordered_map<
722 uint32 /*script id*/,
723 std::unique_ptr<ScriptType>
724 > ScriptStoreType;
725
726 typedef typename ScriptStoreType::iterator ScriptStoreIteratorType;
727
728 void ReleaseContext(std::string const& context) final override
729 {
730 this->BeforeReleaseContext(context);
731
732 auto const bounds = _ids_of_contexts.equal_range(context);
733 for (auto itr = bounds.first; itr != bounds.second; ++itr)
734 _scripts.erase(itr->second);
735 }
736
737 void SwapContext(bool initialize) final override
738 {
739 this->BeforeSwapContext(initialize);
740
741 _recently_added_ids.clear();
742 }
743
744 void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override
745 {
746 for (auto const& script : _scripts)
747 scripts.erase(script.second->GetName());
748 }
749
750 void Unload() final override
751 {
752 this->BeforeUnload();
753
754 ASSERT(_recently_added_ids.empty(),
755 "Recently added script ids should be empty here!");
756
757 _scripts.clear();
758 _ids_of_contexts.clear();
759 }
760
761 // Adds a database bound script
762 void AddScript(ScriptType* script)
763 {
764 ASSERT(script,
765 "Tried to call AddScript with a nullpointer!");
766 ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(),
767 "Tried to register a script without being in a valid script context!");
768
769 std::unique_ptr<ScriptType> script_ptr(script);
770
771 // Get an ID for the script. An ID only exists if it's a script that is assigned in the database
772 // through a script name (or similar).
773 if (uint32 const id = sObjectMgr->GetScriptId(script->GetName()))
774 {
775 // Try to find an existing script.
776 for (auto const& stored_script : _scripts)
777 {
778 // If the script names match...
779 if (stored_script.second->GetName() == script->GetName())
780 {
781 // If the script is already assigned -> delete it!
782 TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, "
783 "so the script can't work.", script->GetName().c_str());
784
785 // Error that should be fixed ASAP.
786 sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
787 ABORT();
788 return;
789 }
790 }
791
792 // If the script isn't assigned -> assign it!
793 _scripts.insert(std::make_pair(id, std::move(script_ptr)));
794 _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id));
795 _recently_added_ids.insert(id);
796
797 sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(),
798 sScriptMgr->GetCurrentScriptContext());
799 }
800 else
801 {
802 // The script uses a script name from database, but isn't assigned to anything.
803 TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.",
804 script->GetName().c_str());
805
806 // Avoid calling "delete script;" because we are currently in the script constructor
807 // In a valid scenario this will not happen because every script has a name assigned in the database
808 sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
809 return;
810 }
811 }
812
813 // Gets a script by its ID (assigned by ObjectMgr).
814 ScriptType* GetScriptById(uint32 id)
815 {
816 auto const itr = _scripts.find(id);
817 if (itr != _scripts.end())
818 return itr->second.get();
819
820 return nullptr;
821 }
822
823 ScriptStoreType& GetScripts()
824 {
825 return _scripts;
826 }
827
828protected:
829 // Returns the script id's which are registered to a certain context
830 std::unordered_set<uint32> GetScriptIDsToRemove(std::string const& context) const
831 {
832 // Create a set of all ids which are removed
833 std::unordered_set<uint32> scripts_to_remove;
834
835 auto const bounds = _ids_of_contexts.equal_range(context);
836 for (auto itr = bounds.first; itr != bounds.second; ++itr)
837 scripts_to_remove.insert(itr->second);
838
839 return scripts_to_remove;
840 }
841
842 std::unordered_set<uint32> const& GetRecentlyAddedScriptIDs() const
843 {
844 return _recently_added_ids;
845 }
846
847private:
848 ScriptStoreType _scripts;
849
850 // Scripts of a specific context
851 std::unordered_multimap<std::string /*context*/, uint32 /*id*/> _ids_of_contexts;
852
853 // Script id's which were registered recently
854 std::unordered_set<uint32> _recently_added_ids;
855};
856
857/// This hook is responsible for swapping CommandScript's
858template<typename Base>
859class ScriptRegistrySwapHooks<CommandScript, Base>
860 : public ScriptRegistrySwapHookBase
861{
862public:
863 void BeforeReleaseContext(std::string const& /*context*/) final override
864 {
865 ChatHandler::invalidateCommandTable();
866 }
867
868 void BeforeSwapContext(bool /*initialize*/) override
869 {
870 ChatHandler::invalidateCommandTable();
871 }
872
873 void BeforeUnload() final override
874 {
875 ChatHandler::invalidateCommandTable();
876 }
877};
878
879// Database unbound script registry
880template<typename ScriptType>
881class SpecializedScriptRegistry<ScriptType, false>
882 : public ScriptRegistryInterface,
883 public ScriptRegistrySwapHooks<ScriptType, ScriptRegistry<ScriptType>>
884{
885 template<typename, typename>
886 friend class ScriptRegistrySwapHooks;
887
888public:
889 typedef std::unordered_multimap<std::string /*context*/, std::unique_ptr<ScriptType>> ScriptStoreType;
890 typedef typename ScriptStoreType::iterator ScriptStoreIteratorType;
891
892 SpecializedScriptRegistry() { }
893
894 void ReleaseContext(std::string const& context) final override
895 {
896 this->BeforeReleaseContext(context);
897
898 _scripts.erase(context);
899 }
900
901 void SwapContext(bool initialize) final override
902 {
903 this->BeforeSwapContext(initialize);
904 }
905
906 void RemoveUsedScriptsFromContainer(std::unordered_set<std::string>& scripts) final override
907 {
908 for (auto const& script : _scripts)
909 scripts.erase(script.second->GetName());
910 }
911
912 void Unload() final override
913 {
914 this->BeforeUnload();
915
916 _scripts.clear();
917 }
918
919 // Adds a non database bound script
920 void AddScript(ScriptType* script)
921 {
922 ASSERT(script,
923 "Tried to call AddScript with a nullpointer!");
924 ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(),
925 "Tried to register a script without being in a valid script context!");
926
927 std::unique_ptr<ScriptType> script_ptr(script);
928
929 for (auto const& entry : _scripts)
930 if (entry.second.get() == script)
931 {
932 static_cast<ScriptRegistry<ScriptType>*>(this)->
933 LogDuplicatedScriptPointerError(script, entry.second.get());
934
935 sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
936 return;
937 }
938
939 // We're dealing with a code-only script, just add it.
940 _scripts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), std::move(script_ptr)));
941 }
942
943 ScriptStoreType& GetScripts()
944 {
945 return _scripts;
946 }
947
948private:
949 ScriptStoreType _scripts;
950};
951
952// Utility macros to refer to the script registry.
953#define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptStoreType
954#define SCR_REG_ITR(T) ScriptRegistry<T>::ScriptStoreIteratorType
955#define SCR_REG_LST(T) ScriptRegistry<T>::Instance()->GetScripts()
956
957// Utility macros for looping over scripts.
958#define FOR_SCRIPTS(T, C, E) \
959 if (!SCR_REG_LST(T).empty()) \
960 for (SCR_REG_ITR(T) C = SCR_REG_LST(T).begin(); \
961 C != SCR_REG_LST(T).end(); ++C)
962
963#define FOR_SCRIPTS_RET(T, C, E, R) \
964 if (SCR_REG_LST(T).empty()) \
965 return R; \
966 \
967 for (SCR_REG_ITR(T) C = SCR_REG_LST(T).begin(); \
968 C != SCR_REG_LST(T).end(); ++C)
969
970#define FOREACH_SCRIPT(T) \
971 FOR_SCRIPTS(T, itr, end) \
972 itr->second
973
974// Utility macros for finding specific scripts.
975#define GET_SCRIPT(T, I, V) \
976 T* V = ScriptRegistry<T>::Instance()->GetScriptById(I); \
977 if (!V) \
978 return;
979
980#define GET_SCRIPT_RET(T, I, V, R) \
981 T* V = ScriptRegistry<T>::Instance()->GetScriptById(I); \
982 if (!V) \
983 return R;
984
985struct TSpellSummary
986{
987 uint8 Targets; // set of enum SelectTarget
988 uint8 Effects; // set of enum SelectEffect
989} *SpellSummary;
990
991ScriptObject::ScriptObject(char const* name) : _name(name)
992{
993 sScriptMgr->IncreaseScriptCount();
994}
995
996ScriptObject::~ScriptObject()
997{
998 sScriptMgr->DecreaseScriptCount();
999}
1000
1001ScriptMgr::ScriptMgr()
1002 : _scriptCount(0), _script_loader_callback(nullptr)
1003{
1004}
1005
1006ScriptMgr::~ScriptMgr() { }
1007
1008ScriptMgr* ScriptMgr::instance()
1009{
1010 static ScriptMgr instance;
1011 return &instance;
1012}
1013
1014void ScriptMgr::Initialize()
1015{
1016 ASSERT(sSpellMgr->GetSpellInfo(SPELL_HOTSWAP_VISUAL_SPELL_EFFECT)
1017 && "Reload hotswap spell effect for creatures isn't valid!");
1018
1019 uint32 oldMSTime = getMSTime();
1020
1021 LoadDatabase();
1022
1023 TC_LOG_INFO("server.loading", "Loading C++ scripts");
1024
1025 FillSpellSummary();
1026
1027 // Load core scripts
1028 SetScriptContext(GetNameOfStaticContext());
1029
1030 // SmartAI
1031 AddSC_SmartScripts();
1032
1033 // LFGScripts
1034 lfg::AddSC_LFGScripts();
1035
1036 // Load all static linked scripts through the script loader function.
1037 ASSERT(_script_loader_callback,
1038 "Script loader callback wasn't registered!");
1039 _script_loader_callback();
1040
1041 // Initialize all dynamic scripts
1042 // and finishes the context switch to do
1043 // bulk loading
1044 sScriptReloadMgr->Initialize();
1045
1046 // Loads all scripts from the current context
1047 sScriptMgr->SwapScriptContext(true);
1048
1049 // Print unused script names.
1050 std::unordered_set<std::string> unusedScriptNames(
1051 sObjectMgr->GetAllScriptNames().begin(),
1052 sObjectMgr->GetAllScriptNames().end());
1053
1054 // Remove the used scripts from the given container.
1055 sScriptRegistryCompositum->RemoveUsedScriptsFromContainer(unusedScriptNames);
1056
1057 for (std::string const& scriptName : unusedScriptNames)
1058 {
1059 // Avoid complaining about empty script names since the
1060 // script name container contains a placeholder as the 0 element.
1061 if (scriptName.empty())
1062 continue;
1063
1064 TC_LOG_ERROR("sql.sql", "ScriptName '%s' exists in database, "
1065 "but no core script found!", scriptName.c_str());
1066 }
1067
1068 TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms",
1069 GetScriptCount(), GetMSTimeDiffToNow(oldMSTime));
1070}
1071
1072void ScriptMgr::SetScriptContext(std::string const& context)
1073{
1074 _currentContext = context;
1075}
1076
1077void ScriptMgr::SwapScriptContext(bool initialize)
1078{
1079 sScriptRegistryCompositum->SwapContext(initialize);
1080 _currentContext.clear();
1081}
1082
1083std::string const& ScriptMgr::GetNameOfStaticContext()
1084{
1085 static std::string const name = "___static___";
1086 return name;
1087}
1088
1089void ScriptMgr::ReleaseScriptContext(std::string const& context)
1090{
1091 sScriptRegistryCompositum->ReleaseContext(context);
1092}
1093
1094std::shared_ptr<ModuleReference>
1095 ScriptMgr::AcquireModuleReferenceOfScriptName(std::string const& scriptname) const
1096{
1097#ifdef TRINITY_API_USE_DYNAMIC_LINKING
1098 // Returns the reference to the module of the given scriptname
1099 return ScriptReloadMgr::AcquireModuleReferenceOfContext(
1100 sScriptRegistryCompositum->GetScriptContextOfScriptName(scriptname));
1101#else
1102 (void)scriptname;
1103 // Something went wrong when this function is used in
1104 // a static linked context.
1105 WPAbort();
1106#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
1107}
1108
1109void ScriptMgr::Unload()
1110{
1111 sScriptRegistryCompositum->Unload();
1112
1113 delete[] SpellSummary;
1114 delete[] UnitAI::AISpellInfo;
1115}
1116
1117void ScriptMgr::LoadDatabase()
1118{
1119 sScriptSystemMgr->LoadScriptWaypoints();
1120 sScriptSystemMgr->LoadScriptSplineChains();
1121}
1122
1123void ScriptMgr::FillSpellSummary()
1124{
1125 UnitAI::FillAISpellInfo();
1126
1127 SpellSummary = new TSpellSummary[sSpellMgr->GetSpellInfoStoreSize()];
1128
1129 SpellInfo const* pTempSpell;
1130
1131 for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i)
1132 {
1133 SpellSummary[i].Effects = 0;
1134 SpellSummary[i].Targets = 0;
1135
1136 pTempSpell = sSpellMgr->GetSpellInfo(i);
1137 // This spell doesn't exist.
1138 if (!pTempSpell)
1139 continue;
1140
1141 for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
1142 {
1143 // Spell targets self.
1144 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER)
1145 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1);
1146
1147 // Spell targets a single enemy.
1148 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY ||
1149 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY)
1150 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1);
1151
1152 // Spell targets AoE at enemy.
1153 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY ||
1154 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY ||
1155 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER ||
1156 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)
1157 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1);
1158
1159 // Spell targets an enemy.
1160 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY ||
1161 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY ||
1162 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY ||
1163 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY ||
1164 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER ||
1165 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)
1166 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1);
1167
1168 // Spell targets a single friend (or self).
1169 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER ||
1170 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY ||
1171 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY)
1172 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1);
1173
1174 // Spell targets AoE friends.
1175 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY ||
1176 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY ||
1177 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER)
1178 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1);
1179
1180 // Spell targets any friend (or self).
1181 if (pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER ||
1182 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY ||
1183 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY ||
1184 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY ||
1185 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY ||
1186 pTempSpell->Effects[j].TargetA.GetTarget() == TARGET_SRC_CASTER)
1187 SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1);
1188
1189 // Make sure that this spell includes a damage effect.
1190 if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE ||
1191 pTempSpell->Effects[j].Effect == SPELL_EFFECT_INSTAKILL ||
1192 pTempSpell->Effects[j].Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE ||
1193 pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEALTH_LEECH)
1194 SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1);
1195
1196 // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal).
1197 if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL ||
1198 pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL_MAX_HEALTH ||
1199 pTempSpell->Effects[j].Effect == SPELL_EFFECT_HEAL_MECHANICAL ||
1200 (pTempSpell->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA && pTempSpell->Effects[j].ApplyAuraName == 8))
1201 SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1);
1202
1203 // Make sure that this spell applies an aura.
1204 if (pTempSpell->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
1205 SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1);
1206 }
1207 }
1208}
1209
1210template<typename T, typename F, typename O>
1211void CreateSpellOrAuraScripts(uint32 spellId, std::vector<T*>& scriptVector, F&& extractor, O* objectInvoker)
1212{
1213 SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId);
1214 for (auto itr = bounds.first; itr != bounds.second; ++itr)
1215 {
1216 // When the script is disabled continue with the next one
1217 if (!itr->second.second)
1218 continue;
1219
1220 SpellScriptLoader* tmpscript = sScriptMgr->GetSpellScriptLoader(itr->second.first);
1221 if (!tmpscript)
1222 continue;
1223
1224 T* script = (*tmpscript.*extractor)();
1225 if (!script)
1226 continue;
1227
1228 script->_Init(&tmpscript->GetName(), spellId);
1229 if (!script->_Load(objectInvoker))
1230 {
1231 delete script;
1232 continue;
1233 }
1234
1235 scriptVector.push_back(script);
1236 }
1237}
1238
1239void ScriptMgr::CreateSpellScripts(uint32 spellId, std::vector<SpellScript*>& scriptVector, Spell* invoker) const
1240{
1241 CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetSpellScript, invoker);
1242}
1243
1244void ScriptMgr::CreateAuraScripts(uint32 spellId, std::vector<AuraScript*>& scriptVector, Aura* invoker) const
1245{
1246 CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetAuraScript, invoker);
1247}
1248
1249SpellScriptLoader* ScriptMgr::GetSpellScriptLoader(uint32 scriptId)
1250{
1251 return ScriptRegistry<SpellScriptLoader>::Instance()->GetScriptById(scriptId);
1252}
1253
1254void ScriptMgr::OnNetworkStart()
1255{
1256 FOREACH_SCRIPT(ServerScript)->OnNetworkStart();
1257}
1258
1259void ScriptMgr::OnNetworkStop()
1260{
1261 FOREACH_SCRIPT(ServerScript)->OnNetworkStop();
1262}
1263
1264void ScriptMgr::OnSocketOpen(std::shared_ptr<WorldSocket> socket)
1265{
1266 ASSERT(socket);
1267
1268 FOREACH_SCRIPT(ServerScript)->OnSocketOpen(socket);
1269}
1270
1271void ScriptMgr::OnSocketClose(std::shared_ptr<WorldSocket> socket)
1272{
1273 ASSERT(socket);
1274
1275 FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket);
1276}
1277
1278void ScriptMgr::OnPacketReceive(WorldSession* session, WorldPacket const& packet)
1279{
1280 if (SCR_REG_LST(ServerScript).empty())
1281 return;
1282
1283 WorldPacket copy(packet);
1284 FOREACH_SCRIPT(ServerScript)->OnPacketReceive(session, copy);
1285}
1286
1287void ScriptMgr::OnPacketSend(WorldSession* session, WorldPacket const& packet)
1288{
1289 ASSERT(session);
1290
1291 if (SCR_REG_LST(ServerScript).empty())
1292 return;
1293
1294 WorldPacket copy(packet);
1295 FOREACH_SCRIPT(ServerScript)->OnPacketSend(session, copy);
1296}
1297
1298void ScriptMgr::OnOpenStateChange(bool open)
1299{
1300 FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open);
1301}
1302
1303void ScriptMgr::OnConfigLoad(bool reload)
1304{
1305 FOREACH_SCRIPT(WorldScript)->OnConfigLoad(reload);
1306}
1307
1308void ScriptMgr::OnMotdChange(std::string& newMotd)
1309{
1310 FOREACH_SCRIPT(WorldScript)->OnMotdChange(newMotd);
1311}
1312
1313void ScriptMgr::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
1314{
1315 FOREACH_SCRIPT(WorldScript)->OnShutdownInitiate(code, mask);
1316}
1317
1318void ScriptMgr::OnShutdownCancel()
1319{
1320 FOREACH_SCRIPT(WorldScript)->OnShutdownCancel();
1321}
1322
1323void ScriptMgr::OnWorldUpdate(uint32 diff)
1324{
1325 FOREACH_SCRIPT(WorldScript)->OnUpdate(diff);
1326}
1327
1328void ScriptMgr::OnHonorCalculation(float& honor, uint8 level, float multiplier)
1329{
1330 FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, multiplier);
1331}
1332
1333void ScriptMgr::OnGrayLevelCalculation(uint8& grayLevel, uint8 playerLevel)
1334{
1335 FOREACH_SCRIPT(FormulaScript)->OnGrayLevelCalculation(grayLevel, playerLevel);
1336}
1337
1338void ScriptMgr::OnColorCodeCalculation(XPColorChar& color, uint8 playerLevel, uint8 mobLevel)
1339{
1340 FOREACH_SCRIPT(FormulaScript)->OnColorCodeCalculation(color, playerLevel, mobLevel);
1341}
1342
1343void ScriptMgr::OnZeroDifferenceCalculation(uint8& diff, uint8 playerLevel)
1344{
1345 FOREACH_SCRIPT(FormulaScript)->OnZeroDifferenceCalculation(diff, playerLevel);
1346}
1347
1348void ScriptMgr::OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content)
1349{
1350 FOREACH_SCRIPT(FormulaScript)->OnBaseGainCalculation(gain, playerLevel, mobLevel, content);
1351}
1352
1353void ScriptMgr::OnGainCalculation(uint32& gain, Player* player, Unit* unit)
1354{
1355 ASSERT(player);
1356 ASSERT(unit);
1357
1358 FOREACH_SCRIPT(FormulaScript)->OnGainCalculation(gain, player, unit);
1359}
1360
1361void ScriptMgr::OnGroupRateCalculation(float& rate, uint32 count, bool isRaid)
1362{
1363 FOREACH_SCRIPT(FormulaScript)->OnGroupRateCalculation(rate, count, isRaid);
1364}
1365
1366#define SCR_MAP_BGN(M, V, I, E, C, T) \
1367 if (V->GetEntry() && V->GetEntry()->T()) \
1368 { \
1369 FOR_SCRIPTS(M, I, E) \
1370 { \
1371 MapEntry const* C = I->second->GetEntry(); \
1372 if (!C) \
1373 continue; \
1374 if (C->MapID == V->GetId()) \
1375 {
1376
1377#define SCR_MAP_END \
1378 return; \
1379 } \
1380 } \
1381 }
1382
1383void ScriptMgr::OnCreateMap(Map* map)
1384{
1385 ASSERT(map);
1386
1387 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1388 itr->second->OnCreate(map);
1389 SCR_MAP_END;
1390
1391 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1392 itr->second->OnCreate((InstanceMap*)map);
1393 SCR_MAP_END;
1394
1395 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1396 itr->second->OnCreate((BattlegroundMap*)map);
1397 SCR_MAP_END;
1398}
1399
1400void ScriptMgr::OnDestroyMap(Map* map)
1401{
1402 ASSERT(map);
1403
1404 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1405 itr->second->OnDestroy(map);
1406 SCR_MAP_END;
1407
1408 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1409 itr->second->OnDestroy((InstanceMap*)map);
1410 SCR_MAP_END;
1411
1412 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1413 itr->second->OnDestroy((BattlegroundMap*)map);
1414 SCR_MAP_END;
1415}
1416
1417void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
1418{
1419 ASSERT(map);
1420 ASSERT(gmap);
1421
1422 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1423 itr->second->OnLoadGridMap(map, gmap, gx, gy);
1424 SCR_MAP_END;
1425
1426 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1427 itr->second->OnLoadGridMap((InstanceMap*)map, gmap, gx, gy);
1428 SCR_MAP_END;
1429
1430 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1431 itr->second->OnLoadGridMap((BattlegroundMap*)map, gmap, gx, gy);
1432 SCR_MAP_END;
1433}
1434
1435void ScriptMgr::OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
1436{
1437 ASSERT(map);
1438 ASSERT(gmap);
1439
1440 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1441 itr->second->OnUnloadGridMap(map, gmap, gx, gy);
1442 SCR_MAP_END;
1443
1444 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1445 itr->second->OnUnloadGridMap((InstanceMap*)map, gmap, gx, gy);
1446 SCR_MAP_END;
1447
1448 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1449 itr->second->OnUnloadGridMap((BattlegroundMap*)map, gmap, gx, gy);
1450 SCR_MAP_END;
1451}
1452
1453void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player)
1454{
1455 ASSERT(map);
1456 ASSERT(player);
1457
1458 FOREACH_SCRIPT(PlayerScript)->OnMapChanged(player);
1459
1460 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1461 itr->second->OnPlayerEnter(map, player);
1462 SCR_MAP_END;
1463
1464 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1465 itr->second->OnPlayerEnter((InstanceMap*)map, player);
1466 SCR_MAP_END;
1467
1468 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1469 itr->second->OnPlayerEnter((BattlegroundMap*)map, player);
1470 SCR_MAP_END;
1471}
1472
1473void ScriptMgr::OnPlayerLeaveMap(Map* map, Player* player)
1474{
1475 ASSERT(map);
1476 ASSERT(player);
1477
1478 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1479 itr->second->OnPlayerLeave(map, player);
1480 SCR_MAP_END;
1481
1482 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1483 itr->second->OnPlayerLeave((InstanceMap*)map, player);
1484 SCR_MAP_END;
1485
1486 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1487 itr->second->OnPlayerLeave((BattlegroundMap*)map, player);
1488 SCR_MAP_END;
1489}
1490
1491void ScriptMgr::OnMapUpdate(Map* map, uint32 diff)
1492{
1493 ASSERT(map);
1494
1495 SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
1496 itr->second->OnUpdate(map, diff);
1497 SCR_MAP_END;
1498
1499 SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
1500 itr->second->OnUpdate((InstanceMap*)map, diff);
1501 SCR_MAP_END;
1502
1503 SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
1504 itr->second->OnUpdate((BattlegroundMap*)map, diff);
1505 SCR_MAP_END;
1506}
1507
1508#undef SCR_MAP_BGN
1509#undef SCR_MAP_END
1510
1511InstanceScript* ScriptMgr::CreateInstanceData(InstanceMap* map)
1512{
1513 ASSERT(map);
1514
1515 GET_SCRIPT_RET(InstanceMapScript, map->GetScriptId(), tmpscript, nullptr);
1516 return tmpscript->GetInstanceScript(map);
1517}
1518
1519bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest)
1520{
1521 ASSERT(player);
1522 ASSERT(item);
1523 ASSERT(quest);
1524
1525 GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
1526 player->PlayerTalkClass->ClearMenus();
1527 return tmpscript->OnQuestAccept(player, item, quest);
1528}
1529
1530bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& targets)
1531{
1532 ASSERT(player);
1533 ASSERT(item);
1534
1535 GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
1536 return tmpscript->OnUse(player, item, targets);
1537}
1538
1539bool ScriptMgr::OnItemExpire(Player* player, ItemTemplate const* proto)
1540{
1541 ASSERT(player);
1542 ASSERT(proto);
1543
1544 GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false);
1545 return tmpscript->OnExpire(player, proto);
1546}
1547
1548bool ScriptMgr::OnItemRemove(Player* player, Item* item)
1549{
1550 ASSERT(player);
1551 ASSERT(item);
1552
1553 GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
1554 return tmpscript->OnRemove(player, item);
1555}
1556
1557bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo const* spellInfo, Item* item)
1558{
1559 ASSERT(player);
1560 ASSERT(victim);
1561 ASSERT(spellInfo);
1562 ASSERT(item);
1563
1564 GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, true);
1565 return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item);
1566}
1567
1568CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
1569{
1570 ASSERT(creature);
1571
1572 GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, nullptr);
1573 return tmpscript->GetAI(creature);
1574}
1575
1576GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject)
1577{
1578 ASSERT(gameobject);
1579
1580 GET_SCRIPT_RET(GameObjectScript, gameobject->GetScriptId(), tmpscript, nullptr);
1581 return tmpscript->GetAI(gameobject);
1582}
1583
1584bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger)
1585{
1586 ASSERT(player);
1587 ASSERT(trigger);
1588
1589 GET_SCRIPT_RET(AreaTriggerScript, sObjectMgr->GetAreaTriggerScriptId(trigger->id), tmpscript, false);
1590 return tmpscript->OnTrigger(player, trigger);
1591}
1592
1593Battleground* ScriptMgr::CreateBattleground(BattlegroundTypeId /*typeId*/)
1594{
1595 /// @todo Implement script-side battlegrounds.
1596 ABORT();
1597 return nullptr;
1598}
1599
1600OutdoorPvP* ScriptMgr::CreateOutdoorPvP(uint32 scriptId)
1601{
1602 GET_SCRIPT_RET(OutdoorPvPScript, scriptId, tmpscript, nullptr);
1603 return tmpscript->GetOutdoorPvP();
1604}
1605
1606std::vector<ChatCommand> ScriptMgr::GetChatCommands()
1607{
1608 std::vector<ChatCommand> table;
1609
1610 FOR_SCRIPTS_RET(CommandScript, itr, end, table)
1611 {
1612 std::vector<ChatCommand> cmds = itr->second->GetCommands();
1613 table.insert(table.end(), cmds.begin(), cmds.end());
1614 }
1615
1616 // Sort commands in alphabetical order
1617 std::sort(table.begin(), table.end(), [](ChatCommand const& a, ChatCommand const& b)
1618 {
1619 return strcmp(a.Name, b.Name) < 0;
1620 });
1621
1622 return table;
1623}
1624
1625void ScriptMgr::OnWeatherChange(Weather* weather, WeatherState state, float grade)
1626{
1627 ASSERT(weather);
1628
1629 GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript);
1630 tmpscript->OnChange(weather, state, grade);
1631}
1632
1633void ScriptMgr::OnWeatherUpdate(Weather* weather, uint32 diff)
1634{
1635 ASSERT(weather);
1636
1637 GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript);
1638 tmpscript->OnUpdate(weather, diff);
1639}
1640
1641void ScriptMgr::OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry)
1642{
1643 ASSERT(ah);
1644 ASSERT(entry);
1645
1646 FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, entry);
1647}
1648
1649void ScriptMgr::OnAuctionRemove(AuctionHouseObject* ah, AuctionEntry* entry)
1650{
1651 ASSERT(ah);
1652 ASSERT(entry);
1653
1654 FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, entry);
1655}
1656
1657void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry)
1658{
1659 ASSERT(ah);
1660 ASSERT(entry);
1661
1662 FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, entry);
1663}
1664
1665void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry)
1666{
1667 ASSERT(ah);
1668 ASSERT(entry);
1669
1670 FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, entry);
1671}
1672
1673bool ScriptMgr::OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo)
1674{
1675 ASSERT(condition);
1676
1677 GET_SCRIPT_RET(ConditionScript, condition->ScriptId, tmpscript, true);
1678 return tmpscript->OnConditionCheck(condition, sourceInfo);
1679}
1680
1681void ScriptMgr::OnInstall(Vehicle* veh)
1682{
1683 ASSERT(veh);
1684 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1685
1686 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1687 tmpscript->OnInstall(veh);
1688}
1689
1690void ScriptMgr::OnUninstall(Vehicle* veh)
1691{
1692 ASSERT(veh);
1693 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1694
1695 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1696 tmpscript->OnUninstall(veh);
1697}
1698
1699void ScriptMgr::OnReset(Vehicle* veh)
1700{
1701 ASSERT(veh);
1702 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1703
1704 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1705 tmpscript->OnReset(veh);
1706}
1707
1708void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory)
1709{
1710 ASSERT(veh);
1711 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1712 ASSERT(accessory);
1713
1714 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1715 tmpscript->OnInstallAccessory(veh, accessory);
1716}
1717
1718void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId)
1719{
1720 ASSERT(veh);
1721 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1722 ASSERT(passenger);
1723
1724 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1725 tmpscript->OnAddPassenger(veh, passenger, seatId);
1726}
1727
1728void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger)
1729{
1730 ASSERT(veh);
1731 ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
1732 ASSERT(passenger);
1733
1734 GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
1735 tmpscript->OnRemovePassenger(veh, passenger);
1736}
1737
1738void ScriptMgr::OnDynamicObjectUpdate(DynamicObject* dynobj, uint32 diff)
1739{
1740 ASSERT(dynobj);
1741
1742 FOR_SCRIPTS(DynamicObjectScript, itr, end)
1743 itr->second->OnUpdate(dynobj, diff);
1744}
1745
1746void ScriptMgr::OnAddPassenger(Transport* transport, Player* player)
1747{
1748 ASSERT(transport);
1749 ASSERT(player);
1750
1751 GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
1752 tmpscript->OnAddPassenger(transport, player);
1753}
1754
1755void ScriptMgr::OnAddCreaturePassenger(Transport* transport, Creature* creature)
1756{
1757 ASSERT(transport);
1758 ASSERT(creature);
1759
1760 GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
1761 tmpscript->OnAddCreaturePassenger(transport, creature);
1762}
1763
1764void ScriptMgr::OnRemovePassenger(Transport* transport, Player* player)
1765{
1766 ASSERT(transport);
1767 ASSERT(player);
1768
1769 GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
1770 tmpscript->OnRemovePassenger(transport, player);
1771}
1772
1773void ScriptMgr::OnTransportUpdate(Transport* transport, uint32 diff)
1774{
1775 ASSERT(transport);
1776
1777 GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
1778 tmpscript->OnUpdate(transport, diff);
1779}
1780
1781void ScriptMgr::OnRelocate(Transport* transport, uint32 waypointId, uint32 mapId, float x, float y, float z)
1782{
1783 GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
1784 tmpscript->OnRelocate(transport, waypointId, mapId, x, y, z);
1785}
1786
1787void ScriptMgr::OnStartup()
1788{
1789 FOREACH_SCRIPT(WorldScript)->OnStartup();
1790}
1791
1792void ScriptMgr::OnShutdown()
1793{
1794 FOREACH_SCRIPT(WorldScript)->OnShutdown();
1795}
1796
1797bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target)
1798{
1799 ASSERT(source);
1800 // target can be NULL.
1801
1802 GET_SCRIPT_RET(AchievementCriteriaScript, scriptId, tmpscript, false);
1803 return tmpscript->OnCheck(source, target);
1804}
1805
1806//Player
1807
1808std::pair<bool, std::string> ScriptMgr::OnEquipItem(Player* player, Item* item)
1809 {
1810 FOREACH_SCRIPT(PlayerScript)->OnEquipItem(player, item);
1811 }
1812
1813
1814void ScriptMgr::OnPVPKill(Player* killer, Player* killed)
1815{
1816 FOREACH_SCRIPT(PlayerScript)->OnPVPKill(killer, killed);
1817}
1818
1819void ScriptMgr::OnCreatureKill(Player* killer, Creature* killed)
1820{
1821 FOREACH_SCRIPT(PlayerScript)->OnCreatureKill(killer, killed);
1822}
1823
1824void ScriptMgr::OnPlayerKilledByCreature(Creature* killer, Player* killed)
1825{
1826 FOREACH_SCRIPT(PlayerScript)->OnPlayerKilledByCreature(killer, killed);
1827}
1828
1829void ScriptMgr::OnPlayerLevelChanged(Player* player, uint8 oldLevel)
1830{
1831 FOREACH_SCRIPT(PlayerScript)->OnLevelChanged(player, oldLevel);
1832}
1833
1834void ScriptMgr::OnPlayerFreeTalentPointsChanged(Player* player, uint32 points)
1835{
1836 FOREACH_SCRIPT(PlayerScript)->OnFreeTalentPointsChanged(player, points);
1837}
1838
1839void ScriptMgr::OnPlayerTalentsReset(Player* player, bool noCost)
1840{
1841 FOREACH_SCRIPT(PlayerScript)->OnTalentsReset(player, noCost);
1842}
1843
1844void ScriptMgr::OnPlayerMoneyChanged(Player* player, int32& amount)
1845{
1846 FOREACH_SCRIPT(PlayerScript)->OnMoneyChanged(player, amount);
1847}
1848
1849void ScriptMgr::OnPlayerMoneyLimit(Player* player, int32 amount)
1850{
1851 FOREACH_SCRIPT(PlayerScript)->OnMoneyLimit(player, amount);
1852}
1853
1854void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim)
1855{
1856 FOREACH_SCRIPT(PlayerScript)->OnGiveXP(player, amount, victim);
1857}
1858
1859void ScriptMgr::OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental)
1860{
1861 FOREACH_SCRIPT(PlayerScript)->OnReputationChange(player, factionID, standing, incremental);
1862}
1863
1864void ScriptMgr::OnPlayerDuelRequest(Player* target, Player* challenger)
1865{
1866 FOREACH_SCRIPT(PlayerScript)->OnDuelRequest(target, challenger);
1867}
1868
1869void ScriptMgr::OnPlayerDuelStart(Player* player1, Player* player2)
1870{
1871 FOREACH_SCRIPT(PlayerScript)->OnDuelStart(player1, player2);
1872}
1873
1874void ScriptMgr::OnPlayerDuelEnd(Player* winner, Player* loser, DuelCompleteType type)
1875{
1876 FOREACH_SCRIPT(PlayerScript)->OnDuelEnd(winner, loser, type);
1877}
1878
1879void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg)
1880{
1881 FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg);
1882}
1883
1884void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver)
1885{
1886 FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, receiver);
1887}
1888
1889void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group)
1890{
1891 FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, group);
1892}
1893
1894void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild)
1895{
1896 FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, guild);
1897}
1898
1899void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel)
1900{
1901 FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, channel);
1902}
1903
1904void ScriptMgr::OnPlayerEmote(Player* player, uint32 emote)
1905{
1906 FOREACH_SCRIPT(PlayerScript)->OnEmote(player, emote);
1907}
1908
1909void ScriptMgr::OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, ObjectGuid guid)
1910{
1911 FOREACH_SCRIPT(PlayerScript)->OnTextEmote(player, textEmote, emoteNum, guid);
1912}
1913
1914void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck)
1915{
1916 FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck);
1917}
1918
1919void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin)
1920{
1921 FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin);
1922}
1923
1924void ScriptMgr::OnPlayerLogout(Player* player)
1925{
1926 FOREACH_SCRIPT(PlayerScript)->OnLogout(player);
1927}
1928
1929void ScriptMgr::OnPlayerCreate(Player* player)
1930{
1931 FOREACH_SCRIPT(PlayerScript)->OnCreate(player);
1932}
1933
1934void ScriptMgr::OnPlayerDelete(ObjectGuid guid, uint32 accountId)
1935{
1936 FOREACH_SCRIPT(PlayerScript)->OnDelete(guid, accountId);
1937}
1938
1939void ScriptMgr::OnPlayerFailedDelete(ObjectGuid guid, uint32 accountId)
1940{
1941 FOREACH_SCRIPT(PlayerScript)->OnFailedDelete(guid, accountId);
1942}
1943
1944void ScriptMgr::OnPlayerSave(Player* player)
1945{
1946 FOREACH_SCRIPT(PlayerScript)->OnSave(player);
1947}
1948
1949void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState)
1950{
1951 FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent, extendState);
1952}
1953
1954void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea)
1955{
1956 FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea);
1957}
1958
1959void ScriptMgr::OnQuestStatusChange(Player* player, uint32 questId)
1960{
1961 FOREACH_SCRIPT(PlayerScript)->OnQuestStatusChange(player, questId);
1962}
1963
1964void ScriptMgr::OnPlayerRepop(Player* player)
1965{
1966 FOREACH_SCRIPT(PlayerScript)->OnPlayerRepop(player);
1967}
1968
1969// Account
1970void ScriptMgr::OnAccountLogin(uint32 accountId)
1971{
1972 FOREACH_SCRIPT(AccountScript)->OnAccountLogin(accountId);
1973}
1974
1975void ScriptMgr::OnFailedAccountLogin(uint32 accountId)
1976{
1977 FOREACH_SCRIPT(AccountScript)->OnFailedAccountLogin(accountId);
1978}
1979
1980void ScriptMgr::OnEmailChange(uint32 accountId)
1981{
1982 FOREACH_SCRIPT(AccountScript)->OnEmailChange(accountId);
1983}
1984
1985void ScriptMgr::OnFailedEmailChange(uint32 accountId)
1986{
1987 FOREACH_SCRIPT(AccountScript)->OnFailedEmailChange(accountId);
1988}
1989
1990void ScriptMgr::OnPasswordChange(uint32 accountId)
1991{
1992 FOREACH_SCRIPT(AccountScript)->OnPasswordChange(accountId);
1993}
1994
1995void ScriptMgr::OnFailedPasswordChange(uint32 accountId)
1996{
1997 FOREACH_SCRIPT(AccountScript)->OnFailedPasswordChange(accountId);
1998}
1999
2000// Guild
2001void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8& plRank)
2002{
2003 FOREACH_SCRIPT(GuildScript)->OnAddMember(guild, player, plRank);
2004}
2005
2006void ScriptMgr::OnGuildRemoveMember(Guild* guild, Player* player, bool isDisbanding, bool isKicked)
2007{
2008 FOREACH_SCRIPT(GuildScript)->OnRemoveMember(guild, player, isDisbanding, isKicked);
2009}
2010
2011void ScriptMgr::OnGuildMOTDChanged(Guild* guild, const std::string& newMotd)
2012{
2013 FOREACH_SCRIPT(GuildScript)->OnMOTDChanged(guild, newMotd);
2014}
2015
2016void ScriptMgr::OnGuildInfoChanged(Guild* guild, const std::string& newInfo)
2017{
2018 FOREACH_SCRIPT(GuildScript)->OnInfoChanged(guild, newInfo);
2019}
2020
2021void ScriptMgr::OnGuildCreate(Guild* guild, Player* leader, const std::string& name)
2022{
2023 FOREACH_SCRIPT(GuildScript)->OnCreate(guild, leader, name);
2024}
2025
2026void ScriptMgr::OnGuildDisband(Guild* guild)
2027{
2028 FOREACH_SCRIPT(GuildScript)->OnDisband(guild);
2029}
2030
2031void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair)
2032{
2033 FOREACH_SCRIPT(GuildScript)->OnMemberWitdrawMoney(guild, player, amount, isRepair);
2034}
2035
2036void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint32 &amount)
2037{
2038 FOREACH_SCRIPT(GuildScript)->OnMemberDepositMoney(guild, player, amount);
2039}
2040
2041void ScriptMgr::OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId,
2042 bool isDestBank, uint8 destContainer, uint8 destSlotId)
2043{
2044 FOREACH_SCRIPT(GuildScript)->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId);
2045}
2046
2047void ScriptMgr::OnGuildEvent(Guild* guild, uint8 eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank)
2048{
2049 FOREACH_SCRIPT(GuildScript)->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank);
2050}
2051
2052void ScriptMgr::OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
2053{
2054 FOREACH_SCRIPT(GuildScript)->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId);
2055}
2056
2057// Group
2058void ScriptMgr::OnGroupAddMember(Group* group, ObjectGuid guid)
2059{
2060 ASSERT(group);
2061 FOREACH_SCRIPT(GroupScript)->OnAddMember(group, guid);
2062}
2063
2064void ScriptMgr::OnGroupInviteMember(Group* group, ObjectGuid guid)
2065{
2066 ASSERT(group);
2067 FOREACH_SCRIPT(GroupScript)->OnInviteMember(group, guid);
2068}
2069
2070void ScriptMgr::OnGroupRemoveMember(Group* group, ObjectGuid guid, RemoveMethod method, ObjectGuid kicker, char const* reason)
2071{
2072 ASSERT(group);
2073 FOREACH_SCRIPT(GroupScript)->OnRemoveMember(group, guid, method, kicker, reason);
2074}
2075
2076void ScriptMgr::OnGroupChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid)
2077{
2078 ASSERT(group);
2079 FOREACH_SCRIPT(GroupScript)->OnChangeLeader(group, newLeaderGuid, oldLeaderGuid);
2080}
2081
2082void ScriptMgr::OnGroupDisband(Group* group)
2083{
2084 ASSERT(group);
2085 FOREACH_SCRIPT(GroupScript)->OnDisband(group);
2086}
2087
2088// Unit
2089void ScriptMgr::OnHeal(Unit* healer, Unit* reciever, uint32& gain)
2090{
2091 FOREACH_SCRIPT(UnitScript)->OnHeal(healer, reciever, gain);
2092 FOREACH_SCRIPT(PlayerScript)->OnHeal(healer, reciever, gain);
2093}
2094
2095void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage)
2096{
2097 FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage);
2098 FOREACH_SCRIPT(PlayerScript)->OnDamage(attacker, victim, damage);
2099}
2100
2101void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage)
2102{
2103 FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage);
2104 FOREACH_SCRIPT(PlayerScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage);
2105}
2106
2107void ScriptMgr::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage)
2108{
2109 FOREACH_SCRIPT(UnitScript)->ModifyMeleeDamage(target, attacker, damage);
2110 FOREACH_SCRIPT(PlayerScript)->ModifyMeleeDamage(target, attacker, damage);
2111}
2112
2113void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage)
2114{
2115 FOREACH_SCRIPT(UnitScript)->ModifySpellDamageTaken(target, attacker, damage);
2116 FOREACH_SCRIPT(PlayerScript)->ModifySpellDamageTaken(target, attacker, damage);
2117}
2118
2119SpellScriptLoader::SpellScriptLoader(char const* name)
2120 : ScriptObject(name)
2121{
2122 ScriptRegistry<SpellScriptLoader>::Instance()->AddScript(this);
2123}
2124
2125ServerScript::ServerScript(char const* name)
2126 : ScriptObject(name)
2127{
2128 ScriptRegistry<ServerScript>::Instance()->AddScript(this);
2129}
2130
2131WorldScript::WorldScript(char const* name)
2132 : ScriptObject(name)
2133{
2134 ScriptRegistry<WorldScript>::Instance()->AddScript(this);
2135}
2136
2137FormulaScript::FormulaScript(char const* name)
2138 : ScriptObject(name)
2139{
2140 ScriptRegistry<FormulaScript>::Instance()->AddScript(this);
2141}
2142
2143UnitScript::UnitScript(char const* name, bool addToScripts)
2144 : ScriptObject(name)
2145{
2146 if (addToScripts)
2147 ScriptRegistry<UnitScript>::Instance()->AddScript(this);
2148}
2149
2150WorldMapScript::WorldMapScript(char const* name, uint32 mapId)
2151 : ScriptObject(name), MapScript<Map>(sMapStore.LookupEntry(mapId))
2152{
2153 if (!GetEntry())
2154 TC_LOG_ERROR("scripts", "Invalid WorldMapScript for %u; no such map ID.", mapId);
2155
2156 if (GetEntry() && !GetEntry()->IsWorldMap())
2157 TC_LOG_ERROR("scripts", "WorldMapScript for map %u is invalid.", mapId);
2158
2159 ScriptRegistry<WorldMapScript>::Instance()->AddScript(this);
2160}
2161
2162InstanceMapScript::InstanceMapScript(char const* name, uint32 mapId)
2163 : ScriptObject(name), MapScript<InstanceMap>(sMapStore.LookupEntry(mapId))
2164{
2165 if (!GetEntry())
2166 TC_LOG_ERROR("scripts", "Invalid InstanceMapScript for %u; no such map ID.", mapId);
2167
2168 if (GetEntry() && !GetEntry()->IsDungeon())
2169 TC_LOG_ERROR("scripts", "InstanceMapScript for map %u is invalid.", mapId);
2170
2171 ScriptRegistry<InstanceMapScript>::Instance()->AddScript(this);
2172}
2173
2174BattlegroundMapScript::BattlegroundMapScript(char const* name, uint32 mapId)
2175 : ScriptObject(name), MapScript<BattlegroundMap>(sMapStore.LookupEntry(mapId))
2176{
2177 if (!GetEntry())
2178 TC_LOG_ERROR("scripts", "Invalid BattlegroundMapScript for %u; no such map ID.", mapId);
2179
2180 if (GetEntry() && !GetEntry()->IsBattleground())
2181 TC_LOG_ERROR("scripts", "BattlegroundMapScript for map %u is invalid.", mapId);
2182
2183 ScriptRegistry<BattlegroundMapScript>::Instance()->AddScript(this);
2184}
2185
2186ItemScript::ItemScript(char const* name)
2187 : ScriptObject(name)
2188{
2189 ScriptRegistry<ItemScript>::Instance()->AddScript(this);
2190}
2191
2192CreatureScript::CreatureScript(char const* name)
2193 : UnitScript(name, false)
2194{
2195 ScriptRegistry<CreatureScript>::Instance()->AddScript(this);
2196}
2197
2198GameObjectScript::GameObjectScript(char const* name)
2199 : ScriptObject(name)
2200{
2201 ScriptRegistry<GameObjectScript>::Instance()->AddScript(this);
2202}
2203
2204AreaTriggerScript::AreaTriggerScript(char const* name)
2205 : ScriptObject(name)
2206{
2207 ScriptRegistry<AreaTriggerScript>::Instance()->AddScript(this);
2208}
2209
2210bool OnlyOnceAreaTriggerScript::OnTrigger(Player* player, AreaTriggerEntry const* trigger)
2211{
2212 uint32 const triggerId = trigger->id;
2213 if (InstanceScript* instance = player->GetInstanceScript())
2214 {
2215 if (instance->IsAreaTriggerDone(triggerId))
2216 return true;
2217 else
2218 instance->MarkAreaTriggerDone(triggerId);
2219 }
2220 return _OnTrigger(player, trigger);
2221}
2222void OnlyOnceAreaTriggerScript::ResetAreaTriggerDone(InstanceScript* script, uint32 triggerId) { script->ResetAreaTriggerDone(triggerId); }
2223void OnlyOnceAreaTriggerScript::ResetAreaTriggerDone(Player const* player, AreaTriggerEntry const* trigger) { if (InstanceScript* instance = player->GetInstanceScript()) ResetAreaTriggerDone(instance, trigger->id); }
2224
2225BattlegroundScript::BattlegroundScript(char const* name)
2226 : ScriptObject(name)
2227{
2228 ScriptRegistry<BattlegroundScript>::Instance()->AddScript(this);
2229}
2230
2231OutdoorPvPScript::OutdoorPvPScript(char const* name)
2232 : ScriptObject(name)
2233{
2234 ScriptRegistry<OutdoorPvPScript>::Instance()->AddScript(this);
2235}
2236
2237CommandScript::CommandScript(char const* name)
2238 : ScriptObject(name)
2239{
2240 ScriptRegistry<CommandScript>::Instance()->AddScript(this);
2241}
2242
2243WeatherScript::WeatherScript(char const* name)
2244 : ScriptObject(name)
2245{
2246 ScriptRegistry<WeatherScript>::Instance()->AddScript(this);
2247}
2248
2249AuctionHouseScript::AuctionHouseScript(char const* name)
2250 : ScriptObject(name)
2251{
2252 ScriptRegistry<AuctionHouseScript>::Instance()->AddScript(this);
2253}
2254
2255ConditionScript::ConditionScript(char const* name)
2256 : ScriptObject(name)
2257{
2258 ScriptRegistry<ConditionScript>::Instance()->AddScript(this);
2259}
2260
2261VehicleScript::VehicleScript(char const* name)
2262 : ScriptObject(name)
2263{
2264 ScriptRegistry<VehicleScript>::Instance()->AddScript(this);
2265}
2266
2267DynamicObjectScript::DynamicObjectScript(char const* name)
2268 : ScriptObject(name)
2269{
2270 ScriptRegistry<DynamicObjectScript>::Instance()->AddScript(this);
2271}
2272
2273TransportScript::TransportScript(char const* name)
2274 : ScriptObject(name)
2275{
2276 ScriptRegistry<TransportScript>::Instance()->AddScript(this);
2277}
2278
2279AchievementCriteriaScript::AchievementCriteriaScript(char const* name)
2280 : ScriptObject(name)
2281{
2282 ScriptRegistry<AchievementCriteriaScript>::Instance()->AddScript(this);
2283}
2284
2285PlayerScript::PlayerScript(char const* name)
2286 : UnitScript(name, false)
2287{
2288 ScriptRegistry<PlayerScript>::Instance()->AddScript(this);
2289}
2290
2291AccountScript::AccountScript(char const* name)
2292 : ScriptObject(name)
2293{
2294 ScriptRegistry<AccountScript>::Instance()->AddScript(this);
2295}
2296
2297GuildScript::GuildScript(char const* name)
2298 : ScriptObject(name)
2299{
2300 ScriptRegistry<GuildScript>::Instance()->AddScript(this);
2301}
2302
2303GroupScript::GroupScript(char const* name)
2304 : ScriptObject(name)
2305{
2306 ScriptRegistry<GroupScript>::Instance()->AddScript(this);
2307}
2308
2309// Specialize for each script type class like so:
2310template class TC_GAME_API ScriptRegistry<SpellScriptLoader>;
2311template class TC_GAME_API ScriptRegistry<ServerScript>;
2312template class TC_GAME_API ScriptRegistry<WorldScript>;
2313template class TC_GAME_API ScriptRegistry<FormulaScript>;
2314template class TC_GAME_API ScriptRegistry<WorldMapScript>;
2315template class TC_GAME_API ScriptRegistry<InstanceMapScript>;
2316template class TC_GAME_API ScriptRegistry<BattlegroundMapScript>;
2317template class TC_GAME_API ScriptRegistry<ItemScript>;
2318template class TC_GAME_API ScriptRegistry<CreatureScript>;
2319template class TC_GAME_API ScriptRegistry<GameObjectScript>;
2320template class TC_GAME_API ScriptRegistry<AreaTriggerScript>;
2321template class TC_GAME_API ScriptRegistry<BattlegroundScript>;
2322template class TC_GAME_API ScriptRegistry<OutdoorPvPScript>;
2323template class TC_GAME_API ScriptRegistry<CommandScript>;
2324template class TC_GAME_API ScriptRegistry<WeatherScript>;
2325template class TC_GAME_API ScriptRegistry<AuctionHouseScript>;
2326template class TC_GAME_API ScriptRegistry<ConditionScript>;
2327template class TC_GAME_API ScriptRegistry<VehicleScript>;
2328template class TC_GAME_API ScriptRegistry<DynamicObjectScript>;
2329template class TC_GAME_API ScriptRegistry<TransportScript>;
2330template class TC_GAME_API ScriptRegistry<AchievementCriteriaScript>;
2331template class TC_GAME_API ScriptRegistry<PlayerScript>;
2332template class TC_GAME_API ScriptRegistry<GuildScript>;
2333template class TC_GAME_API ScriptRegistry<GroupScript>;
2334template class TC_GAME_API ScriptRegistry<UnitScript>;
2335template class TC_GAME_API ScriptRegistry<AccountScript>;