General Fixes, Backend Improvements, Library Updates.
Release Documentation: - Classic now uses the same combat log reader as retail (Flamanis). - Merged Rage of Fyr'alath spells (equara). - Added Rogue Ambushes to merged spells (WillowGryph). - The Remove Common Segments option now also removes segments trash between raid bosses. - Fixed an issue where auras applied before combat start, such as Power Infusion and Prescience, which are counted towards the target, were not being accounted for. - Added to Combat Class: classCombat:GetRunTimeNoDefault(). This returns the run time of the Mythic+ if available, nil otherwise. Technical Notes: - Classic now uses retail parser. - Combat class now have the member: classCombat:GetRunTimeNoDefault(); Returns the run time of a M+ (after completed). - The Utility class's buff scan at the start of combat has been improved, and the code has been cleaned. Also, the scan runs now on the next frame after combat start. - Augmentation Evoker won't track auras from the combat start aura scan, if the player isn't in combat (example: a player in the group enters in combat). - Remove tier bonus for Augmentation Evoker Ebon Might damage prediction and nerfed Close as Cluthmates to 10%. - Segments Container's ResetDataByCombatType() now supports multiple combat types per classification. - Code cleanup on Segments menu code to use the new Mythic+ functions added to Combat class. - Mythic+ start detection produced errors if a WORLD_STATE_TIMER_START event triggered before the CHALLENGE_MODE_START event. - Mythic+ finish code was bugging when 'time' returned by C_ChallengeMode.GetCompletionInfo() wasn't being checked again nil value. - Rogue's Ambush ability and Rage of Fyr'alath spellIds added to override_spellId within the parser. - Details! Framework updated. - Open Raid Library updated.
This commit is contained in:
+28
-79
@@ -115,26 +115,6 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
--return the table which contain information about the end of a encounter
|
||||
function Details:GetEncounterEndInfo (mapid, encounterid)
|
||||
local bossindex = Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].encounter_ids and Details.EncounterInformation [mapid].encounter_ids [encounterid]
|
||||
if (bossindex) then
|
||||
return Details.EncounterInformation [mapid].encounters [bossindex] and Details.EncounterInformation [mapid].encounters [bossindex].encounter_end
|
||||
end
|
||||
end
|
||||
|
||||
--return the function for the boss
|
||||
function Details:GetEncounterEnd (mapid, bossindex)
|
||||
local t = Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].encounters [bossindex]
|
||||
if (t) then
|
||||
local _end = t.combat_end
|
||||
if (_end) then
|
||||
return unpack(_end)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--generic boss find function
|
||||
function Details:GetRaidBossFindFunction (mapid)
|
||||
return Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].find_boss_encounter
|
||||
@@ -145,15 +125,6 @@ do
|
||||
return Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].encounters [bossindex] and Details.EncounterInformation [mapid].encounters [bossindex].equalize
|
||||
end
|
||||
|
||||
--return the function for the boss
|
||||
function Details:GetBossFunction (mapid, bossindex)
|
||||
local func = Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].encounters [bossindex] and Details.EncounterInformation [mapid].encounters [bossindex].func
|
||||
if (func) then
|
||||
return func, Details.EncounterInformation [mapid].encounters [bossindex].funcType
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--return the boss table with information about name, adds, spells, etc
|
||||
function Details:GetBossDetails (mapid, bossindex)
|
||||
return Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].encounters [bossindex]
|
||||
@@ -199,13 +170,13 @@ do
|
||||
end
|
||||
|
||||
--return a table with all encounter names present in raid instance
|
||||
function Details:GetBossNames (mapid)
|
||||
return Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].boss_names
|
||||
function Details:GetBossNames(mapId)
|
||||
return Details.EncounterInformation[mapId] and Details.EncounterInformation[mapId].boss_names
|
||||
end
|
||||
|
||||
--return the encounter name
|
||||
function Details:GetBossName (mapid, bossindex)
|
||||
return Details.EncounterInformation [mapid] and Details.EncounterInformation [mapid].boss_names [bossindex]
|
||||
function Details:GetBossName(mapid, bossindex)
|
||||
return Details.EncounterInformation[mapid] and Details.EncounterInformation[mapid].boss_names[bossindex]
|
||||
end
|
||||
|
||||
--same thing as GetBossDetails, just a alias
|
||||
@@ -382,48 +353,45 @@ do
|
||||
return actors
|
||||
end
|
||||
|
||||
function Details:GetInstanceEJID (mapid)
|
||||
mapid = mapid or select(8, GetInstanceInfo())
|
||||
if (mapid) then
|
||||
local instance_info = Details.EncounterInformation [mapid]
|
||||
if (instance_info) then
|
||||
return instance_info.ej_id or 0
|
||||
function Details:GetInstanceEJID(mapId)
|
||||
mapId = mapId or select(8, GetInstanceInfo())
|
||||
if (mapId) then
|
||||
local instanceInfo = Details.EncounterInformation[mapId]
|
||||
if (instanceInfo) then
|
||||
return instanceInfo.ej_id or 0
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function Details:GetCurrentDungeonBossListFromEJ()
|
||||
|
||||
local mapID = C_Map.GetBestMapForUnit ("player")
|
||||
|
||||
if (not mapID) then
|
||||
--print("Details! exeption handled: zone has no map")
|
||||
return
|
||||
end
|
||||
|
||||
local EJ_CInstance = DetailsFramework.EncounterJournal.EJ_GetInstanceForMap(mapID)
|
||||
local instanceId = DetailsFramework.EncounterJournal.EJ_GetInstanceForMap(mapID)
|
||||
|
||||
if (EJ_CInstance and EJ_CInstance ~= 0) then
|
||||
if (Details.encounter_dungeons [EJ_CInstance]) then
|
||||
return Details.encounter_dungeons [EJ_CInstance]
|
||||
if (instanceId and instanceId ~= 0) then
|
||||
if (Details.encounter_dungeons[instanceId]) then
|
||||
return Details.encounter_dungeons[instanceId]
|
||||
end
|
||||
|
||||
DetailsFramework.EncounterJournal.EJ_SelectInstance (EJ_CInstance)
|
||||
DetailsFramework.EncounterJournal.EJ_SelectInstance(instanceId)
|
||||
local name, description, bgImage, buttonImage, loreImage, dungeonAreaMapID, link = DetailsFramework.EncounterJournal.EJ_GetInstanceInfo(instanceId)
|
||||
|
||||
local name, description, bgImage, buttonImage, loreImage, dungeonAreaMapID, link = DetailsFramework.EncounterJournal.EJ_GetInstanceInfo (EJ_CInstance)
|
||||
|
||||
local boss_list = {
|
||||
[EJ_CInstance] = {name, description, bgImage, buttonImage, loreImage, dungeonAreaMapID, link}
|
||||
local bossList = {
|
||||
[instanceId] = {name, description, bgImage, buttonImage, loreImage, dungeonAreaMapID, link}
|
||||
}
|
||||
|
||||
for i = 1, 20 do
|
||||
local encounterName, description, encounterID, rootSectionID, link = DetailsFramework.EncounterJournal.EJ_GetEncounterInfoByIndex (i, EJ_CInstance)
|
||||
local encounterName, description, encounterID, rootSectionID, link = DetailsFramework.EncounterJournal.EJ_GetEncounterInfoByIndex(i, instanceId)
|
||||
if (encounterName) then
|
||||
for o = 1, 6 do
|
||||
local id, creatureName, creatureDescription, displayInfo, iconImage = DetailsFramework.EncounterJournal.EJ_GetCreatureInfo (o, encounterID)
|
||||
local id, creatureName, creatureDescription, displayInfo, iconImage = DetailsFramework.EncounterJournal.EJ_GetCreatureInfo(o, encounterID)
|
||||
if (id) then
|
||||
boss_list [creatureName] = {encounterName, encounterID, creatureName, iconImage, EJ_CInstance}
|
||||
bossList[creatureName] = {encounterName, encounterID, creatureName, iconImage, instanceId}
|
||||
else
|
||||
break
|
||||
end
|
||||
@@ -433,14 +401,13 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
Details.encounter_dungeons [EJ_CInstance] = boss_list
|
||||
|
||||
return boss_list
|
||||
Details.encounter_dungeons[instanceId] = bossList
|
||||
return bossList
|
||||
end
|
||||
end
|
||||
|
||||
function Details:IsRaidRegistered(mapid)
|
||||
return Details.EncounterInformation [mapid] and true
|
||||
function Details:IsRaidRegistered(mapId)
|
||||
return Details.EncounterInformation[mapId] and true
|
||||
end
|
||||
|
||||
--this cache is local and isn't shared with other components of the addon
|
||||
@@ -629,14 +596,6 @@ do
|
||||
--delay the cache createation as it is not needed right away
|
||||
--createEJCache() will check if encounter journal is loaded, if not it will load it and then create the cache
|
||||
local createEJCache = function()
|
||||
--check if the encounter journal added is loaded
|
||||
if (not EncounterJournal) then
|
||||
--local startTime = debugprofilestop()
|
||||
--[[EncounterJournal_LoadUI()]]
|
||||
--local endTime = debugprofilestop()
|
||||
--print("DE loading EJ:", endTime - startTime)
|
||||
end
|
||||
|
||||
--[[hooksecurefunc("EncounterJournal_OpenJournalLink", Details222.EJCache.OnClickEncounterJournalLink)]]
|
||||
|
||||
---iterate among all raid instances, by passing true in the second argument of EJ_GetInstanceByIndex, indicates to the API we want to get raid instances
|
||||
@@ -653,12 +612,12 @@ do
|
||||
|
||||
---increment this each expansion
|
||||
---@type number
|
||||
local currentTierId = 10 --maintenance
|
||||
local currentTierId = 10 --maintenance | 10 is "Dragonflight"
|
||||
|
||||
---is the id of where it shows the mythic+ dungeons available for the season
|
||||
---can be found in the adventure guide in the dungeons tab > dropdown
|
||||
---@type number
|
||||
local currentMythicPlusTierId = 11 --maintenance
|
||||
local currentMythicPlusTierId = 11 --maintenance | 11 is "Current Season"
|
||||
|
||||
---maximum amount of raid tiers in the expansion
|
||||
---@type number
|
||||
@@ -753,8 +712,6 @@ do
|
||||
|
||||
do --get current expansion dungeon instances data and mythic+ data
|
||||
bGetRaidInstances = false
|
||||
--EncounterJournalDungeonTab:Click()
|
||||
--EncounterJournal_TierDropDown_Select(_, 11) --select mythic+
|
||||
|
||||
--get mythic+ dungeon data
|
||||
EJ_SelectTier(currentMythicPlusTierId)
|
||||
@@ -762,8 +719,6 @@ do
|
||||
for instanceIndex = maxAmountOfDungeons, 1, -1 do
|
||||
local journalInstanceID, instanceName, description, bgImage, buttonImage1, loreImage, buttonImage2, dungeonAreaMapID = EJ_GetInstanceByIndex(instanceIndex, bGetRaidInstances)
|
||||
if (journalInstanceID) then
|
||||
--tell the encounter journal to display the dungeon instance by the instanceId
|
||||
--EncounterJournal_DisplayInstance(journalInstanceID)
|
||||
EJ_SelectInstance(journalInstanceID)
|
||||
|
||||
--build a table with data of the raid instance
|
||||
@@ -828,7 +783,6 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
--EncounterJournal_TierDropDown_Select(_, 10) --select Dragonflight
|
||||
--get current expansion dungeons data
|
||||
EJ_SelectTier(currentTierId)
|
||||
|
||||
@@ -837,7 +791,6 @@ do
|
||||
|
||||
if (journalInstanceID and not Details222.EJCache.CacheDungeonData_ByInstanceId[journalInstanceID]) then
|
||||
--tell the encounter journal to display the dungeon instance by the instanceId
|
||||
--EncounterJournal_DisplayInstance(journalInstanceID)
|
||||
EJ_SelectInstance(journalInstanceID)
|
||||
|
||||
--build a table with data of the raid instance
|
||||
@@ -909,17 +862,13 @@ do
|
||||
EncounterJournal_ResetDisplay(nil, "none")
|
||||
end
|
||||
end)
|
||||
|
||||
--EncounterJournal_OpenJournalLink(tag, jtype, id, difficultyID)
|
||||
--EncounterJournal_OpenJournal(difficultyID, instanceID, encounterID, sectionID, creatureID, itemID, tierIndex)
|
||||
end
|
||||
|
||||
--todo: should run one second after the player_login event or entering_world
|
||||
--todo: should run one second after the player_login event or entering_world | 2023-12-05: already executing on the player_login event
|
||||
C_Timer.After(1, function()
|
||||
if (not EncounterJournal_LoadUI) then
|
||||
return
|
||||
end
|
||||
|
||||
createEJCache()
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
local Details = _G.Details
|
||||
local addonName, Details222 = ...
|
||||
local ipairs = ipairs --lua local
|
||||
local detailsFramework = DetailsFramework
|
||||
|
||||
local ejTable = Details222.EncounterJournalDump
|
||||
|
||||
|
||||
function Details.CreateEncounterJournalDump()
|
||||
local data = {}
|
||||
|
||||
---iterate among all raid instances, by passing true in the second argument of EJ_GetInstanceByIndex, indicates to the API we want to get raid instances
|
||||
---@type boolean
|
||||
local bGetRaidInstances = true
|
||||
|
||||
---returns the number of valid encounter journal tier indices
|
||||
---@type number
|
||||
local tierAmount = EJ_GetNumTiers()
|
||||
|
||||
---returns the currently active encounter journal tier index
|
||||
---@type number
|
||||
local currentTier = EJ_GetCurrentTier()
|
||||
|
||||
---increment this each expansion
|
||||
---@type number
|
||||
local currentTierId = 10 --maintenance | 10 is "Dragonflight"
|
||||
|
||||
---is the id of where it shows the mythic+ dungeons available for the season
|
||||
---can be found in the adventure guide in the dungeons tab > dropdown
|
||||
---@type number
|
||||
local currentMythicPlusTierId = 11 --maintenance | 11 is "Current Season"
|
||||
|
||||
---maximum amount of raid tiers in the expansion
|
||||
---@type number
|
||||
local maxAmountOfRaidTiers = 10
|
||||
|
||||
---maximum amount of dungeons in the expansion
|
||||
---@type number
|
||||
local maxAmountOfDungeons = 20
|
||||
|
||||
---the index of the first raid tier in the expansion, ignoring the first tier as it is open world bosses
|
||||
---@type number
|
||||
local raidTierStartIndex = 2
|
||||
|
||||
---max amount of bosses which a raid tier can have
|
||||
---@type number
|
||||
local maxRaidBosses = 20
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -25,7 +25,7 @@ end
|
||||
---@param tag any tag isn't used
|
||||
---@param journalTypeString string
|
||||
---@param idString string
|
||||
function Details222.EJCache.OnClickEncounterJournalLink(tag, journalTypeString, idString)
|
||||
function Details222.EJCache.OnClickEncounterJournalLink(tag, journalTypeString, idString) --not in use
|
||||
local journalType = tonumber(journalTypeString)
|
||||
local id = tonumber(idString)
|
||||
|
||||
|
||||
@@ -577,11 +577,6 @@ function SlashCmdList.DETAILS (msg, editbox)
|
||||
end
|
||||
end
|
||||
|
||||
elseif (msg == "teste") then
|
||||
|
||||
local a, b = Details:GetEncounterEnd (1098, 3)
|
||||
print(a, unpack(b))
|
||||
|
||||
elseif (msg == "yesno") then
|
||||
--_detalhes:Show()
|
||||
|
||||
@@ -1042,33 +1037,7 @@ function SlashCmdList.DETAILS (msg, editbox)
|
||||
1 --school =
|
||||
)
|
||||
|
||||
elseif (msg == "ejloot") then
|
||||
DetailsFramework.EncounterJournal.EJ_SelectInstance (669) -- hellfire citadel
|
||||
DetailsFramework.EncounterJournal.EJ_SetDifficulty (16)
|
||||
|
||||
local r = {}
|
||||
local total = 0
|
||||
|
||||
for i = 1, 100 do
|
||||
local name, description, encounterID, rootSectionID, link = DetailsFramework.EncounterJournal.EJ_GetEncounterInfoByIndex (i, 669)
|
||||
if (name) then
|
||||
DetailsFramework.EncounterJournal.EJ_SelectEncounter (encounterID)
|
||||
print(name, encounterID, DetailsFramework.EncounterJournal.EJ_GetNumLoot())
|
||||
|
||||
for o = 1, DetailsFramework.EncounterJournal.EJ_GetNumLoot() do
|
||||
local name, icon, slot, armorType, itemID, link, encounterID = DetailsFramework.EncounterJournal.EJ_GetLootInfoByIndex (o)
|
||||
r[slot] = r[slot] or {}
|
||||
table.insert(r[slot], {itemID, encounterID})
|
||||
total = total + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("total loot", total)
|
||||
_detalhes_global.ALOOT = r
|
||||
|
||||
elseif (msg == "ilvl" or msg == "itemlevel" or msg == "ilevel") then
|
||||
|
||||
local item_amount = 16
|
||||
local item_level = 0
|
||||
local failed = 0
|
||||
|
||||
@@ -16,6 +16,10 @@ local playerRealmName = GetRealmName()
|
||||
|
||||
|
||||
function augmentationFunctions.BuffIn(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellschool, auraType, amount)
|
||||
if (not UnitAffectingCombat("player")) then --need documentation
|
||||
return
|
||||
end
|
||||
|
||||
if (spellId == 395152) then --ebom might on third parties
|
||||
local auraName, texture, count, auraType, duration, expirationTime, sourceUnit, isStealable, nameplateShowPersonal, spellId, canApplyAura, isBossAura, isFromPlayerOrPlayerPet, nameplateShowAll, timeMod, v1, v2, v3, v4, v5 = Details:FindBuffCastedByUnitName(targetName, spellId, sourceName)
|
||||
local attributeGained = v2
|
||||
@@ -24,6 +28,7 @@ function augmentationFunctions.BuffIn(token, time, sourceSerial, sourceName, sou
|
||||
augmentationCache.ebon_might[targetSerial] = augmentationCache.ebon_might[targetSerial] or {}
|
||||
local evokerInfo = {sourceSerial, sourceName, sourceFlags, attributeGained}
|
||||
table.insert(augmentationCache.ebon_might[targetSerial], evokerInfo)
|
||||
--print("ebom might added, cache:", Details.augmentation_cache, #augmentationCache.ebon_might[targetSerial])
|
||||
end
|
||||
|
||||
elseif (spellId == 413984) then --ss
|
||||
@@ -37,12 +42,12 @@ function augmentationFunctions.BuffIn(token, time, sourceSerial, sourceName, sou
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellId == 410089) then
|
||||
elseif (spellId == 410089) then --prescience
|
||||
augmentationCache.prescience[targetSerial] = augmentationCache.prescience[targetSerial] or {}
|
||||
local evokerInfo = {sourceSerial, sourceName, sourceFlags, amount}
|
||||
table.insert(augmentationCache.prescience[targetSerial], evokerInfo)
|
||||
|
||||
elseif (spellId == 409560) then
|
||||
elseif (spellId == 409560) then --eons breath
|
||||
local unitIDAffected = Details:FindUnitIDByUnitSerial(targetSerial)
|
||||
if (unitIDAffected) then
|
||||
local duration, expirationTime = Details:FindDebuffDuration(unitIDAffected, spellId, Details:Ambiguate(sourceName))
|
||||
@@ -59,12 +64,12 @@ function augmentationFunctions.BuffIn(token, time, sourceSerial, sourceName, sou
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellId == 360827) then
|
||||
elseif (spellId == 360827) then --tank shield
|
||||
augmentationCache.shield[targetSerial] = augmentationCache.shield[targetSerial] or {}
|
||||
local evokerInfo = {sourceSerial, sourceName, sourceFlags, amount}
|
||||
table.insert(augmentationCache.shield[targetSerial], evokerInfo)
|
||||
|
||||
elseif (spellId == 410263) then
|
||||
elseif (spellId == 410263) then --inferno bless
|
||||
augmentationCache.infernobless[targetSerial] = augmentationCache.infernobless[targetSerial] or {}
|
||||
local evokerInfo = {sourceSerial, sourceName, sourceFlags}
|
||||
table.insert(augmentationCache.infernobless[targetSerial], evokerInfo)
|
||||
@@ -140,18 +145,21 @@ end
|
||||
|
||||
|
||||
|
||||
function augmentationFunctions.BuffOut(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellid, spellName, spellSchool, tipo, amount)
|
||||
if (spellid == 395152) then
|
||||
function augmentationFunctions.BuffOut(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetFlags2, spellId, spellName, spellSchool, tipo, amount)
|
||||
if (spellId == 395152) then
|
||||
if (augmentationCache.ebon_might[targetSerial]) then
|
||||
--print("tinha buff", targetName, targetSerial)
|
||||
for index, evokerInfo in ipairs(augmentationCache.ebon_might[targetSerial]) do
|
||||
if (evokerInfo[1] == sourceSerial) then
|
||||
--print("ebom might finished, removing from cache:", Details.augmentation_cache, #augmentationCache.ebon_might[targetSerial])
|
||||
table.remove(augmentationCache.ebon_might[targetSerial], index)
|
||||
--print("ebom might finished, removing from cache:", Details.augmentation_cache, #augmentationCache.ebon_might[targetSerial])
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellid == 413984) then
|
||||
elseif (spellId == 413984) then
|
||||
if (augmentationCache.ss[targetSerial]) then
|
||||
for index, evokerInfo in ipairs(augmentationCache.ss[targetSerial]) do
|
||||
if (evokerInfo[1] == sourceSerial) then
|
||||
@@ -161,7 +169,7 @@ function augmentationFunctions.BuffOut(token, time, sourceSerial, sourceName, so
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellid == 410089) then
|
||||
elseif (spellId == 410089) then
|
||||
if (augmentationCache.prescience[targetSerial]) then
|
||||
for index, evokerInfo in ipairs(augmentationCache.prescience[targetSerial]) do
|
||||
if (evokerInfo[1] == sourceSerial) then
|
||||
@@ -171,7 +179,7 @@ function augmentationFunctions.BuffOut(token, time, sourceSerial, sourceName, so
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellid == 360827) then
|
||||
elseif (spellId == 360827) then
|
||||
if (augmentationCache.shield[targetSerial]) then
|
||||
for index, evokerInfo in ipairs(augmentationCache.shield[targetSerial]) do
|
||||
if (evokerInfo[1] == sourceSerial) then
|
||||
@@ -181,7 +189,7 @@ function augmentationFunctions.BuffOut(token, time, sourceSerial, sourceName, so
|
||||
end
|
||||
end
|
||||
|
||||
elseif (spellid == 410263) then
|
||||
elseif (spellId == 410263) then
|
||||
if (augmentationCache.infernobless[targetSerial]) then
|
||||
for index, evokerInfo in ipairs(augmentationCache.infernobless[targetSerial]) do
|
||||
if (evokerInfo[1] == sourceSerial) then
|
||||
|
||||
Reference in New Issue
Block a user