-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgstar.lua
2545 lines (2346 loc) · 121 KB
/
gstar.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
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
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
-- AceConfig, AceGUI = LibStub("AceConfig-3.0"), LibStub("AceGUI-3.0")
local AC, ACD = LibStub("AceConfig-3.0"), LibStub("AceConfigDialog-3.0")
local GS = {}
GSD = {}
local _ = nil
-- Main Stuff
GS.PreventExecution = false
GS.SpellThrottle = 0
GS.WaitForCombatLog = false
function GS.MainFrameEvents(self, originalEvent, ...)
if originalEvent == "PLAYER_ENTERING_WORLD" then
GS.PreventExecution = true
table.wipe(GS.MobTargets)
table.wipe(GS.AllyTargets)
GS.MonitorAnimationToggle("off")
return
elseif originalEvent == "LOADING_SCREEN_DISABLED" then
GS.PreventExecution = false
GS.Start = false
GS.MonitorAnimationToggle("off")
return
elseif originalEvent == "PLAYER_SPECIALIZATION_CHANGED" then
GS.Spec = GetSpecialization()
GS.CacheTalents()
return
elseif originalEvent == "PLAYER_TALENT_UPDATE" then
GS.CacheTalents()
return
end
end
function GS.CombatFrameCreation()
if not GSCombatFrame then GS.CombatFrame = CreateFrame("Frame", "GSCombatFrame", GSMainFrame) end
GSCombatFrame:SetScript("OnUpdate", GS.ExecuteRotation)
end
function GS.ExecuteRotation()
if not FireHack or GS.PreventExecution or not GS.Start or UnitIsDeadOrGhost("player") then return end
if not GS.RanOnce then
if not ReadFile(GetFireHackDirectory().."\\Scripts\\GStar Rotations\\Revision.txt") then
GS.CheckUpdateFailed("no local file")
else
DownloadURL("raw.githubusercontent.com", "/g1zstar/GStar-Rotations/master/Revision.txt", true, GS.CheckUpdate, GS.DownloadURLFailed)
end
GS.RanOnce = true
end
if GSR.RaFFollow then
GS.RaFQuesting()
end
if GSR.LevelingRAF and GS.Spec and GSR.Class and GS[GSR.Class..GS.Spec.."90"] then
GS.RotationCacheCounter = GS.RotationCacheCounter + 1
GS[GSR.Class..GS.Spec.."90"]()
return
elseif GS.Spec and GSR.Class and GS[GSR.Class..GS.Spec] then
GS.RotationCacheCounter = GS.RotationCacheCounter + 1
GS[GSR.Class..GS.Spec]()
return
elseif not GS.Spec and GSR.Class and GS[GSR.Class] then
GS.RotationCacheCounter = GS.RotationCacheCounter + 1
GS[GSR.Class]()
return
else
print("No such specialization and class combo available.")
GS.Start = false
GS.MonitorAnimationToggle("off")
return
end
end
function GS.CombatInformationFrameCreation()
GS.MobTargetsPreliminary, GS.MobTargets = {}, {}
GS.AllyTargets = {}
GS.TTDM, GS.TTD = {}, {}
GS.DebugTable = {}
-- debugStack = "", pointer = 0, nameOfTarget = "", ogSpell = 0, Spell = "", x = 0, y = 0, z = 0, interrupt = "", time = 0, timeSinceLast = 0, reason = ""
if not GSCombatInfoFrame then GS.InformationGatheringFrame = CreateFrame("Frame", "GSCombatInfoFrame", GSMainFrame) end
GSCombatInfoFrame:RegisterEvent("PLAYER_DEAD")
GSCombatInfoFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
GSCombatInfoFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
GSCombatInfoFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
-- GSCombatInfoFrame:RegisterEvent("COMBAT_LOG_EVENT")
GSCombatInfoFrame:SetScript("OnEvent", GS.CombatInformationFrameEvents) -- This responds to the combat log
GSCombatInfoFrame:SetScript("OnUpdate", GS.CombatInformationFrameCuration) -- this gathers information about mobs
end
function GS.HealingTooltipFrameCreation()
if not GSHealingTooltipFrame then
GS.HealingTooltipFrame = CreateFrame("GameTooltip", "GSHealingTooltipFrame", nil, "GameTooltipTemplate")
GSHealingTooltipFrame:SetOwner(UIParent, "ANCHOR_NONE")
end
end
function GS.MonitorFrameCreation()
if not GSMonitorParentFrame then
GS.MonitorParentFrame = CreateFrame("Frame", "GSMonitorParentFrame", UIParent)
GSMonitorParentFrame:SetFrameStrata("MEDIUM")
GSMonitorParentFrame:SetWidth("64")
GSMonitorParentFrame:SetHeight("64")
if GSR.MonitorX and GSR.MonitorY then
GSMonitorParentFrame:ClearAllPoints()
GSMonitorParentFrame:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", GSR.MonitorX, GSR.MonitorY)
else
GSMonitorParentFrame:ClearAllPoints()
GSMonitorParentFrame:SetPoint("CENTER")
end
GS.MonitorTexture = GSMonitorParentFrame:CreateTexture("GSMonitorTexture")
GSMonitorTexture:SetTexture("Interface\\Textures\\GStarMonitor.tga") -- GetFireHackDirectory().."\\Scripts\\GStar Rotations\\GStarMonitor.tga"
GSMonitorTexture:SetAllPoints(GSMonitorParentFrame)
GSAoEOnTexture = GSMonitorParentFrame:CreateTexture("GSAoEOnTexture")
GSAoEOffTexture = GSMonitorParentFrame:CreateTexture("GSAoEOffTexture")
GSAoEOnTexture:SetTexture("Interface\\Textures\\eyes.tga")
GSAoEOffTexture:SetTexture("Interface\\Textures\\no.tga")
GSAoEOnTexture:SetPoint("RIGHT", -10, 3)
GSAoEOnTexture:SetSize(20, 20)
GSAoEOffTexture:SetPoint("RIGHT", -10, 3)
GSAoEOffTexture:SetSize(20, 20)
GSCDsOnTexture = GSMonitorParentFrame:CreateTexture("GSCDsOnTexture")
GSCDsOffTexture = GSMonitorParentFrame:CreateTexture("GSCDsOffTexture")
GSCDsOnTexture:SetTexture("Interface\\Textures\\eyes.tga")
GSCDsOffTexture:SetTexture("Interface\\Textures\\no.tga")
GSCDsOnTexture:SetPoint("BOTTOMRIGHT", -10, 4)
GSCDsOnTexture:SetSize(20, 20)
GSCDsOffTexture:SetPoint("BOTTOMRIGHT", -10, 4)
GSCDsOffTexture:SetSize(20, 20)
GSMonitorParentFrame:SetMovable(1)
GSMonitorParentFrame:EnableMouse(true)
GSMonitorParentFrame:RegisterForDrag("LeftButton")
end
GSMonitorParentFrame:SetScript("OnMouseDown", function() if GSAoEOffTexture:IsMouseOver() then GS.ToggleAoE() elseif GSCDsOffTexture:IsMouseOver() then GS.ToggleCDs() end end)
GSMonitorParentFrame:SetScript("OnDragStart", GSMonitorParentFrame.StartMoving)
GSMonitorParentFrame:SetScript("OnDragStop", function(self) local variableX, variableY = self:GetRect(); GS.SaveToGSR("MonitorX", variableX); GS.SaveToGSR("MonitorY", variableY); GSMonitorParentFrame:StopMovingOrSizing() end)
GSAoEOnTexture:Hide()
GSCDsOnTexture:Hide()
end
function GS.MonitorAnimation(self, elapsed)
if GS.AoE then
if not GSAoEOnTexture:IsVisible() or GSAoEOffTexture:IsVisible() then
GSAoEOnTexture:Show()
GSAoEOffTexture:Hide()
end
AnimateTexCoords(GSAoEOnTexture, 512, 256, 64, 64, 29, elapsed, 0.029)
elseif GSAoEOnTexture:IsVisible() or not GSAoEOffTexture:IsVisible() then
GSAoEOffTexture:Show()
GSAoEOnTexture:Hide()
end
if GS.CDs then
if not GSCDsOnTexture:IsVisible() or GSCDsOffTexture:IsVisible() then
GSCDsOnTexture:Show()
GSCDsOffTexture:Hide()
end
AnimateTexCoords(GSCDsOnTexture, 512, 256, 64, 64, 29, elapsed, 0.029)
elseif GSCDsOnTexture:IsVisible() or not GSCDsOffTexture:IsVisible() then
GSCDsOnTexture:Hide()
GSCDsOffTexture:Show()
end
end
function GS.MonitorAnimationToggle(argument)
if argument == "off" then
GSMonitorParentFrame:SetScript("OnUpdate", nil)
GSMonitorParentFrame:Hide()
end
if argument == "on" then
GSMonitorParentFrame:SetScript("OnUpdate", GS.MonitorAnimation)
GSMonitorParentFrame:Show()
end
end
function GS.SaveToGSR(i,v)
GSR[i] = v
SetCharacterCustomVariable("GSR", GSR)
end
function GS.Log(message)
if GSR.Dev.Logging then
GS.File = ReadFile("C:\\Garrison.json")
local debugStack = string.gsub(debugstack(2, 100, 100), '%[string "local function GetScriptName %(%) return "gst..."%]', "line")
debugStack = string.gsub(debugStack, "\n", ", ")
WriteFile("C:\\Garrison.json", GS.File..",\n{\n\t"..message.."\n\t\"time\":"..GetTime()..",\n\t\"Line Number\": "..debugStack.."\n}")
end
end
-- Rotation toggles
function GSD.RotationToggle(command)
command = command:lower()
if command == "toggle" or command == "t" then
GS.Start = not GS.Start
GS.MonitorAnimationToggle(GS.Start and "on" or "off")
print("GStar Rotations: "..(GS.Start and "On" or "Off"))
return true
end
if command == "aoe" then GS.ToggleAoE() return true end
if command == "cds" then GS.ToggleCDs() return true end
if command == "debug" or command == "d" then
-- for k,v in pairs(GS) do
-- GSD[k] = v
-- end
-- return true
return GS
end
if command == "wipe" or command == "w" then
print("GStar Rotations: Reloading Files")
GSCombatFrame:SetScript("OnUpdate", nil)
GSCombatInfoFrame:SetScript("OnEvent", nil)
GSCombatInfoFrame:SetScript("OnUpdate", nil)
GSMainFrame:SetScript("OnEvent", nil)
GSMonitorParentFrame:SetScript("OnDragStart", nil)
GSMonitorParentFrame:SetScript("OnDragStop", nil)
GSMonitorParentFrame:SetScript("OnMouseDown", nil)
GSMonitorParentFrame:SetScript("OnUpdate", nil)
GS = nil
GSD = nil
LoadScript("GStar Rotations\\gstar.lua")
return true
end
if command == "options" then
ACD:Open("GS_Settings")
return true
end
end
function GS.ToggleAoE()
GS.AoE = not GS.AoE
print("GStar Rotations: AoE now "..(GS.AoE and "on" or "off")..".")
end
function GS.ToggleCDs()
GS.CDs = not GS.CDs
print("GStar Rotations: CDs now "..(GS.CDs and "on" or "off")..".")
end
function GSD.ToggleInterrupt()
GS.SaveToGSR("Interrupt", not GSR.Interrupt)
print("GStar Rotations: Interrupt now "..(GSR.Interrupt and "on" or "off")..".")
end
-- Meat
local rotationUnitIterator, rotationUnitPlaceholder = nil, nil
local rotationXC, rotationYC, rotationZC
local mobTargetsSize, allyTargetsSize = 0, 0
local auraTable = {}
local toggleLog = false
local healingStringPlaceholderOne, healingStringPlaceholderTwo = "", ""
GS.RotationCacheCounter = 0
GS.SpellNotKnown, GS.SpellOutranged = {}, {}
GS.CombatStart = math.huge
GS.Talent11, GS.Talent12, GS.Talent13, GS.Talent21, GS.Talent22, GS.Talent23, GS.Talent31, GS.Talent32, GS.Talent33, GS.Talent41, GS.Talent42, GS.Talent43, GS.Talent51, GS.Talent52, GS.Talent53, GS.Talent61, GS.Talent62, GS.Talent63, GS.Talent71, GS.Talent72, GS.Talent73 = false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false
GS.SkipLoS = {
76585, -- Ragewing
77692, -- Kromog
77182, -- Oregorger
}
GS.MobNamesToIgnore = {
"Unknown",
"Manifestation",
"Kor'Kron Cannon",
"Spike Mine",
"Prismatic Crystal",
}
GS.MobTypesToIgnore = {
"Critter",
"Critter nil",
"Wild Pet",
"Pet",
"Totem",
"Not specified",
}
-- todo: populate with boss IDs
GS.BossList = {}
-- todo: should healing/tanking/instance dummies be under this?
GS.DummiesID = {
31144, -- 080
31146, -- ???
32541, -- 055
32542, -- 065
32545, -- 055
32546, -- 080
32543, -- 075
32666, -- 060
32667, -- 070
46647, -- 085
67127, -- 090
79414, -- 095 Talador
87317, -- 100 Garrison (Mage Tower?)
87318, -- 102 Garrison (Lunarfall)
87320, -- ??? Alliance Ashran and Garrison (Lunarfall) Dummy
-- 87321, -- 100 Alliance Ashran Healing Dummy
-- 87322, -- 102 Alliance Ashran Tanking Dummy
-- 87329, -- ??? Alliance Ashran Tanking Dummy
87760, -- 100 Garrison (Frostwall)
87761, -- 102 Garrison (Frostwall)
87762, -- ??? Horde Ashran and Garrison (Frostwall) Dummy
-- 88288, -- 102 Garrison (Frostwall) Tanking Dummy
-- 88289, -- 100 Garrison Healing Dummy (Frostwall)
-- 88314, -- 102 Garrison (Lunarfall) Tanking Dummy
-- 88316, -- 100 Garrison Healing Dummy (Lunarfall)
-- 88835, -- 100 Horde Ashran Healing Dummy
-- 88836, -- 102 Horde Ashran Tanking Dummy
-- 88837, -- ??? Horde Ashran Tanking Dummy
88967, -- 100 Garrison
89078, -- ??? Garrison
-- 89321, -- 100 Garrison Healing Dummy
-- Unknown Location Commented out for now
-- 24792, -- ???
-- 30527, -- ???
-- 79987, -- ???
-- Dungeons Commented out for now
-- 17578, -- 001 The Shattered Halls
-- 60197, -- 001 Scarlet Monastery
-- 64446, -- 001 Scarlet Monastery
-- Raids Commented out for now
-- 70245, -- ??? Throne of Thunder
-- 93828, -- 102 Hellfire Citadel
-- Starting Zone Dummies Commented out for now
-- 44171, -- 003
-- 44389, -- 003
-- 44548, -- 003
-- 44614, -- 003
-- 44703, -- 003
-- 44794, -- 003
-- 44820, -- 003
-- 44848, -- 003
-- 44937, -- 003
-- 48304, -- 003
-- Added in Legion Patches
-- 92164, -- ??? Training Dummy <Damage>
-- 92165, -- ??? Dungeoneer's Training Dummy <Damage>
-- 92166, -- ??? Raider's Training Dummy <Damage>
-- 92167, -- ??? Training Dummy <Healing>
-- 92168, -- ??? Dungeoneer's Training Dummy <Tanking>
-- 92169, -- ??? Raider's Training Dummy <Tanking>
-- 96442, -- ??? Training Dummy <Damage>
-- 97668, -- ??? Boxer's Training Dummy
-- 98581, -- ??? Prepfoot Training Dummy
-- 107557, -- ??? Training Dummy <Healing>
-- 108420, -- ??? Training Dummy
-- 109595, -- ??? Training Dummy
-- 111824, -- ??? Training Dummy
-- 113858, -- ??? Training Dummy <Damage>
-- 113859, -- ??? Dungeoneer's Training Dummy <Damage>
-- 113860, -- ??? Raider's Training Dummy <Damage>
-- 113862, -- ??? Training Dummy <Damage>
-- 113863, -- ??? Dungeoneer's Training Dummy <Damage>
-- 113864, -- ??? Raider's Training Dummy <Damage>
-- 113871, -- ??? Bombardier's Training Dummy <Damage>
-- 113963, -- ??? Raider's Training Dummy <Damage>
-- 113964, -- ??? Raider's Training Dummy <Tanking>
-- 113966, -- ??? Dungeoneer's Training Dummy <Damage>
-- 113967, -- ??? Training Dummy <Healing>
-- 114832, -- ??? PvP Training Dummy
-- 114840, -- ??? PvP Training Dummy
}
GS.Dummies = {
"Training Bag",
"Training Dummy",
"Dungeoneer's Training Dummy",
"Raider's Training Dummy",
"Initiate's Training Dummy",
"Disciple's Training Dummy",
"Veterans's Training Dummy",
"Ebon Knight's Training Dummy",
"Highlord's Nemesis Trainer",
"Small Illusionary Amber-Weaver",
"Large Illusionary Amber-Weaver",
"Small Illusionary Mystic",
"Large Illusionary Mystic",
"Small Illusionary Guardian",
"Large Illusionary Guardian",
"Small Illusionary Slayer",
"Large Illusionary Slayer",
"Small Illusionary Varmint",
"Large Illusionary Varmint",
"Small Illusionary Banana-Tosser",
"Large Illusionary Banana-Tosser",
}
GS.MobsThatInterrupt = {
"Thok the Bloodthirsty",
"Pol",
"Franzok",
"Grom'kar Firemender",
"Blade Dancer Illianna",
}
GS.SpellData = {
AffectedByHaste = {Key = {}, Value = {}, Size = 19},
SpellNameRange = {
"Insanity",
"Expel Harm",
"MMMarked Shot"
},
SpellRange = {
40,
40,
40,
},
Execute = {
111240, -- Dispatch
17877, -- Shadowburn
}
}
GS.DoTThrottleList = {
34914, -- Vampiric Touch
157736, -- Immolate
348, -- Immolate
}
GS.SpellKnownTransformTable = {
[106830] = 106832
}
-- Paladin
GS.SpellData.AffectedByHaste.Key[1] = 20473 -- Holy Shock
GS.SpellData.AffectedByHaste.Key[2] = 20271 -- Judgment
GS.SpellData.AffectedByHaste.Key[3] = 35395 -- CS
GS.SpellData.AffectedByHaste.Key[4] = 53595 -- HotR
GS.SpellData.AffectedByHaste.Key[5] = 26573 -- Consecration
GS.SpellData.AffectedByHaste.Key[6] = 119072 -- Holy Wrath
GS.SpellData.AffectedByHaste.Key[7] = 31935 -- Avenger's Shield
GS.SpellData.AffectedByHaste.Key[8] = 53600 -- SotR
GS.SpellData.AffectedByHaste.Key[9] = 879 -- Exorcism
GS.SpellData.AffectedByHaste.Key[10] = 122032 -- Exorcism
GS.SpellData.AffectedByHaste.Key[11] = 24275 -- Hammer of Wrath
GS.SpellData.AffectedByHaste.Value[1] = 6
GS.SpellData.AffectedByHaste.Value[2] = 6
GS.SpellData.AffectedByHaste.Value[3] = 4.5
GS.SpellData.AffectedByHaste.Value[4] = 4.5
GS.SpellData.AffectedByHaste.Value[5] = 9
GS.SpellData.AffectedByHaste.Value[6] = 15
GS.SpellData.AffectedByHaste.Value[7] = 15
GS.SpellData.AffectedByHaste.Value[8] = 1.5
GS.SpellData.AffectedByHaste.Value[9] = 15
GS.SpellData.AffectedByHaste.Value[10] = 15
GS.SpellData.AffectedByHaste.Value[11] = 6
-- Shaman
GS.SpellData.AffectedByHaste.Key[12] = 17364 -- Stormstrike
GS.SpellData.AffectedByHaste.Key[13] = 115356 -- Windstrike
GS.SpellData.AffectedByHaste.Key[14] = 60103 -- Lava Lash
GS.SpellData.AffectedByHaste.Key[15] = 8050 -- Flame Shock
GS.SpellData.AffectedByHaste.Key[16] = 8056 -- Frost Shock
GS.SpellData.AffectedByHaste.Key[17] = 8042 -- Earth Shock
GS.SpellData.AffectedByHaste.Key[18] = 73680 -- Unleash Elements
GS.SpellData.AffectedByHaste.Key[19] = 1535 -- Fire Nova
GS.SpellData.AffectedByHaste.Value[12] = 7.5
GS.SpellData.AffectedByHaste.Value[13] = 7.5
GS.SpellData.AffectedByHaste.Value[14] = 10.5
GS.SpellData.AffectedByHaste.Value[15] = 6
GS.SpellData.AffectedByHaste.Value[16] = 6
GS.SpellData.AffectedByHaste.Value[17] = 6
GS.SpellData.AffectedByHaste.Value[18] = 15
GS.SpellData.AffectedByHaste.Value[19] = 4.5
GS.Warrior = {}
GS.Paladin = {
}
GS.Rogue = {
}
GS.Priest = {
Voidform = {},
ApparitionsInFlight = 0
}
GS.Monk = {
LastCast = 0,
SoothingMistTarget = 0,
}
GS.Druid = {
RakeMultiplier = {}
}
function GS.CacheTalents()
for i = 1, 7 do
for v = 1, 3 do
GS["Talent"..i..v] = GS.PlayerHasTalent(i, v)
end
end
end
function GS.IncreaseRotationCacheCounter()
GS.RotationCacheCounter = GS.RotationCacheCounter + 1
end
function GS.RaFQuesting()
if GetNumGroupMembers() < 6 and ObjectExists("focus") then
AssistUnit("focus")
if GS.Distance("focus") > 1 then
MoveTo(ObjectPosition("focus"))
elseif not UnitUsingVehicle("player") then
FaceDirection(ObjectFacing("focus"))
if UnitExists("target") and UnitCanAttack("player", "target") and not UnitIsDeadOrGhost("target") then StartAttack() end
end
end
end
function GS.CheckUpdate(Revision)
if ReadFile(GetFireHackDirectory().."\\Scripts\\GStar Rotations\\Revision.txt") < Revision then print("GStar Rotations: Update Available") return end
end
function GS.CheckUpdateFailed(reason)
if reason == "no local file" then
print("GStar Rotations: No Revision.txt found in "..GetFireHackDirectory().."\\Scripts\\GStar Rotations\\\nCannot check for updates.")
end
end
function GS.DownloadURLFailed()
print("GStar Rotations: Could not check for updates due to failure in DownloadURL().\nCannot check for updates.")
end
function GS.CombatInformationFrameEvents(self, registeredEvent, ...)
if not FireHack or GS.PreventExecution then return end
-- if registeredEvent == "PLAYER_DEAD" then
-- identical
-- end
--[[else]]
if registeredEvent == "PLAYER_REGEN_DISABLED" then
GS.CombatStart = GetTime()
GS.SpellNotKnown = {}
GS.SpellOutranged = {}
GS.CacheTalents()
-- identical
return
elseif registeredEvent == "PLAYER_REGEN_ENABLED" then
-- GS.Monk.LastCast = 0
return
elseif registeredEvent == "COMBAT_LOG_EVENT_UNFILTERED" then
local timeNow = GetTime()
local timeStamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, spellID, spellName, spellSchool, failedType = ...
-- if event == "UNIT_DIED" then
-- throttled projectile disjointed due to unit death goes in here
-- end
if sourceName ~= UnitName("player") and not tContains(GS.MobsThatInterrupt, sourceName) then return end
if event == "SPELL_CAST_START" then -- MobsThatInterrupt functionality would go in here + healing and projectile throttles
return
end
if event == "SPELL_CAST_FAILED" then
if failedType ~= "Another action is in progress" and failedType ~= "Not yet recovered" and failedType ~= "You can't do that yet" then
GS.SpellThrottle = 0
-- GS.LastTargetCast = nil
GS.Log(spellName..": Unthrottling "..failedType)
end
return
end
if event == "SPELL_CAST_SUCCESS" then
if GS.WaitForCombatLog then GS.WaitForCombatLog = false end
if spellID ~= 147193 then -- Ghosts shadow priests
GS.SpellThrottle = (GetTime()+math.random(20, 60)*.001)+GS.SpellCDDuration(61304)
end
-- Priest
if spellID == 147193 and GS.Talent52 then
GS.Priest.ApparitionsInFlight = GS.Priest.ApparitionsInFlight + 1
return
end
-- Monk
if spellID == 115175 then
GS.Monk.SoothingMistTarget = destGUID
return
end
if GSR.Class == "MONK" and GS.Spec == 3 and tContains(GS.Monk.HitComboTable, spellID) then
GS.Monk.LastCast = spellID
return
end
return
end
if event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" then -- aura detection stuff goes in here eg: hunter steady focus and mob specific dot throttles
-- Priest
if spellID == 34914 then
-- GS.Priest.VampiricTouchTarget = nil
GS.DoTThrottle = nil
return
end
if spellID == 194249 then -- Entered Void Form
GS.Priest.Voidform.PreviousStackTime = timeNow
GS.Priest.Voidform.VoidTorrentStart = nil
GS.Priest.Voidform.DispersionStart = nil
GS.Priest.Voidform.DrainStacks = 1
GS.Priest.Voidform.StartTime = timeNow
GS.Priest.Voidform.TotalStacks = 1
GS.Priest.Voidform.VoidTorrentStacks = 0
GS.Priest.Voidform.DispersionStacks = 0
return
end
if spellID == 212570 then -- StM
GS.Priest.Voidform.StMActivated = true
GS.Priest.Voidform.StMStart = timeNow
return
end
if spellID == 205065 then -- Void Torrent
GS.Priest.Voidform.VoidTorrentStart = timeNow
return
end
if spellID == 47585 then -- Dispersion
GS.Priest.Voidform.DispersionStart = timeNow
return
end
-- Warlock
if spellID == 157736 then -- Immolate
GS.DoTThrottle = nil
return
end
return
end
if event == "SPELL_AURA_APPLIED_DOSE" then -- Never seen this before. it's used for buffs that gain stacks without refreshing duration aka void form (mongoose bite?)
-- Priest
if spellID == 194249 then -- Gained Void Form Stack
GS.Priest.Voidform.PreviousStackTime = timeNow
GS.Priest.Voidform.TotalStacks = GS.Priest.Voidform.TotalStacks + 1
if GS.Priest.Voidform.VoidTorrentStart == nil and GS.Priest.Voidform.DispersionStart == nil then
GS.Priest.Voidform.DrainStacks = GS.Priest.Voidform.DrainStacks + 1
elseif GS.Priest.Voidform.VoidTorrentStart ~= nil then
GS.Priest.Voidform.VoidTorrentStacks = GS.Priest.Voidform.VoidTorrentStacks + 1
else
GS.Priest.Voidform.DispersionStacks = GS.Priest.Voidform.DispersionStacks + 1
end
return
end
return
end
if event == "SPELL_AURA_REMOVED" then
-- Priest
if spellID == 194249 then -- Exited Void Form
GS.Priest.Voidform.VoidTorrentStart = nil
GS.Priest.Voidform.DispersionStart = nil
GS.Priest.Voidform.DrainStacks = 0
GS.Priest.Voidform.StartTime = nil
GS.Priest.Voidform.TotalStacks = 0
GS.Priest.Voidform.VoidTorrentStacks = 0
GS.Priest.Voidform.DispersionStacks = 0
return
end
if spellID == 212570 then -- StM
GS.Priest.Voidform.StMActivated = false
return
end
if spellID == 205065 and GS.Priest.Voidform.VoidTorrentStart ~= nil then -- Void Torrent
GS.Priest.Voidform.VoidTorrentStart = nil
return
end
if spellID == 47585 and GS.Priest.Voidform.DispersionStart ~= nil then -- Dispersion
GS.Priest.Voidform.DispersionStart = nil
return
end
return
end
if event == "SPELL_DAMAGE" then -- projectile unthrottles would go in here
-- Priest
if spellID == 148859 and GS.Talent52 then
GS.Priest.ApparitionsInFlight = GS.Priest.ApparitionsInFlight - 1
return
end
return
end
if event == "SPELL_PERIODIC_DAMAGE" then
-- General
if GS.InterruptNextTick and GS.InterruptNextTick == spellName then -- Interrupt Channeling On Tick
SpellStopCasting()
GS.InterruptNextTick = nil
return
end
return
end
end
end
function GS.CombatInformationFrameCuration()
if not FireHack or GS.PreventExecution or UnitIsDeadOrGhost("player") then return end
if not GSR.Mobs and #GS.MobTargets > 0 then table.wipe(GS.MobTargets) end
if not GSR.Healing and #GS.AllyTargets > 0 then table.wipe(GS.AllyTargets) end
local unitPlaceholder = nil
mobTargetsSize = #GS.MobTargets
allyTargetsSize = #GS.AllyTargets
for i = 1, ObjectCount() do
unitPlaceholder = ObjectWithIndex(i)
if (not GSR.Mobs or not tContains(GS.MobTargets, unitPlaceholder)) and (not GSR.Healing or GS.AllyNotDuplicate(unitPlaceholder)) -- make sure it isn't a duplicate
and ObjectExists(unitPlaceholder) and UnitExists(unitPlaceholder) -- make sure it exists
and (bit.band(ObjectType(unitPlaceholder), 0x8) > 0--[[ or bit.band(ObjectType(unitPlaceholder), 0x10) > 0]]) -- make sure it's a mob or player
then
if not GSR.PvPMode and --[[GSR.Mobs and]] bit.band(ObjectType(unitPlaceholder), 0x8) > 0 and bit.band(ObjectType(unitPlaceholder), 0x10) == 0 then -- mobs
if GSR.Healing and UnitInParty(unitPlaceholder) then -- friendly mobs
if GS.AllyTargetsAuraBlacklist(unitPlaceholder) then
GS.AllyTargets[allyTargetsSize+1] = {Player = unitPlaceholder, Stats = {Position = {true,true,true}}, Role = UnitGroupRolesAssigned(unitPlaceholder)}
allyTargetsSize = allyTargetsSize + 1
end
elseif GSR.Mobs and not UnitInParty(unitPlaceholder) and GS.Health(unitPlaceholder) > 0 and UnitCanAttack("player", unitPlaceholder) then -- hostile mobs
if not tContains(GS.MobNamesToIgnore, UnitName(unitPlaceholder)) and not tContains(GS.MobTypesToIgnore, UnitCreatureType(unitPlaceholder)) and GS.MobTargetsAuraBlacklist(unitPlaceholder) then
GS.MobTargets[mobTargetsSize+1] = unitPlaceholder
mobTargetsSize = mobTargetsSize + 1
end
end
elseif GSR.PvPMode and GSR.Mobs and bit.band(ObjectType(unitPlaceholder), 0x10) > 0 and UnitCanAttack("player", unitPlaceholder) then -- enemy players
if not tContains(GS.MobNamesToIgnore, UnitName(unitPlaceholder)) and not tContains(GS.MobTypesToIgnore, UnitCreatureType(unitPlaceholder)) and GS.MobTargetsAuraBlacklist(unitPlaceholder) then
end
elseif GSR.Healing and bit.band(ObjectType(unitPlaceholder), 0x10) > 0 and UnitInParty(unitPlaceholder) then -- friendly players
if GS.AllyTargetsAuraBlacklist(unitPlaceholder) then
GS.AllyTargets[allyTargetsSize+1] = {Player = unitPlaceholder, Stats = {Position = {true,true,true}}, Role = UnitGroupRolesAssigned(unitPlaceholder)}
allyTargetsSize = allyTargetsSize + 1
end
end
end
end
for i = 1, mobTargetsSize do
unitPlaceholder = GS.MobTargets[i]
if not GSR.Mobs or not ObjectExists(unitPlaceholder) or not UnitExists(unitPlaceholder) or GS.Health(unitPlaceholder) == 0 or not UnitCanAttack("player", unitPlaceholder) or not GS.MobTargetsAuraBlacklist(unitPlaceholder) then _G["removeMobTargets"..i] = true end
end
for i = mobTargetsSize, 1, -1 do
if _G["removeMobTargets"..i] then
table.remove(GS.MobTargets, i)
_G["removeMobTargets"..i] = false
end
end
for i = 1, allyTargetsSize do
unitPlaceholder = GS.AllyTargets[i].Player
if not GSR.Healing or not ObjectExists(unitPlaceholder) or not UnitExists(unitPlaceholder) or GS.Health(unitPlaceholder) == 0 or UnitName(unitPlaceholder) == "Unknown" then _G["removeAllyTargets"..i] = true end
end
for i = allyTargetsSize, 1, -1 do
if _G["removeAllyTargets"..i] then
table.remove(GS.AllyTargets, i)
_G["removeAllyTargets"..i] = false
end
end
mobTargetsSize = #GS.MobTargets
allyTargetsSize = #GS.AllyTargets
for i = 1, mobTargetsSize do
unitPlaceholder = GS.MobTargets[i]
if ObjectExists(unitPlaceholder) and UnitExists(unitPlaceholder) and (UnitAffectingCombat(unitPlaceholder) or tContains(GS.Dummies, UnitName(unitPlaceholder))) then
GS.TTDF(unitPlaceholder)
end
end
for k,v in pairs(GS.TTD) do if not ObjectExists(k) or not UnitExists(k) or GS.Health(k) == 0 or not UnitCanAttack("player", k) or not GS.MobTargetsAuraBlacklist(k) then GS.TTD[k] = nil end end
end
function GS.AllyNotDuplicate(unitPassed)
for i = 1, allyTargetsSize do
unit = GS.AllyTargets[i].Player
if unit == unitPassed then return false end
end
return true
end
-- ripped from CommanderSirow of the wowace forums
function GS.TTDF(unit) -- keep updated: see if this can be optimized
-- Setup trigger (once)
if not nMaxSamples then
-- User variables
nMaxSamples = 15 -- Max number of samples
nScanThrottle = 0.5 -- Time between samples
end
-- Training Dummy alternate between 4 and 200 for cooldowns
if tContains(GS.Dummies, UnitName(unit)) then
if not GSR.DummyTTDMode or GSR.DummyTTDMode == 1 then
if (not GS.TTD[unit] or GS.TTD[unit] == 200) then GS.TTD[unit] = 4 return else GS.TTD[unit] = 200 return end
elseif GSR.DummyTTDMode == 2 then
GS.TTD[unit] = 4
return
else
GS.TTD[unit] = 200
return
end
end
-- if health = 0 then set time to death to negative
if GS.Health(unit) == 0 then GS.TTD[unit] = -1 return end
-- Query current time (throttle updating over time)
local nTime = GetTime()
if not GS.TTDM[unit] or nTime - GS.TTDM[unit].nLastScan >= nScanThrottle then
-- Current data
local data = GS.Health(unit)
if not GS.TTDM[unit] then GS.TTDM[unit] = {start = nTime, index = 1, maxvalue = GS.Health(unit, max)/2, values = {}, nLastScan = nTime, estimate = nil} end
-- Remember current time
GS.TTDM[unit].nLastScan = nTime
if GS.TTDM[unit].index > nMaxSamples then GS.TTDM[unit].index = 1 end
-- Save new data (Use relative values to prevent "overflow")
GS.TTDM[unit].values[GS.TTDM[unit].index] = {dmg = data - GS.TTDM[unit].maxvalue, time = nTime - GS.TTDM[unit].start}
if #GS.TTDM[unit].values >= 2 then
-- Estimation variables
local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0
-- Calc pre-solution values
for i = 1, #GS.TTDM[unit].values do
z = GS.TTDM[unit].values[i]
-- Calc mean value
x_M = x_M + z.time / #GS.TTDM[unit].values
y_M = y_M + z.dmg / #GS.TTDM[unit].values
-- Calc sum of squares
SS_xx = SS_xx + z.time * z.time
SS_xy = SS_xy + z.time * z.dmg
end
-- for i = 1, #GS.TTDM[unit].values do
-- -- Calc mean value
-- x_M = x_M + GS.TTDM[unit].values[i].time / #GS.TTDM[unit].values
-- y_M = y_M + GS.TTDM[unit].values[i].dmg / #GS.TTDM[unit].values
-- -- Calc sum of squares
-- SS_xx = SS_xx + GS.TTDM[unit].values[i].time * GS.TTDM[unit].values[i].time
-- SS_xy = SS_xy + GS.TTDM[unit].values[i].time * GS.TTDM[unit].values[i].dmg
-- end
-- Few last addition to mean value / sum of squares
SS_xx = SS_xx - #GS.TTDM[unit].values * x_M * x_M
SS_xy = SS_xy - #GS.TTDM[unit].values * x_M * y_M
-- Results
local a_0, a_1, x = 0, 0, 0
-- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
a_1 = SS_xy / SS_xx
a_0 = y_M - a_1 * x_M
-- Find zero-point (Switch back to absolute values)
a_0 = a_0 + GS.TTDM[unit].maxvalue
x = - (a_0 / a_1)
-- Valid/Usable solution
if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
GS.TTDM[unit].estimate = x + GS.TTDM[unit].start
-- Fallback
else
GS.TTDM[unit].estimate = nil
end
-- Not enough data
else
GS.TTDM[unit].estimate = nil
end
GS.TTDM[unit].index = GS.TTDM[unit].index + 1 -- enable
end
if not GS.TTDM[unit].estimate then
GS.TTD[unit] = math.huge
elseif nTime > GS.TTDM[unit].estimate then
GS.TTD[unit] = -1
else
GS.TTD[unit] = GS.TTDM[unit].estimate-nTime
end
end
-- ripped from CommanderSirow of the wowace forums
-- Bread
GS.SavedReturns = {
SIR = {RotationCacheCounter = 0},
SCA = {RotationCacheCounter = 0},
SpellIsUsable = {RotationCacheCounter = 0},
SpellIsUsableExecute = {RotationCacheCounter = 0},
SpellCDDuration = {RotationCacheCounter = 0},
PoolCheck = {RotationCacheCounter = 0},
InRange = {RotationCacheCounter = 0},
InRangeNew = {RotationCacheCounter = 0},
FracCalc = {RotationCacheCounter = 0},
GCD = {RotationCacheCounter = 0},
IsCAOCH = {RotationCacheCounter = 0},
IsCA = {RotationCacheCounter = 0},
IsCH = {RotationCacheCounter = 0},
}
-- Combat Check Functions
function GS.ValidTarget()
if ObjectExists("target")
and UnitExists("target")
and UnitCanAttack("player", "target")
and (tContains(GS.Dummies, UnitName("target")) or GS.Health("target") > 1)
and not UnitIsDead("target")
and GS.MobTargetsAuraBlacklist("target")
and (not GSR.CCed or not GS.UnitIsCCed("target"))
then
return true
else
return false
end
end
function GS.UnitIsTappedByPlayer(mob)
if UnitTarget("player") and mob == UnitTarget("player") then return true end
if UnitAffectingCombat(mob) and UnitTarget(mob) then
local mobTarget = UnitTarget(mob)
mobTarget = UnitCreator(mobTarget) or mobTarget
if UnitInParty(mobTarget) then return true end
end
return false
end
GS.MobTargetsAurasToIgnore = {
"Arcane Protection",
"Water Bubble",
}
function GS.MobTargetsAuraBlacklist(object)
local auraToCheck = nil
for i = 1, #GS.MobTargetsAurasToIgnore do
auraToCheck = GS.MobTargetsAurasToIgnore[i]
if GS.Aura(object, auraToCheck) then return false end
end
return true
end
GS.AllyTargetsAurasToIgnore = {
}
function GS.AllyTargetsAuraBlacklist(object)
local auraToCheck = nil
for i = 1, #GS.AllyTargetsAurasToIgnore do
auraToCheck = GS.AllyTargetsAurasToIgnore[i]
if GS.Aura(object, auraToCheck) then return false end
end
return true
end
-- Gear Functions
-- Sorting Functions
function GS.SortMobTargetsByLowestHealth(a,b)
return not GS.MobTargetsAuraBlacklist(a) and false or not GS.MobTargetsAuraBlacklist(b) and true or GS.Health(a) < GS.Health(b)
end
function GS.SortMobTargetsByHighestTTD(a,b)
return GS.GetTTD(a) == math.huge and false or GS.GetTTD(b) == math.huge and true or GS.GetTTD(a) > GS.GetTTD(b)
end
function GS.SortMobTargetsByLowestTTD(a,b)
return GS.GetTTD(a) < GS.GetTTD(b)
end
function GS.SortMobTargetsByLowestDistance(a,b)
return not UnitExists(a) and false or not UnitExists(b) and true or GS.Distance(a)-UnitCombatReach(a) < GS.Distance(b)-UnitCombatReach(b)
end
function GS.SortMobTargetsByLowestDeadlyPoison(a, b)
return not GS.Aura(a, 2818, "", "PLAYER") and true or not GS.Aura(b, 2818, "", "PLAYER") and false or (select(7, GS.Aura(a, 2818, "", "PLAYER"))-GetTime()) < (select(7, GS.Aura(b, 2818, "", "PLAYER"))-GetTime())
end
function GS.SortAllyTargetsByGreatestDeficit(a,b)
return (GS.Health(a.Player, _, _, true) > GS.Health(b.Player, _, _, true) or GS.Health(a.Player, _, _, true) == GS.Health(b.Player, _, _, true) and UnitGroupRolesAssigned(a.Player) == "TANK")
end
function GS.SortAllyTargetsByLowestDeficit(a,b)
return (GS.Health(a.Player, _, _, true) < GS.Health(b.Player, _, _, true) or GS.Health(a.Player, _, _, true) == GS.Health(b.Player, _, _, true) and UnitGroupRolesAssigned(a.Player) == "TANK")
end
function GS.SortAllyTargetsByTankHealerDamagerNone(a,b)
return (UnitGroupRolesAssigned(a.Player) == "TANK" and true or UnitGroupRolesAssigned(a.Player) == "HEALER" and UnitGroupRolesAssigned(b.Player) ~= "TANK" and true or UnitGroupRolesAssigned(a.Player) == "DAMAGER" and UnitGroupRolesAssigned(b.Player) ~= "TANK" and UnitGroupRolesAssigned(b.Player) ~= "HEALER" and true or false)
end
function GS.SortAllyTargetsByLowestDistance(a,b)
return not UnitExists(a.Player) and false or not UnitExists(b.Player) and true or GS.Distance(a.Player) < GS.Distance(b.Player)
end
-- Unit Functions
function GS.IsCAOCH(unit)
if not unit then unit = "player" end
local unitPointer = ObjectPointer(unit)
if GSR.Dev.CachedFunctions and GS.SavedReturns.IsCAOCH.RotationCacheCounter == GS.RotationCacheCounter then
if GS.SavedReturns.IsCAOCH[GS.RotationCacheCounter..unitPointer] then return GS.SavedReturns.IsCAOCH[GS.RotationCacheCounter..unitPointer] end