-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathparser.lua
251 lines (210 loc) · 7.05 KB
/
parser.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
-- load public variables into local
local parser = ShaguDPS.parser
local data = ShaguDPS.data
local config = ShaguDPS.config
local round = ShaguDPS.round
-- populate all valid player units
local validUnits = { ["player"] = true }
for i=1,4 do validUnits["party" .. i] = true end
for i=1,40 do validUnits["raid" .. i] = true end
-- populate all valid player pets
local validPets = { ["pet"] = true }
for i=1,4 do validPets["partypet" .. i] = true end
for i=1,40 do validPets["raidpet" .. i] = true end
-- find unitstr by name
local unit_cache = {}
local function UnitByName(name)
-- skip all scans if cache is still valid
if unit_cache[name] and UnitName(unit_cache[name]) == name then
return unit_cache[name]
end
-- scan players for current name
for unit in pairs(validUnits) do
if UnitName(unit) == name then
unit_cache[name] = unit
return unit
end
end
-- scan pets for current name
for unit in pairs(validPets) do
if UnitName(unit) == name then
unit_cache[name] = unit
return unit
end
end
end
-- trim leading and trailing spaces
local function trim(str)
return gsub(str, "^%s*(.-)%s*$", "%1")
end
local function combat()
-- check if in combat
if UnitAffectingCombat("player") or UnitAffectingCombat("pet") then
return true
end
local raid = GetNumRaidMembers()
local group = GetNumPartyMembers()
if raid >= 1 then
for i = 1, raid do
-- check if any raid member is infight
if UnitAffectingCombat("raid"..i) or UnitAffectingCombat("raidpet"..i) then return true end
end
else
for i = 1, group do
-- check if any group member is infight
if UnitAffectingCombat("party"..i) or UnitAffectingCombat("partypet"..i) then return true end
end
end
return nil
end
local start_next_segment = nil
parser.combat = CreateFrame("Frame", "ShaguDPSCombatState", UIParent)
parser.combat:RegisterEvent("PLAYER_REGEN_DISABLED")
parser.combat:RegisterEvent("PLAYER_REGEN_ENABLED")
-- scan and trigger combat state changes
parser.combat.UpdateState = function(self)
local state = combat() == true and "COMBAT" or "NO_COMBAT"
if not self.oldstate or self.oldstate ~= state then
self.oldstate = state
if state == "NO_COMBAT" then
start_next_segment = true
end
end
end
-- check when player leaves/enters combat
parser.combat:SetScript("OnEvent", function()
this:UpdateState()
end)
-- check each second
parser.combat:SetScript("OnUpdate", function()
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end
this:UpdateState()
end)
parser.ScanName = function(self, name)
-- check if name matches a real player
for unit, _ in pairs(validUnits) do
if UnitExists(unit) and UnitName(unit) == name then
if UnitIsPlayer(unit) then
local _, class = UnitClass(unit)
data["classes"][name] = class
return "PLAYER"
end
end
end
-- detect SuperWoW pet owner
local match, _, owner = string.find(name, "%((.*)%)", 1)
if match and owner then
if parser:ScanName(owner) == "PLAYER" then
data["classes"][name] = owner
return "PET"
end
end
-- check if name matches a player pet
for unit, _ in pairs(validPets) do
if UnitExists(unit) and UnitName(unit) == name then
-- parse and set pet owners
if strsub(unit,0,3) == "pet" then
data["classes"][name] = UnitName("player")
elseif strsub(unit,0,8) == "partypet" then
data["classes"][name] = UnitName("party" .. strsub(unit,9))
elseif strsub(unit,0,7) == "raidpet" then
data["classes"][name] = UnitName("raid" .. strsub(unit,8))
end
return "PET"
end
end
-- assign class other if tracking of all units is set
if config.track_all_units == 1 then
data["classes"][name] = data["classes"][name] or "__other__"
return "OTHER"
else
return nil
end
end
parser.AddData = function(self, source, action, target, value, school, datatype)
-- abort on invalid input
if type(source) ~= "string" then return end
-- trim leading and trailing spaces
source = trim(source)
-- prevent self-damage from being tracked
if datatype == "damage" and source == target then
return
end
-- clear "current" on fight start
if start_next_segment and data["classes"][source] and data["classes"][source] ~= "__other__" then
data["damage"][1] = {}
data["heal"][1] = {}
start_next_segment = nil
end
-- calculate effective value (heal)
local effective = 0
if datatype == "heal" then
local unitstr = UnitByName(target)
if unitstr then
-- calculate the effective healing of the current data
effective = math.min(UnitHealthMax(unitstr) - UnitHealth(unitstr), value)
end
end
-- write both (overall and current segment)
for segment = 0, 1 do
local entry = data[datatype][segment]
-- detect source and write initial table
if not entry[source] then
local type = parser:ScanName(source)
if type == "PET" then
-- create owner table if not yet existing
local owner = data["classes"][source]
if not entry[owner] and parser:ScanName(owner) then
entry[owner] = { ["_sum"] = 0, ["_ctime"] = 1 }
end
elseif not type then
-- invalid or disabled unit type
break
end
-- create base damage table
entry[source] = { ["_sum"] = 0, ["_ctime"] = 1 }
end
-- write pet damage into owners data if enabled
local action, source = action, source
if config.merge_pets == 1 and -- merge pets?
data["classes"][source] ~= "__other__" and -- valid unit?
entry[data["classes"][source]] -- has owner?
then
-- remove pet data
entry[source] = nil
action = "Pet: " .. source
source = data["classes"][source]
-- write data into owner
if not entry[source] then
entry[source] = { ["_sum"] = 0, ["_ctime"] = 1 }
end
end
if entry[source] then
-- write overall value and per spell
entry[source][action] = (entry[source][action] or 0) + tonumber(value)
entry[source]["_sum"] = (entry[source]["_sum"] or 0) + tonumber(value)
if datatype == "heal" then
-- write effective healing sumary
entry[source]["_esum"] = (entry[source]["_esum"] or 0) + tonumber(effective)
-- write effective healing per spell
entry[source]["_effective"] = entry[source]["_effective"] or {}
entry[source]["_effective"][action] = (entry[source]["_effective"][action] or 0) + tonumber(effective)
end
entry[source]["_ctime"] = entry[source]["_ctime"] or 1
entry[source]["_tick"] = entry[source]["_tick"] or GetTime()
if entry[source]["_tick"] + 5 < GetTime() then
entry[source]["_tick"] = GetTime()
entry[source]["_ctime"] = entry[source]["_ctime"] + 5
else
entry[source]["_ctime"] = entry[source]["_ctime"] + (GetTime() - entry[source]["_tick"])
entry[source]["_tick"] = GetTime()
end
end
end
for id, callback in pairs(parser.callbacks.refresh) do
callback()
end
end
parser.callbacks = {
["refresh"] = {}
}