diff --git a/Source/Framework/Constants/CreatureConst.cs b/Source/Framework/Constants/CreatureConst.cs
index bf1bb00e6..531f60d0b 100644
--- a/Source/Framework/Constants/CreatureConst.cs
+++ b/Source/Framework/Constants/CreatureConst.cs
@@ -543,7 +543,7 @@ namespace Framework.Constants
Unused25 = 0x2000000,
Unused26 = 0x4000000,
Unused27 = 0x8000000,
- DungeonBoss = 0x10000000, // Creature Is A Dungeon Boss (Set Dynamically, Do Not Add In Db)
+ DungeonBoss = 0x10000000, // Creature Is A Dungeon Boss
IgnorePathfinding = 0x20000000, // creature ignore pathfinding
ImmunityKnockback = 0x40000000, // creature is immune to knockback effects
Unused31 = 0x80000000,
diff --git a/Source/Framework/Constants/MapConst.cs b/Source/Framework/Constants/MapConst.cs
index 5bf339567..549f65bb3 100644
--- a/Source/Framework/Constants/MapConst.cs
+++ b/Source/Framework/Constants/MapConst.cs
@@ -151,12 +151,6 @@ namespace Framework.Constants
ToBeDecided = 5
}
- public enum EncounterCreditType
- {
- KillCreature = 0,
- CastSpell = 1
- }
-
public enum DoorType
{
Room = 0, // Door can open if encounter is not in progress
diff --git a/Source/Game/Chat/Commands/GoCommands.cs b/Source/Game/Chat/Commands/GoCommands.cs
index 44dd1da6f..4f9ced66e 100644
--- a/Source/Game/Chat/Commands/GoCommands.cs
+++ b/Source/Game/Chat/Commands/GoCommands.cs
@@ -41,8 +41,6 @@ namespace Game.Chat.Commands
foreach (var pair in Global.ObjectMgr.GetCreatureTemplates())
{
CreatureTemplate data = pair.Value;
- if (!data.FlagsExtra.HasFlag(CreatureFlagsExtra.DungeonBoss))
- continue;
uint count = 0;
string scriptName = Global.ObjectMgr.GetScriptName(data.ScriptID);
diff --git a/Source/Game/DungeonFinding/LFGManager.cs b/Source/Game/DungeonFinding/LFGManager.cs
index ecf5d44af..2f9449ccf 100644
--- a/Source/Game/DungeonFinding/LFGManager.cs
+++ b/Source/Game/DungeonFinding/LFGManager.cs
@@ -1335,6 +1335,35 @@ namespace Game.DungeonFinding
Log.outDebug(LogFilter.Lfg, "TeleportPlayer: Player {0} is being teleported in to map {1} (x: {2}, y: {3}, z: {4}) Result: {5}", player.GetName(), dungeon.map, dungeon.x, dungeon.y, dungeon.z, error);
}
+ ///
+ /// Check if dungeon can be rewarded, if any.
+ ///
+ /// Group guid
+ /// DungeonEncounter that was just completed
+ /// Map of the instance where encounter was completed
+ public void OnDungeonEncounterDone(ObjectGuid gguid, uint[] dungeonEncounterIds, Map currMap)
+ {
+ if (GetState(gguid) == LfgState.FinishedDungeon) // Shouldn't happen. Do not reward multiple times
+ {
+ Log.outDebug(LogFilter.Lfg, $"Group: {gguid} already rewarded");
+ return;
+ }
+
+ uint gDungeonId = GetDungeon(gguid);
+ LFGDungeonData dungeonDone = GetLFGDungeon(gDungeonId);
+ // LFGDungeons can point to a DungeonEncounter from any difficulty so we need this kind of lenient check
+ if (!dungeonEncounterIds.Contains(dungeonDone.finalDungeonEncounterId))
+ return;
+
+ FinishDungeon(gguid, gDungeonId, currMap);
+ }
+
+ ///
+ /// Finish a dungeon and give reward, if any.
+ ///
+ /// Group guid
+ /// Dungeonid
+ /// Map of the instance where encounter was completed
public void FinishDungeon(ObjectGuid gguid, uint dungeonId, Map currMap)
{
uint gDungeonId = GetDungeon(gguid);
@@ -2289,6 +2318,10 @@ namespace Game.DungeonFinding
contentTuningId = dbc.ContentTuningID;
difficulty = dbc.DifficultyID;
seasonal = dbc.Flags[0].HasAnyFlag(LfgFlags.Seasonal);
+
+ var journalEncounter = CliDB.JournalEncounterStorage.LookupByKey(dbc.FinalEncounterID);
+ if (journalEncounter != null)
+ finalDungeonEncounterId = journalEncounter.DungeonEncounterID;
}
public uint id;
@@ -2302,6 +2335,7 @@ namespace Game.DungeonFinding
public bool seasonal;
public float x, y, z, o;
public ushort requiredItemLevel;
+ public uint finalDungeonEncounterId;
// Helpers
public uint Entry() { return (uint)(id + ((int)type << 24)); }
diff --git a/Source/Game/Entities/Player/KillRewarder.cs b/Source/Game/Entities/Player/KillRewarder.cs
index 4c9324e4d..91f4be5a4 100644
--- a/Source/Game/Entities/Player/KillRewarder.cs
+++ b/Source/Game/Entities/Player/KillRewarder.cs
@@ -84,13 +84,6 @@ namespace Game.Entities
Creature victim = _victim.ToCreature();
if (victim != null)
{
- if (victim.IsDungeonBoss())
- {
- InstanceScript instance = _victim.GetInstanceScript();
- if (instance != null)
- instance.UpdateEncounterStateForKilledCreature(_victim.GetEntry(), _victim);
- }
-
if (!_killers.Empty())
{
uint guildId = victim.GetMap().GetOwnerGuildId();
diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs
index c170ad95a..e04692121 100644
--- a/Source/Game/Globals/ObjectManager.cs
+++ b/Source/Game/Globals/ObjectManager.cs
@@ -5495,97 +5495,6 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} access requirement definitions in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
}
- public void LoadInstanceEncounters()
- {
- uint oldMSTime = Time.GetMSTime();
-
- // 0 1 2 3
- SQLResult result = DB.World.Query("SELECT entry, creditType, creditEntry, lastEncounterDungeon FROM instance_encounters");
- if (result.IsEmpty())
- {
- Log.outInfo(LogFilter.ServerLoading, "Loaded 0 instance encounters, table is empty!");
- return;
- }
-
- uint count = 0;
- Dictionary> dungeonLastBosses = new();
- do
- {
- uint entry = result.Read(0);
- EncounterCreditType creditType = (EncounterCreditType)result.Read(1);
- uint creditEntry = result.Read(2);
- uint lastEncounterDungeon = result.Read(3);
- DungeonEncounterRecord dungeonEncounter = CliDB.DungeonEncounterStorage.LookupByKey(entry);
- if (dungeonEncounter == null)
- {
- Log.outError(LogFilter.Sql, "Table `instance_encounters` has an invalid encounter id {0}, skipped!", entry);
- continue;
- }
-
- if (lastEncounterDungeon != 0 && Global.LFGMgr.GetLFGDungeonEntry(lastEncounterDungeon) == 0)
- {
- Log.outError(LogFilter.Sql, "Table `instance_encounters` has an encounter {0} ({1}) marked as final for invalid dungeon id {2}, skipped!",
- entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()], lastEncounterDungeon);
- continue;
- }
-
- var pair = dungeonLastBosses.LookupByKey(lastEncounterDungeon);
- if (lastEncounterDungeon != 0)
- {
- if (pair != null)
- {
- Log.outError(LogFilter.Sql, "Table `instance_encounters` specified encounter {0} ({1}) as last encounter but {2} ({3}) is already marked as one, skipped!",
- entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()], pair.Item1, pair.Item2.Name[Global.WorldMgr.GetDefaultDbcLocale()]);
- continue;
- }
-
- dungeonLastBosses[lastEncounterDungeon] = Tuple.Create(entry, dungeonEncounter);
- }
-
- switch (creditType)
- {
- case EncounterCreditType.KillCreature:
- {
- CreatureTemplate creatureInfo = GetCreatureTemplate(creditEntry);
- if (creatureInfo == null)
- {
- Log.outError(LogFilter.Sql, "Table `instance_encounters` has an invalid creature (entry {0}) linked to the encounter {1} ({2}), skipped!",
- creditEntry, entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()]);
- continue;
- }
- creatureInfo.FlagsExtra |= CreatureFlagsExtra.DungeonBoss;
- break;
- }
- case EncounterCreditType.CastSpell:
- if (!Global.SpellMgr.HasSpellInfo(creditEntry, Difficulty.None))
- {
- Log.outError(LogFilter.Sql, "Table `instance_encounters` has an invalid spell (entry {0}) linked to the encounter {1} ({2}), skipped!",
- creditEntry, entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()]);
- continue;
- }
- break;
- default:
- Log.outError(LogFilter.Sql, "Table `instance_encounters` has an invalid credit type ({0}) for encounter {1} ({2}), skipped!",
- creditType, entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()]);
- continue;
- }
-
- if (dungeonEncounter.DifficultyID == 0)
- {
- foreach (var difficulty in CliDB.DifficultyStorage.Values)
- {
- if (Global.DB2Mgr.GetMapDifficultyData((uint)dungeonEncounter.MapID, (Difficulty)difficulty.Id) != null)
- _dungeonEncounterStorage.Add(MathFunctions.MakePair64((uint)dungeonEncounter.MapID, difficulty.Id), new DungeonEncounter(dungeonEncounter, creditType, creditEntry, lastEncounterDungeon));
- }
- }
- else
- _dungeonEncounterStorage.Add(MathFunctions.MakePair64((uint)dungeonEncounter.MapID, (uint)dungeonEncounter.DifficultyID), new DungeonEncounter(dungeonEncounter, creditType, creditEntry, lastEncounterDungeon));
-
- ++count;
- } while (result.NextRow());
-
- Log.outInfo(LogFilter.ServerLoading, "Loaded {0} instance encounters in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
- }
public void LoadSpawnGroupTemplates()
{
uint oldMSTime = Time.GetMSTime();
@@ -5876,10 +5785,6 @@ namespace Game
return false;
}
- public List GetDungeonEncounterList(uint mapId, Difficulty difficulty)
- {
- return _dungeonEncounterStorage.LookupByKey(MathFunctions.MakePair64(mapId, (uint)difficulty));
- }
public bool IsTransportMap(uint mapId) { return _transportMaps.Contains((ushort)mapId); }
public SpawnGroupTemplateData GetSpawnGroupData(uint groupId) { return _spawnGroupDataStorage.LookupByKey(groupId); }
public SpawnGroupTemplateData GetSpawnGroupData(SpawnObjectType type, ulong spawnId)
@@ -10992,7 +10897,6 @@ namespace Game
List _tavernAreaTriggerStorage = new();
Dictionary _areaTriggerStorage = new();
Dictionary _accessRequirementStorage = new();
- MultiMap _dungeonEncounterStorage = new();
Dictionary _worldSafeLocs = new();
Dictionary _guidGenerators = new();
@@ -11530,22 +11434,6 @@ namespace Game
public uint PortLocId;
}
- public class DungeonEncounter
- {
- public DungeonEncounter(DungeonEncounterRecord _dbcEntry, EncounterCreditType _creditType, uint _creditEntry, uint _lastEncounterDungeon)
- {
- dbcEntry = _dbcEntry;
- creditType = _creditType;
- creditEntry = _creditEntry;
- lastEncounterDungeon = _lastEncounterDungeon;
- }
-
- public DungeonEncounterRecord dbcEntry;
- public EncounterCreditType creditType;
- public uint creditEntry;
- public uint lastEncounterDungeon;
- }
-
public class MailLevelReward
{
public MailLevelReward(RaceMask _raceMask, uint _mailTemplateId = 0, uint _senderEntry = 0)
diff --git a/Source/Game/Maps/Instances/InstanceScript.cs b/Source/Game/Maps/Instances/InstanceScript.cs
index 699895f9f..3e0095cca 100644
--- a/Source/Game/Maps/Instances/InstanceScript.cs
+++ b/Source/Game/Maps/Instances/InstanceScript.cs
@@ -385,6 +385,8 @@ namespace Game.Maps
SendBossKillCredit(dungeonEncounter.Id);
if (dungeonEncounter.CompleteWorldStateID != 0)
DoUpdateWorldState((uint)dungeonEncounter.CompleteWorldStateID, 1);
+
+ UpdateLfgEncounterState(bossInfo);
}
instance.DoOnPlayers(player => player.AtEndOfEncounter(EncounterType.DungeonEncounter));
@@ -796,53 +798,18 @@ namespace Game.Maps
instance.SendToPlayers(bossKillCreditMessage);
}
- public void UpdateEncounterStateForKilledCreature(uint creatureId, Unit source)
+ void UpdateLfgEncounterState(BossInfo bossInfo)
{
- UpdateEncounterState(EncounterCreditType.KillCreature, creatureId, source);
- }
-
- public void UpdateEncounterStateForSpellCast(uint spellId, Unit source)
- {
- UpdateEncounterState(EncounterCreditType.CastSpell, spellId, source);
- }
-
- void UpdateEncounterState(EncounterCreditType type, uint creditEntry, Unit source)
- {
- var encounters = Global.ObjectMgr.GetDungeonEncounterList(instance.GetId(), instance.GetDifficultyID());
- if (encounters.Empty())
- return;
-
- uint dungeonId = 0;
-
- foreach (var encounter in encounters)
+ foreach (var player in instance.GetPlayers())
{
- if (encounter.creditType == type && encounter.creditEntry == creditEntry)
- {
- if (encounter.dbcEntry.CompleteWorldStateID != 0)
- DoUpdateWorldState((uint)encounter.dbcEntry.CompleteWorldStateID, 1);
-
- if (encounter.lastEncounterDungeon != 0)
- {
- dungeonId = encounter.lastEncounterDungeon;
- Log.outDebug(LogFilter.Lfg, "UpdateEncounterState: Instance {0} (instanceId {1}) completed encounter {2}. Credit Dungeon: {3}",
- instance.GetMapName(), instance.GetInstanceId(), encounter.dbcEntry.Name[Global.WorldMgr.GetDefaultDbcLocale()], dungeonId);
- break;
- }
- }
- }
-
- if (dungeonId != 0)
- {
- var players = instance.GetPlayers();
- foreach (var player in players)
+ if (player != null)
{
Group grp = player.GetGroup();
- if (grp != null)
- if (grp.IsLFGGroup())
- {
- Global.LFGMgr.FinishDungeon(grp.GetGUID(), dungeonId, instance);
- return;
- }
+ if (grp != null && grp.IsLFGGroup())
+ {
+ Global.LFGMgr.OnDungeonEncounterDone(grp.GetGUID(), bossInfo.DungeonEncounters.Select(entry => entry.Id).ToArray(), instance);
+ break;
+ }
}
}
}
diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs
index a44394496..041f66e53 100644
--- a/Source/Game/World/WorldManager.cs
+++ b/Source/Game/World/WorldManager.cs
@@ -743,9 +743,6 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loading LFG entrance positions..."); // Must be after areatriggers
Global.LFGMgr.LoadLFGDungeons();
- Log.outInfo(LogFilter.ServerLoading, "Loading Dungeon boss data...");
- Global.ObjectMgr.LoadInstanceEncounters();
-
Log.outInfo(LogFilter.ServerLoading, "Loading LFG rewards...");
Global.LFGMgr.LoadRewards();
diff --git a/Source/Scripts/Spells/Generic.cs b/Source/Scripts/Spells/Generic.cs
index e7664dbff..14b6c0fee 100644
--- a/Source/Scripts/Spells/Generic.cs
+++ b/Source/Scripts/Spells/Generic.cs
@@ -1339,35 +1339,6 @@ namespace Scripts.Spells.Generic
}
}
- [Script]
- class spell_gen_dungeon_credit : SpellScript
- {
- public override bool Load()
- {
- return GetCaster().GetTypeId() == TypeId.Unit;
- }
-
- void CreditEncounter()
- {
- // This hook is executed for every target, make sure we only credit instance once
- if (_handled)
- return;
-
- _handled = true;
- Unit caster = GetCaster();
- InstanceScript instance = caster.GetInstanceScript();
- if (instance != null)
- instance.UpdateEncounterStateForSpellCast(GetSpellInfo().Id, caster);
- }
-
- public override void Register()
- {
- AfterHit.Add(new(CreditEncounter));
- }
-
- bool _handled = false;
- }
-
[Script] // 50051 - Ethereal Pet Aura
class spell_ethereal_pet_AuraScript : AuraScript
{