frenado05

Untitled

May 25th, 2026 (edited)
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.75 KB | None | 0 0
  1. ----------------------------------------[[
  2. -- Initialization
  3. ----------------------------------------]]
  4.  
  5. local version = select(4, GetBuildInfo())
  6. if version < 120000 then
  7. print('Preservation Stasis Tracker is designed only for Midnight.')
  8. return
  9. end
  10. local _, class = UnitClass("player")
  11. if class ~= "EVOKER" then return end
  12.  
  13. -- ============================================
  14. -- DEBUG MODE: поставь false чтобы отключить дебаг
  15. -- ============================================
  16. local DEBUG = false
  17.  
  18. if DEBUG then
  19. print("=== Preservation Stasis Tracker LOADED (DEBUG MODE) ===")
  20. end
  21.  
  22. ----------------------------------------[[
  23. -- Display
  24. ----------------------------------------]]
  25. local stasisDisplay = CreateFrame("Frame", "PreservationStasisTrackerDisplay", UIParent)
  26. stasisDisplay:SetSize(120, 55)
  27. stasisDisplay:SetPoint("CENTER")
  28. stasisDisplay:SetClampedToScreen(true)
  29.  
  30. stasisDisplay.icons = {}
  31. for i = 1, 3 do
  32. stasisDisplay.icons[i] = stasisDisplay:CreateTexture(nil, "BACKGROUND")
  33. stasisDisplay.icons[i]:SetSize(40, 40)
  34. stasisDisplay.icons[i]:SetTexture(134400)
  35. if i == 1 then
  36. stasisDisplay.icons[i]:SetPoint("BOTTOMLEFT", stasisDisplay, "BOTTOMLEFT")
  37. else
  38. stasisDisplay.icons[i]:SetPoint("LEFT", stasisDisplay.icons[i - 1], "RIGHT")
  39. end
  40. end
  41.  
  42. stasisDisplay.bar = CreateFrame("StatusBar", nil, stasisDisplay)
  43. stasisDisplay.bar:SetFrameStrata("LOW")
  44. stasisDisplay.bar:SetSize(120, 15)
  45. stasisDisplay.bar:SetPoint("TOPLEFT", stasisDisplay, "TOPLEFT")
  46. stasisDisplay.bar:SetStatusBarTexture("Interface/Buttons/WHITE8x8")
  47. stasisDisplay.bar:SetStatusBarColor(0.2, 0.5, 0.4)
  48. stasisDisplay.bar:SetMinMaxValues(0, 30)
  49. stasisDisplay.bar:SetValue(15)
  50.  
  51. stasisDisplay.barBackground = stasisDisplay.bar:CreateTexture(nil, 'BACKGROUND')
  52. stasisDisplay.barBackground:SetAllPoints(stasisDisplay.bar)
  53. stasisDisplay.barBackground:SetColorTexture(0, 0, 0, 1)
  54.  
  55. stasisDisplay.text = stasisDisplay:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  56. stasisDisplay.text:SetPoint("CENTER", stasisDisplay.bar, "CENTER")
  57. stasisDisplay.text:SetShadowColor(0, 0, 0, 1)
  58. stasisDisplay.text:SetShadowOffset(-1, -1)
  59. stasisDisplay.text:SetScale(1.2)
  60. stasisDisplay.text:SetText('15')
  61.  
  62. local function ChangeIconSize(value, orientation, iconPadding)
  63. if not iconPadding then iconPadding = 0 end
  64. for i = 1, 3 do
  65. stasisDisplay.icons[i]:SetSize(value, value)
  66. end
  67. local width, height
  68. if orientation and orientation == 'Vertical' then
  69. width, height = value + 15, (value * 3) + iconPadding * 2
  70. stasisDisplay.bar:SetSize(15, height)
  71. else
  72. width, height = (value * 3) + iconPadding * 2, value + 15
  73. stasisDisplay.bar:SetSize(width, 15)
  74. end
  75. stasisDisplay:SetSize(width, height)
  76. PSTDB['iconSize'] = value
  77. end
  78.  
  79. local function ShowExample()
  80. stasisDisplay.bar:SetValue(15)
  81. stasisDisplay:Show()
  82. for i = 1, 3 do
  83. stasisDisplay.icons[i]:SetTexture(134400)
  84. end
  85. end
  86.  
  87. local function ChangeIconPadding(value, orientation, iconSize)
  88. if not iconSize then iconSize = 40 end
  89. local xPad, yPad, point, rel, barX, barY, width, height
  90. if orientation and orientation == 'Vertical' then
  91. xPad, yPad, point, rel, barX, barY = 0, value, 'BOTTOM', 'TOP', 15, ((iconSize * 3) + value * 2)
  92. width, height = iconSize + barX, barY
  93. else
  94. xPad, yPad, point, rel, barX, barY = value, 0, 'LEFT', 'RIGHT', ((iconSize * 3) + value * 2), 15
  95. width, height = barX, iconSize + barY
  96. end
  97. for i = 2, 3 do
  98. stasisDisplay.icons[i]:ClearAllPoints()
  99. stasisDisplay.icons[i]:SetPoint(point, stasisDisplay.icons[i - 1], rel, xPad, yPad)
  100. end
  101. stasisDisplay:SetSize(width, height)
  102. stasisDisplay.bar:SetSize(barX, barY)
  103. PSTDB['iconPadding'] = value
  104. end
  105.  
  106. local function SetGrowDirection(direction, layout)
  107. local point, rel, padX, padY, barX, barY, width, height
  108. if direction == "Horizontal" then
  109. point, rel, padX, padY, barX, barY = "LEFT", "RIGHT", PSTDB[layout].iconPadding, 0, ((PSTDB[layout].iconSize * 3) + PSTDB[layout].iconPadding * 2), 15
  110. width, height = barX, PSTDB[layout].iconSize + barY
  111. stasisDisplay:SetSize(PSTDB[layout].iconSize * 3, PSTDB[layout].iconSize + 15)
  112. stasisDisplay.bar:ClearAllPoints()
  113. stasisDisplay.bar:SetPoint("TOPLEFT", stasisDisplay, "TOPLEFT")
  114. stasisDisplay.bar:SetOrientation('HORIZONTAL')
  115. elseif direction == "Vertical" then
  116. point, rel, padX, padY, barX, barY = "BOTTOM", "TOP", 0, PSTDB[layout].iconPadding, 15, ((PSTDB[layout].iconSize * 3) + PSTDB[layout].iconPadding * 2)
  117. width, height = PSTDB[layout].iconSize + barX, barY
  118. stasisDisplay:SetSize(PSTDB[layout].iconSize + 15, PSTDB[layout].iconSize * 3)
  119. stasisDisplay.bar:ClearAllPoints()
  120. stasisDisplay.bar:SetPoint("BOTTOMRIGHT", stasisDisplay, "BOTTOMRIGHT")
  121. stasisDisplay.bar:SetOrientation('VERTICAL')
  122. end
  123. stasisDisplay:SetSize(width, height)
  124. stasisDisplay.bar:SetSize(barX, barY)
  125. for i = 2, 3 do
  126. stasisDisplay.icons[i]:ClearAllPoints()
  127. stasisDisplay.icons[i]:SetPoint(point, stasisDisplay.icons[i - 1], rel, padX, padY)
  128. end
  129. end
  130.  
  131. stasisDisplay:Hide()
  132.  
  133. ----------------------------------------[[
  134. -- Functionality
  135. ----------------------------------------]]
  136.  
  137. local spellList = {
  138. [370537] = 'Stasis Store',
  139. [370564] = 'Stasis Release',
  140. [361509] = 'Living Flame',
  141. [364343] = 'Echo',
  142. [360995] = 'Verdant Embrace',
  143. [366155] = 'Reversion',
  144. [1256581] = 'Merithras Blessing',
  145. [355913] = 'Emerald Blossom',
  146. [374251] = 'Cauterizing Flame',
  147. [360823] = 'Naturalize',
  148. [373861] = 'Temporal Anomaly',
  149. [1291636] = 'Temporal Barrier'
  150. }
  151.  
  152. local empowers = {
  153. TTS = 370553,
  154. DreamBreath = {
  155. 355936,
  156. 382614
  157. },
  158. FireBreath = {
  159. 357208,
  160. 382266
  161. }
  162. }
  163.  
  164. local currentState = {
  165. showing = false,
  166. storedSpells = 0,
  167. fillTime = nil,
  168. ticker = nil,
  169. tts = false,
  170. ttsStored = false
  171. }
  172.  
  173. local function log(...)
  174. if DEBUG then
  175. print(...)
  176. end
  177. end
  178.  
  179. local function StartStasis()
  180. log("[DEBUG] ========================================")
  181. log("[DEBUG] StartStasis() called")
  182. stasisDisplay:Show()
  183. currentState.storedSpells = 0
  184. currentState.showing = true
  185. stasisDisplay.text:SetText('')
  186. stasisDisplay.bar:SetValue(0)
  187. for i = 1, 3 do
  188. stasisDisplay.icons[i]:SetTexture(134400)
  189. end
  190. if currentState.ttsStored then
  191. log("[DEBUG] StartStasis: restoring tts from ttsStored")
  192. currentState.tts = true
  193. end
  194. log("[DEBUG] StartStasis: showing=true, tts=" .. tostring(currentState.tts))
  195. end
  196.  
  197. local function ReleaseStasis()
  198. log("[DEBUG] ReleaseStasis() called")
  199. if currentState.ticker then
  200. currentState.ticker:Cancel()
  201. end
  202. currentState.showing = false
  203. stasisDisplay:Hide()
  204. end
  205.  
  206. local function FillStasis()
  207. log("[DEBUG] FillStasis() called - all 3 spells stored")
  208. currentState.fillTime = GetTime()
  209. currentState.ticker = C_Timer.NewTicker(0.2, function()
  210. local timeLeft = currentState.fillTime + 30 - GetTime()
  211. if timeLeft <= 0 then
  212. ReleaseStasis()
  213. end
  214. stasisDisplay.text:SetText(math.floor(timeLeft))
  215. stasisDisplay.bar:SetValue(timeLeft)
  216. end)
  217. end
  218.  
  219. local function AddSpell(spellId)
  220. local spellName = C_Spell.GetSpellInfo(spellId).name
  221. log(string.format("[DEBUG] >>> ADDSPELL: %s (ID: %d), storedSpells: %d -> %d", spellName, spellId, currentState.storedSpells, currentState.storedSpells + 1))
  222. currentState.storedSpells = currentState.storedSpells + 1
  223. if stasisDisplay.icons[currentState.storedSpells] then
  224. stasisDisplay.icons[currentState.storedSpells]:SetTexture(C_Spell.GetSpellTexture(spellId))
  225. end
  226. if currentState.storedSpells == 3 then
  227. FillStasis()
  228. end
  229. end
  230.  
  231. function CancelAuraStasis()
  232. log("[DEBUG] CancelAuraStasis() manual call")
  233. ReleaseStasis()
  234. end
  235.  
  236. -- Event Tracker Frame
  237. local castTracker = CreateFrame("Frame")
  238. castTracker:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
  239. castTracker:RegisterEvent("UNIT_SPELLCAST_EMPOWER_STOP")
  240. castTracker:SetScript("OnEvent", function(self, event, ...)
  241. if event == "UNIT_SPELLCAST_SUCCEEDED" then
  242. local unit, _, spellId = ...
  243. local spellName = spellList[spellId] or (C_Spell.GetSpellInfo(spellId) and C_Spell.GetSpellInfo(spellId).name) or "Unknown"
  244.  
  245. if DEBUG then
  246. print(string.format("[DEBUG] EVENT: SUCCEEDED | unit=%s | spell=%s (ID: %d) | showing=%s | stored=%d | tts=%s | ttsStored=%s",
  247. unit, spellName, spellId,
  248. tostring(currentState.showing),
  249. currentState.storedSpells,
  250. tostring(currentState.tts),
  251. tostring(currentState.ttsStored)))
  252. end
  253.  
  254. -- Убрали issecretvalue полностью
  255. if unit == "player" then
  256. -- TTS обрабатывается ВСЕГДА, независимо от showing
  257. if spellId == empowers.TTS then
  258. log("[DEBUG] ACTION: TTS detected - setting ttsStored=true, tts=true")
  259. currentState.ttsStored = true
  260. currentState.tts = true
  261. end
  262.  
  263. -- Обработка Dream Breath с TTS даже если Stasis не активен (сбрасываем флаги)
  264. if (spellId == empowers.DreamBreath[1] or spellId == empowers.DreamBreath[2]) and currentState.tts then
  265. log("[DEBUG] ACTION: Dream Breath with tts=true - clearing flags (tts=false, ttsStored=false)")
  266. currentState.tts = false
  267. currentState.ttsStored = false
  268. if currentState.showing then
  269. log("[DEBUG] ACTION: Stasis active, adding Dream Breath")
  270. AddSpell(spellId)
  271. else
  272. log("[DEBUG] ACTION: Stasis NOT active, just clearing flags (not adding)")
  273. end
  274. end
  275.  
  276. -- Обработка Fire Breath с TTS даже если Stasis не активен (сбрасываем флаги, НЕ добавляем)
  277. if (spellId == empowers.FireBreath[1] or spellId == empowers.FireBreath[2]) and currentState.tts then
  278. log("[DEBUG] ACTION: Fire Breath with tts=true - clearing flags (tts=false, ttsStored=false) (NOT adding)")
  279. currentState.tts = false
  280. currentState.ttsStored = false
  281. end
  282.  
  283. if not currentState.showing and spellList[spellId] == 'Stasis Store' then
  284. log("[DEBUG] ACTION: Stasis Store -> StartStasis()")
  285. StartStasis()
  286. elseif currentState.showing then
  287. if currentState.storedSpells < 3 then
  288. if spellList[spellId] then
  289. log("[DEBUG] ACTION: Recognized spell from list -> AddSpell()")
  290. AddSpell(spellId)
  291. elseif currentState.tts then
  292. if spellId == empowers.DreamBreath[1] or spellId == empowers.DreamBreath[2] then
  293. log("[DEBUG] ACTION: Dream Breath with tts=true -> AddSpell() and clear flags")
  294. currentState.tts = false
  295. currentState.ttsStored = false
  296. AddSpell(spellId)
  297. elseif spellId == empowers.FireBreath[1] or spellId == empowers.FireBreath[2] then
  298. log("[DEBUG] ACTION: Fire Breath with tts=true -> clearing flags (NOT adding)")
  299. currentState.tts = false
  300. currentState.ttsStored = false
  301. else
  302. log("[DEBUG] ACTION: Unknown spell with tts=true, ignoring")
  303. end
  304. else
  305. log("[DEBUG] ACTION: Spell not recognized (tts=false), ignoring")
  306. end
  307. elseif spellList[spellId] == 'Stasis Release' then
  308. log("[DEBUG] ACTION: Stasis Release -> ReleaseStasis()")
  309. ReleaseStasis()
  310. else
  311. log("[DEBUG] ACTION: Stasis full, ignoring")
  312. end
  313. end
  314. end
  315.  
  316. elseif event == "UNIT_SPELLCAST_EMPOWER_STOP" then
  317. local unit, _, spellId, success = ...
  318. local spellName = spellId and C_Spell.GetSpellInfo(spellId) and C_Spell.GetSpellInfo(spellId).name or "Unknown"
  319.  
  320. if DEBUG then
  321. print(string.format("[DEBUG] EVENT: EMPOWER_STOP | unit=%s | spell=%s (ID: %d) | success=%s | showing=%s | stored=%d | tts=%s | ttsStored=%s",
  322. unit, spellName, spellId, tostring(success),
  323. tostring(currentState.showing),
  324. currentState.storedSpells,
  325. tostring(currentState.tts),
  326. tostring(currentState.ttsStored)))
  327. end
  328.  
  329. -- Убрали issecretvalue полностью
  330. if unit == "player" then
  331. if success and (spellId == empowers.DreamBreath[1] or spellId == empowers.DreamBreath[2]) then
  332. if not currentState.tts then
  333. log("[DEBUG] ACTION: EMPOWER_STOP Dream Breath -> AddSpell()")
  334. AddSpell(spellId)
  335. else
  336. log("[DEBUG] ACTION: EMPOWER_STOP Dream Breath - SKIPPING because tts=true")
  337. end
  338. end
  339. else
  340. if DEBUG and unit ~= "player" then
  341. log("[DEBUG] ACTION: EMPOWER_STOP ignoring (unit=" .. tostring(unit) .. ")")
  342. end
  343. end
  344. end
  345. end)
  346.  
  347. ----------------------------------------[[
  348. -- Options
  349. ----------------------------------------]]
  350.  
  351. local optionsFrame = CreateFrame('Frame')
  352. optionsFrame:RegisterEvent("PLAYER_LOGIN")
  353. optionsFrame:SetScript("OnEvent", function()
  354. PSTDB = PSTDB or {}
  355.  
  356. local defaultData = {
  357. point = 'CENTER',
  358. x = 0,
  359. y = 0,
  360. iconSize = 40,
  361. growDirection = 'Horizontal',
  362. iconPadding = 0,
  363. color = { r = 0.2, g = 0.5, b = 0.4}
  364. }
  365.  
  366. local function displayPositionChanged(frame, layout, point, x, y)
  367. PSTDB[layout].point = point
  368. PSTDB[layout].x = x
  369. PSTDB[layout].y = y
  370. end
  371.  
  372. local LEM = LibStub('LibEditMode')
  373.  
  374. LEM:RegisterCallback('enter', function()
  375. ShowExample()
  376. end)
  377.  
  378. LEM:RegisterCallback('exit', function()
  379. stasisDisplay:Hide()
  380. end)
  381.  
  382. LEM:RegisterCallback('layout', function(layout)
  383. if not PSTDB[layout] then
  384. PSTDB[layout] = CopyTable(defaultData)
  385. end
  386. stasisDisplay:ClearAllPoints()
  387. stasisDisplay:SetPoint(PSTDB[layout].point, PSTDB[layout].x, PSTDB[layout].y)
  388. stasisDisplay.bar:SetStatusBarColor(PSTDB[layout].color.r, PSTDB[layout].color.g, PSTDB[layout].color.b)
  389. ChangeIconSize(PSTDB[layout].iconSize, PSTDB[layout].growDirection, PSTDB[layout].iconPadding)
  390. SetGrowDirection(PSTDB[layout].growDirection, layout)
  391. ChangeIconPadding(PSTDB[layout].iconPadding, PSTDB[layout].growDirection, PSTDB[layout].iconSize)
  392. end)
  393.  
  394. LEM:AddFrame(stasisDisplay, displayPositionChanged, defaultData)
  395.  
  396. LEM:AddFrameSettings(stasisDisplay, {
  397. {
  398. name = 'Icon Size',
  399. kind = LEM.SettingType.Slider,
  400. default = defaultData.iconSize,
  401. get = function(layout)
  402. return PSTDB[layout].iconSize
  403. end,
  404. set = function(layout, value)
  405. PSTDB[layout].iconSize = value
  406. ChangeIconSize(value, PSTDB[layout].growDirection, PSTDB[layout].iconPadding)
  407. end,
  408. minValue = 20,
  409. maxValue = 60,
  410. valueStep = 1
  411. },
  412. {
  413. name = 'Icon Padding',
  414. kind = LEM.SettingType.Slider,
  415. default = defaultData.iconPadding,
  416. get = function(layout)
  417. return PSTDB[layout].iconPadding
  418. end,
  419. set = function(layout, value)
  420. PSTDB[layout].iconPadding = value
  421. ChangeIconPadding(value, PSTDB[layout].growDirection, PSTDB[layout].iconSize)
  422. end,
  423. minValue = -5,
  424. maxValue = 5,
  425. valueStep = 1
  426. },
  427. {
  428. name = 'Grow Direction',
  429. kind = LEM.SettingType.Dropdown,
  430. default = defaultData.growDirection,
  431. get = function(layout)
  432. return PSTDB[layout].growDirection
  433. end,
  434. set = function(layout, value)
  435. PSTDB[layout].growDirection = value
  436. SetGrowDirection(value, layout)
  437. end,
  438. values = {
  439. { text = 'Horizontal' },
  440. { text = 'Vertical' }
  441. }
  442. },
  443. {
  444. name = 'Bar Color',
  445. kind = LEM.SettingType.ColorPicker,
  446. default = CreateColor(defaultData.color.r, defaultData.color.g, defaultData.color.b),
  447. get = function(layout)
  448. return CreateColor(PSTDB[layout].color.r, PSTDB[layout].color.g, PSTDB[layout].color.b)
  449. end,
  450. set = function(layout, color)
  451. local colorDataR, colorDataG, colorDataB = color:GetRGB()
  452. PSTDB[layout].color = { r = colorDataR, g = colorDataG, b = colorDataB }
  453. stasisDisplay.bar:SetStatusBarColor(colorDataR, colorDataG, colorDataB)
  454. end
  455. }
  456. })
  457.  
  458. end)
Advertisement
Add Comment
Please, Sign In to add comment