TrinityCore
InstanceScript.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 "InstanceScript.h"
19#include "AreaBoundary.h"
20#include "Creature.h"
21#include "CreatureAI.h"
22#include "CreatureAIImpl.h"
23#include "DatabaseEnv.h"
24#include "DB2Stores.h"
25#include "GameEventSender.h"
26#include "GameObject.h"
27#include "Group.h"
28#include "InstancePackets.h"
29#include "InstanceScenario.h"
30#include "InstanceScriptData.h"
31#include "LFGMgr.h"
32#include "Log.h"
33#include "Map.h"
34#include "ObjectMgr.h"
35#include "PhasingHandler.h"
36#include "Player.h"
37#include "RBAC.h"
38#include "ScriptedCreature.h"
39#include "ScriptReloadMgr.h"
40#include "SmartEnum.h"
41#include "SpellMgr.h"
42#include "World.h"
43#include "WorldSession.h"
44#include "WorldStateMgr.h"
45#include <cstdarg>
46
47#ifdef TRINITY_API_USE_DYNAMIC_LINKING
48#include "ScriptMgr.h"
49#endif
50
52{
53 for (const_iterator it = begin(); it != end(); ++it)
54 delete it->Boundary;
55}
56
58{
59 auto itr = std::find_if(DungeonEncounters.begin(), DungeonEncounters.end(), [difficulty](DungeonEncounterEntry const* dungeonEncounter)
60 {
61 return dungeonEncounter && (dungeonEncounter->DifficultyID == 0 || Difficulty(dungeonEncounter->DifficultyID) == difficulty);
62 });
63
64 return itr != DungeonEncounters.end() ? *itr : nullptr;
65}
66
67InstanceScript::InstanceScript(InstanceMap* map) : instance(map), _instanceSpawnGroups(sObjectMgr->GetInstanceSpawnGroupsForMap(map->GetId())),
68_entranceId(0), _temporaryEntranceId(0), _combatResurrectionTimer(0), _combatResurrectionCharges(0), _combatResurrectionTimerStarted(false)
69{
70#ifdef TRINITY_API_USE_DYNAMIC_LINKING
71 uint32 scriptId = sObjectMgr->GetInstanceTemplate(map->GetId())->ScriptId;
72 auto const scriptname = sObjectMgr->GetScriptName(scriptId);
73 ASSERT(!scriptname.empty());
74 // Acquire a strong reference from the script module
75 // to keep it loaded until this object is destroyed.
76 module_reference = sScriptMgr->AcquireModuleReferenceOfScriptName(scriptname);
77#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
78}
79
81{
82}
83
85{
86 for (std::vector<BossInfo>::const_iterator itr = bosses.begin(); itr != bosses.end(); ++itr)
87 if (itr->state == IN_PROGRESS)
88 return true;
89
90 return false;
91}
92
94{
95 AddObject(creature, true);
96 AddMinion(creature, true);
97}
98
100{
101 AddObject(creature, false);
102 AddMinion(creature, false);
103}
104
106{
107 AddObject(go, true);
108 AddDoor(go, true);
109}
110
112{
113 AddObject(go, false);
114 AddDoor(go, false);
115}
116
118{
119 ObjectGuidMap::const_iterator i = _objectGuids.find(type);
120 if (i != _objectGuids.end())
121 return i->second;
122 return ObjectGuid::Empty;
123}
124
126{
127 return GetObjectGuid(type);
128}
129
130void InstanceScript::TriggerGameEvent(uint32 gameEventId, WorldObject* source /*= nullptr*/, WorldObject* target /*= nullptr*/)
131{
132 if (source)
133 {
134 ZoneScript::TriggerGameEvent(gameEventId, source, target);
135 return;
136 }
137
138 ProcessEvent(target, gameEventId, source);
139 instance->DoOnPlayers([gameEventId](Player* player)
140 {
141 GameEvents::TriggerForPlayer(gameEventId, player);
142 });
143
145}
146
148{
149 return instance->GetCreature(GetObjectGuid(type));
150}
151
153{
154 return instance->GetGameObject(GetObjectGuid(type));
155}
156
157void InstanceScript::SetHeaders(std::string const& dataHeaders)
158{
159 headers = dataHeaders;
160}
161
163{
164 for (BossBoundaryEntry const& entry : data)
165 if (entry.BossId < bosses.size())
166 bosses[entry.BossId].boundary.push_back(entry.Boundary);
167}
168
170{
171 while (data->entry)
172 {
173 if (data->bossId < bosses.size())
174 minions.insert(std::make_pair(data->entry, MinionInfo(&bosses[data->bossId])));
175
176 ++data;
177 }
178 TC_LOG_DEBUG("scripts", "InstanceScript::LoadMinionData: {} minions loaded.", uint64(minions.size()));
179}
180
182{
183 while (data->entry)
184 {
185 if (data->bossId < bosses.size())
186 doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->Behavior)));
187
188 ++data;
189 }
190 TC_LOG_DEBUG("scripts", "InstanceScript::LoadDoorData: {} doors loaded.", uint64(doors.size()));
191}
192
194{
195 if (creatureData)
197
198 if (gameObjectData)
200
201 TC_LOG_DEBUG("scripts", "InstanceScript::LoadObjectData: {} objects loaded.", _creatureInfo.size() + _gameObjectInfo.size());
202}
203
205{
206 while (data->entry)
207 {
208 ASSERT(objectInfo.find(data->entry) == objectInfo.end());
209 objectInfo[data->entry] = data->type;
210 ++data;
211 }
212}
213
214void InstanceScript::LoadDungeonEncounterData(uint32 bossId, std::array<uint32, MAX_DUNGEON_ENCOUNTERS_PER_BOSS> const& dungeonEncounterIds)
215{
216 if (bossId < bosses.size())
217 for (std::size_t i = 0; i < MAX_DUNGEON_ENCOUNTERS_PER_BOSS; ++i)
218 bosses[bossId].DungeonEncounters[i] = sDungeonEncounterStore.LookupEntry(dungeonEncounterIds[i]);
219}
220
222{
223 DoorInfoMapBounds range = doors.equal_range(door->GetEntry());
224 if (range.first == range.second)
225 return;
226
227 bool open = true;
228 for (; range.first != range.second && open; ++range.first)
229 {
230 DoorInfo const& info = range.first->second;
231 switch (info.Behavior)
232 {
234 open = (info.bossInfo->state != IN_PROGRESS);
235 break;
237 open = (info.bossInfo->state == DONE);
238 break;
240 open = (info.bossInfo->state == IN_PROGRESS);
241 break;
243 open = (info.bossInfo->state != DONE);
244 break;
245 default:
246 break;
247 }
248 }
249
251}
252
254{
255 switch (state)
256 {
257 case NOT_STARTED:
258 if (!minion->IsAlive())
259 minion->Respawn();
260 else if (minion->IsInCombat())
261 minion->AI()->EnterEvadeMode();
262 break;
263 case IN_PROGRESS:
264 if (!minion->IsAlive())
265 minion->Respawn();
266 else if (!minion->GetVictim())
267 minion->AI()->DoZoneInCombat();
268 break;
269 default:
270 break;
271 }
272}
273
275{
277 return;
278 enum states { BLOCK, SPAWN, FORCEBLOCK };
279 std::unordered_map<uint32, states> newStates;
280 for (auto it = _instanceSpawnGroups->begin(), end = _instanceSpawnGroups->end(); it != end; ++it)
281 {
282 InstanceSpawnGroupInfo const& info = *it;
283 states& curValue = newStates[info.SpawnGroupId]; // makes sure there's a BLOCK value in the map
284 if (curValue == FORCEBLOCK) // nothing will change this
285 continue;
286 if (!((1 << GetBossState(info.BossStateId)) & info.BossStates))
287 continue;
290 continue;
292 curValue = FORCEBLOCK;
294 curValue = SPAWN;
295 }
296 for (auto const& pair : newStates)
297 {
298 uint32 const groupId = pair.first;
299 bool const doSpawn = (pair.second == SPAWN);
300 if (instance->IsSpawnGroupActive(groupId) == doSpawn)
301 continue; // nothing to do here
302 // if we should spawn group, then spawn it...
303 if (doSpawn)
304 instance->SpawnGroupSpawn(groupId);
305 else // otherwise, set it as inactive so it no longer respawns (but don't despawn it)
307 }
308}
309
311{
312 ASSERT(id < bosses.size());
313 return &bosses[id];
314}
315
317{
318 ObjectInfoMap::const_iterator j = _creatureInfo.find(obj->GetEntry());
319 if (j != _creatureInfo.end())
320 AddObject(obj, j->second, add);
321}
322
324{
325 ObjectInfoMap::const_iterator j = _gameObjectInfo.find(obj->GetEntry());
326 if (j != _gameObjectInfo.end())
327 AddObject(obj, j->second, add);
328}
329
331{
332 if (add)
333 _objectGuids[type] = obj->GetGUID();
334 else
335 {
336 ObjectGuidMap::iterator i = _objectGuids.find(type);
337 if (i != _objectGuids.end() && i->second == obj->GetGUID())
338 _objectGuids.erase(i);
339 }
340}
341
343{
344 DoorInfoMapBounds range = doors.equal_range(door->GetEntry());
345 if (range.first == range.second)
346 return;
347
348 for (; range.first != range.second; ++range.first)
349 {
350 DoorInfo const& data = range.first->second;
351
352 if (add)
353 data.bossInfo->door[AsUnderlyingType(data.Behavior)].insert(door->GetGUID());
354 else
355 data.bossInfo->door[AsUnderlyingType(data.Behavior)].erase(door->GetGUID());
356 }
357
358 if (add)
359 UpdateDoorState(door);
360}
361
362void InstanceScript::AddMinion(Creature* minion, bool add)
363{
364 MinionInfoMap::iterator itr = minions.find(minion->GetEntry());
365 if (itr == minions.end())
366 return;
367
368 if (add)
369 itr->second.bossInfo->minion.insert(minion->GetGUID());
370 else
371 itr->second.bossInfo->minion.erase(minion->GetGUID());
372}
373
375{
376 if (id < bosses.size())
377 {
378 BossInfo* bossInfo = &bosses[id];
379 if (bossInfo->state == TO_BE_DECIDED) // loading
380 {
381 bossInfo->state = state;
382 TC_LOG_DEBUG("scripts", "InstanceScript: Initialize boss {} state as {} (map {}, {}).", id, GetBossStateName(state), instance->GetId(), instance->GetInstanceId());
383 return false;
384 }
385 else
386 {
387 if (bossInfo->state == state)
388 return false;
389
390 if (bossInfo->state == DONE)
391 {
392 TC_LOG_ERROR("map", "InstanceScript: Tried to set instance boss {} state from {} back to {} for map {}, instance id {}. Blocked!", id, GetBossStateName(bossInfo->state), GetBossStateName(state), instance->GetId(), instance->GetInstanceId());
393 return false;
394 }
395
396 if (state == DONE)
397 for (GuidSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
398 if (Creature* minion = instance->GetCreature(*i))
399 if (minion->isWorldBoss() && minion->IsAlive())
400 return false;
401
402 DungeonEncounterEntry const* dungeonEncounter = nullptr;
403 switch (state)
404 {
405 case IN_PROGRESS:
406 {
408 InitializeCombatResurrections(1, resInterval);
409 SendEncounterStart(1, 9, resInterval, resInterval);
410
411 instance->DoOnPlayers([](Player* player)
412 {
414 });
415 break;
416 }
417 case FAIL:
418 {
421
422 instance->DoOnPlayers([](Player* player)
423 {
425 });
426 break;
427 }
428 case DONE:
429 {
432 dungeonEncounter = bossInfo->GetDungeonEncounterForDifficulty(instance->GetDifficultyID());
433 if (dungeonEncounter)
434 {
435 instance->DoOnPlayers([&](Player* player)
436 {
437 if (!player->IsLockedToDungeonEncounter(dungeonEncounter->ID))
439 });
440
442 SendBossKillCredit(dungeonEncounter->ID);
443 if (dungeonEncounter->CompleteWorldStateID)
444 DoUpdateWorldState(dungeonEncounter->CompleteWorldStateID, 1);
445
446 UpdateLfgEncounterState(bossInfo);
447 }
448
449 instance->DoOnPlayers([](Player* player)
450 {
452 });
453 break;
454 }
455 default:
456 break;
457 }
458
459 bossInfo->state = state;
460 if (dungeonEncounter)
461 instance->UpdateInstanceLock({ dungeonEncounter, id, state });
462 }
463
464 for (GuidSet const& doorSet : bossInfo->door)
465 for (ObjectGuid const& doorGUID : doorSet)
466 if (GameObject* door = instance->GetGameObject(doorGUID))
467 UpdateDoorState(door);
468
469 GuidSet minions = bossInfo->minion; // Copy to prevent iterator invalidation (minion might be unsummoned in UpdateMinionState)
470 for (GuidSet::iterator i = minions.begin(); i != minions.end(); ++i)
471 if (Creature* minion = instance->GetCreature(*i))
472 UpdateMinionState(minion, state);
473
475 return true;
476 }
477 return false;
478}
479
480bool InstanceScript::_SkipCheckRequiredBosses(Player const* player /*= nullptr*/) const
481{
483}
484
486{
487 for (size_t i = 0; i < bosses.size(); ++i)
490}
491
492void InstanceScript::Load(char const* data)
493{
494 if (!data)
495 {
497 return;
498 }
499
500 OUT_LOAD_INST_DATA(data);
501
502 InstanceScriptDataReader reader(*this);
503 if (reader.Load(data) == InstanceScriptDataReader::Result::Ok)
504 {
505 // in loot-based lockouts instance can be loaded with later boss marked as killed without preceding bosses
506 // but we still need to have them alive
507 for (uint32 i = 0; i < bosses.size(); ++i)
508 {
509 if (bosses[i].state == DONE && !CheckRequiredBosses(i))
510 bosses[i].state = NOT_STARTED;
511
512 if (DungeonEncounterEntry const* dungeonEncounter = bosses[i].GetDungeonEncounterForDifficulty(instance->GetDifficultyID()))
513 if (dungeonEncounter->CompleteWorldStateID)
514 DoUpdateWorldState(dungeonEncounter->CompleteWorldStateID, bosses[i].state == DONE ? 1 : 0);
515 }
516
519 }
520 else
522
524}
525
527{
529
530 InstanceScriptDataWriter writer(*this);
531
532 writer.FillData();
533
535
536 return writer.GetString();
537}
538
539std::string InstanceScript::UpdateBossStateSaveData(std::string const& oldData, UpdateBossStateSaveDataEvent const& event)
540{
542 return GetSaveData();
543
544 InstanceScriptDataWriter writer(*this);
545 writer.FillDataFrom(oldData);
546 writer.SetBossState(event);
547 return writer.GetString();
548}
549
550std::string InstanceScript::UpdateAdditionalSaveData(std::string const& oldData, UpdateAdditionalSaveDataEvent const& event)
551{
553 return GetSaveData();
554
555 InstanceScriptDataWriter writer(*this);
556 writer.FillDataFrom(oldData);
557 writer.SetAdditionalData(event);
558 return writer.GetString();
559}
560
562{
564 return _entranceId;
565
566 return ComputeEntranceLocationForCompletedEncounters(completedEncountersMask);
567}
568
570{
571 return { };
572}
573
574void InstanceScript::HandleGameObject(ObjectGuid guid, bool open, GameObject* go /*= nullptr*/)
575{
576 if (!go)
577 go = instance->GetGameObject(guid);
578 if (go)
580 else
581 TC_LOG_DEBUG("scripts", "InstanceScript: HandleGameObject failed");
582}
583
584void InstanceScript::DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime /*= 0*/, bool useAlternativeState /*= false*/)
585{
586 if (!guid)
587 return;
588
589 if (GameObject* go = instance->GetGameObject(guid))
590 {
591 if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
592 {
593 if (go->getLootState() == GO_READY)
594 go->UseDoorOrButton(withRestoreTime, useAlternativeState);
595 else if (go->getLootState() == GO_ACTIVATED)
596 go->ResetDoorOrButton();
597 }
598 else
599 TC_LOG_ERROR("scripts", "InstanceScript: DoUseDoorOrButton can't use gameobject entry {}, because type is {}.", go->GetEntry(), go->GetGoType());
600 }
601 else
602 TC_LOG_DEBUG("scripts", "InstanceScript: DoUseDoorOrButton failed");
603}
604
606{
607 if (!guid)
608 return;
609
610 if (GameObject* go = instance->GetGameObject(guid))
611 {
612 if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
613 {
614 if (go->getLootState() == GO_ACTIVATED)
615 go->ResetDoorOrButton();
616 }
617 else
618 TC_LOG_ERROR("scripts", "InstanceScript: DoCloseDoorOrButton can't use gameobject entry {}, because type is {}.", go->GetEntry(), go->GetGoType());
619 }
620 else
621 TC_LOG_DEBUG("scripts", "InstanceScript: DoCloseDoorOrButton failed");
622}
623
624void InstanceScript::DoRespawnGameObject(ObjectGuid guid, Seconds timeToDespawn /*= 1min */)
625{
626 if (GameObject* go = instance->GetGameObject(guid))
627 {
628 switch (go->GetGoType())
629 {
634 // not expect any of these should ever be handled
635 TC_LOG_ERROR("scripts", "InstanceScript: DoRespawnGameObject can't respawn gameobject entry {}, because type is {}.", go->GetEntry(), go->GetGoType());
636 return;
637 default:
638 break;
639 }
640
641 if (go->isSpawned())
642 return;
643
644 go->SetRespawnTime(timeToDespawn.count());
645 }
646 else
647 TC_LOG_DEBUG("scripts", "InstanceScript: DoRespawnGameObject failed");
648}
649
651{
652 sWorldStateMgr->SetValue(worldStateId, value, false, instance);
653}
654
655// Send Notify to all players in instance
656void InstanceScript::DoSendNotifyToInstance(char const* format, ...)
657{
658 va_list ap;
659 va_start(ap, format);
660 char buff[1024];
661 vsnprintf(buff, 1024, format, ap);
662 va_end(ap);
663
664 instance->DoOnPlayers([&buff](Player const* player)
665 {
666 player->GetSession()->SendNotification("%s", buff);
667 });
668}
669
670// Update Achievement Criteria for all players in instance
671void InstanceScript::DoUpdateCriteria(CriteriaType type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= nullptr*/)
672{
673 instance->DoOnPlayers([type, miscValue1, miscValue2, unit](Player* player)
674 {
675 player->UpdateCriteria(type, miscValue1, miscValue2, 0, unit);
676 });
677}
678
679void InstanceScript::DoRemoveAurasDueToSpellOnPlayers(uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/)
680{
681 instance->DoOnPlayers([this, spell, includePets, includeControlled](Player* player)
682 {
683 DoRemoveAurasDueToSpellOnPlayer(player, spell, includePets, includeControlled);
684 });
685}
686
687void InstanceScript::DoRemoveAurasDueToSpellOnPlayer(Player* player, uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/)
688{
689 if (!player)
690 return;
691
692 player->RemoveAurasDueToSpell(spell);
693
694 if (!includePets)
695 return;
696
697 for (uint8 itr2 = 0; itr2 < MAX_SUMMON_SLOT; ++itr2)
698 {
699 ObjectGuid summonGUID = player->m_SummonSlot[itr2];
700 if (!summonGUID.IsEmpty())
701 if (Creature* summon = instance->GetCreature(summonGUID))
702 summon->RemoveAurasDueToSpell(spell);
703 }
704
705 if (!includeControlled)
706 return;
707
708 for (auto itr2 = player->m_Controlled.begin(); itr2 != player->m_Controlled.end(); ++itr2)
709 {
710 if (Unit* controlled = *itr2)
711 if (controlled->IsInWorld() && controlled->GetTypeId() == TYPEID_UNIT)
712 controlled->RemoveAurasDueToSpell(spell);
713 }
714}
715
716void InstanceScript::DoCastSpellOnPlayers(uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/)
717{
718 instance->DoOnPlayers([this, spell, includePets, includeControlled](Player* player)
719 {
720 DoCastSpellOnPlayer(player, spell, includePets, includeControlled);
721 });
722}
723
724void InstanceScript::DoCastSpellOnPlayer(Player* player, uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/)
725{
726 if (!player)
727 return;
728
729 player->CastSpell(player, spell, true);
730
731 if (!includePets)
732 return;
733
734 for (uint8 itr2 = 0; itr2 < MAX_SUMMON_SLOT; ++itr2)
735 {
736 ObjectGuid summonGUID = player->m_SummonSlot[itr2];
737 if (!summonGUID.IsEmpty())
738 if (Creature* summon = instance->GetCreature(summonGUID))
739 summon->CastSpell(player, spell, true);
740 }
741
742 if (!includeControlled)
743 return;
744
745 for (auto itr2 = player->m_Controlled.begin(); itr2 != player->m_Controlled.end(); ++itr2)
746 {
747 if (Unit* controlled = *itr2)
748 if (controlled->IsInWorld() && controlled->GetTypeId() == TYPEID_UNIT)
749 controlled->CastSpell(player, spell, true);
750 }
751}
752
754{
755 return sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP);
756}
757
759{
760 return id < bosses.size() ? bosses[id].GetDungeonEncounterForDifficulty(instance->GetDifficultyID()) : nullptr;
761}
762
764{
765 if (BossAI const* bossAi = dynamic_cast<BossAI const*>(creature->GetAI()))
766 return GetBossDungeonEncounter(bossAi->GetBossId());
767
768 return nullptr;
769}
770
771bool InstanceScript::CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/ /*= nullptr*/, uint32 /*miscvalue1*/ /*= 0*/)
772{
773 TC_LOG_ERROR("misc", "Achievement system call InstanceScript::CheckAchievementCriteriaMeet but instance script for map {} not have implementation for achievement criteria {}",
774 instance->GetId(), criteria_id);
775 return false;
776}
777
778bool InstanceScript::IsEncounterCompleted(uint32 dungeonEncounterId) const
779{
780 for (std::size_t i = 0; i < bosses.size(); ++i)
781 for (std::size_t j = 0; j < bosses[i].DungeonEncounters.size(); ++j)
782 if (bosses[i].DungeonEncounters[j] && bosses[i].DungeonEncounters[j]->ID == dungeonEncounterId)
783 return bosses[i].state == DONE;
784
785 return false;
786}
787
788bool InstanceScript::IsEncounterCompletedInMaskByBossId(uint32 completedEncountersMask, uint32 bossId) const
789{
790 if (DungeonEncounterEntry const* dungeonEncounter = GetBossDungeonEncounter(bossId))
791 if (completedEncountersMask & (1 << dungeonEncounter->Bit))
792 return bosses[bossId].state == DONE;
793
794 return false;
795}
796
798{
799 _entranceId = worldSafeLocationId;
801}
802
803void InstanceScript::SendEncounterUnit(EncounterFrameType type, Unit const* unit, Optional<int32> param1 /*= {}*/, Optional<int32> param2 /*= {}*/)
804{
805 switch (type)
806 {
807 case ENCOUNTER_FRAME_ENGAGE: // SMSG_INSTANCE_ENCOUNTER_ENGAGE_UNIT
808 {
809 if (!unit)
810 return;
811
813 encounterEngageMessage.Unit = unit->GetGUID();
814 encounterEngageMessage.TargetFramePriority = param1.value_or(0);
815 instance->SendToPlayers(encounterEngageMessage.Write());
816 break;
817 }
818 case ENCOUNTER_FRAME_DISENGAGE: // SMSG_INSTANCE_ENCOUNTER_DISENGAGE_UNIT
819 {
820 if (!unit)
821 return;
822
824 encounterDisengageMessage.Unit = unit->GetGUID();
825 instance->SendToPlayers(encounterDisengageMessage.Write());
826 break;
827 }
828 case ENCOUNTER_FRAME_UPDATE_PRIORITY: // SMSG_INSTANCE_ENCOUNTER_CHANGE_PRIORITY
829 {
830 if (!unit)
831 return;
832
833 WorldPackets::Instance::InstanceEncounterChangePriority encounterChangePriorityMessage;
834 encounterChangePriorityMessage.Unit = unit->GetGUID();
835 encounterChangePriorityMessage.TargetFramePriority = param1.value_or(0);
836 instance->SendToPlayers(encounterChangePriorityMessage.Write());
837 break;
838 }
840 {
841 WorldPackets::Instance::InstanceEncounterTimerStart instanceEncounterTimerStart;
842 instanceEncounterTimerStart.TimeRemaining = param1.value_or(0);
843 instance->SendToPlayers(instanceEncounterTimerStart.Write());
844 break;
845 }
847 {
848 WorldPackets::Instance::InstanceEncounterObjectiveStart instanceEncounterObjectiveStart;
849 instanceEncounterObjectiveStart.ObjectiveID = param1.value_or(0);
850 instance->SendToPlayers(instanceEncounterObjectiveStart.Write());
851 break;
852 }
854 {
855 WorldPackets::Instance::InstanceEncounterObjectiveUpdate instanceEncounterObjectiveUpdate;
856 instanceEncounterObjectiveUpdate.ObjectiveID = param1.value_or(0);
857 instanceEncounterObjectiveUpdate.ProgressAmount = param2.value_or(0);
858 instance->SendToPlayers(instanceEncounterObjectiveUpdate.Write());
859 break;
860 }
862 {
863 WorldPackets::Instance::InstanceEncounterObjectiveComplete instanceEncounterObjectiveComplete;
864 instanceEncounterObjectiveComplete.ObjectiveID = param1.value_or(0);
865 instance->SendToPlayers(instanceEncounterObjectiveComplete.Write());
866 break;
867 }
869 {
870 WorldPackets::Instance::InstanceEncounterPhaseShiftChanged instanceEncounterPhaseShiftChanged;
871 instance->SendToPlayers(instanceEncounterPhaseShiftChanged.Write());
872 break;
873 }
874 default:
875 break;
876 }
877}
878
879void InstanceScript::SendEncounterStart(uint32 inCombatResCount /*= 0*/, uint32 maxInCombatResCount /*= 0*/, uint32 inCombatResChargeRecovery /*= 0*/, uint32 nextCombatResChargeTime /*= 0*/)
880{
882 encounterStartMessage.InCombatResCount = inCombatResCount;
883 encounterStartMessage.MaxInCombatResCount = maxInCombatResCount;
884 encounterStartMessage.CombatResChargeRecovery = inCombatResChargeRecovery;
885 encounterStartMessage.NextCombatResChargeTime = nextCombatResChargeTime;
886
887 instance->SendToPlayers(encounterStartMessage.Write());
888}
889
891{
893 instance->SendToPlayers(encounterEndMessage.Write());
894}
895
897{
898 WorldPackets::Instance::BossKill bossKillCreditMessage;
899 bossKillCreditMessage.DungeonEncounterID = encounterId;
900
901 instance->SendToPlayers(bossKillCreditMessage.Write());
902}
903
905{
906 for (auto const& ref : instance->GetPlayers())
907 {
908 if (Player* player = ref.GetSource())
909 {
910 if (Group* grp = player->GetGroup())
911 {
912 if (grp->isLFGGroup())
913 {
914 std::array<uint32, MAX_DUNGEON_ENCOUNTERS_PER_BOSS> dungeonEncounterIds;
915 std::transform(bossInfo->DungeonEncounters.begin(), bossInfo->DungeonEncounters.end(), dungeonEncounterIds.begin(),
916 [](DungeonEncounterEntry const* entry) { return entry->ID; });
917 sLFGMgr->OnDungeonEncounterDone(grp->GetGUID(), dungeonEncounterIds, instance);
918 break;
919 }
920 }
921 }
922 }
923}
924
926{
927 instance->DoOnPlayers([](Player const* player)
928 {
930 });
931}
932
934{
936}
937
939{
941 return;
942
943 if (_combatResurrectionTimer <= diff)
945 else
947}
948
949void InstanceScript::InitializeCombatResurrections(uint8 charges /*= 1*/, uint32 interval /*= 0*/)
950{
952 if (!interval)
953 return;
954
955 _combatResurrectionTimer = interval;
957}
958
960{
963
965 gainCombatResurrectionCharge.InCombatResCount = _combatResurrectionCharges;
966 gainCombatResurrectionCharge.CombatResChargeRecovery = _combatResurrectionTimer;
967 instance->SendToPlayers(gainCombatResurrectionCharge.Write());
968}
969
971{
973
975}
976
978{
982}
983
985{
986 uint32 interval = 0;
987 if (uint32 playerCount = instance->GetPlayers().getSize())
988 interval = 90 * MINUTE * IN_MILLISECONDS / playerCount;
989
990 return interval;
991}
992
993PersistentInstanceScriptValueBase::PersistentInstanceScriptValueBase(InstanceScript& instance, char const* name, std::variant<int64, double> value)
994 : _instance(instance), _name(name), _value(std::move(value))
995{
997}
998
1000
1002{
1004}
1005
1006bool InstanceHasScript(WorldObject const* obj, char const* scriptName)
1007{
1008 if (InstanceMap* instance = obj->GetMap()->ToInstanceMap())
1009 return instance->GetScriptName() == scriptName;
1010
1011 return false;
1012}
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
DB2Storage< DungeonEncounterEntry > sDungeonEncounterStore("DungeonEncounter.db2", &DungeonEncounterLoadInfo::Instance)
Difficulty
Definition: DBCEnums.h:873
CriteriaType
Definition: DBCEnums.h:503
@ DefeatDungeonEncounter
@ DefeatDungeonEncounterWhileElegibleForLoot
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
#define ASSERT
Definition: Errors.h:68
@ GO_ACTIVATED
Definition: GameObject.h:158
@ GO_READY
Definition: GameObject.h:157
bool InstanceHasScript(WorldObject const *obj, char const *scriptName)
static constexpr uint32 MAX_DUNGEON_ENCOUNTERS_PER_BOSS
#define OUT_LOAD_INST_DATA_FAIL
EncounterState
@ IN_PROGRESS
@ FAIL
@ DONE
@ NOT_STARTED
@ TO_BE_DECIDED
EncounterFrameType
@ ENCOUNTER_FRAME_ENABLE_OBJECTIVE
@ ENCOUNTER_FRAME_DISENGAGE
@ ENCOUNTER_FRAME_UPDATE_PRIORITY
@ ENCOUNTER_FRAME_DISABLE_OBJECTIVE
@ ENCOUNTER_FRAME_UPDATE_OBJECTIVE
@ ENCOUNTER_FRAME_ADD_TIMER
@ ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED
@ ENCOUNTER_FRAME_ENGAGE
#define OUT_SAVE_INST_DATA_COMPLETE
#define OUT_LOAD_INST_DATA_COMPLETE
#define OUT_SAVE_INST_DATA
#define OUT_LOAD_INST_DATA(a)
std::map< uint32, uint32 > ObjectInfoMap
std::pair< DoorInfoMap::const_iterator, DoorInfoMap::const_iterator > DoorInfoMapBounds
#define sLFGMgr
Definition: LFGMgr.h:507
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
std::set< ObjectGuid > GuidSet
Definition: ObjectGuid.h:393
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
Role Based Access Control related classes definition.
#define sScriptMgr
Definition: ScriptMgr.h:1418
@ GAMEOBJECT_TYPE_BUTTON
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_FISHINGNODE
@ GAMEOBJECT_TYPE_DOOR
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ MAX_SUMMON_SLOT
@ GO_STATE_READY
@ GO_STATE_ACTIVE
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
#define sWorldStateMgr
Definition: WorldStateMgr.h:50
void DoZoneInCombat()
Definition: CreatureAI.h:161
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
Definition: CreatureAI.cpp:219
void Respawn(bool force=false)
Definition: Creature.cpp:2303
CreatureAI * AI() const
Definition: Creature.h:214
static char const * ToConstant(Enum value)
Definition: SmartEnum.h:120
void SetGoState(GOState state)
Definition: Group.h:197
TeamId GetTeamIdInInstance() const
Definition: Map.cpp:3376
void UpdateInstanceLock(UpdateBossStateSaveDataEvent const &updateSaveDataEvent)
Definition: Map.cpp:3103
Result Load(char const *data)
void SetAdditionalData(UpdateAdditionalSaveDataEvent const &data)
void FillDataFrom(std::string const &data)
void FillData(bool withValues=true)
void SetBossState(UpdateBossStateSaveDataEvent const &data)
std::string GetSaveData()
void UpdateMinionState(Creature *minion, EncounterState state)
virtual bool SetBossState(uint32 id, EncounterState state)
virtual void OnCreatureCreate(Creature *creature) override
void DoCloseDoorOrButton(ObjectGuid guid)
void DoRemoveAurasDueToSpellOnPlayers(uint32 spell, bool includePets=false, bool includeControlled=false)
void DoCastSpellOnPlayers(uint32 spell, bool includePets=false, bool includeControlled=false)
uint32 GetCombatResurrectionChargeInterval() const
void UpdateLfgEncounterState(BossInfo const *bossInfo)
Creature * GetCreature(uint32 type)
void HandleGameObject(ObjectGuid guid, bool open, GameObject *go=nullptr)
void LoadDungeonEncounterData(T const &encounters)
uint32 _combatResurrectionTimer
MinionInfoMap minions
void DoUpdateWorldState(int32 worldStateId, int32 value)
Optional< uint32 > GetEntranceLocationForCompletedEncounters(uint32 completedEncountersMask) const
void DoCastSpellOnPlayer(Player *player, uint32 spell, bool includePets=false, bool includeControlled=false)
virtual bool CheckAchievementCriteriaMeet(uint32, Player const *, Unit const *=nullptr, uint32=0)
InstanceScript(InstanceMap *map)
void Load(char const *data)
virtual void OnCreatureRemove(Creature *creature) override
static bool ServerAllowsTwoSideGroups()
void SendBossKillCredit(uint32 encounterId)
virtual ObjectGuid GetGuidData(uint32 type) const override
void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime=0, bool useAlternativeState=false)
virtual void OnGameObjectRemove(GameObject *go) override
BossInfo * GetBossInfo(uint32 id)
static char const * GetBossStateName(uint8 state)
InstanceMap * instance
ObjectGuidMap _objectGuids
void DoUpdateCriteria(CriteriaType type, uint32 miscValue1=0, uint32 miscValue2=0, Unit *unit=nullptr)
DungeonEncounterEntry const * GetBossDungeonEncounter(uint32 id) const
DoorInfoMap doors
void AddMinion(Creature *minion, bool add)
ObjectInfoMap _gameObjectInfo
EncounterState GetBossState(uint32 id) const
void TriggerGameEvent(uint32 gameEventId, WorldObject *source=nullptr, WorldObject *target=nullptr) override
void InitializeCombatResurrections(uint8 charges=1, uint32 interval=0)
bool IsEncounterCompletedInMaskByBossId(uint32 completedEncountersMask, uint32 bossId) const
uint32 _temporaryEntranceId
virtual Optional< uint32 > ComputeEntranceLocationForCompletedEncounters(uint32 completedEncountersMask) const
void AddObject(Creature *obj, bool add)
void DoRespawnGameObject(ObjectGuid guid, Seconds timeToDespawn=1min)
void UseCombatResurrection()
virtual void OnGameObjectCreate(GameObject *go) override
virtual bool IsEncounterInProgress() const
ObjectInfoMap _creatureInfo
void UpdateCombatResurrection(uint32 diff)
void ResetCombatResurrections()
bool _combatResurrectionTimerStarted
virtual void AddDoor(GameObject *door, bool add)
void RegisterPersistentScriptValue(PersistentInstanceScriptValueBase *value)
void LoadMinionData(MinionData const *data)
void SendEncounterStart(uint32 inCombatResCount=0, uint32 maxInCombatResCount=0, uint32 inCombatResChargeRecovery=0, uint32 nextCombatResChargeTime=0)
std::string headers
void LoadDoorData(DoorData const *data)
virtual bool CheckRequiredBosses(uint32, Player const *=nullptr) const
virtual void Create()
void SendEncounterUnit(EncounterFrameType type, Unit const *unit, Optional< int32 > param1={}, Optional< int32 > param2={})
void SetEntranceLocation(uint32 worldSafeLocationId)
std::vector< BossInfo > bosses
virtual ~InstanceScript()
std::string UpdateAdditionalSaveData(std::string const &oldData, UpdateAdditionalSaveDataEvent const &event)
void DoRemoveAurasDueToSpellOnPlayer(Player *player, uint32 spell, bool includePets=false, bool includeControlled=false)
GameObject * GetGameObject(uint32 type)
void LoadBossBoundaries(BossBoundaryData const &data)
virtual void AfterDataLoad()
void AddCombatResurrectionCharge()
virtual void UpdateDoorState(GameObject *door)
bool _SkipCheckRequiredBosses(Player const *player=nullptr) const
uint8 _combatResurrectionCharges
bool IsEncounterCompleted(uint32 dungeonEncounterId) const
std::string UpdateBossStateSaveData(std::string const &oldData, UpdateBossStateSaveDataEvent const &event)
void SetHeaders(std::string const &dataHeaders)
std::vector< InstanceSpawnGroupInfo > const *const _instanceSpawnGroups
ObjectGuid GetObjectGuid(uint32 type) const
void DoSendNotifyToInstance(char const *format,...)
void LoadObjectData(ObjectData const *creatureData, ObjectData const *gameObjectData)
uint32 getSize() const
Definition: LinkedList.h:128
void SetSpawnGroupInactive(uint32 groupId)
Definition: Map.h:713
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition: Map.cpp:2348
MapDifficultyEntry const * GetMapDifficulty() const
Definition: Map.cpp:3223
void DoOnPlayers(T &&fn)
Definition: Map.h:370
void SendToPlayers(WorldPacket const *data) const
Definition: Map.cpp:2690
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
bool IsSpawnGroupActive(uint32 groupId) const
Definition: Map.cpp:2474
Difficulty GetDifficultyID() const
Definition: Map.h:324
uint32 GetId() const
Definition: Map.cpp:3228
InstanceMap * ToInstanceMap()
Definition: Map.h:454
uint32 GetInstanceId() const
Definition: Map.h:314
PlayerList const & GetPlayers() const
Definition: Map.h:367
Creature * GetCreature(ObjectGuid const &guid)
Definition: Map.cpp:3479
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
PersistentInstanceScriptValueBase(InstanceScript &instance, char const *name, std::variant< int64, double > value)
UpdateAdditionalSaveDataEvent CreateEvent() const
static void SendToPlayer(Player const *player, PhaseShift const &phaseShift)
WorldSession * GetSession() const
Definition: Player.h:2101
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
bool IsLockedToDungeonEncounter(uint32 dungeonEncounterId) const
Definition: Player.cpp:21399
Definition: Unit.h:627
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition: Unit.h:1460
void AtEndOfEncounter(EncounterType type)
Definition: Unit.cpp:536
bool IsAlive() const
Definition: Unit.h:1164
void AtStartOfEncounter(EncounterType type)
Definition: Unit.cpp:516
ControlList m_Controlled
Definition: Unit.h:1211
UnitAI * GetAI() const
Definition: Unit.h:660
Unit * GetVictim() const
Definition: Unit.h:715
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
bool IsInCombat() const
Definition: Unit.h:1043
Map * GetMap() const
Definition: Object.h:624
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
WorldPacket const * Write() override
WorldPacket const * Write() override
bool HasPermission(uint32 permissionId)
virtual void TriggerGameEvent(uint32 gameEventId, WorldObject *source=nullptr, WorldObject *target=nullptr)
Definition: ZoneScript.cpp:34
virtual void ProcessEvent(WorldObject *, uint32, WorldObject *)
Definition: ZoneScript.h:95
#define sWorld
Definition: World.h:931
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition: World.h:111
ObjectData const creatureData[]
ObjectData const gameObjectData[]
TC_GAME_API uint32 GetId(std::string_view username)
TC_GAME_API void TriggerForMap(uint32 gameEventId, Map *map, WorldObject *source=nullptr, WorldObject *target=nullptr)
TC_GAME_API void TriggerForPlayer(uint32 gameEventId, Player *source)
@ RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES
Definition: RBAC.h:66
STL namespace.
const_iterator begin() const
const_iterator end() const
StorageType::const_iterator const_iterator
EncounterState state
DungeonEncounterEntry const * GetDungeonEncounterForDifficulty(Difficulty difficulty) const
std::array< DungeonEncounterEntry const *, MAX_DUNGEON_ENCOUNTERS_PER_BOSS > DungeonEncounters
GuidSet minion
std::array< GuidSet, static_cast< uint8 >(EncounterDoorBehavior::Max)> door
uint32 entry
EncounterDoorBehavior Behavior
uint32 bossId
BossInfo * bossInfo
EncounterDoorBehavior Behavior
bool IsUsingEncounterLocks() const