-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRestedXP-TomTom.lua
More file actions
executable file
·843 lines (734 loc) · 27.7 KB
/
Copy pathRestedXP-TomTom.lua
File metadata and controls
executable file
·843 lines (734 loc) · 27.7 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
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
-- RestedXP-TomTom: mirror the RestedXP arrow target into a TomTom waypoint.
-- Keeps TomTom arrow active while hiding the RXP arrow (unless explicitly allowed).
local addonName = ...
-- Event driver for login/addon lifecycle hooks.
local frame = CreateFrame("Frame")
-- State for the active TomTom waypoint and per-step cache.
local currentWaypointUid
local currentWaypointKey
local currentStepKey
local stepWaypointUids = {}
local stepWaypointElements = {}
local debugEnabled = false
local tick
local currentOptionsKey
local rxpHooked = false
local lastElementSignature
-- Default saved variable settings.
local defaults = {
showWorldMap = false,
showMinimap = false,
}
-- Ensure and return the saved variables table.
local function getConfig()
if type(_G.RXPTT_DB) ~= "table" then
_G.RXPTT_DB = {}
end
local db = _G.RXPTT_DB
if db.showWorldMap == nil then
db.showWorldMap = defaults.showWorldMap
end
if db.showMinimap == nil then
db.showMinimap = defaults.showMinimap
end
return db
end
-- Legacy/placeholder fields for more complex switching heuristics (currently unused).
local pendingElementKey
local pendingElement
local pendingSince
local arrivedCooldownUntil
-- Timestamp used to debounce "no target" clears.
local noTargetSince
-- Legacy tuning knobs kept for future waypoint switching logic (unused today).
local SWITCH_STABLE_SECONDS = 1.0 -- must remain the same target for this long (unused)
local ARRIVE_DISTANCE = 15 -- yards-ish (TomTom distance), switch immediately if closer than this (unused)
local SWITCH_DISTANCE_ADVANTAGE = 10 -- require new waypoint to be this much closer to switch (unused)
-- Debounce time to avoid flicker when RXP temporarily has no waypoint.
local NO_TARGET_CLEAR_SECONDS = 1.0
-- Debug-only chat output.
local function dbg(fmt, ...)
if not debugEnabled then
return
end
if select("#", ...) > 0 then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r %s", addonName, string.format(fmt, ...)))
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r %s", addonName, fmt))
end
end
-- User-facing chat output.
local function msg(fmt, ...)
if select("#", ...) > 0 then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r %s", addonName, string.format(fmt, ...)))
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r %s", addonName, fmt))
end
end
-- Safely get the RestedXP arrow frame, if present.
local function getRxpArrowFrame()
local af = _G.RXPG_ARROW
if af and type(af) == "table" and type(af.Hide) == "function" then
return af
end
end
-- Read the debug toggle table used to allow the RXP arrow to show.
local function getRxpDebugState()
local dbg = _G.RXPTOMTOM_DEBUG
if type(dbg) == "table" then
return dbg
end
end
-- Whether the RXP arrow should be visible (debug override).
local function isRxpArrowAllowed()
local dbg = getRxpDebugState()
return dbg and dbg.allowRxpArrow
end
-- Return the TomTom API table if available.
local function ensureTomTom()
local tt = _G.TomTom
if type(tt) == "table" and type(tt.AddWaypoint) == "function" and type(tt.RemoveWaypoint) == "function" then
return tt
end
end
-- Hide the RXP arrow while keeping its frame alive so RestedXP continues updating.
local function safeDisableRxpArrow()
local arrowFrame = getRxpArrowFrame()
if not arrowFrame then
return
end
if not arrowFrame.__rxptt_hooked then
arrowFrame.__rxptt_hooked = true
-- Wrap Show/SetShown once so we can zero alpha unless the debug flag allows it.
local originalShow = arrowFrame.Show
arrowFrame.__rxptt_originalShow = originalShow
arrowFrame.Show = function(self, ...)
if type(originalShow) == "function" then
originalShow(self, ...)
end
if not isRxpArrowAllowed() then
if type(self.SetAlpha) == "function" then
self:SetAlpha(0)
end
end
end
local originalSetShown = arrowFrame.SetShown
arrowFrame.__rxptt_originalSetShown = originalSetShown
arrowFrame.SetShown = function(self, shown)
if type(originalSetShown) == "function" then
if not isRxpArrowAllowed() then
originalSetShown(self, true)
else
originalSetShown(self, shown)
end
end
if not isRxpArrowAllowed() then
if type(self.SetAlpha) == "function" then
self:SetAlpha(0)
end
end
end
arrowFrame.__rxptt_originalOnUpdate = arrowFrame:GetScript("OnUpdate")
end
-- Restore the original OnUpdate to avoid interfering with RXP's own logic.
local originalOnUpdate = arrowFrame.__rxptt_originalOnUpdate
if originalOnUpdate then
arrowFrame:SetScript("OnUpdate", originalOnUpdate)
end
if isRxpArrowAllowed() then
if type(arrowFrame.SetAlpha) == "function" then
arrowFrame:SetAlpha(1)
end
arrowFrame:Show()
return
end
-- Keep the frame alive so RestedXP continues updating its element.
if type(arrowFrame.SetAlpha) == "function" then
arrowFrame:SetAlpha(0)
end
arrowFrame:Show()
end
-- Expose for external toggles/macros.
_G.RXPTOMTOM_ApplyRxpArrowState = safeDisableRxpArrow
-- Quantize a number for stable keys.
local function q(n, scale)
if type(n) ~= "number" then return 0 end
return math.floor(n * scale + 0.5)
end
-- Build a stable key for a step object or index.
local function getStepKey(step)
if not step then
return nil
end
if step.index ~= nil then
return tostring(step.index)
end
return tostring(step)
end
-- Build a stable key for a waypoint element using quantized coords.
local function getElementKey(element)
if not element then
return nil
end
local hasZone = (type(element.zone) == "number") and (type(element.x) == "number") and (type(element.y) == "number")
local hasWorld = (type(element.wx) == "number") and (type(element.wy) == "number")
if not hasZone and not hasWorld then
return nil
end
local zone = (type(element.zone) == "number") and element.zone or 0
local inst = (type(element.instance) == "number") and element.instance or 0
-- RXP x/y are typically percent (0..100). Quantize to 0.01% to avoid jitter.
local x = hasZone and q(element.x, 100) or 0
local y = hasZone and q(element.y, 100) or 0
-- World coords can exist too; quantize lightly.
local wx = hasWorld and q(element.wx, 1) or 0
local wy = hasWorld and q(element.wy, 1) or 0
return table.concat({ inst, zone, x, y, wx, wy }, ":")
end
-- Build a high-resolution signature to detect subtle target changes.
local function getElementSignature(element)
if not element then
return nil
end
local hasZone = (type(element.zone) == "number") and (type(element.x) == "number") and (type(element.y) == "number")
local hasWorld = (type(element.wx) == "number") and (type(element.wy) == "number")
if not hasZone and not hasWorld then
return nil
end
local zone = (type(element.zone) == "number") and element.zone or 0
local inst = (type(element.instance) == "number") and element.instance or 0
-- Use tighter quantization than getElementKey to reduce missed updates.
local x = hasZone and q(element.x, 10000) or 0
local y = hasZone and q(element.y, 10000) or 0
local wx = hasWorld and q(element.wx, 10) or 0
local wy = hasWorld and q(element.wy, 10) or 0
return table.concat({ inst, zone, x, y, wx, wy }, ":")
end
-- Remove all known waypoints for the current step and reset state.
local function clearTomTomWaypoints(tomtom)
if not tomtom then
return
end
for _, uid in pairs(stepWaypointUids) do
pcall(tomtom.RemoveWaypoint, tomtom, uid)
end
stepWaypointUids = {}
stepWaypointElements = {}
currentWaypointUid = nil
currentWaypointKey = nil
currentOptionsKey = nil
lastElementSignature = nil
end
-- Remove a specific TomTom waypoint by uid.
local function clearWaypointByUid(tomtom, uid)
if not (tomtom and uid) then
return
end
pcall(tomtom.RemoveWaypoint, tomtom, uid)
end
-- Remove the cached waypoint for a specific step key.
local function clearStepWaypoint(tomtom, stepKey)
if not stepKey then
return
end
local uid = stepWaypointUids[stepKey]
if uid then
clearWaypointByUid(tomtom, uid)
end
stepWaypointUids[stepKey] = nil
stepWaypointElements[stepKey] = nil
end
-- Check whether a waypoint still exists (currently unused).
local function isTomTomWaypointValid(tomtom, uid)
if not uid then
return false
end
if type(tomtom.IsValidWaypoint) == "function" then
local ok, valid = pcall(tomtom.IsValidWaypoint, tomtom, uid)
return ok and valid
end
if type(tomtom.GetDistanceToWaypoint) ~= "function" then
return true
end
local ok = pcall(tomtom.GetDistanceToWaypoint, tomtom, uid)
return ok
end
-- Add a TomTom waypoint using an RXP element's coordinates.
local function addTomTomWaypointFromElement(tomtom, element, opts)
if not (tomtom and element) then
return
end
local map = element.zone
local x = element.x and element.x / 100
local y = element.y and element.y / 100
-- Prefer zone coordinates; fall back to world coords via HereBeDragons if needed.
if not (map and x and y) then
local hbd = _G.LibStub and LibStub("HereBeDragons-2.0", true) or nil
if hbd and element.wx and element.wy then
map = map or hbd:GetPlayerZone()
if type(map) == "number" then
x, y = hbd:GetZoneCoordinatesFromWorld(element.wx, element.wy, map, true)
end
end
end
if not (type(map) == "number" and type(x) == "number" and type(y) == "number") then
return
end
-- TomTom expects normalized 0..1 coordinates.
if x < 0 or y < 0 or x > 1 or y > 1 then
return
end
-- Build a human-friendly title with a step index if available.
local title
if element.step and element.step.index then
title = string.format("RXP Step %s", tostring(element.step.index))
end
title = title or element.title
if not title and element.step then
title = element.step.arrowtext or element.step.title
end
title = title or "RXP"
local waypointOpts = {
title = title,
source = "RXPGuides",
crazy = opts and opts.crazy or false,
minimap = false,
world = false,
persistent = false,
silent = true,
}
local db = getConfig()
waypointOpts.minimap = db.showMinimap and true or false
waypointOpts.world = db.showWorldMap and true or false
if opts then
if opts.minimap ~= nil then waypointOpts.minimap = opts.minimap end
if opts.world ~= nil then waypointOpts.world = opts.world end
end
local uid = tomtom:AddWaypoint(map, x, y, waypointOpts)
dbg("Add TomTom waypoint: map=%s x=%.4f y=%.4f title=%s", tostring(map), x, y, tostring(title))
if uid and element.step and element.step.index ~= nil then
local stepKey = getStepKey(element.step)
if stepKey then
stepWaypointUids[stepKey] = uid
stepWaypointElements[stepKey] = element
end
end
return uid
end
-- Create a TomTom waypoint from the current RXP arrow element.
local function setTomTomFromCurrentArrow()
local tomtom = ensureTomTom()
local arrowFrame = getRxpArrowFrame()
if not (tomtom and arrowFrame and arrowFrame.element) then
msg("Unable to set TomTom waypoint (missing arrow element)")
return
end
clearTomTomWaypoints(tomtom)
local arrivalDist = (tomtom.profile and tomtom.profile.arrow and tomtom.profile.arrow.arrival) or 0
local uid = addTomTomWaypointFromElement(tomtom, arrowFrame.element, { crazy = false })
if uid and type(tomtom.SetCrazyArrow) == "function" then
pcall(tomtom.SetCrazyArrow, tomtom, uid, arrivalDist, uid.title)
end
end
-- Expose a manual command for menu entries or macros.
_G.RXPTOMTOM_SetCurrentWaypoint = setTomTomFromCurrentArrow
-- Inject "Set TomTom waypoint" into RestedXP menus.
local function ensureRxpMenuHook()
if _G.RXPTOMTOM_MenuHooked then
return
end
_G.RXPTOMTOM_MenuHooked = true
if type(hooksecurefunc) ~= "function" then
return
end
local function injectMenuItem(menu, frame)
if type(menu) ~= "table" then
return
end
local frameName = frame and frame.GetName and frame:GetName() or nil
local isStepMenu = false
local isMinimapMenu = false
if _G.RXPFrame and menu == _G.RXPFrame.menuList then
isStepMenu = true
elseif frameName == "RXP_MMMenuFrame" then
isMinimapMenu = true
end
if debugEnabled then
local texts = {}
for i = 1, math.min(#menu, 6) do
local item = menu[i]
if type(item) == "table" then
texts[#texts + 1] = tostring(item.text or "?")
end
end
dbg("Menu hook: frame=%s stepMenu=%s minimapMenu=%s items=%d first=%s",
tostring(frameName),
isStepMenu and "yes" or "no",
isMinimapMenu and "yes" or "no",
#menu,
table.concat(texts, " | "))
end
if not (isStepMenu or isMinimapMenu) then
return
end
local alreadyAdded
local insertIndex = #menu + 1
for i, item in ipairs(menu) do
if type(item) == "table" then
if item.text == "Set TomTom waypoint" then
alreadyAdded = true
elseif item.text == _G.CLOSE then
insertIndex = i
end
end
end
if alreadyAdded then
return
end
table.insert(menu, insertIndex, {
text = "Set TomTom waypoint",
notCheckable = 1,
func = function()
if type(_G.RXPTOMTOM_SetCurrentWaypoint) == "function" then
_G.RXPTOMTOM_SetCurrentWaypoint()
end
end,
})
end
-- Step list menu is a static table; inject immediately so it appears on first open.
if _G.RXPFrame and type(_G.RXPFrame.bottomMenu) == "table" then
injectMenuItem(_G.RXPFrame.bottomMenu, _G.RXPFrame.MenuFrame)
end
if type(EasyMenu) == "function" then
hooksecurefunc("EasyMenu", function(menu, frame, anchor, x, y, displayMode, autoHideDelay)
injectMenuItem(menu, frame)
end)
end
local libdd = _G.LibStub and LibStub("LibUIDropDownMenu-4.0", true) or nil
if libdd and type(libdd.EasyMenu) == "function" then
hooksecurefunc(libdd, "EasyMenu", function(_, menu, frame, anchor, x, y, displayMode, autoHideDelay)
injectMenuItem(menu, frame)
end)
end
end
-- Collect waypoint elements for a step (currently unused).
local function collectStepWaypoints(arrowElement)
if not arrowElement or not arrowElement.step then
return {}
end
local step = arrowElement.step
local out = {}
local rxp = _G.RXP
if rxp and type(rxp.activeWaypoints) == "table" then
for _, element in ipairs(rxp.activeWaypoints) do
if element.step == step then
table.insert(out, element)
end
end
end
if #out == 0 and type(step.elements) == "table" then
for _, element in ipairs(step.elements) do
if element.arrow and not element.hidden and not element.skip then
table.insert(out, element)
end
end
end
if #out == 0 then
table.insert(out, arrowElement)
end
return out
end
-- Pick the nearest waypoint key by distance (currently unused).
local function selectBestWaypointKey(tomtom, keys, excludeKey)
if not keys or not tomtom then
return nil
end
if type(tomtom.GetDistanceToWaypoint) ~= "function" then
for key in pairs(keys) do
if key ~= excludeKey then
return key, nil
end
end
for key in pairs(keys) do
return key, nil
end
return nil
end
local bestKey
local bestDist
for key in pairs(keys) do
if key ~= excludeKey then
local uid = stepWaypointUids[key]
if uid then
local ok, dist = pcall(tomtom.GetDistanceToWaypoint, tomtom, uid)
if ok and type(dist) == "number" then
if not bestDist or dist < bestDist then
bestDist = dist
bestKey = key
end
end
end
end
end
if bestKey then
return bestKey, bestDist
end
if excludeKey then
return selectBestWaypointKey(tomtom, keys, nil)
end
for key in pairs(keys) do
return key, nil
end
return nil
end
-- Main update loop: sync TomTom waypoint with the current RXP arrow element.
tick = function()
local tomtom = ensureTomTom()
local arrowFrame = getRxpArrowFrame()
if not (tomtom and arrowFrame) then
return
end
safeDisableRxpArrow()
local now = GetTime()
local element = arrowFrame.element
local db = getConfig()
local signature = getElementSignature(element)
if not signature then
if not noTargetSince then
noTargetSince = now
end
-- If the arrow is briefly missing a target, wait a beat before clearing.
if (now - noTargetSince) >= NO_TARGET_CLEAR_SECONDS then
clearTomTomWaypoints(tomtom)
currentStepKey = nil
pendingElementKey = nil
pendingElement = nil
pendingSince = nil
arrivedCooldownUntil = nil
noTargetSince = nil
end
return
end
noTargetSince = nil
-- Clear and rebuild if display options changed.
local optionsKey = (db.showWorldMap and "1" or "0") .. (db.showMinimap and "1" or "0")
if currentOptionsKey ~= optionsKey then
clearTomTomWaypoints(tomtom)
currentOptionsKey = optionsKey
end
local elementKey = element.wpHash or signature
local stepKey = (element and element.step) and getStepKey(element.step) or nil
if stepKey and currentStepKey and stepKey ~= currentStepKey then
clearStepWaypoint(tomtom, currentStepKey)
end
currentStepKey = stepKey
-- Avoid churn when the element hasn't materially changed.
if lastElementSignature and lastElementSignature == signature and currentWaypointUid and currentWaypointKey == elementKey then
return
end
local arrivalDist = (tomtom.profile and tomtom.profile.arrow and tomtom.profile.arrow.arrival) or 0
-- Replace the old waypoint if the element key changed.
if currentWaypointKey and currentWaypointKey ~= elementKey then
clearWaypointByUid(tomtom, currentWaypointUid)
currentWaypointUid = nil
currentWaypointKey = nil
lastElementSignature = nil
end
-- Add/update the TomTom waypoint and arrow.
local uid = addTomTomWaypointFromElement(tomtom, element, { crazy = false })
if uid then
currentWaypointKey = elementKey
currentWaypointUid = uid
lastElementSignature = signature
if type(tomtom.SetCrazyArrow) == "function" then
pcall(tomtom.SetCrazyArrow, tomtom, uid, arrivalDist, uid.title)
end
end
end
-- Hook RestedXP's DrawArrow so we can sync on every arrow update.
local function ensureRxpHook()
if rxpHooked then
return
end
local rxp = _G.RXPGuides
if rxp and type(rxp.DrawArrow) == "function" then
hooksecurefunc(rxp, "DrawArrow", function()
tick()
end)
rxpHooked = true
end
end
-- Event handler for addon lifecycle and player state changes.
frame:SetScript("OnEvent", function(_, event, arg1)
if event == "PLAYER_LOGIN" then
ensureRxpMenuHook()
ensureRxpHook()
-- Build the options panel lazily at login.
local function createOptionsPanel()
local panel = CreateFrame("Frame", "RXPTOMTOM_OptionsPanel", UIParent)
panel.name = "RestedXP-TomTom"
local title = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
title:SetPoint("TOPLEFT", 16, -16)
title:SetText("RestedXP-TomTom")
local subtitle = panel:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
subtitle:SetText("TomTom waypoint display options")
local worldCheck = CreateFrame("CheckButton", nil, panel, "InterfaceOptionsCheckButtonTemplate")
worldCheck:SetPoint("TOPLEFT", subtitle, "BOTTOMLEFT", 0, -12)
worldCheck.Text:SetText("Show waypoint on world map")
local minimapCheck = CreateFrame("CheckButton", nil, panel, "InterfaceOptionsCheckButtonTemplate")
minimapCheck:SetPoint("TOPLEFT", worldCheck, "BOTTOMLEFT", 0, -8)
minimapCheck.Text:SetText("Show waypoint on minimap")
local reloadBtn = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
reloadBtn:SetSize(140, 22)
reloadBtn:SetPoint("TOPLEFT", minimapCheck, "BOTTOMLEFT", 0, -12)
reloadBtn:SetText("Reload to apply")
-- Sync checkboxes from saved variables when opened.
panel.refresh = function()
local db = getConfig()
worldCheck:SetChecked(db.showWorldMap)
minimapCheck:SetChecked(db.showMinimap)
end
panel:SetScript("OnShow", panel.refresh)
-- Update saved vars and rebuild TomTom waypoint when toggled.
worldCheck:SetScript("OnClick", function(self)
local db = getConfig()
db.showWorldMap = self:GetChecked() and true or false
local tt = ensureTomTom()
if tt then
clearTomTomWaypoints(tt)
end
currentOptionsKey = nil
tick()
end)
minimapCheck:SetScript("OnClick", function(self)
local db = getConfig()
db.showMinimap = self:GetChecked() and true or false
local tt = ensureTomTom()
if tt then
clearTomTomWaypoints(tt)
end
currentOptionsKey = nil
tick()
end)
-- Some UI changes don't reflect immediately in older clients.
reloadBtn:SetScript("OnClick", function()
if type(ReloadUI) == "function" then
ReloadUI()
end
end)
-- Register panel with the modern Settings UI or legacy interface options.
if type(Settings) == "table" and type(Settings.RegisterCanvasLayoutCategory) == "function" then
local category = Settings.RegisterCanvasLayoutCategory(panel, panel.name)
Settings.RegisterAddOnCategory(category)
elseif type(InterfaceOptions_AddCategory) == "function" then
InterfaceOptions_AddCategory(panel)
elseif type(InterfaceOptionsFrameAddCategory) == "function" then
InterfaceOptionsFrameAddCategory(panel)
end
_G.RXPTOMTOM_OptionsPanel = panel
end
createOptionsPanel()
-- Slash command: /rxptomtom [options|debug|clear]
SLASH_RXPTOMTOM1 = "/rxptomtom"
SlashCmdList.RXPTOMTOM = function(msg)
msg = (msg or ""):lower():gsub("^%s+", ""):gsub("%s+$", "")
if msg == "options" or msg == "opt" then
local panel = _G.RXPTOMTOM_OptionsPanel
if panel then
if type(Settings) == "table" and type(Settings.OpenToCategory) == "function" then
Settings.OpenToCategory(panel.name)
elseif type(InterfaceOptionsFrame_OpenToCategory) == "function" then
InterfaceOptionsFrame_OpenToCategory(panel)
InterfaceOptionsFrame_OpenToCategory(panel)
end
end
return
end
if msg == "debug" then
debugEnabled = not debugEnabled
dbg("Debug %s", debugEnabled and "enabled" or "disabled")
return
end
if msg == "clear" then
local tt = ensureTomTom()
if tt then
clearTomTomWaypoints(tt)
msg("Cleared TomTom waypoints")
end
return
end
-- Default output: quick status dump for diagnostics.
local tt = ensureTomTom()
local af = getRxpArrowFrame()
local el = af and af.element
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r TomTom=%s RXP_ARROW=%s element=%s",
addonName,
tt and "ok" or "missing",
af and "ok" or "missing",
el and "yes" or "no"
))
if el then
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r zone=%s x=%s y=%s wx=%s wy=%s title=%s",
addonName,
tostring(el.zone), tostring(el.x), tostring(el.y), tostring(el.wx), tostring(el.wy), tostring(el.title)
))
end
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cffffd200%s:|r hint=auto-updates from RestedXP arrow target", addonName))
end
msg("For the best experience, make sure to keep your RestedXP Guides up to date.")
-- Fallback polling until we successfully hook DrawArrow.
frame:SetScript("OnUpdate", function(_, elapsed)
if rxpHooked then
return
end
frame._t = (frame._t or 0) + elapsed
if frame._t < 0.25 then
return
end
frame._t = 0
tick()
end)
-- RXP can populate the arrow element after login; retry briefly in case hook isn't ready yet.
if type(C_Timer) == "table" and type(C_Timer.NewTicker) == "function" then
local attempts = 0
local ticker
ticker = C_Timer.NewTicker(0.5, function()
attempts = attempts + 1
ensureRxpHook()
tick()
local af = getRxpArrowFrame()
if (af and af.element) or attempts >= 10 then
if ticker and type(ticker.Cancel) == "function" then
ticker:Cancel()
end
end
end)
elseif type(C_Timer) == "table" and type(C_Timer.After) == "function" then
C_Timer.After(0.5, function()
ensureRxpHook()
tick()
end)
C_Timer.After(1.5, function()
ensureRxpHook()
tick()
end)
end
return
end
if event == "ADDON_LOADED" and (arg1 == "RXPGuides" or arg1 == "TomTom") then
ensureRxpMenuHook()
ensureRxpHook()
tick()
return
end
if event == "PLAYER_CONTROL_GAINED" or event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_ALIVE" then
tick()
end
end)
-- Event subscriptions.
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("ADDON_LOADED")
frame:RegisterEvent("PLAYER_CONTROL_GAINED")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("PLAYER_ALIVE")