---Track spells casted by enemies, susceptibility to crowd control and base health and add them to the dataset local db local f local MDT = MDT MDT.DataCollection = {} local DC = MDT.DataCollection function DC:Init() print("MDT: Spell+Characteristics Tracking Init") db = MDT:GetDB() db.dataCollection = db.dataCollection or {} db.dataCollectionCC = db.dataCollectionCC or {} db.dataCollectionGUID = db.dataCollectionGUID or {} f = CreateFrame("Frame") f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") f:RegisterEvent("CHALLENGE_MODE_START") f:RegisterEvent("CHALLENGE_MODE_COMPLETED") f:RegisterEvent("PLAYER_ENTERING_WORLD") f:SetScript("OnEvent", function(self, event, ...) return DC[event](self, ...) end) end function DC:AddCollectedDataToEnemyTable(dungeonIndex, ignoreSpells, ignoreCC) if not dungeonIndex then dungeonIndex = db.currentDungeonIdx end --add spells/characteristics from db to dungeonEnemies local spellsAdded = 0 local ccAdded = 0 local enemies = MDT.dungeonEnemies[dungeonIndex] local collectedData = db.dataCollection[dungeonIndex] if collectedData and not ignoreSpells then for id, spells in pairs(collectedData) do for enemyIdx, enemy in pairs(enemies) do if enemy.id == id then enemy.spells = enemy.spells or {} for spellId, _ in pairs(spells) do if not enemy.spells[spellId] then spellsAdded = spellsAdded + 1 end enemy.spells[spellId] = enemy.spells[spellId] or {} end end end end end local collectedCC = db.dataCollectionCC[dungeonIndex] if collectedCC and not ignoreCC then for id, characteristics in pairs(collectedCC) do for enemyIdx, enemy in pairs(enemies) do if enemy.id == id then enemy.characteristics = enemy.characteristics or {} for characteristic, _ in pairs(characteristics) do if not enemy.characteristics[characteristic] then ccAdded = ccAdded + 1 end enemy.characteristics[characteristic] = true end end end end end if not ignoreSpells then print("Added " .. spellsAdded .. " new spells") end if not ignoreCC then print("Added " .. ccAdded .. " new CC characteristics") end end local trackedEvents = { ["SPELL_CAST_SUCCESS"] = true, ["SPELL_CAST_START"] = true, ["SPELL_MISSED"] = true, ["SPELL_DAMAGE"] = true, ["SPELL_AURA_REMOVED"] = true, ["SPELL_AURA_APPLIED"] = true, } local characteristicsSpells = { ["Slow"] = { [3409] = true; --Crippling Poison [45524] = true; --Chains of Ice }; ["Stun"] = { [1833] = true, --Cheap Shot [408] = true, --Kidney Shot [179057] = true, --Chaos Nova [119381] = true, --Leg Sweep [30283] = true, --Shadowfury [108194] = true, --Asphyxiate }, ["Sap"] = { [6770] = true, }, ["Imprison"] = { [217832] = true, }, ["Incapacitate"] = { [1776] = true, --Gouge [115078] = true, --Paralysis }, ["Repentance"] = { [20066] = true, }, ["Disorient"] = { [2094] = true, --Blind [31661] = true, --Dragon's breath }, ["Banish"] = { [710] = true, --Banish }, ["Fear"] = { [118699] = true, --Fear [8122] = true, --Psychich Scream [5246] = true, --Intimidating Shout [207685] = true, --Sigil of Misery }, ["Root"] = { [122] = true, --Frost Nova [339] = true, --Entangling Roots [102359] = true, --Mass Root [117526] = true, --Binding Shot }, ["Polymorph"] = { [161354] = true, [126819] = true, [61780] = true, [118] = true, [277787] = true, [277792] = true, [161355] = true, [161372] = true, [61721] = true, [61305] = true, [28271] = true, [28272] = true, [33786] = true, [20066] = true, [5782] = true, [51514] = true, [277778] = true, [277784] = true, [269352] = true, [211004] = true, [211010] = true, [211015] = true, [210873] = true, }, ["Shackle Undead"] = { [9484] = true, }, ["Mind Control"] = { [605] = true, [205364] = true, }, ["Grip"] = {}, ["Knock"] = {}, ["Silence"] = { [15487] = true, --Silence [204490] = true, --Sigil of Silence }, ["Taunt"] = { [56222] = true, --Dark Command [355] = true, --Taunt [185245] = true, --Torment [116189] = true, --Provoke }, ["Control Undead"] = { [111673] = true, }, ["Subjugate Demon"] = { [1098] = true, }, } local cmsTimeStamp function DC.CHALLENGE_MODE_START(self, ...) local _, timeCM = GetWorldElapsedTime(1) if timeCM > 0 then return end cmsTimeStamp = GetTime() end function DC.CHALLENGE_MODE_COMPLETED(self, ...) cmsTimeStamp = nil end function DC.PLAYER_ENTERING_WORLD(self, ...) if C_ChallengeMode.IsChallengeModeActive() then return end cmsTimeStamp = nil end -- CHANGE HERE TO DEFINE WHICH DUNGEONS TO TRACK FOR DATA COLLECTION local dungeonsToTrack = { [1] = 40, [2] = 41, [3] = 37, [4] = 38, [5] = 25, [6] = 26, [7] = 9, [8] = 10, } function DC.COMBAT_LOG_EVENT_UNFILTERED(self, ...) local timestamp, subevent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, spellId, spellName, spellSchool = CombatLogGetCurrentEventInfo() --enemy spells if trackedEvents[subevent] then local unitType, _, serverId, instanceId, zoneId, id, spawnUid = strsplit("-", sourceGUID) id = tonumber(id) --dungeon for _, i in pairs(dungeonsToTrack) do local enemies = MDT.dungeonEnemies[i] --enemy for enemyIdx, enemy in pairs(enemies) do if id and spellId and enemy.id == id then db.dataCollection[i] = db.dataCollection[i] or {} db.dataCollection[i][id] = db.dataCollection[i][id] or {} db.dataCollection[i][id][spellId] = {} enemy.spells = enemy.spells or {} enemy.spells[spellId] = enemy.spells[spellId] or {} break end end end end --characteristics if subevent == "SPELL_AURA_APPLIED" then local unitType, _, serverId, instanceId, zoneId, id, spawnUid = strsplit("-", destGUID) id = tonumber(id) or 0 --dungeon for _, i in pairs(dungeonsToTrack) do local enemies = MDT.dungeonEnemies[i] --enemy for enemyIdx, enemy in pairs(enemies) do if enemy.id == id then for characteristic, spells in pairs(characteristicsSpells) do if spells[spellId] then db.dataCollectionCC[i] = db.dataCollectionCC[i] or {} db.dataCollectionCC[i][id] = db.dataCollectionCC[i][id] or {} db.dataCollectionCC[i][id][characteristic] = true enemy.characteristics = enemy.characteristics or {} enemy.characteristics[characteristic] = true end end break end end end end end ---Request users in party/raid to distribute their collected data function MDT:RequestDataCollectionUpdate() print("MDT: Requesting collected data from group members...") local distribution = self:IsPlayerInGroup() if not distribution then return end MDTcommsObject:SendCommMessage(self.dataCollectionPrefixes.request, "0", distribution, nil, "ALERT") end ---Distribute collected data to party/raid function DC:DistributeData() print("MDT: Distributing collected data to group members") local distribution = MDT:IsPlayerInGroup() if not distribution then return end db = MDT:GetDB() local package = { [1] = db.dataCollection, [2] = db.dataCollectionCC } local export = MDT:TableToString(package, false, 5) MDTcommsObject:SendCommMessage(MDT.dataCollectionPrefixes.distribute, export, distribution, nil, "BULK", nil, nil) end ---Merge received collected data into own data collection function DC:MergeReceiveData(package) print("MDT: Merging received collected data") db = MDT:GetDB() local collection, collectionCC = unpack(package) --db.dataCollection[dungeonIdx][npcId][spellId] for dungeonIdx, npcs in pairs(collection) do if not db.dataCollection[dungeonIdx] then db.dataCollection[dungeonIdx] = npcs else for npcId, spells in pairs(npcs) do if not db.dataCollection[dungeonIdx][npcId] then db.dataCollection[dungeonIdx][npcId] = spells else for spellId, tracked in pairs(spells) do db.dataCollection[dungeonIdx][npcId][spellId] = true end end end end end --db.dataCollectionCC[dungeonIdx][npcId][characteristic] for dungeonIdx, npcs in pairs(collectionCC) do if not db.dataCollectionCC[dungeonIdx] then db.dataCollectionCC[dungeonIdx] = npcs else for npcId, characteristics in pairs(npcs) do if not db.dataCollectionCC[dungeonIdx][npcId] then db.dataCollectionCC[dungeonIdx][npcId] = characteristics else for characteristic, tracked in pairs(characteristics) do db.dataCollectionCC[dungeonIdx][npcId][characteristic] = true end end end end end DC:AddCollectedDataToEnemyTable() end function DC:InitHealthTrack() print("MDT: Health Tracking Init") db = MDT:GetDB() db.healthTracking = db.healthTracking or {} local healthTrackingFrame = CreateFrame("Frame") healthTrackingFrame:RegisterEvent("UPDATE_MOUSEOVER_UNIT") healthTrackingFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED") healthTrackingFrame:SetScript("OnEvent", function(_, event, ...) --check difficulty if challenge mode and m+ level local difficultyID = GetDungeonDifficultyID() local isChallenge = difficultyID and C_ChallengeMode.IsChallengeModeActive() local level, activeAffixIDs = C_ChallengeMode.GetActiveKeystoneInfo() local fortified = activeAffixIDs[1] == 10 level = isChallenge and level or -1 if level > -1 then local unit if event == "UPDATE_MOUSEOVER_UNIT" then unit = "mouseover" elseif event == "NAME_PLATE_UNIT_ADDED" then unit = ... end if unit then local guid = UnitGUID(unit) local npcId if guid then npcId = select(6, strsplit("-", guid)) end if npcId then db.healthTracking[tonumber(npcId)] = { ["health"] = UnitHealthMax(unit), ["name"] = UnitName(unit), ["level"] = level, ["fortified"] = fortified } end end end end) function MDT:ProcessHealthTrack() local enemies = MDT.dungeonEnemies[db.currentDungeonIdx] if enemies then local numEnemyHealthChanged = 0 for enemyIdx, enemy in pairs(enemies) do local tracked = db.healthTracking[enemy.id] if tracked then local isBoss = enemy.isBoss and true or false local baseHealth = MDT:ReverseCalcEnemyHealth(tracked.health, tracked.level, isBoss, tracked.fortified) if baseHealth ~= enemy.health then numEnemyHealthChanged = numEnemyHealthChanged + 1 end enemy.health = baseHealth else print("MDT HPTRACK: Missing: " .. enemy.name .. " id: " .. enemy.id) end end print("MDT HPTRACK: Processed " .. numEnemyHealthChanged .. " enemies") end end end