Repository navigation
Expand file tree
/
Copy pathWCS_BrainCombatCache.lua
More file actions
391 lines (323 loc) · 11.4 KB
/
Copy pathWCS_BrainCombatCache.lua
File metadata and controls
391 lines (323 loc) · 11.4 KB
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
--[[
WCS_BrainCombatCache.lua - Cache Compartido de Estado de Combate
Compatible con Lua 5.0 (WoW 1.12 / Turtle WoW)
Version: 1.0.0
Proporciona un cache centralizado para evitar duplicación de cálculos
entre DQN, SmartAI y PetAI
]]--
if WCS_Brain and WCS_Brain.ENABLED == false then return end
WCS_BrainCombatCache = WCS_BrainCombatCache or {}
local Cache = WCS_BrainCombatCache
Cache.VERSION = "1.0.0"
-- ============================================================================
-- UTILIDADES LUA 5.0
-- ============================================================================
local function getTime()
return GetTime and GetTime() or 0
end
-- Función para contar elementos en array (compatible Lua 5.0)
local function tableCount(t)
return table.getn(t)
end
-- ============================================================================
-- CACHE DE DOTS COMPARTIDO
-- ============================================================================
Cache.DoTs = {
-- Estructura: [targetID] = { [dotName] = {applied = time, duration = dur, damage = dmg} }
active = {},
-- Duraciones base (sin talentos)
baseDurations = {
["Corruption"] = 18,
["Immolate"] = 15,
["Curse of Agony"] = 24,
["Siphon Life"] = 30,
["Curse of Doom"] = 60,
["Curse of Tongues"] = 30,
["Curse of Weakness"] = 120,
["Curse of the Elements"] = 300,
["Curse of Shadow"] = 300
}
}
-- Registrar aplicación de DoT
function Cache.DoTs:Register(dotName, targetID, damage)
if not targetID or not dotName then return end
if not self.active[targetID] then
self.active[targetID] = {}
end
local duration = self.baseDurations[dotName] or 18
self.active[targetID][dotName] = {
applied = getTime(),
duration = duration,
damage = damage or 0
}
end
-- Obtener tiempo restante de DoT
function Cache.DoTs:GetTimeRemaining(dotName, targetID)
if not targetID or not self.active[targetID] then return 0 end
local dot = self.active[targetID][dotName]
if not dot then return 0 end
local elapsed = getTime() - dot.applied
local remaining = dot.duration - elapsed
if remaining < 0 then
self.active[targetID][dotName] = nil
return 0
end
return remaining
end
-- Verificar si DoT necesita refresh (pandemic window)
function Cache.DoTs:NeedsRefresh(dotName, targetID, pandemicPercent)
pandemicPercent = pandemicPercent or 0.3
local remaining = self:GetTimeRemaining(dotName, targetID)
local baseDuration = self.baseDurations[dotName] or 18
return remaining < (baseDuration * pandemicPercent)
end
-- Limpiar DoTs expirados
function Cache.DoTs:Cleanup()
local now = getTime()
local toRemove = {}
for targetID, dots in pairs(self.active) do
for dotName, data in pairs(dots) do
local remaining = data.duration - (now - data.applied)
if remaining <= 0 then
if not toRemove[targetID] then
toRemove[targetID] = {}
end
table.insert(toRemove[targetID], dotName)
end
end
end
for targetID, dotList in pairs(toRemove) do
for i, dotName in ipairs(dotList) do
self.active[targetID][dotName] = nil
end
-- Si el target no tiene más DoTs, remover entrada
local hasDoTs = false
for k, v in pairs(self.active[targetID]) do
hasDoTs = true
break
end
if not hasDoTs then
self.active[targetID] = nil
end
end
end
-- Obtener todos los DoTs activos en un target
function Cache.DoTs:GetActiveDoTs(targetID)
if not targetID or not self.active[targetID] then return {} end
local result = {}
for dotName, data in pairs(self.active[targetID]) do
local remaining = self:GetTimeRemaining(dotName, targetID)
if remaining > 0 then
table.insert(result, {
name = dotName,
remaining = remaining,
damage = data.damage
})
end
end
return result
end
-- ============================================================================
-- CACHE DE AMENAZA (THREAT)
-- ============================================================================
Cache.Threat = {
playerThreat = 0,
lastReset = 0,
history = {}
}
-- Agregar amenaza
function Cache.Threat:Add(amount, source)
self.playerThreat = self.playerThreat + amount
table.insert(self.history, {
time = getTime(),
amount = amount,
source = source or "unknown",
total = self.playerThreat
})
-- Limitar historial
local historyCount = tableCount(self.history)
if historyCount > 100 then
table.remove(self.history, 1)
end
end
-- Resetear amenaza (cambio de target, salir de combate)
function Cache.Threat:Reset()
self.playerThreat = 0
self.lastReset = getTime()
self.history = {}
end
-- Obtener nivel de amenaza estimado (0-100)
function Cache.Threat:GetLevel()
-- Esto es una estimación, en Vanilla no hay API de threat real
-- Basado en acumulación de amenaza vs tiempo en combate
local combatDuration = 0
if WCS_BrainCombatController and WCS_BrainCombatController.SharedCache then
combatDuration = WCS_BrainCombatController.SharedCache.combatDuration
end
if combatDuration <= 0 then return 0 end
-- Threat por segundo
local tps = self.playerThreat / combatDuration
-- Normalizar a 0-100 (asumiendo 100 TPS = 100%)
local level = math.min((tps / 100) * 100, 100)
return level
end
-- ============================================================================
-- CACHE DE COOLDOWNS
-- ============================================================================
Cache.Cooldowns = {
spells = {},
items = {}
}
-- Registrar cooldown de hechizo
function Cache.Cooldowns:RegisterSpell(spellName, duration)
self.spells[spellName] = {
start = getTime(),
duration = duration
}
end
-- Verificar si hechizo está en cooldown
function Cache.Cooldowns:IsSpellOnCooldown(spellName)
local cd = self.spells[spellName]
if not cd then return false end
local elapsed = getTime() - cd.start
if elapsed >= cd.duration then
self.spells[spellName] = nil
return false
end
return true
end
-- Obtener tiempo restante de cooldown
function Cache.Cooldowns:GetSpellCooldownRemaining(spellName)
local cd = self.spells[spellName]
if not cd then return 0 end
local elapsed = getTime() - cd.start
local remaining = cd.duration - elapsed
if remaining <= 0 then
self.spells[spellName] = nil
return 0
end
return remaining
end
-- ============================================================================
-- CACHE DE ANÁLISIS DE TARGET
-- ============================================================================
Cache.Target = {
current = nil,
healthHistory = {},
dpsEstimate = 0,
ttk = 0, -- Time to kill
lastUpdate = 0
}
-- Actualizar análisis de target
function Cache.Target:Update(targetID, health, healthMax)
local now = getTime()
if targetID ~= self.current then
-- Nuevo target, resetear
self.current = targetID
self.healthHistory = {}
self.dpsEstimate = 0
self.ttk = 0
end
-- Guardar health en historial
table.insert(self.healthHistory, {
time = now,
health = health,
healthMax = healthMax
})
-- Limitar historial a 20 entradas
local historyCount = tableCount(self.healthHistory)
if historyCount > 20 then
table.remove(self.healthHistory, 1)
end
-- Calcular DPS si tenemos suficiente historial
historyCount = tableCount(self.healthHistory)
if historyCount >= 3 then
local oldest = self.healthHistory[1]
local newest = self.healthHistory[historyCount]
local timeDiff = newest.time - oldest.time
local healthDiff = oldest.health - newest.health
if timeDiff > 0 and healthDiff > 0 then
self.dpsEstimate = healthDiff / timeDiff
-- Calcular TTK
if self.dpsEstimate > 0 then
self.ttk = newest.health / self.dpsEstimate
end
end
end
self.lastUpdate = now
end
-- Obtener DPS estimado
function Cache.Target:GetDPS()
return self.dpsEstimate
end
-- Obtener tiempo estimado hasta muerte
function Cache.Target:GetTTK()
return self.ttk
end
-- ============================================================================
-- SINCRONIZACIÓN CON SISTEMAS EXISTENTES
-- ============================================================================
-- Sincronizar con WCS_BrainAI.DoTTimers
function Cache:SyncWithBrainAI()
if not WCS_BrainAI or not WCS_BrainAI.DoTTimers then return end
-- Copiar DoTs de BrainAI a cache compartido
for targetID, dots in pairs(WCS_BrainAI.DoTTimers) do
for dotName, data in pairs(dots) do
if not self.DoTs.active[targetID] then
self.DoTs.active[targetID] = {}
end
self.DoTs.active[targetID][dotName] = data
end
end
-- Actualizar BrainAI con cache compartido
WCS_BrainAI.DoTTimers = self.DoTs.active
end
-- Sincronizar con WCS_BrainSmartAI.CombatCache
function Cache:SyncWithSmartAI()
if not WCS_BrainSmartAI then return end
-- Compartir threat data
if WCS_BrainSmartAI.CombatCache then
WCS_BrainSmartAI.CombatCache.playerThreat = self.Threat.playerThreat
end
end
-- ============================================================================
-- LIMPIEZA PERIÓDICA
-- ============================================================================
Cache.lastCleanup = 0
Cache.cleanupInterval = 5 -- segundos
function Cache:PeriodicCleanup()
local now = getTime()
if now - self.lastCleanup < self.cleanupInterval then
return
end
self.DoTs:Cleanup()
self.lastCleanup = now
end
-- ============================================================================
-- EVENTOS
-- ============================================================================
local cacheFrame = CreateFrame("Frame")
cacheFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
cacheFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
cacheFrame:SetScript("OnEvent", function()
if event == "PLAYER_REGEN_ENABLED" then
-- Salir de combate, resetear threat
Cache.Threat:Reset()
elseif event == "PLAYER_TARGET_CHANGED" then
-- Cambio de target, resetear threat
Cache.Threat:Reset()
end
end)
-- Update loop
local updateFrame = CreateFrame("Frame")
local elapsed = 0
updateFrame:SetScript("OnUpdate", function()
elapsed = elapsed + arg1
if elapsed > 1.0 then
Cache:PeriodicCleanup()
Cache:SyncWithBrainAI()
Cache:SyncWithSmartAI()
elapsed = 0
end
end)
DEFAULT_CHAT_FRAME:AddMessage("|cFF00FFAA[CombatCache]|r Inicializado v" .. Cache.VERSION)