From 8d0b18817cd3e886e19cf95834fcb6635212ea74 Mon Sep 17 00:00:00 2001 From: "Michael (a.k.a. Codermik)" Date: Tue, 19 Jul 2022 20:53:35 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 2 + Bindings.xml | 11 + Icons/Deathknight.tga | Bin 0 -> 3628 bytes Icons/DeathknightPet.tga | Bin 0 -> 3592 bytes Icons/Demonhunter.tga | Bin 0 -> 3357 bytes Icons/Druid.tga | Bin 0 -> 4645 bytes Icons/Hunter.tga | Bin 0 -> 4593 bytes Icons/HunterPet.tga | Bin 0 -> 4491 bytes Icons/IconDisabled.tga | Bin 0 -> 3116 bytes Icons/IconEnabled.tga | Bin 0 -> 3116 bytes Icons/Mage.tga | Bin 0 -> 4645 bytes Icons/MiniMapButtonDisabled.tga | Bin 0 -> 16428 bytes Icons/MiniMapButtonEnabled.tga | Bin 0 -> 16428 bytes Icons/Monk.tga | Bin 0 -> 3654 bytes Icons/Paladin.tga | Bin 0 -> 4645 bytes Icons/Priest.tga | Bin 0 -> 4645 bytes Icons/Rogue.tga | Bin 0 -> 4645 bytes Icons/Shaman.tga | Bin 0 -> 4645 bytes Icons/Warlock.tga | Bin 0 -> 4645 bytes Icons/WarlockPet.tga | Bin 0 -> 4497 bytes Icons/Warrior.tga | Bin 0 -> 4645 bytes Icons/empty.tga | Bin 0 -> 3552 bytes README.md | 2 + ReadMe.txt | 60 + SmartBuff-Classic.toc | 20 + SmartBuff-Wrath.toc | 20 + SmartBuff.buffs.lua | 995 ++++ SmartBuff.globals.lua | 61 + SmartBuff.lua | 5043 +++++++++++++++++ SmartBuff.toc | 20 + SmartBuff.xml | 3299 +++++++++++ lib/Broker_SmartBuff/Broker_SmartBuff.lua | 45 + lib/Broker_SmartBuff/LibDataBroker-1.1.lua | 90 + .../CallbackHandler-1.0.lua | 212 + .../LibClassicDurations.xml | 7 + lib/LibClassicDurations/classAbilities.lua | 1145 ++++ lib/LibClassicDurations/core.lua | 1161 ++++ .../diminishingReturns.lua | 176 + lib/LibClassicDurations/npcAbilities.lua | 576 ++ lib/LibStub/LibStub.lua | 30 + localization.cn.lua | 427 ++ localization.de.lua | 208 + localization.en.lua | 234 + localization.es.lua | 204 + localization.fr.lua | 205 + localization.ru.lua | 202 + localization.tw.lua | 210 + 47 files changed, 14665 insertions(+) create mode 100644 .gitattributes create mode 100644 Bindings.xml create mode 100644 Icons/Deathknight.tga create mode 100644 Icons/DeathknightPet.tga create mode 100644 Icons/Demonhunter.tga create mode 100644 Icons/Druid.tga create mode 100644 Icons/Hunter.tga create mode 100644 Icons/HunterPet.tga create mode 100644 Icons/IconDisabled.tga create mode 100644 Icons/IconEnabled.tga create mode 100644 Icons/Mage.tga create mode 100644 Icons/MiniMapButtonDisabled.tga create mode 100644 Icons/MiniMapButtonEnabled.tga create mode 100644 Icons/Monk.tga create mode 100644 Icons/Paladin.tga create mode 100644 Icons/Priest.tga create mode 100644 Icons/Rogue.tga create mode 100644 Icons/Shaman.tga create mode 100644 Icons/Warlock.tga create mode 100644 Icons/WarlockPet.tga create mode 100644 Icons/Warrior.tga create mode 100644 Icons/empty.tga create mode 100644 README.md create mode 100644 ReadMe.txt create mode 100644 SmartBuff-Classic.toc create mode 100644 SmartBuff-Wrath.toc create mode 100644 SmartBuff.buffs.lua create mode 100644 SmartBuff.globals.lua create mode 100644 SmartBuff.lua create mode 100644 SmartBuff.toc create mode 100644 SmartBuff.xml create mode 100644 lib/Broker_SmartBuff/Broker_SmartBuff.lua create mode 100644 lib/Broker_SmartBuff/LibDataBroker-1.1.lua create mode 100644 lib/CallbackHandler-1.0/CallbackHandler-1.0.lua create mode 100644 lib/LibClassicDurations/LibClassicDurations.xml create mode 100644 lib/LibClassicDurations/classAbilities.lua create mode 100644 lib/LibClassicDurations/core.lua create mode 100644 lib/LibClassicDurations/diminishingReturns.lua create mode 100644 lib/LibClassicDurations/npcAbilities.lua create mode 100644 lib/LibStub/LibStub.lua create mode 100644 localization.cn.lua create mode 100644 localization.de.lua create mode 100644 localization.en.lua create mode 100644 localization.es.lua create mode 100644 localization.fr.lua create mode 100644 localization.ru.lua create mode 100644 localization.tw.lua diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/Bindings.xml b/Bindings.xml new file mode 100644 index 0000000..11ed7a1 --- /dev/null +++ b/Bindings.xml @@ -0,0 +1,11 @@ + + + SMARTBUFF_Check(0); + + + SMARTBUFF_OptionsFrame_Toggle(); + + + SMARTBUFF_ResetBuffTimers(0); + + diff --git a/Icons/Deathknight.tga b/Icons/Deathknight.tga new file mode 100644 index 0000000000000000000000000000000000000000..6a337ffe48812872838f69e4a8767fc9bfece7b7 GIT binary patch literal 3628 zcmYk9c~n$qn#PN@*c3!I*+D?|O}1i}z1WIX7J&lU3MfGKMRr61A%Li@t>BIZ#JCbo z$L?06#+Y)d*u=RWWIz3=l$Bu0|| zKb$4vV=%LMD|P5NM$DNFV(&jD_VFW9K6#4EgFoZ=!8((#|HSm>Q&XE4laS&9GD^!y zk}L3yj3M09od6e0d@US__HZXMK8C{bdP;`R5i+-e)#M2#H~%@YdD&T*ktd0Dv6I9q zN=YwICoFO=))pa{=-Q$y4aZ!^5*rf}tW6Ek(bGj&dmG!0jB&LNCP@}S<$+@MPA=2@ z)jvpgHrtANWHYp7`N3|9dzzfw?1RWd+}W{RAAdVnTy1w@W4lv?(?Yx}`Vu`%we{F0 zPCYGsw6zT}($yiv#~CMkI~0EQOv9~a%Ee=YhVqIX0%&=;#;{ z>FGvIdKPZ4KB8gcAsUpiO{iTRC8d(Y@-k9m^DwvZVUKSJjsfX}%hJdS4kXOMg6ar= zR{I*ca=4RQlVhwe&hhZdGQYoZjW0It@%;8Gt0!iu++T!5ONyP16`_tvl!hhY^6)o8 zXak7`ZFCdT&PCk1*Y=Z?m&*>R5t-RV^o~vwl~77fb{Y9Xe`TzUgCSmwWW{l`tbj>n zG4H7xI6pGTnV|vB4i9kQ=m=M)j_~27^IV>r!p(6vjuy7Kd+nw&H3hdb*Ksj3kZ4f1 zpyfleBr40;ZRduWfgyf=AtY7|6P{9mEIOUk_%u?(WsDVP(H7-JPi7)L*(vlE7seTb=^KBk*h%r#ZwXl#PBtrcM|)_8Y!k@>+RegQ3O>mlB0Ck9&E zMAhveBVLYAgo6CGCF=U7QRJ0U({Px^>@1PraFpTx90>ELIw=vABA3RZa)w*m8B@2> zU0%iUu3qLk4zb+ZiaI73cS{Q){x))4t#LSeeGA%YQ*aAqtyn5W?9kE0RMdE`w*!Uo z3HS!>V_^0K%MUl`oL(TUteb*V1-U~1d>S90laqEl2_k^xw=~{0*ORJz^i$HY+0x%Nn@I`Vj0SeCU0*5 z@|0YXvQ-S7ze#D&DS|_jiHuAmIXZ=$h%gl4q2%mKr#M%MvZ$J-nsx@eM(Jrrfvz@>jx_VziFS>~*@-F0 z(~Aj@$s;r-pS`kdBBHX9g{P7tizY29n$m;Aq$K20R#1tuq@Mb^UZzH-nHw2rth$i} zQ3m(Up5fh_*L=8m6k}Z}_Pbn>9a*OT(ruhvGb)MAEx}Z3$nG76e7&~Fvx{e#6y=;3 z7sI~LNP_&M2~9glXl6apISs@YHWO9Qjx4`}+=dC__jiz3(o0NI31t->)GAvTXzJkN z#BnYk9_8-*9G`!1gZ7+6>`e@C++jz?@HEn71x`)}S_q3xMXIY$xb1end$7#Qn=72? z?Pj5;jTmol{5?YmODQ8FrxBm196_QE*We^vL(=d`K1fF6GzpdCL<@r5gA1rty&O`i zcz^yBE5j2!Sw7FoXdk7%j(F@e)>L9#Mj^KQ>u_?eY{xe+N)Rw0$Ip$wfAdTbxXF@W z|Ld`147PNUotjTjbRGf8m3V|HICB0T@`7rz_ScBt)A0;RBy;j(3WlySwzPp#*~XEM z5gweo%Dw4XzPqU=Js>aoGvjDXymj&?8zkbQ*ckl3g zZJlFny{IedsVS?+FCv@7(mt9-&+*>1kGa0_l-fgsWFJtY9y(39qLuQKPdLytPFYzC zgN;4hKYN*f`S3CS`Qi!x{`>p<^yCtCG9N6Zx&+A**J^5v~rDuNtv7qe*3J~`G|H8@%2H{rTB0eu}U z&UMyn2)uj#oLB3&=~HbIsGz8#jeYV;awRAy)5i@YCP^iwkQTT%BnP-@2t-%)pyv}R6p&@% ztvGjP@_o0*2;!}`f-dL z_Mqv6R;o7P6C5zxZot=DJ(?V(lC+PY%-&>4~kGB_Tmx*eFVV z?u0fi-RudDM%ToMR>APYg?Z78E{i!jOMgWTi@hUsHxJU(GEU3DX^QH{=$^Pt|I`X2 zGb@ZQtkONZ%85I#nH)OG+3^u-{T+$3Gb3lO4|hjfg%cSh&e;+ZBQy49m0}Ph|CxYu zm>lop3z$pIFcb}GxU85b=a#sA@>g7)oZ(dOAOq@tT2+U6Z*-piLqk+&=1`fELS=X$ z)v*!uGBVL z0>^@4O!cJfFx2H(Z6%-Hyv4icpYrPZO{UrhXjgS|VdfM|QzvLCE+;P}fJ}jq?rcGh zhn+}n9-W=X7#f)5&e;Xg)pir-XikE?8QxYqakJS)VpauGulQejfY_2Mwq05xP?m{~ zz7e7Bo~+F+@IQb2hQEIFJ3hO1laJ3`63#{}`;I=2ib-3Op2=`d62+pRgDtlaEtJj- z@~69AO@C7}gDNHaTrIE?gHK<_6qn$5^a}Ecjf(vxwD3U^r|@Jf#%2gJb;Lw80)G!L zZk|5L>uXmu3;5l$7kqpFE^i+`=hJ3Y<8k9F5_rd z2X5B(B9BJc+c{w(2ET!;`=$z8rfbV$ZqwJ6?DX`*Veuq!euYdXX1Gp%*JlEcdsuR9{Gvn=OH2ro?%=lAn=ILSj1BI!3sNn8w0Y zS%k{O+;Q2mm|F%qNW897XdGrYt`N}CijQ=s@ZnMct3!;)%WFVGv_C_k@e<6HA-lIWGn&oPHeY8yc1LHi=g1^G=4UWpTEuI1 z4UZ#NvF|!1QhE%-rfEzMO<6G0Q~!6rcklh~ zyWf)}jr7yYO%iX_0sT*>-U6)CC?>Y(BudwLOZQS4g9G8pl&@}a!X8lw9^^-RI z^(>a;=8=?=NnlJoQNCUTyW0?G?LwTl7cukW$MZmS$#VQbJ}fsd=eH#)M&K9gbG+fLs}crLhh6S}k@uHO2}#a+w+C8dE&%LP?6A z%j!2?C#o^HEV0+wVQj1>#@CaA)O0*QzRHHnV+LP;4y)C}>QNK(R+5~s3`_d}d;-I92~H(C zGm5Ng2MRy1VEb1ZcK%7tju#RQdQi36Nn-Ou6KwrdNJdH=?QMy0Ng_8g3HPyU{~wsw z+A5NkEoFvMLt4gb?5wROHQk$>4Gyf{Ye&H;ONuAVsQg|-_KBas7PlKy`(H{5?^}?5 z%oGb}9WK@mc=^p@b@C!SyN3A(&r+&eNnEv(S&p7qsMO4z!mS+80vO6E0Y z7|YQKmX~Du(6BL<{o58(TN}f^rex}SqG`MkMc$wzZ{v;HMc^9!$RD$a^`_MPVI~!~ z0x7xVM`?F7n;OC>DvM!LNi-`~grOGo3U)V)&ZO28WL!*?_xp@Hx^CPIqccFf* zH+5D1H0}(g^|&?(iV$9Qn1Zzq?#$~fPl>SiOh`s4H=$}>1|u!28EMYvbax&X`inVsEs+oZ{02(fX$~3Sl#)y$vO+=g z_+0ik&!=g367}T*x;Tx!CF#`e-IR`TZc3PeP4kvy?T?|eDV+nml6bp3oyM)H zG;dqZfwC+r3Ns9_@i7a~t=x{eV{Q>1zIyT)@z<9h^W^?Dp4_{}{i)MD`Q<2Y)&(0v zX&RM4uoXu>jOXCt5CNUUq3T#_50@=O(Yz&%<}FKT zDNe>lFlA13BIfzE=m8o`@*|!;9pi@|9_O)mv6!&Yyl?5MzmBH(_EUy`Mx?PZVmI``5X7pAe17}xo;%GKKEy;9Oq;RMxl6|X!*t^n)E!oqV4qlRh z<$_dn4hz>XXJHoRqA|ABSMvPf9j0zxWb)=2#y+iKaC{e!{@lln7YDij?P+$6CL6q# z1gu>5BeXoB)QVg8c5&gKO1Lmk%7wx0)LuGPiQ;T~F=yM0*i)2l$aP$P1&V+O;d694 z{+VxJX{u&^)NKCv+ZQ~z^8pjTIK$*G&NKe&V@$m4=ia{z@Y%nQuymh~0oX{Sq2Noi z>0YPIZwq0|yP=GnE@iNP9cPY}ic!M3?g}x=r#E5TRJj%hTYG}n)uVCt!Byl!JhM5?@z|`aSdHJVbvF-2*oD$Tcm+LnmW5>fNAu=S)T}^OZ zY|6O@o8Xg9PP3&PTKQN^bi;9d3bZjmYY zx3poYv_K_SFg9|QXHTYh{O}e}1@~Wk^PE5Y^&1}j^DTyNck57cJ#;FOnfmWc5s!O zcSpE!_YCJQ^w8hGkCP`4)7`d{zOH@rbkx$_x|7cR70mW@$J2f$iRo{m^qc>8o!K!V zCm*wcsp0m#YWuhnkqYd!31E!+di4UB3MK8DIV8EABrY=f?PDP7WXD(tD>2@olT$ zNN-Oo{X<9TJARn*qPGb23_vXeqLZU5TG5tO9$x5vrYaqUrY$sRSl=L=J35&cl!#6; z!Ca`t?6fq7dJgdM9g*Tk<9zk>RD>b13N#5^p{3=v$qg#e|MP{~TM1!E$j!l>N6 zi_@nD7=7;yPrmq6Ku>Yy`WOQPL$n-drJ!If-g80;eI-FiDtkPaZosMh5CL;Ve)Ycn zqmtI&5e$mn+9oazm+jTKcAvyArvMuxBaB618_8s-gkYB>xe)3y6hf%WL2Y#*R@NPJX)AqxH3XP~YHKW_Q7sus=%ybFE z+bMAR8r7n=ql}sp#Udds;*(NXAZ}tw$r;3oct!?A5aJz(;VJ!-`d8Mn?1d{*mZxN9 O1iii}C2iqs>3;yZdsKJ; literal 0 HcmV?d00001 diff --git a/Icons/Demonhunter.tga b/Icons/Demonhunter.tga new file mode 100644 index 0000000000000000000000000000000000000000..9470d01b91b6e74151d19d13a374374b5e3559a1 GIT binary patch literal 3357 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 CHQ>Gg literal 0 HcmV?d00001 diff --git a/Icons/Druid.tga b/Icons/Druid.tga new file mode 100644 index 0000000000000000000000000000000000000000..c95ff258d88279eef4ac432fa36ee837cb6f7456 GIT binary patch literal 4645 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 b=9OFb>@|1na7-I6T4$@^|>Y+<}$Xc|Zg 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 NU#ZbCu~C1A{sTwWa0>tc literal 0 HcmV?d00001 diff --git a/Icons/IconEnabled.tga b/Icons/IconEnabled.tga new file mode 100644 index 0000000000000000000000000000000000000000..709884254e60ba116a1a072cd111cae7f1c20580 GIT binary patch literal 3116 zcmXw52T)XZ9{%(!@sgY|G11GIJL6s2+(o@OYPu#)j0K~DiamBc%UOa7f&x;Mq7)TS z6qF)hL0FXD>xxJf1u05L`YsFG-*^9)ne6Pm*?qh3*S_-m10(UrYbvHp{)j9)w6(78O?b{DvfNW*+jEsq*h0@fm$<%$sQB4hIrA;^VA)nW)u6? z^W{uFpTerwRY_3C!K}cbLd2iQyf^r0BpW}Y-hP-KG+v?ffaU-LBZjHau|%SZl4LT` zNS&U;W@y;-8p%w98_Bvwl-H?dG+qQoE?jjIy zlJU$R*%k>Fzc(yeC>qBWEB0<<$H&wjkwgoI6=wc6%)=V`>X}8U_xJeyW;W=VZ=}M= zI7+u9DyR>kZa0l9sb0svHSAx~tpMjnn-b>?2ntx^Y4Au(-M@h=x0WBTJqOok+ z$>DV7|D848vu1ox3D~ucuXga+*X-X!^%ClAXbdy4Kue{GsYVtU8L8z76Aw!~pral8 ze`L?MR9moj6WhLE`TOQf^d+J%Nz7ydbx{)I+2cj!ByBoa_8Qe2ST~O~v)N-o)qHB5 zsl8=nS~q?A>8ayQGapcMoSMBH{#D{`s+Y0%JJ!!(<5E8Tghe0n;YWNlS(OO3?_s|$ zyKVKXVCPO2jb!l{)_u#0iG1-Do4(}0PZHf|IyEGtY&lE^6Map*$^N5kvt;`UcCKdI zYSzwT<-e%>h|lKg@-dJHRR);*KJ{_T|BzX4vH75$B{W=P{Zc+#!m_tm_c0s9i1zcP z75mqkc$Cr)dLEUyliD>jony~Zw#;P9S8QIuvMDmdi>9&YpQa)-i^&v^r#hHwzidyG zc;aOss9a0c1DX~_YLG?cB*Bfai(V9IosM%u@iPY2BK8dY! zSpGH(-eAsOsGQB_T~yoC7{Puo<9(#Kqvax+{Ghvnp>TowWNHQRUP#Pl{}$HIVA*uG ztf$U_tt(jbIeWfl`*hZRz*m;+Tgm#r%2Y3%%kuf`I8JRgjm1>?vfi>Q8jpNYe;H+N zNIHn_%jk&)(?>987VEarB(mhvFcFv~Y-eaMoMQoVQ7suHf zPD2EBm-uuwGpF=Kp!PBblA%dJjW5Et zq)bTZ&?kr#wNv`k~^tgcXTbBw5}@(emJL5e~7DP-O8jPx|=(>)3J5g+l{t%=(;Awym$S75cxWXvZ_iTToH!_Z* z!VBh9Xzqih9~hX)28(nXRC~ghgdyR^3N(kKEC88~2-}K~wYahxg>L8!MfynuuSBCA zTHTRu3$uuv|4v1)aEzJ4)0ncX+8OCbp|C|&Fm%F6l#{5v%{H&HlSum?hHs(w4)n>; z-@{`M>dT+l6^ z%^0DIL#+_?!x?5O+3s6thp6o`I+6Pjz6FI&GF8~Lo>Bz!CzpDmEeJuYaOV)T4`50{ z+yO*cqref~n~`RZ>)UZ`G0s?_>8hxF+;9pi{LmqYQN2Q9DJ!=o9mds-2;YU^?eMY2 ztvzVGAb_4sv4&nwtB;ji_Fn{d3*>uZFcI2#gj(bBdZaia^_U#_z&wQQ0aHc{rJ*7S zE!V)r32d^bxrB-d0qYQCjX-PouZNd40@grr5Up3hp=*3KZ?FL6o^bsUr&dB?hiX4` zhNJl=&RF2?b|fE%{X!i49t|R9#<)TkD2}0B@G$KiwuVw$YKVcaCC)8}*K(X)29ICh zvmCegqvIl|QLyVcb0^iDfx`kE{RJs@C_aYk>(Cd8_8SP;gcKVb`3_0;f-sW=lf!nS z!UwH4AqfhV@1sG<)Ia&GhT9@IEyBs4;k*FeixId1gHfPa$p#08jxt?C;2IgksJ*Ck zgWqDgl8z*#T!3Pi%vF;xpA2LRa-Kr%CA5lXb4D?HHl-TYEDG5M_oZ^1j*H;A5S~jA zvkNSlDh>~<`E6K;<<4v6e(+iW-&LscK=?)+{sNcwp)nbGr%@LO%`K#R;DIaBoKbon z+EfgPH4!tGn)}q;WWu=UJ#bzM$A$2>!u8Ei--3MXG2UhEqTT?shoJ8+ihK~c1NSx~ z(-uz4VDlYngV7R=_HZOQAo>uBg-C_m#Gxhk&C)?{Y#^+39d3|X>0vQHv(6@*yY;xM2<`z54o zL$WPO&ZAhYUd%V1=QuP$=l=Qrde5Mm4|$tHq?(qKSW(!y@M;x#@(1X|xpu=~%sjjFX2G+b0}PEWYAt3yH<1ksBU?PPLGo zR)XI>5{)i`A||YQyL?*EYAo0_cHF8Bx513lVMKN6(PFn0k>sOMqUbc~ za`;g-Uir-<=FNEZdI8UbBIW{qALXGYW>z#2J@@*3a|xS)?4FG@P3j=YXd&O9!h*g{ zl+EhJU)oM6qk+!8W0cQ0g2mN^(OE8e$wF`OVAT6iRJVM0p;MC4Xyb=L4lO!^m2{7v z?EFmTj%_CE@b?pDAB_i?Sc0+5`xrf^i_Ekv#*C`PYtYiZXeq_dK1ZOSp3-r1h)$fz z%zZy1-1{PW`&=~19oVf+7_B+z#k?kdXuYUv5@v&4P>`r4IcA-W^fVt8Q6EG4)-&<+ zs|oXu+&5pfrk{pzGA7AYY<@o@CU#5o5vDzVfpa^17?GP#_N2vBBn6oK&=ES1e}FH4 zC8^1iq#`TOxk^wJ$-R<_Mk5GF-ZdHnT7yl>&Vb2eL6N=NGkl~U8H_$*J{SI?5;Qp#Oyr7&8As7B4x@=AV8*`qsnfXFrao_aK(;qtqY0z~(DoQ+?=TJavzw zx~kDQ>e1QDr5K`;jetPnmVI4lrS@zBiOXhYe0?41Yj)jtpn1W1LMEs5O%fJ&Ikvz! zEauS!%Qi6Z(M|R*UCcvo{G8NZeo02h7D_rFrgGMP$|pQbY{3BCTb`i*jo%R4{4+{B zcBA?yptY8X15pfWCI)dtubMGSRcm#6f~gr)Z9mS&6E6|Ym@t>Rju|+OaSvT+%y~GH z8_^jX<-CR7mu~XotCu-(^A-hXZ%Xnnko@3t*nag#(%$|(p(oB!GJ69#A{y-`Qp3SEYmPKIV$Axt;Wy)hOmBX7>*;_w2j4 z+Yhkf(q#%-j-hvSVsS>WN>HlMpjJ9lD|Hrkptf4}?pjYcZRT<^^2*W1>Dc1K=ExH+ zEf89+K%-WWG43#)vZq*e^dcYLyT{IZu=uy1a`pBtmR|T8-`*>Pa`)l3l~THHfU=)_ zK=sy>Og?;G2yzKdSF;p$CPt%lMIw3?mtLWyYBY{{j}rFJSxrt+l`yDIAhHRcgyg~; zL1P#u+XxJ{iRjWE!P9Vvr+@bquiX7_cKq-fZ=U-vu3fv$(;t0HQOhg1%{yg=RFFJ< zB}1Qihvnx#XGHr6?9N_{t{NeNG-*qh>}?@QuOW9-3}4Ga!rsZt$S7^Zpwq~oHmL)j zpplKLFO;4xz~U=GFOlT;Tx8eft6cf^4v#$b4wrs&mjg$?V)xTG_`!wi60GDHt}P6?fx!!htdKDH+p=Lk6uzBgCP2 zWm=}m3=!D!I&r1N(58&S=Idj0&l~*i%Wvu1{}uy>KID@tci7N(i-Sjh&p)60R1o-> zsN*6@DGP`O+n9g&V{u?B$+<09&6z0107eNg?m*4Fe)I+9fb@eRu!_%%n*eZkpZe8HmrTMQrd87(!R zvUbf)oX#Usm_n2Ucyl!R+=M zgrXNo)?deLnTN->h`gRt7?SFwqjIGiQUnDXWhMFe+h*KnLjTG>a);MoH;YISF=7)3 zv@*_Z`W$J`44Edm!u93M-~S#je13NDQ|;x@gL&DnsibhR&SBCWg4o(OliwZOtrE54n!(q40-HH+(zMSQApOf13JIZ zXo^IiiA8c}GDWE9`aWY9o*-Jao4OUhX5seN>3ilf>%Vt}iS1XJ-*%ne|_GGP-3p#{7na<^QDx>SoNte&QI#RTCv}p#qtr8X+xJn<`C_D&GS_;Yny6 zMPxLrm(NBbHJhmJdY*8@ehOwCqwCafnf~2R=y~#OHa-7S>gRul@W?gNU@f?WgQCM5 z(05LzZe-nk^Me8`Tsa2M*1c3XLs*3j3_6h!idlNaC8h^8U9x95s!jM=6U6CjkRj2E z)8B<9I178>Qk=OO3Ag1Dx<+Eyekpg z{Zff>L2Z-L&B1Dm$Xpd2?=L1KvNEe<3BkU{DHt)B%S1qlX8})2O%0*-n+YE|N&bw5 zBKVz;;)QXGYmA~I`Q$lbn+q$l>`K6a4&eW%FTev;sN(SVBvFfZGKbM+3= zCijvWDkUdanD8v|c=cF(8&hRTCCwr!YMWv-%2Qg?*j7dgJ{3jf6z2?Hz9)X=SDHUR z5dP!y|2G1$74sJLjP04XwlFek!GiSlo^zO@{v)iXcTYao_{;&-IOP18$MH1MLDCn z(c)G#pZ%*kqTQ|d|MSUBw+sh132nt+?emtbTo;+Vc-87i``T55zx~~7&^36=Ul+pv E08#dd0ssI2 literal 0 HcmV?d00001 diff --git a/Icons/MiniMapButtonDisabled.tga b/Icons/MiniMapButtonDisabled.tga new file mode 100644 index 0000000000000000000000000000000000000000..67ccf661606e212fe2e4ffa510cd7c8f0797d984 GIT binary patch literal 16428 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 literal 0 HcmV?d00001 diff --git a/Icons/Monk.tga b/Icons/Monk.tga new file mode 100644 index 0000000000000000000000000000000000000000..a67ae1a42839ed36483391dd92a6ed0efbf6102d GIT binary patch literal 3654 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

V>1*zO_upK6`3=2ye@sg6Bq6nX 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 literal 0 HcmV?d00001 diff --git a/Icons/Shaman.tga b/Icons/Shaman.tga new file mode 100644 index 0000000000000000000000000000000000000000..6aac4d48ba4b2e6f739f8b5b3ce50671bf3b014c GIT binary patch literal 4645 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 St)ut;>@_bi`pO>z;eP-WDO)7~ literal 0 HcmV?d00001 diff --git a/Icons/Warlock.tga b/Icons/Warlock.tga new file mode 100644 index 0000000000000000000000000000000000000000..f187dccefda492c6833d8119c95a2b3ca402b797 GIT binary patch literal 4645 zcmeH~X;hR~n#Zf4s4DiYfC35%O7=~l*mv2BMfP1}M_FVO1eLfTAS$@vhEZ_CXk4Px z#x}COg{YPQcSmVrca;K{jERr`=0x}Z{7FS z^MCHMU#Y}G^1I7RB5tK*8jvVGHtr^Q?lviJJ|yMgJ+j|>g7>X|!1MYwrhfE7tUJDcLN%21Z9um;XJl^_+(=x)t6DJ_s_@swVJfqr zCubd_rP~>87-rK*J0k~L*txEY{Z)e;su*WW%@Cs_J+wCz(3q4%MPw#P{_&Wanv)RV zLu+0kK0mxq$L+gDsIjG;>{=q~jQTa?q?F>I4(7zbHjXu)D(_gcniP||{?RtfY>aFPgquID; zfL9iVNT`X&*4CCtw+Qr_a8wF=>@BQ_@pd6-(+~yM?-}8Dyo8VMA0|!fh*E0Jz^+~f z?{#wE-8p7Inc~QY+ZZlGl=Ob>H-eJDtB!`cVFg88H!oe9j3VYGn>(IzFl*iVx zvv@+-Z-nBgOf=S3$Yhq-nkWf$b)!^xrbG88qY{h)1a25*b$m355dk!mma|ht%6R!G zhbG6F9UEtEztU4;}(75V|A75b0*&Aqe`HiHM)L^SHCnq6=p_U%jM)j~UW)DXz z=Xfx5jWg#uxifNw*H53J{c;}LyT-XVeTp1i9tFPT#Hterch_TxE9CR1pR+cijZ!hM zcaIRMOo`IcP5|5BV(y04PKT$xJNeu9qR1*jtF7xHCM5@jOio2%F+J1m?0$WUrmC%E zsk@lTp5@%83q09%hc8cj%=4)a`RT+%es<+=ne9A=hovuJo)H8&2QyeZ#O=8^iLy&1 z$1|TSzjSQm_LxcSa5M8DNF70lTbR)sQ}Ziut87Q>)i^*%c%l$MNosNmC2e(#-x}oN zKki}t)d_NZI@lI=gp0MO_|>(q`R&`khl2+OeKwz7dB&w( z=LockBu@~EP#-u^kaUwce%+aPWhN+RMjuxZ+fR^8BtUuZlL zx@cDUW;3(?0JR~lWT~>w|9Tdi^b<$+H{VQoK8Z#BCxhqVQprL|0)A6g{^3v z%ev6%(~+A>3G()*tfZBulzz&>S}^#Ov&uW4AlEp`b4wVi8)QetR<>pK5T%Qtvp_^l zZa2Ltjr1osGL<{TqscdU@AA7GA6uX~vyCKe3_+GF(8^WVh&&)um>Ny6GJiD=>3L|~ zvYLs=D#u0?+5k7q^ zS64sf-slC6w@&fx^Kba*^ar%ZwGd+Kg@cHFnTZ^Gxf(0E$OR(OEG^_l0g{@AF$<0s z8i+3>sHhGHOLN>@RRp-W<1T}Y;C4KwVIa9cIxsPuyb%kVQPV!vznFb zc46V+k1-QEukT0a=7FuJ6Dp-8SpnJf8hU9+sv<{|OTJej$*NQ`G+Fc*`uW+t&-mrF zkND}Sx4GDHkj2iUyuJ4x*EV0~aP5BX?6}FZ`Se`FFSRhrp!a7vm)ONb*)Ux>9keZVFKQk7 z!djHchL-|(#TW?McL)cOCSzPf$ns66uW^WnZ$0FlOLw`k?-EysFR;)s$MM?3EUrJx ztqnK0GyDekC*R=N!ehRC<2jF}f56S1S4noy7A4UWR~r{1-NRX_iX_Y>loj?X2=a2n zuD%MH6_IN9E- zDfX$RKBR$tA`l+k{D4byi&SQmA55`MV>)5d0@8k;6Y z7~fIph@WF5TBQaL3pExpb0nq`OvJE|Nsx;F?@N6zx0#Lsp?DlVLTYFR8l?)EnK?3v2}-#M61fD4 zLWYTn45_L3E#MVOsS(=R%pMQ>V1jHTSSeC{o_@7R59y-LsPGm%Ek$RgijFtJ88>Kb zpq;hRsn}gQ&&rLx1S=fz5QW)ZDnV)@hE$HZ#6n~T0VS1+u{>`gzFC-hNWWjog;nA&E_h zmk5odLj1?4us=AB!~9_aXRhEkzKCY%s4(Ad%)9nt+c$xGSv#(tdi*pYM#*+BaoD#+ zl(7-9WQ&#}InzM8IHhIgtR_+DCnhwSaKGi{dzV&zC;i=l@UPFmYz-JTG_7mPX=@q? z@mkf=GPJR`ebCF$(-QUvQoEXYEzNx>?mv2!msVs|8p;est3#`^4Fy?Ye}*Ge|52`g z{qU!1AWANAll+}RDoK=t8vpa-!_K1t;_aL3BL7HkOTQ^}kVvn8Ad4$@kf{Id(CBaE kv!g6?FK+7S8T2Y!-`nR^Jka~6BL2U18oT9*KXiou0W3U200000 literal 0 HcmV?d00001 diff --git a/Icons/WarlockPet.tga b/Icons/WarlockPet.tga new file mode 100644 index 0000000000000000000000000000000000000000..bebaaedc6662172e966c886b7203d060b4bfc8bd GIT binary patch literal 4497 zcmeH~X>3$g7=~{{+nEl~meO_#beWd!OlhHXnYJ@6baPtT(gkS?wXFrp2xYZpiGni) z8CfEN2t?T;Dv21-C;@~ZDv8EFE*N8?Ci=%{qQnr5T9ViMe#5y10soo!!#3yK+jH;z zp6`9nch0>H(kz<#v1$6RS=$9bGbgOu4(GwMaJ_j6u1n`p^ZvU?e(MV)o_-DfkFM$W zKzqvQ#?NYRLw#o#s@zSmmpDR2+hdHu3m<7X}1Jb!INgp6c~^3Ep(nyB$X4Jec-6v=jF|z{EJU886M}QSdnlj zpk3f*W)R)IL|+iPoBADfpS>pXkA8F2;CtyowDND#dnbiR14w2D^qDN->GQzM*yuf5 z`yV&3;O9UNE&a<8wPHvN5Pa6aV`y{~Nbz-DJ$`Szh4}1&1`toA2-fR})6S++;klQc zY5tk#F!0+C2AtCB%3VlU;~$0B^bLw`R{q@g4+xyze|Y^{nR?M~;skPC(0SGs6Odxi zITPb1!^>`%BVI}krdHzUsAKC9Y&w1h=9Ky#xSBf*9Fes7E}Z3d9Brl?5(watjbr@V z$1arWmB|WRzhwtZ)lD!bEnJC0SFHi2&U=ERxkpeZV-if0RRSsr1!sZrK9189T3z?u zMMHOa{d`P*a4F2Tp0%*&l^S@?G4Ztc4x6Ko96M_0WO$<46h@)>H|v1~Pp`P2C_Kf{ zc4x^PL@XM__$i$$kdj$o;Fo=R`VPz0B7gVFJ9ii>n^q9?sW-db0L6DDwd zzB#2V(ix6Qg!g)p6xY2P={XL$iS@{xMa?%oVC(6A$e2|sQ_5LnTs(vl!g1N0Z&d@~ zyq|N=*xWW$0vWU2ur@4)Ikt5^CKrR+3HgE{n|bEeHzI0I9ZZv}AI6O8HiOOA8(n5#R*fJ99>mzxC)-v8 zqi{=MbY4+Jwe*-J1F(@y^?atRcRfO;6(BU$(SYoxg)*piwCcw^@_>&|#ZWi%P$k93 z8J4DVs?{F*_mw^&!zNMGWLE516%gG&3`;@=Ox#dom#w)2t?HWOVRk-ZBgKbXTuP(? z${XfG78~b{jVw{2UyEz%7~RC;Rt_O!W|=Tq-h6kl${Jhs_p^=@ql1*(VVQFR#_@~< zl6hpc^I=s=ikRQf3A58J#BeIK6}pkV^BE!XW;XQ|K&p~q*sEtD*t^*r;Uw|}yW#s! zBoy6M&PH~vfGILg*nwBIb!ZzB+X5?(a=H50m;iS$);4!8N@u%08PYhvlTrscd)%rmPAfkG`tITphg_fBZ1=9CJlKH+!O03Ti`Sf9ymTI0PiJ71dJS1nbT-`d7s=#N_5l z>XP-7^k{;!Lifg1itv|?And{=3J@RPQ^o8Hp|iti%l@bCb&Ha-FFycH~A2k z7f4j1`57|YZp*>cvIb;q^<%=GU5Glo4_UikMf%ngh#%aKasAs7wtNR7R&T?U)}@$~ zn2+>$yJWVV5q7dO7tJU_jsEg?R=F`p|BtAuwh^VeErmG+$V(60zJqsO4^sbp{eS## zJK!GZ?O#&6q<5{|HoLEHaNVkRjY0D V)~>q$y~X#xq-p+$z}348;V<1Jp;!O_ literal 0 HcmV?d00001 diff --git a/Icons/Warrior.tga b/Icons/Warrior.tga new file mode 100644 index 0000000000000000000000000000000000000000..daef21a8571e538b635b1487f2f0ca8f2129fa94 GIT binary patch literal 4645 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 Df&lNC literal 0 HcmV?d00001 diff --git a/Icons/empty.tga b/Icons/empty.tga new file mode 100644 index 0000000000000000000000000000000000000000..c21e7e1e6044cae2402baff9dedf8c6c36a44e28 GIT binary patch literal 3552 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e53607 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# SmartBuff Classic + Classic, SoM, TBC Classic and WOTLK diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..3be805b --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,60 @@ +*********************************************************************** + +SmartBuff - Retail / Classic TBC / Seasons of Mastery / WOTLK versions by Codermik + +You will find me on: + Classic Server: Mik/Castanova/Amarantine/Paramedic on EU-Mirage Raceway + Retail: Challenger, Castanova, Paramedic and many others on EU-Aszune + +Join me on discord to offer feedback, report bugs and much more: https://discord.gg/R6EkZ94TKK + +If you would like to help support the addon development please see the addon options screen. + +*********************************************************************** + +SmartBuff is a buff addon to cast buffs easily and quickly. All classes are supported. +Bind a key and it checks if you, a party/raid member, also hunter and warlock pets, needs your buff and cast it. +Use the options menu to configure it you like, as example: buffs, raid subgroups, pets, etc. +Run the mod when ever you wish, if nothing is buffed, there is no penalty or cool down. + +Features: +- Supports all classes +- Supports EN/DE/FR clients +- Checks buffs and rebuff you, raid/party members, raid/party pets +- Setup your own buff templates (Solo, Party, Raid, Battleground, MC, Onyxia, BWL, AQ, ZG, Custom 1-5) +- Auto switch templates +- Individual setup for each buff +- Supports group buffs: 'Gift of the Wild'/'Arcane Brilliance'/'Prayer of Fortitude'/'Prayer of Spirit', incl. group size and reagence check +- Supports class buffs: all greater blessings of the Paladin +- Supports self buffs +- Supports weapon buffs (individual for main and off hand): Shaman, all poisons (Rogue), all stones and oils, incl. reagence check +- Supports character level based buffs +- Supports tracking abilities +- Reminder if a buff is missing (Splash/chat/sound) +- ReBuff Timer +- Scrollwhell or only one key is needed +- Fast and easy to use +- FuBar support +- Titan Panel support + + +Usage: +Minimap button: +Left click: opens SmartBuff options frame +Right click: enables/disables SmartBuff +Alt-Left click: SmartDebuff +Shift-Left click: move minimap button + +Chat: +Type /sbm for options menu in game +Type /sb [command] or /smartbuff [command] in game +- cast buff +toggle - Toggles SmartBuff On/Off +menu - Show/hide options menu +rbt - reset buff timers +sdb - SmartDebuff +rafp - reset all frame positions + +Options frame: +Right click on buff checkbox: opens buff setup frame + diff --git a/SmartBuff-Classic.toc b/SmartBuff-Classic.toc new file mode 100644 index 0000000..65110ac --- /dev/null +++ b/SmartBuff-Classic.toc @@ -0,0 +1,20 @@ +## Interface: 11403 +## Title: SmartBuff |cffffffff(Classic)|r by |cff00ff00Codermik & Aeldra|r +## Version: 21.11403 +## Author: |cff20d2ffCodermik (Mik / Castanova on EU-Mirage Raceway) & Aeldra|r (EU-Proudmoore) +## Notes: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## DefaultState: Enabled +## LoadOnDemand: 0 +## Notes-deDE: Castet die wichtigsten Buffs auf dich selbst, Gruppe/Raid Mitglieder/Pets. Benutze /sbm um das Men� zu �ffnen +## Notes-frFR: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## SavedVariables: SMARTBUFF_OptionsGlobal +## SavedVariablesPerCharacter: SMARTBUFF_Options, SMARTBUFF_Buffs + +lib\LibStub\LibStub.lua +lib\CallbackHandler-1.0\CallbackHandler-1.0.lua +lib\LibClassicDurations\LibClassicDurations.xml +SmartBuff.globals.lua +SmartBuff.xml + +lib\Broker_SmartBuff\LibDataBroker-1.1.lua +lib\Broker_SmartBuff\Broker_SmartBuff.lua diff --git a/SmartBuff-Wrath.toc b/SmartBuff-Wrath.toc new file mode 100644 index 0000000..785fceb --- /dev/null +++ b/SmartBuff-Wrath.toc @@ -0,0 +1,20 @@ +## Interface: 30400 +## Title: SmartBuff |cffffffff(Classic WOTLK)|r by |cff00ff00Codermik & Aeldra|r +## Version: 21.30400 +## Author: |cff20d2ffCodermik (Mik / Castanova on EU-Mirage Raceway) & Aeldra|r (EU-Proudmoore) +## Notes: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## DefaultState: Enabled +## LoadOnDemand: 0 +## Notes-deDE: Castet die wichtigsten Buffs auf dich selbst, Gruppe/Raid Mitglieder/Pets. Benutze /sbm um das Men� zu �ffnen +## Notes-frFR: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## SavedVariables: SMARTBUFF_OptionsGlobal +## SavedVariablesPerCharacter: SMARTBUFF_Options, SMARTBUFF_Buffs + +lib\LibStub\LibStub.lua +lib\CallbackHandler-1.0\CallbackHandler-1.0.lua +lib\LibClassicDurations\LibClassicDurations.xml +SmartBuff.globals.lua +SmartBuff.xml + +lib\Broker_SmartBuff\LibDataBroker-1.1.lua +lib\Broker_SmartBuff\Broker_SmartBuff.lua diff --git a/SmartBuff.buffs.lua b/SmartBuff.buffs.lua new file mode 100644 index 0000000..921e910 --- /dev/null +++ b/SmartBuff.buffs.lua @@ -0,0 +1,995 @@ +------------------------------------------------------------------------------- +-- SmartBuff +-- Originally created by Aeldra (EU-Proudmoore) +-- Classic versions by Codermik (Mik/Castanova/Amarantine EU-Mirage Raceway) +-- Discord: https://discord.gg/R6EkZ94TKK +-- Cast the most important buffs on you, tanks or party/raid members/pets. +------------------------------------------------------------------------------- + +local _; +local S = SMARTBUFF_GLOBALS; + +SMARTBUFF_PLAYERCLASS = nil; +SMARTBUFF_BUFFLIST = nil; + +-- Buff types +SMARTBUFF_CONST_ALL = "ALL"; +SMARTBUFF_CONST_GROUP = "GROUP"; +SMARTBUFF_CONST_GROUPALL = "GROUPALL"; +SMARTBUFF_CONST_SELF = "SELF"; +SMARTBUFF_CONST_FORCESELF = "FORCESELF"; +SMARTBUFF_CONST_TRACK = "TRACK"; +SMARTBUFF_CONST_WEAPON = "WEAPON"; +SMARTBUFF_CONST_INV = "INVENTORY"; +SMARTBUFF_CONST_FOOD = "FOOD"; +SMARTBUFF_CONST_SCROLL = "SCROLL"; +SMARTBUFF_CONST_POTION = "POTION"; +SMARTBUFF_CONST_STANCE = "STANCE"; +SMARTBUFF_CONST_ITEM = "ITEM"; +SMARTBUFF_CONST_ITEMGROUP = "ITEMGROUP"; +SMARTBUFF_CONST_TOY = "TOY"; + +S.CheckPet = "CHECKPET"; +S.CheckPetNeeded = "CHECKPETNEEDED"; +S.CheckFishingPole = "CHECKFISHINGPOLE"; +S.NIL = "x"; +S.Toybox = { }; + +local function GetItems(items) + local t = { }; + for _, id in pairs(items) do + local name = GetItemInfo(id); + if (name) then + --print("Item found: "..id..", "..name); + tinsert(t, name); + end + end + return t; +end + +local function InsertItem(t, type, itemId, spellId, duration, link) + local item = GetItemInfo(itemId); + local spell = GetSpellInfo(spellId); + if (item and spell) then + --print("Item found: "..item..", "..spell); + tinsert(t, {item, duration, type, nil, spell, link}); + end +end + +local function AddItem(itemId, spellId, duration, link) + InsertItem(SMARTBUFF_SCROLL, SMARTBUFF_CONST_SCROLL, itemId, spellId, duration, link); +end + + +---------------------------------------------------------------------------------------------------------------------------------- +--- +--- Initialise Item List +--- +---------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_InitItemList() + + -- Reagents + SMARTBUFF_WILDBERRIES = GetItemInfo(17021); -- Wild Berries + SMARTBUFF_WILDTHORNROOT = GetItemInfo(17026); -- Wild Thornroot + SMARTBUFF_WILDQUILLVINE = GetItemInfo(22148); -- Wild Quillvine + SMARTBUFF_ARCANEPOWDER = GetItemInfo(17020); -- Arcane Powder + SMARTBUFF_HOLYCANDLE = GetItemInfo(17028); -- Holy Candle + SMARTBUFF_SACREDCANDLE = GetItemInfo(17029); -- Sacred Candle + SMARTBUFF_SYMBOLOFKINGS = GetItemInfo(21177); -- Symbol of Kings + + -- Stones and oils etc. + SMARTBUFF_LESSERMANAOIL = GetItemInfo(20747); -- Lesser Mana Oil + SMARTBUFF_BRILLIANTMANAOIL = GetItemInfo(20748); -- Brilliant Mana Oil + SMARTBUFF_BRILLIANTWIZARDOIL = GetItemInfo(20749); -- Brilliant Wizard Oil + SMARTBUFF_SUPERIORMANAOIL = GetItemInfo(22521); -- Brilliant Mana Oil + SMARTBUFF_SUPERIORWIZARDOIL = GetItemInfo(22522); -- Superior Wizard Oil + SMARTBUFF_OILOFIMMOLATION = GetItemInfo(8956); -- Oil of Immolation + SMARTBUFF_SOLIDWSTONE = GetItemInfo(7965); -- Solid Weighstone + SMARTBUFF_SOLIDSSTONE = GetItemInfo(7964); -- Solid Sharpening Stone + SMARTBUFF_ELEMENTALSSTONE = GetItemInfo(18262); -- Solid Weightstone + SMARTBUFF_ADAMANTITEWSTONE = GetItemInfo(28421); -- Adamantite Weightstone + SMARTBUFF_ADAMANTITESSTONE = GetItemInfo(23529); -- Adamantite Sharpening Stone + SMARTBUFF_HEAVYWSTONE = GetItemInfo(3241); -- Heavy Weighstone + SMARTBUFF_HEAVYSSTONE = GetItemInfo(2871); -- Heavy Sharpening Stone + SMARTBUFF_WEIGHSTONE = GetItemInfo(28420); -- Fel Weighstone + SMARTBUFF_FELSHARPENINGSTONE = GetItemInfo(23528); -- Greater Rune of Warding + + -- Poisons (some + SMARTBUFF_INSTANTPOISON1 = GetItemInfo(6947); -- Instant Poison + SMARTBUFF_INSTANTPOISON2 = GetItemInfo(6949); -- Instant Poison II + SMARTBUFF_INSTANTPOISON3 = GetItemInfo(6950); -- Instant Poison III + SMARTBUFF_INSTANTPOISON4 = GetItemInfo(8926); -- Instant Poison IV + SMARTBUFF_INSTANTPOISON5 = GetItemInfo(8927); -- Instant Poison V + SMARTBUFF_INSTANTPOISON6 = GetItemInfo(8928); -- Instant Poison VI + SMARTBUFF_INSTANTPOISON7 = GetItemInfo(21927); -- Instant Poison VII + SMARTBUFF_WOUNDPOISON1 = GetItemInfo(10918); -- Wound Poison + SMARTBUFF_WOUNDPOISON2 = GetItemInfo(10920); -- Wound Poison II + SMARTBUFF_WOUNDPOISON3 = GetItemInfo(10921); -- Wound Poison III + SMARTBUFF_WOUNDPOISON4 = GetItemInfo(10922); -- Wound Poison IV + SMARTBUFF_WOUNDPOISON5 = GetItemInfo(22055); -- Wound Poison V + SMARTBUFF_MINDPOISON1 = GetItemInfo(5237); -- Mind-numbing Poison + SMARTBUFF_MINDPOISON2 = GetItemInfo(6951); -- Mind-numbing Poison II + SMARTBUFF_MINDPOISON3 = GetItemInfo(9186); -- Mind-numbing Poison III + SMARTBUFF_DEADLYPOISON1 = GetItemInfo(2892); -- Deadly Poison + SMARTBUFF_DEADLYPOISON2 = GetItemInfo(2893); -- Deadly Poison II + SMARTBUFF_DEADLYPOISON3 = GetItemInfo(8984); -- Deadly Poison III + SMARTBUFF_DEADLYPOISON4 = GetItemInfo(8985); -- Deadly Poison IV + SMARTBUFF_DEADLYPOISON5 = GetItemInfo(20844); -- Deadly Poison V + SMARTBUFF_DEADLYPOISON6 = GetItemInfo(22053); -- Deadly Poison VI + SMARTBUFF_DEADLYPOISON7 = GetItemInfo(22054); -- Deadly Poison VII + SMARTBUFF_CRIPPLINGPOISON1 = GetItemInfo(3775); -- Crippling Poison + SMARTBUFF_CRIPPLINGPOISON2 = GetItemInfo(3776); -- Crippling Poison II + SMARTBUFF_ANESTHETICPOISON1 = GetItemInfo(21835); -- Anesthetic Poison + + -- Food + SMARTBUFF_GOLDENFISHSTICKS_ITEM = GetItemInfo(27666); -- Golden Fish Sticks + SMARTBUFF_FISHERMANSFEAST_ITEM = GetItemInfo(33052); -- Fisherman's Feast + SMARTBUFF_SKULLFISHSOUP_ITEM = GetItemInfo(33825); -- Skullfish Soup + SMARTBUFF_SPICYHOTTALBUK_ITEM = GetItemInfo(33872); -- Spicy Hot Talbuk + SMARTBUFF_BLACKENEDBASILISK_ITEM = GetItemInfo(27657); -- Blackened Basilisk + SMARTBUFF_BLACKENEDSPOREFISH_ITEM = GetItemInfo(27663); -- Blackened Sporefish + SMARTBUFF_BUZZARDBITES_ITEM = GetItemInfo(27651); -- Buzzard Bites + SMARTBUFF_CLAMBAR_ITEM = GetItemInfo(30155); -- Clam Bar + SMARTBUFF_CRUNCHYSERPENT_ITEM = GetItemInfo(31673); -- Crunchy Serpent + SMARTBUFF_FELTAILDELIGHT_ITEM = GetItemInfo(27662); -- Feltail Delight + SMARTBUFF_GRILLEDMUDFISH_ITEM = GetItemInfo(27664); -- Grilled Mudfish + SMARTBUFF_HELBOARBACON_ITEM = GetItemInfo(29292); -- Hellboar Bacon + SMARTBUFF_MOKNATHAKSHORTRIBS_ITEM = GetItemInfo(31672); -- Mok'Nathal Shortribs + SMARTBUFF_POACHEDBLUEFISH_ITEM = GetItemInfo(27665); -- Poached Bluefish + SMARTBUFF_RAVAGERDOG_ITEM = GetItemInfo(27655); -- Ravager Dog + SMARTBUFF_ROASTEDCLEFTHOOF_ITEM = GetItemInfo(27658); -- Roasted Clefthoof + SMARTBUFF_SPICYCRAWDAD_ITEM = GetItemInfo(27667); -- Spicy Crawdad + SMARTBUFF_TALBUKSTEAK_ITEM = GetItemInfo(27660); -- Talbuk Steak + SMARTBUFF_WARPBURGER_ITEM = GetItemInfo(27659); -- Warp Burger + SMARTBUFF_CHARREDBEARKABOBS_ITEM = GetItemInfo(35563); -- Charred Bear Kabobs + SMARTBUFF_ORONOKSTUBERSPELL_ITEM = GetItemInfo(30361); -- Oronok's Tuber of Spell Power + SMARTBUFF_ORONOKSTUBERAGILITY_ITEM = GetItemInfo(30358); -- Oronok's Tuber of Agility + SMARTBUFF_ORONOKSTUBERHEALS_ITEM = GetItemInfo(30357); -- Oronok's Tuber of Healing + SMARTBUFF_ORONOKSTUBERSTRENGTH_ITEM = GetItemInfo(30359); -- Oronok's Tuber of Strength + SMARTBUFF_HOTAPPLECIDER_ITEM = GetItemInfo(34411); -- Hot Apple Cider + SMARTBUFF_SKYGUARDRATIONS_ITEM = GetItemInfo(32721); -- Skyguard Rations + SMARTBUFF_DIRGESKICKINCHOPS_ITEM = GetItemInfo(21023); -- Dirge's Kickin' Chimaerok Chops + SMARTBUFF_JUICYBEARBURGER_ITEM = GetItemInfo(35565); -- Juicy Bear Burger + SMARTBUFF_NIGHTFINSOUP_ITEM = GetItemInfo(13931); -- Nightfin Soup + + + -- Conjured mage food / Water IDs + S.FoodMage = GetItems({587, 597, 990, 6129, 10144, 10145, 28612, 33717 }); + S.WaterMage = GetItems({5504, 5505, 5506, 6127, 10138, 10139, 10140, 37420, 27090}); + S.MageManaBuscuit = ({34062}); + + -- Scrolls + SMARTBUFF_SOAGILITY1 = GetItemInfo(3012); -- Scroll of Agility I + SMARTBUFF_SOAGILITY2 = GetItemInfo(1477); -- Scroll of Agility II + SMARTBUFF_SOAGILITY3 = GetItemInfo(4425); -- Scroll of Agility III + SMARTBUFF_SOAGILITY4 = GetItemInfo(10309); -- Scroll of Agility IV + SMARTBUFF_SOAGILITY5 = GetItemInfo(27498); -- Scroll of Agility V + SMARTBUFF_SOINTELLECT1 = GetItemInfo(955); -- Scroll of Intellect I + SMARTBUFF_SOINTELLECT2 = GetItemInfo(2290); -- Scroll of Intellect II + SMARTBUFF_SOINTELLECT3 = GetItemInfo(4419); -- Scroll of Intellect III + SMARTBUFF_SOINTELLECT4 = GetItemInfo(10308); -- Scroll of Intellect IV + SMARTBUFF_SOINTELLECT5 = GetItemInfo(27499); -- Scroll of Intellect V + SMARTBUFF_SOSTAMINA1 = GetItemInfo(1180); -- Scroll of Stamina I + SMARTBUFF_SOSTAMINA2 = GetItemInfo(1711); -- Scroll of Stamina II + SMARTBUFF_SOSTAMINA3 = GetItemInfo(4422); -- Scroll of Stamina III + SMARTBUFF_SOSTAMINA4 = GetItemInfo(10307); -- Scroll of Stamina IV + SMARTBUFF_SOSTAMINA5 = GetItemInfo(27502); -- Scroll of Stamina V + SMARTBUFF_SOSPIRIT1 = GetItemInfo(1181); -- Scroll of Spirit I + SMARTBUFF_SOSPIRIT2 = GetItemInfo(1712); -- Scroll of Spirit II + SMARTBUFF_SOSPIRIT3 = GetItemInfo(4424); -- Scroll of Spirit III + SMARTBUFF_SOSPIRIT4 = GetItemInfo(10306); -- Scroll of Spirit IV + SMARTBUFF_SOSPIRIT5 = GetItemInfo(27501); -- Scroll of Spirit V + SMARTBUFF_SOSTRENGHT1 = GetItemInfo(954); -- Scroll of Strength I + SMARTBUFF_SOSTRENGHT2 = GetItemInfo(2289); -- Scroll of Strength II + SMARTBUFF_SOSTRENGHT3 = GetItemInfo(4426); -- Scroll of Strength III + SMARTBUFF_SOSTRENGHT4 = GetItemInfo(10310); -- Scroll of Strength IV + SMARTBUFF_SOSTRENGHT5 = GetItemInfo(27503); -- Scroll of Strength V + SMARTBUFF_SOPROTECTION1 = GetItemInfo(3013); -- Scroll of Protection I + SMARTBUFF_SOPROTECTION2 = GetItemInfo(1478); -- Scroll of Protection II + SMARTBUFF_SOPROTECTION3 = GetItemInfo(4421); -- Scroll of Protection III + SMARTBUFF_SOPROTECTION4 = GetItemInfo(10305); -- Scroll of Protection IV + SMARTBUFF_SOPROTECTION5 = GetItemInfo(27500); -- Scroll of Protection IV + + -- Potions / Elixirs / Flasks Items + SMARTBUFF_ADEPTELIXIR_ITEM = GetItemInfo(28103); -- Adept's Elixir + SMARTBUFF_MAJORDEFENSE_ITEM = GetItemInfo(22834); -- Major Defense + SMARTBUFF_MAJORAGILITY_ITEM = GetItemInfo(22831); -- Major Agility + SMARTBUFF_DRAENICWISDOM_ITEM = GetItemInfo(32067); -- Draenic Wisdom + SMARTBUFF_MAJORFROSTPOWER_ITEM = GetItemInfo(22827); -- Major Frost Power + SMARTBUFF_EARTHEN_ITEM = GetItemInfo(32063); -- Earthen Elixir + SMARTBUFF_MASTERY_ITEM = GetItemInfo(28104); -- Elixir of Mastery + SMARTBUFF_CAMOUFLAGE_ITEM = GetItemInfo(22823); -- Elixir of Camouflage + SMARTBUFF_HEALINGPOWER_ITEM = GetItemInfo(22825); -- Elixir of Healing Power + SMARTBUFF_MAJORFORTITUDE_ITEM = GetItemInfo(32062); -- Elixir of Major Fortitude + SMARTBUFF_MAJORSTRENGTH_ITEM = GetItemInfo(22824); -- Elixir of Major Strength + SMARTBUFF_ONSLAUGHTELIXIR_ITEM = GetItemInfo(28102); -- Onslaught Elixir + SMARTBUFF_GREATERARCANE_ITEM = GetItemInfo(13454); -- Greater Arcane + SMARTBUFF_MONGOOSEELIXIR_ITEM = GetItemInfo(13452); -- Elixir of Mongoose + SMARTBUFF_BRUTEFORCE_ITEM = GetItemInfo(13453); -- Elixir of Brute Force + SMARTBUFF_SAGESELIXIR_ITEM = GetItemInfo(13447); -- Elixir of Sages + SMARTBUFF_SUPERIORDEFENSE_ITEM = GetItemInfo(13445); -- Elixir of Superior Defense + SMARTBUFF_DEMONSLAYING_ITEM = GetItemInfo(9224); -- Elixir of Demon Slaying + SMARTBUFF_MAJORFIREPOWER_ITEM = GetItemInfo(22833); -- Elixir of Major Fire Power + SMARTBUFF_GREATERFIREPOWER_ITEM = GetItemInfo(21546); -- Elixir of Greater Fire Power + SMARTBUFF_SHADOWPOWER_ITEM = GetItemInfo(9264); -- Elixir of Shadow Power + SMARTBUFF_GIANTSELIXIR_ITEM = GetItemInfo(9206); -- Elixir of Giants + SMARTBUFF_GREATERAGILITY_ITEM = GetItemInfo(9187); -- Elixir of Greater Agility + SMARTBUFF_GIFTOFARTHAS_ITEM = GetItemInfo(9088); -- Gift of Arthas + SMARTBUFF_ARANCEELIXIR_ITEM = GetItemInfo(9155); -- Arcane Elixir + SMARTBUFF_GREATERINTELLECT_ITEM = GetItemInfo(9179); -- Elixir of Greater Intellect + SMARTBUFF_MAJORNATUREPROT_ITEM = GetItemInfo(22844); -- Major Natur Protection Potion + SMARTBUFF_MAJORMAGEBLOOD_ITEM = GetItemInfo(22840); -- Major Mageblood + SMARTBUFF_MAJORSHADOWPWR_ITEM = GetItemInfo(22835); -- Major Shadow Power + SMARTBUFF_MAJORIRONSKIN_ITEM = GetItemInfo(32068); -- Major Ironskin + SMARTBUFF_BLINDINGLIGHTFLASK_ITEM = GetItemInfo(22861); -- Flask of Blinding Light + SMARTBUFF_FORTIFICATIONFLASK_ITEM = GetItemInfo(22851); -- Flask of Fortification + SMARTBUFF_RESTORATIONFLASK_ITEM = GetItemInfo(22853); -- Flask of Restoration + SMARTBUFF_PUREDEATHFLASK_ITEM = GetItemInfo(22866); -- Flask of Pure Death + SMARTBUFF_RELENTLESSFLASK_ITEM = GetItemInfo(22854); -- Flask of Relentless Assault + SMARTBUFF_CHROMATICFLASK_ITEM = GetItemInfo(13513); -- Flask of Chromatic Resistance + SMARTBUFF_DISTILLEDFLASK_ITEM = GetItemInfo(13511); -- Flask of Distilled Wisdom + SMARTBUFF_SUPREMEPWRFLASK_ITEM = GetItemInfo(13512); -- Flask of Supreme Power + + -- Misc Items + _, _, _, _, _, _, S.FishingPole = GetItemInfo(6256); --"Fishing Pole" + + SMARTBUFF_AddMsgD(">>>> Item list's have been initialised."); + +end + + +---------------------------------------------------------------------------------------------------------------------------------- +--- +--- Initialise Spell Id +--- +---------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_InitSpellIDs() + + -- Druid + SMARTBUFF_DRUID_CAT = GetSpellInfo(768); --"Cat Form" + SMARTBUFF_DRUID_TREE = GetSpellInfo(33891); --"Tree of Life" + SMARTBUFF_DRUID_MOONKIN = GetSpellInfo(24858); --"Moonkin Form" + SMARTBUFF_DRUID_TRACK = GetSpellInfo(5225); --"Track Humanoids" + SMARTBUFF_MOTW = GetSpellInfo(1126); --"Mark of the Wild" + SMARTBUFF_GOTWRB1 = GetSpellInfo(21849); --"Gift of the Wild" + SMARTBUFF_THORNS = GetSpellInfo(467); --"Thorns" + SMARTBUFF_IMPTHORNS = GetSpellInfo(16836); --"Improved Thorns" + SMARTBUFF_BARKSKIN = GetSpellInfo(22812); --"Barkskin" + SMARTBUFF_NATURESGRASP = GetSpellInfo(16689); --"Nature's Grasp" + SMARTBUFF_TIGERSFURY = GetSpellInfo(5217); --"Tiger's Fury" + SMARTBUFF_SAVAGEROAR = GetSpellInfo(52610); --"Savage Roar" + SMARTBUFF_OMENOFCLARITY = GetSpellInfo(16864); --"Omen of Clarity" + + -- Druid linked + S.LinkDruidThorns = { SMARTBUFF_THORNS, SMARTBUFF_IMPTHORNS }; + S.LinkDruidGOTW = { SMARTBUFF_MOTW, SMARTBUFF_GOTWRB1} + + -- Priest + SMARTBUFF_PWF = GetSpellInfo(1243); --"Power Word: Fortitude" + SMARTBUFF_POFRB1 = GetSpellInfo(21562); --"Prayer of Fortitude" + SMARTBUFF_SP = GetSpellInfo(976); --"Shadow Protection" + SMARTBUFF_POSPRB1 = GetSpellInfo(27683); --"Prayer of Shadow Protection" + SMARTBUFF_INNERFIRE = GetSpellInfo(588); --"Inner Fire" + SMARTBUFF_DS = GetSpellInfo(14752); --"Divine Spirit" + SMARTBUFF_POSRB1 = GetSpellInfo(27681); --"Prayer of Spirit" + SMARTBUFF_PWS = GetSpellInfo(17); --"Power Word: Shield" + SMARTBUFF_SHADOWFORM = GetSpellInfo(15473); --"Shadowform" + SMARTBUFF_FEARWARD = GetSpellInfo(6346); --"Fear Ward" + SMARTBUFF_ELUNESGRACE = GetSpellInfo(2651); --"Elune's Grace" + SMARTBUFF_FEEDBACK = GetSpellInfo(13896); --"Feedback" + SMARTBUFF_SHADOWGUARD = GetSpellInfo(18137); --"Shadowguard" + SMARTBUFF_TOUCHOFWEAKNESS = GetSpellInfo(2652); --"Touch of Weakness" + SMARTBUFF_INNERFOCUS = GetSpellInfo(14751); --"Inner Focus" + SMARTBUFF_RENEW = GetSpellInfo(139); --"Renew" + + + S.ChainPriestFortBuffs = { SMARTBUFF_PWF, SMARTBUFF_POFRB1}; + S.ChainPriestSpiritBuffs = { SMARTBUFF_DS, SMARTBUFF_POSRB1}; + S.ChainPriestShadowBuffs = { SMARTBUFF_SP, SMARTBUFF_POSPRB1}; + + + -- Mage + SMARTBUFF_AI = GetSpellInfo(1459); --"Arcane Intellect" + SMARTBUFF_ABRB1 = GetSpellInfo(23028); --"Arcane Brilliance" + SMARTBUFF_ICEARMOR = GetSpellInfo(7302); --"Ice Armor" + SMARTBUFF_FROSTARMOR = GetSpellInfo(168); --"Frost Armor" + SMARTBUFF_MAGEARMOR = GetSpellInfo(6117); --"Mage Armor" + SMARTBUFF_MOLTENARMOR = GetSpellInfo(30482); --"Molten Armor" + SMARTBUFF_DAMPENMAGIC = GetSpellInfo(604); --"Dampen Magic" + SMARTBUFF_AMPLIFYMAGIC = GetSpellInfo(1008); --"Amplify Magic" + SMARTBUFF_MANASHIELD = GetSpellInfo(1463); --"Mana Shield" + SMARTBUFF_FIREWARD = GetSpellInfo(543); --"Fire Ward" + SMARTBUFF_FROSTWARD = GetSpellInfo(6143); --"Frost Ward" + SMARTBUFF_ICEBARRIER = GetSpellInfo(11426); --"Ice Barrier" + SMARTBUFF_COMBUSTION = GetSpellInfo(11129); --"Combustion" + SMARTBUFF_ARCANEPOWER = GetSpellInfo(12042); --"Arcane Power" + SMARTBUFF_PRESENCEOFMIND = GetSpellInfo(12043); --"Presence of Mind" + SMARTBUFF_ICYVEINS = GetSpellInfo(12472); --"Icy Veins" + SMARTBUFF_SUMMONWATERELE = GetSpellInfo(31687); --"Summon Water Elemental" + SMARTBUFF_FOCUSMAGIC = GetSpellInfo(54646); --"Focus Magic" + + -- Mage chained + S.ChainMageArmor = { SMARTBUFF_ICEARMOR, SMARTBUFF_FROSTARMOR, SMARTBUFF_MAGEARMOR, SMARTBUFF_MOLTENARMOR }; + S.ChainMageBuffs = { SMARTBUFF_AI, SMARTBUFF_ABRB1}; + + -- Warlock + SMARTBUFF_FELARMOR = GetSpellInfo(28176); --"Fel Armor" + SMARTBUFF_DEMONARMOR = GetSpellInfo(706); --"Demon Armor" + SMARTBUFF_DEMONSKIN = GetSpellInfo(687); --"Demon Skin" + SMARTBUFF_UNENDINGBREATH = GetSpellInfo(5697); --"Unending Breath" + SMARTBUFF_DINVISIBILITY = GetSpellInfo(132); --"Detect Invisibility" + SMARTBUFF_SOULLINK = GetSpellInfo(19028); --"Soul Link" + SMARTBUFF_SHADOWWARD = GetSpellInfo(6229); --"Shadow Ward" + SMARTBUFF_DARKPACT = GetSpellInfo(18220); --"Dark Pact" + SMARTBUFF_LIFETAP = GetSpellInfo(1454); --"Life Tap" + SMARTBUFF_CREATEHSMIN = GetSpellInfo(6201); --"Create Healthstone (Minor)" + SMARTBUFF_CREATEHSLES = GetSpellInfo(6202); --"Create Healthstone (Lesser)" + SMARTBUFF_CREATEHS = GetSpellInfo(5699); --"Create Healthstone" + SMARTBUFF_CREATEHSGRE = GetSpellInfo(11729); --"Create Healthstone (Greater)" + SMARTBUFF_CREATEHSMAJ = GetSpellInfo(11730); --"Create Healthstone (Major)" + SMARTBUFF_SOULSTONE = GetSpellInfo(20707); --"Soulstone" + SMARTBUFF_CREATESSMIN = GetSpellInfo(693); --"Create Soulstone (Minor)" + SMARTBUFF_CREATESSLES = GetSpellInfo(20752); --"Create Soulstone (Lesser)" + SMARTBUFF_CREATESS = GetSpellInfo(20755); --"Create Soulstone" + SMARTBUFF_CREATESSGRE = GetSpellInfo(20756); --"Create Soulstone (Greater)" + SMARTBUFF_CREATESSMAJ = GetSpellInfo(20757); --"Create Soulstone (Major)" + + -- Warlock chained + S.ChainWarlockArmor = { SMARTBUFF_DEMONSKIN, SMARTBUFF_DEMONARMOR, SMARTBUFF_FELARMOR }; + + + -- Hunter + SMARTBUFF_TRUESHOTAURA = GetSpellInfo(19506); --"Trueshot Aura" + SMARTBUFF_RAPIDFIRE = GetSpellInfo(3045); --"Rapid Fire" + SMARTBUFF_AOTH = GetSpellInfo(13165); --"Aspect of the Hawk" + SMARTBUFF_AOTM = GetSpellInfo(13163); --"Aspect of the Monkey" + SMARTBUFF_AOTW = GetSpellInfo(20043); --"Aspect of the Wild" + SMARTBUFF_AOTB = GetSpellInfo(13161); --"Aspect of the Beast" + SMARTBUFF_AOTC = GetSpellInfo(5118); --"Aspect of the Cheetah" + SMARTBUFF_AOTP = GetSpellInfo(13159); --"Aspect of the Pack" + SMARTBUFF_AOTV = GetSpellInfo(34074); --"Aspect of the Viper" + SMARTBUFF_AOTDH = GetSpellInfo(61846); --"Aspect of the Dragonhawk" + + -- Hunter chained + S.ChainAspects = { SMARTBUFF_AOTH,SMARTBUFF_AOTM,SMARTBUFF_AOTW,SMARTBUFF_AOTB,SMARTBUFF_AOTC,SMARTBUFF_AOTP,SMARTBUFF_AOTV,SMARTBUFF_AOTDH }; + + + -- Shaman + SMARTBUFF_LIGHTNINGSHIELD = GetSpellInfo(324); --"Lightning Shield" + SMARTBUFF_WATERSHIELD = GetSpellInfo(24398); --"Water Shield" + SMARTBUFF_EARTHSHIELD = GetSpellInfo(974); --"Earth Shield" + SMARTBUFF_ROCKBITERW = GetSpellInfo(8017); --"Rockbiter Weapon" + SMARTBUFF_FROSTBRANDW = GetSpellInfo(8033); --"Frostbrand Weapon" + SMARTBUFF_FLAMETONGUEW = GetSpellInfo(8024); --"Flametongue Weapon" + SMARTBUFF_WINDFURYW = GetSpellInfo(8232); --"Windfury Weapon" + SMARTBUFF_EARTHLIVINGW = GetSpellInfo(51730); --"Earthliving Weapon" + SMARTBUFF_WATERBREATHING = GetSpellInfo(131); --"Water Breathing" + SMARTBUFF_WATERWALKING = GetSpellInfo(546); --"Water Walking" + + -- Shaman chained + S.ChainShamanShield = { SMARTBUFF_LIGHTNINGSHIELD, SMARTBUFF_WATERSHIELD, SMARTBUFF_EARTHSHIELD }; + + + -- Warrior + SMARTBUFF_BATTLESHOUT = GetSpellInfo(6673); --"Battle Shout" + SMARTBUFF_COMMANDINGSHOUT = GetSpellInfo(469); --"Commanding Shout" + SMARTBUFF_BERSERKERRAGE = GetSpellInfo(18499); --"Berserker Rage" + SMARTBUFF_BLOODRAGE = GetSpellInfo(2687); --"Bloodrage" + SMARTBUFF_RAMPAGE = GetSpellInfo(29801); --"Rampage" + SMARTBUFF_VIGILANCE = GetSpellInfo(50720); --"Vigilance" + SMARTBUFF_SHIELDBLOCK = GetSpellInfo(2565); --"Shield Block" + + -- Warrior chained + S.ChainWarriorShout = { SMARTBUFF_BATTLESHOUT, SMARTBUFF_COMMANDINGSHOUT }; + + + -- Rogue + SMARTBUFF_BLADEFLURRY = GetSpellInfo(13877); --"Blade Flurry" + SMARTBUFF_SAD = GetSpellInfo(5171); --"Slice and Dice" + SMARTBUFF_EVASION = GetSpellInfo(5277); --"Evasion" + SMARTBUFF_HUNGERFORBLOOD = GetSpellInfo(51662); --"Hunger For Blood" + SMARTBUFF_STEALTH = GetSpellInfo(1784); --"Stealth" + + + -- Paladin + SMARTBUFF_RIGHTEOUSFURY = GetSpellInfo(25780); --"Righteous Fury" + SMARTBUFF_HOLYSHIELD = GetSpellInfo(20925); --"Holy Shield" + SMARTBUFF_BOM = GetSpellInfo(19740); --"Blessing of Might" + SMARTBUFF_GBOM = GetSpellInfo(25782); --"Greater Blessing of Might" + SMARTBUFF_BOW = GetSpellInfo(19742); --"Blessing of Wisdom" + SMARTBUFF_GBOW = GetSpellInfo(25894); --"Greater Blessing of Wisdom" + SMARTBUFF_BOSAL = GetSpellInfo(1038); --"Blessing of Salvation" + SMARTBUFF_GBOSAL = GetSpellInfo(25895); --"Greater Blessing of Salvation" + SMARTBUFF_BOK = GetSpellInfo(20217); --"Blessing of Kings" + SMARTBUFF_GBOK = GetSpellInfo(25898); --"Greater Blessing of Kings" + SMARTBUFF_BOSAN = GetSpellInfo(20911); --"Blessing of Sanctuary" + SMARTBUFF_GBOSAN = GetSpellInfo(25899); --"Greater Blessing of Sanctuary" +-- SMARTBUFF_BOF = GetSpellInfo(1044); --"Blessing of Freedom" +-- SMARTBUFF_BOP = GetSpellInfo(1022); --"Blessing of Protection" + SMARTBUFF_SOCOMMAND = GetSpellInfo(20375); --"Seal of Command" + SMARTBUFF_SOJUSTICE = GetSpellInfo(20164); --"Seal of Justice" + SMARTBUFF_SOLIGHT = GetSpellInfo(20165); --"Seal of Light" + SMARTBUFF_SORIGHTEOUSNESS = GetSpellInfo(21084); --"Seal of Righteousness" + SMARTBUFF_SOWISDOM = GetSpellInfo(20166); --"Seal of Wisdom" + SMARTBUFF_SOTCRUSADER = GetSpellInfo(21082); --"Seal of the Crusader" + SMARTBUFF_SOVENGEANCE = GetSpellInfo(31801); --"Seal of Vengeance" + SMARTBUFF_SOBLOOD = GetSpellInfo(31892); --"Seal of Blood" + SMARTBUFF_SOCORRUPTION = GetSpellInfo(53736); --"Seal of Corruption" + SMARTBUFF_SOMARTYR = GetSpellInfo(53720); --"Seal of the Martyr" + SMARTBUFF_DEVOTIONAURA = GetSpellInfo(465); --"Devotion Aura" + SMARTBUFF_RETRIBUTIONAURA = GetSpellInfo(7294); --"Retribution Aura" + SMARTBUFF_CONCENTRATIONAURA = GetSpellInfo(19746); --"Concentration Aura" + SMARTBUFF_SHADOWRESISTANCEAURA = GetSpellInfo(19876); --"Shadow Resistance Aura" + SMARTBUFF_FROSTRESISTANCEAURA = GetSpellInfo(19888); --"Frost Resistance Aura" + SMARTBUFF_FIRERESISTANCEAURA = GetSpellInfo(19891); --"Fire Resistance Aura" + SMARTBUFF_SANCTITYAURA = GetSpellInfo(20218); --"Sanctity Aura" + SMARTBUFF_CRUSADERAURA = GetSpellInfo(32223); --"Crusader Aura" + + -- Paladin chained + S.ChainPaladinBOM = { SMARTBUFF_BOM, SMARTBUFF_GBOM }; + S.ChainPaladinBOW = { SMARTBUFF_BOW, SMARTBUFF_GBOW }; + S.ChainPaladinSAL = { SMARTBUFF_BOSAL, SMARTBUFF_GBOSAL }; + S.ChainPaladinBOK = { SMARTBUFF_BOK, SMARTBUFF_GBOK }; + S.ChainPaladinSAN = { SMARTBUFF_BOSAN, SMARTBUFF_GBOSAN }; + S.ChainPaladinSeal = { SMARTBUFF_SOCOMMAND, SMARTBUFF_SOJUSTICE, SMARTBUFF_SOLIGHT, SMARTBUFF_SORIGHTEOUSNESS, SMARTBUFF_SOWISDOM, SMARTBUFF_SOTCRUSADER, SMARTBUFF_SOVENGEANCE, SMARTBUFF_SOBLOOD, SMARTBUFF_SOCORRUPTION, SMARTBUFF_SOMARTYR }; + S.ChainPaladinAura = { SMARTBUFF_DEVOTIONAURA, SMARTBUFF_RETRIBUTIONAURA, SMARTBUFF_CONCENTRATIONAURA, SMARTBUFF_SHADOWRESISTANCEAURA, SMARTBUFF_FROSTRESISTANCEAURA, SMARTBUFF_FIRERESISTANCEAURA, SMARTBUFF_SANCTITYAURA, SMARTBUFF_CRUSADERAURA }; + + -- Death Knight + SMARTBUFF_DANCINGRW = GetSpellInfo(49028); --"Dancing Rune Weapon" +-- SMARTBUFF_BLOODPRESENCE = GetSpellInfo(48263); --"Blood Presence" +-- SMARTBUFF_FROSTPRESENCE = GetSpellInfo(48266); --"Frost Presence" +-- SMARTBUFF_UNHOLYPRESENCE = GetSpellInfo(48265); --"Unholy Presence" + SMARTBUFF_PATHOFFROST = GetSpellInfo(3714); --"Path of Frost" +-- SMARTBUFF_BONESHIELD = GetSpellInfo(49222); --"Bone Shield" + SMARTBUFF_HORNOFWINTER = GetSpellInfo(57330); --"Horn of Winter" + SMARTBUFF_RAISEDEAD = GetSpellInfo(46584); --"Raise Dead" +-- SMARTBUFF_POTGRAVE = GetSpellInfo(155522); --"Power of the Grave" (P) + + -- Death Knight buff links + S.ChainDKPresence = { SMARTBUFF_BLOODPRESENCE, SMARTBUFF_FROSTPRESENCE, SMARTBUFF_UNHOLYPRESENCE }; + + + -- Tracking + SMARTBUFF_FINDMINERALS = GetSpellInfo(2580); --"Find Minerals" + SMARTBUFF_FINDHERBS = GetSpellInfo(2383); --"Find Herbs" + SMARTBUFF_FINDTREASURE = GetSpellInfo(2481); --"Find Treasure" + SMARTBUFF_TRACKHUMANOIDS = GetSpellInfo(19883); --"Track Humanoids" + SMARTBUFF_TRACKBEASTS = GetSpellInfo(1494); --"Track Beasts" + SMARTBUFF_TRACKUNDEAD = GetSpellInfo(19884); --"Track Undead" + SMARTBUFF_TRACKHIDDEN = GetSpellInfo(19885); --"Track Hidden" + SMARTBUFF_TRACKELEMENTALS = GetSpellInfo(19880); --"Track Elementals" + SMARTBUFF_TRACKDEMONS = GetSpellInfo(19878); --"Track Demons" + SMARTBUFF_TRACKGIANTS = GetSpellInfo(19882); --"Track Giants" + SMARTBUFF_TRACKDRAGONKIN = GetSpellInfo(19879); --"Track Dragonkin" + SMARTBUFF_SENSEDEMONS = GetSpellInfo(5500); --"Sense Demons" + SMARTBUFF_SENSEUNDEAD = GetSpellInfo(5502); --"Sense Undead" + + -- Racial + SMARTBUFF_STONEFORM = GetSpellInfo(20594); --"Stoneform" + SMARTBUFF_BLOODFURY = GetSpellInfo(20572); --"Blood Fury" 33697, 33702 + SMARTBUFF_BERSERKING = GetSpellInfo(26297); --"Berserking" + SMARTBUFF_WOTFORSAKEN = GetSpellInfo(7744); --"Will of the Forsaken" + SMARTBUFF_WarStomp = GetSpellInfo(20549); --"War Stomp" + + -- Food + SMARTBUFF_FOOD_AURA = GetSpellInfo(19705); --"Well Fed" + SMARTBUFF_FOOD_SPELL = GetSpellInfo(433); --"Food" + SMARTBUFF_DRINK_SPELL = GetSpellInfo(430); --"Drink" + + -- Misc + SMARTBUFF_KIRUSSOV = GetSpellInfo(46302); --"K'iru's Song of Victory" + SMARTBUFF_FISHING = GetSpellInfo(7620) or GetSpellInfo(111541); --"Fishing" + + + -- Scroll + SMARTBUFF_SBAGILITY = GetSpellInfo(8115); -- Scroll buff: Agility + SMARTBUFF_SBINTELLECT = GetSpellInfo(8096); -- Scroll buff: Intellect + SMARTBUFF_SBSTAMINA = GetSpellInfo(8099); -- Scroll buff: Stamina + SMARTBUFF_SBSPIRIT = GetSpellInfo(8112); -- Scroll buff: Spirit + SMARTBUFF_SBSTRENGHT = GetSpellInfo(8118); -- Scroll buff: Strength + SMARTBUFF_SBPROTECTION = GetSpellInfo(89344); -- Scroll buff: Armor + + --- Burning Crusade Classic - Potions / Flasks / Elixirs + SMARTBUFF_ADEPTELIXIR_BUFF = GetSpellInfo(33740); -- Adept's Elixir + SMARTBUFF_MAJORDEFENSE_BUFF = GetSpellInfo(28557); -- Major Defense + SMARTBUFF_MAJORAGILITY_BUFF = GetSpellInfo(28497); -- Major Agility + SMARTBUFF_DRAENICWISDOM_BUFF = GetSpellInfo(39638); -- Draenic Wisdom + SMARTBUFF_MAJORFROSTPOWER_BUFF = GetSpellInfo(28549); -- Major Frost Power + SMARTBUFF_EARTHEN_BUFF = GetSpellInfo(39637); -- Earthen Elixir + SMARTBUFF_MASTERY_BUFF = GetSpellInfo(33741); -- Elixir of Mastery + SMARTBUFF_CAMOUFLAGE_BUFF = GetSpellInfo(28543); -- Elixir of Camouflage + SMARTBUFF_HEALINGPOWER_BUFF = GetSpellInfo(28545); -- Elixir of Healing Power + SMARTBUFF_MAJORFORTITUDE_BUFF = GetSpellInfo(39636); -- Elixir of Major Fortitude + SMARTBUFF_MAJORSTRENGTH_BUFF = GetSpellInfo(28544); -- Elixir of Major Strength + SMARTBUFF_ONSLAUGHTELIXIR_BUFF = GetSpellInfo(33738); -- Onslaught Elixir + SMARTBUFF_GREATERARCANE_BUFF = GetSpellInfo(17573); -- Greater Arcane + SMARTBUFF_MONGOOSEELIXIR_BUFF = GetSpellInfo(17571); -- Elixir of Mongoose + SMARTBUFF_BRUTEFORCE_BUFF = GetSpellInfo(17557); -- Elixir of Brute Force + SMARTBUFF_SAGESELIXIR_BUFF = GetSpellInfo(17555); -- Elixir of Sages + SMARTBUFF_SUPERIORDEFENSE_BUFF = GetSpellInfo(17554); -- Elixir of Superior Defense + SMARTBUFF_DEMONSLAYING_BUFF = GetSpellInfo(11477); -- Elixir of Demon Slaying + SMARTBUFF_MAJORFIREPOWER_BUFF = GetSpellInfo(28556); -- Elixir of Major Fire Power + SMARTBUFF_GREATERFIREPOWER_BUFF = GetSpellInfo(26277); -- Elixir of Greater Fire Power + SMARTBUFF_SHADOWPOWER_BUFF = GetSpellInfo(11476); -- Elixir of Shadow Power + SMARTBUFF_GIANTSELIXIR_BUFF = GetSpellInfo(11472); -- Elixir of Giants + SMARTBUFF_GREATERAGILITY_BUFF = GetSpellInfo(11467); -- Elixir of Greater Agility + SMARTBUFF_GIFTOFARTHAS_BUFF = GetSpellInfo(11466); -- Gift of Arthas + SMARTBUFF_ARANCEELIXIR_BUFF = GetSpellInfo(11461); -- Arcane Elixir + SMARTBUFF_GREATERINTELLECT_BUFF = GetSpellInfo(11465); -- Elixir of Greater Intellect + SMARTBUFF_MAJORNATUREPROT_BUFF = GetSpellInfo(28573); -- Major Natur Protection Potion + SMARTBUFF_MAJORMAGEBLOOD_BUFF = GetSpellInfo(28570); -- Major Mageblood + SMARTBUFF_MAJORSHADOWPWR_BUFF = GetSpellInfo(28558); -- Major Shadow Power + SMARTBUFF_MAJORIRONSKIN_BUFF = GetSpellInfo(39639); -- Major Ironskin + SMARTBUFF_BLINDINGLIGHTFLASK_BUFF = GetSpellInfo(28590); -- Flask of Blinding Light + SMARTBUFF_FORTIFICATIONFLASK_BUFF = GetSpellInfo(28587); -- Flask of Fortification + SMARTBUFF_RESTORATIONFLASK_BUFF = GetSpellInfo(28588); -- Flask of Restoration + SMARTBUFF_PUREDEATHFLASK_BUFF = GetSpellInfo(28591); -- Flask of Pure Death + SMARTBUFF_RELENTLESSFLASK_BUFF = GetSpellInfo(28589); -- Flask of Relentless Assault + SMARTBUFF_CHROMATICFLASK_BUFF = GetSpellInfo(17638); -- Flask of Chromatic Resistance + SMARTBUFF_DISTILLEDFLASK_BUFF = GetSpellInfo(17636); -- Flask of Distilled Wisdom + SMARTBUFF_SUPREMEPWRFLASK_BUFF = GetSpellInfo(17637); -- Flask of Supreme Power + + + -- Buff map + S.LinkStats = { SMARTBUFF_BOK, SMARTBUFF_MOTW, SMARTBUFF_LOTE, SMARTBUFF_LOTWT, SMARTBUFF_MOTWR1, SMARTBUFF_MOTWR2, SMARTBUFF_MOTWR3, + SMARTBUFF_MOTWR4, SMARTBUFF_MOTWR5, SMARTBUFF_MOTWR6, SMARTBUFF_MOTWR7, SMARTBUFF_GOTWR1, SMARTBUFF_GOTWR2, + GetSpellInfo(159988), -- Bark of the Wild + GetSpellInfo(203538), -- Greater Blessing of Kings + GetSpellInfo(90363), -- Embrace of the Shale Spider + GetSpellInfo(160077), -- Strength of the Earth + SMARTBUFF_DSR1, SMARTBUFF_DSR2, SMARTBUFF_DSR3, SMARTBUFF_DSR4, SMARTBUFF_SWPR1, SMARTBUFF_SWPR2, SMARTBUFF_SWPR3, + SMARTBUFF_PSWPR1, SMARTBUFF_POSR1, + }; + + S.LinkFlaskTBC = { SMARTBUFF_BLINDINGLIGHTFLASK_BUFF, SMARTBUFF_FORTIFICATIONFLASK_BUFF, SMARTBUFF_RESTORATIONFLASK_BUFF, SMARTBUFF_PUREDEATHFLASK_BUFF, + SMARTBUFF_RELENTLESSFLASK_BUFF, SMARTBUFF_CHROMATICFLASK_BUFF, SMARTBUFF_DISTILLEDFLASK_BUFF, SMARTBUFF_SUPREMEPWRFLASK_BUFF}; + + + S.LinkSp = { SMARTBUFF_POSPRB1, SMARTBUFF_POSPRB2 } + S.LinkAp = { SMARTBUFF_HORNOFWINTER, SMARTBUFF_BATTLESHOUT, SMARTBUFF_TRUESHOTAURA }; + + S.LinkMa = { SMARTBUFF_BOM, SMARTBUFF_DRUID_MKAURA, SMARTBUFF_GRACEOFAIR, SMARTBUFF_POTGRAVE, + GetSpellInfo(93435), -- Roar of Courage + GetSpellInfo(160039), -- Keen Senses + GetSpellInfo(128997), -- Spirit Beast Blessing + GetSpellInfo(160073) -- Plainswalking + }; + + S.LinkInt = { SMARTBUFF_BOW, SMARTBUFF_ABRB1, SMARTBUFF_ABRB2, SMARTBUFF_ABR1, SMARTBUFF_AIR1, SMARTBUFF_AIR2, SMARTBUFF_AIR3, SMARTBUFF_AIR4, SMARTBUFF_AIR5, SMARTBUFF_DALARANB }; + + SMARTBUFF_AddMsgD(">>>> Spell ID's have been initialised."); + +end + + +---------------------------------------------------------------------------------------------------------------------------------- +--- +--- Initialise Spell List +--- +---------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_InitSpellList() + if (SMARTBUFF_PLAYERCLASS == nil) then return; end + + -- Druid + if (SMARTBUFF_PLAYERCLASS == "DRUID") then + SMARTBUFF_BUFFLIST = { + -- mark of the wild + {SMARTBUFF_MOTW, 30, SMARTBUFF_CONST_GROUP, {1,10,20,30,40,50,60,70,80}, "HPET;WPET", S.LinkDruidGOTW}, + -- gift of the wild + {SMARTBUFF_GOTWRB1, 60, SMARTBUFF_CONST_GROUP, {50,60,70,80}, "HPET;WPET", S.LinkDruidGOTW, {SMARTBUFF_WILDBERRIES,SMARTBUFF_WILDTHORNROOT}}, + {SMARTBUFF_IMPTHORNS, 10, SMARTBUFF_CONST_GROUP, {6,14}, "HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;WPET;DKPET", S.LinkDruidThorns}, + {SMARTBUFF_THORNS, 10, SMARTBUFF_CONST_GROUP, {6,14,24,34,44,54, 64, 74}, "HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;WPET;DKPET", S.LinkDruidThorns}, + {SMARTBUFF_OMENOFCLARITY, 10, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_BARKSKIN, 0.25, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_NATURESGRASP, 0.75, SMARTBUFF_CONST_FORCESELF}, + {SMARTBUFF_TIGERSFURY, 0.1, SMARTBUFF_CONST_SELF, nil, SMARTBUFF_DRUID_CAT}, + {SMARTBUFF_SAVAGEROAR, 0.15, SMARTBUFF_CONST_SELF, nil, SMARTBUFF_DRUID_CAT}, + {SMARTBUFF_DRUID_MOONKIN, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_DRUID_TREE, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_CENARIONWARD, 0.5, SMARTBUFF_CONST_GROUP, {1}, "WARRIOR;DRUID;SHAMAN;HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;DEATHKNIGHT;MONK;DEMONHUNTER"}, + }; + end + + + -- Priest + if (SMARTBUFF_PLAYERCLASS == "PRIEST") then + SMARTBUFF_BUFFLIST = { + + -- fortitude / prayer of fortitude + {SMARTBUFF_PWF, 30, SMARTBUFF_CONST_GROUP, {1,12,24,36,48,60,70,80}, "HPET;WPET", S.ChainPriestFortBuffs}, + {SMARTBUFF_POFRB1, 60, SMARTBUFF_CONST_GROUP, {48,60,70,80}, "HPET;WPET", S.ChainPriestFortBuffs, {SMARTBUFF_SACREDCANDLE}}, + -- shadow protection / prayer of shadow protection + {SMARTBUFF_SP, 30, SMARTBUFF_CONST_GROUP, {30,42,56,68,76}, "HPET;WPET", S.ChainPriestShadowBuffs}, + {SMARTBUFF_POSPRB1, 60, SMARTBUFF_CONST_GROUP, {48,60,70,80}, "HPET;WPET", S.ChainPriestShadowBuffs, {SMARTBUFF_SACREDCANDLE}}, + -- spirit / divine spirit + {SMARTBUFF_DS, 30, SMARTBUFF_CONST_GROUP, {30,40,50,60,70,80}, "HPET;WPET", S.ChainPriestSpiritBuffs}, + {SMARTBUFF_POSRB1, 60, SMARTBUFF_CONST_GROUP, {48,60,70,80}, "HPET;WPET", S.ChainPriestSpiritBuffs, {SMARTBUFF_SACREDCANDLE}}, + + {SMARTBUFF_INNERFIRE, 10, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_DS, 30, SMARTBUFF_CONST_GROUP, {40,42,54,60,70,80}, "ROGUE;WARRIOR;HPET;WPET", nil, nil, SMARTBUFF_POSRB1, 60, {60}, {SMARTBUFF_SACREDCANDLE}}, +-- {SMARTBUFF_POSRB1, 60, SMARTBUFF_CONST_GROUP, {60}, "ROGUE;WARRIOR;HPET;WPET", nil, nil, SMARTBUFF_POSRB2, 60, {70}, {SMARTBUFF_SACREDCANDLE}}, + {SMARTBUFF_PWS, 0.5, SMARTBUFF_CONST_GROUP, {6,12,18,24,30,36,42,48,54,60,65,70,75,80}, "MAGE;WARLOCK;DEATHKNIGHT;ROGUE;PALADIN;WARRIOR;DRUID;HUNTER;SHAMAN;HPET;WPET"}, + {SMARTBUFF_SHADOWFORM, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_FEARWARD, 10, SMARTBUFF_CONST_GROUP, {20}}, + {SMARTBUFF_ELUNESGRACE, 0.25, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_FEEDBACK, 0.25, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_SHADOWGUARD, 10, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_TOUCHOFWEAKNESS, 10, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_INNERFOCUS, -1, SMARTBUFF_CONST_SELF} + }; + end + + -- Mage + if (SMARTBUFF_PLAYERCLASS == "MAGE") then + SMARTBUFF_BUFFLIST = { + -- arcane intellect + {SMARTBUFF_AI, 30, SMARTBUFF_CONST_GROUP, {1,14,28,42,56,70,80}, "ROGUE;WARRIOR;HPET;WPET", S.ChainMageBuffs}, + -- arcane brilliance + {SMARTBUFF_ABRB1, 60, SMARTBUFF_CONST_GROUP, {56, 70, 80}, "ROGUE;WARRIOR;HPET;WPET", {SMARTBUFF_ARCANEPOWDER}, S.ChainMageBuffs}, + {SMARTBUFF_FOCUSMAGIC, 30, SMARTBUFF_CONST_GROUP, {20}, "WARRIOR;DRUID;SHAMAN;HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;DEATHKNIGHT;HPET;WPET"}, + {SMARTBUFF_ICEARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainMageArmor}, + {SMARTBUFF_FROSTARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainMageArmor}, + {SMARTBUFF_MAGEARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainMageArmor}, + {SMARTBUFF_MOLTENARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainMageArmor}, + {SMARTBUFF_DAMPENMAGIC, 10, SMARTBUFF_CONST_GROUP, {12,24,36,48,60}, "HPET;WPET"}, + {SMARTBUFF_AMPLIFYMAGIC, 10, SMARTBUFF_CONST_GROUP, {18,30,42,54}, "HPET;WPET"}, + {SMARTBUFF_MANASHIELD, 1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_FIREWARD, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_FROSTWARD, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_ICEBARRIER, 1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_COMBUSTION, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_ICYVEINS, 0.33, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_ARCANEPOWER, 0.25, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_PRESENCEOFMIND, 0.165, SMARTBUFF_CONST_SELF} + }; + end + + -- Warlock + if (SMARTBUFF_PLAYERCLASS == "WARLOCK") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_FELARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainWarlockArmor}, + {SMARTBUFF_DEMONARMOR, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainWarlockArmor}, + {SMARTBUFF_DEMONSKIN, 30, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainWarlockArmor}, + {SMARTBUFF_SOULLINK, 0, SMARTBUFF_CONST_SELF, nil, S.CheckPetNeeded}, + {SMARTBUFF_DINVISIBILITY, 10, SMARTBUFF_CONST_GROUP, {26}, "HPET;WPET"}, + {SMARTBUFF_UNENDINGBREATH, 10, SMARTBUFF_CONST_GROUP, {16}, "HPET;WPET"}, + {SMARTBUFF_LIFETAP, 0.025, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_SHADOWWARD, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_DARKPACT, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_SOULSTONE, 15, SMARTBUFF_CONST_GROUP, {18}, "WARRIOR;DRUID;SHAMAN;HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;DEATHKNIGHT;MONK;DEMONHUNTER;HPET;WPET;DKPET"}, + {SMARTBUFF_CREATEHSMAJ, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_HEALTHSTONEGEM}, + {SMARTBUFF_CREATEHSGRE, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_HEALTHSTONEGEM}, + {SMARTBUFF_CREATEHS, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_HEALTHSTONEGEM}, + {SMARTBUFF_CREATEHSLES, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_HEALTHSTONEGEM}, + {SMARTBUFF_CREATEHSMIN, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_HEALTHSTONEGEM}, + {SMARTBUFF_CREATESSMAJ, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_SOULSTONEGEM}, + {SMARTBUFF_CREATESSGRE, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_SOULSTONEGEM}, + {SMARTBUFF_CREATESS, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_SOULSTONEGEM}, + {SMARTBUFF_CREATESSLES, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_SOULSTONEGEM}, + {SMARTBUFF_CREATESSMIN, 0.03, SMARTBUFF_CONST_ITEM, nil, SMARTBUFF_SOULSTONEGEM}, + {SMARTBUFF_SPELLSTONE6, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SPELLSTONE5, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SPELLSTONE4, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SPELLSTONE3, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SPELLSTONE2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SPELLSTONE1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE7, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE6, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE5, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE4, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE3, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FIRESTONE1, 60, SMARTBUFF_CONST_INV} + }; + end + + -- Hunter + if (SMARTBUFF_PLAYERCLASS == "HUNTER") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_TRUESHOTAURA, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_RAPIDFIRE, 0.2, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_AOTDH, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTH, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTM, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTV, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTW, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTB, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTC, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects}, + {SMARTBUFF_AOTP, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainAspects} + }; + end + + -- Shaman + if (SMARTBUFF_PLAYERCLASS == "SHAMAN") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_LIGHTNINGSHIELD, 10, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainShamanShield}, + {SMARTBUFF_WATERSHIELD, 10, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainShamanShield}, + {SMARTBUFF_EARTHSHIELD, 10, SMARTBUFF_CONST_GROUP, {50,60}, "WARRIOR;DEATHKNIGHT;DRUID;SHAMAN;HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;HPET;WPET", nil, S.ChainShamanShield}, + {SMARTBUFF_WINDFURYW, 30, SMARTBUFF_CONST_WEAPON}, + {SMARTBUFF_FLAMETONGUEW, 30, SMARTBUFF_CONST_WEAPON}, + {SMARTBUFF_FROSTBRANDW, 30, SMARTBUFF_CONST_WEAPON}, + {SMARTBUFF_ROCKBITERW, 30, SMARTBUFF_CONST_WEAPON}, + {SMARTBUFF_EARTHLIVINGW, 30, SMARTBUFF_CONST_WEAPON}, + {SMARTBUFF_WATERBREATHING, 10, SMARTBUFF_CONST_GROUP, {22}}, + {SMARTBUFF_WATERWALKING, 10, SMARTBUFF_CONST_GROUP, {28}} + }; + end + + -- Warrior + if (SMARTBUFF_PLAYERCLASS == "WARRIOR") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_BATTLESHOUT, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainWarriorShout}, + {SMARTBUFF_COMMANDINGSHOUT, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainWarriorShout}, + {SMARTBUFF_BERSERKERRAGE, 0.165, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_SHIELDBLOCK, 0.1666, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_BLOODRAGE, 0.165, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_RAMPAGE, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_VIGILANCE, 30, SMARTBUFF_CONST_GROUP, {40}, "WARRIOR;DRUID;SHAMAN;HUNTER;ROGUE;MAGE;PRIEST;PALADIN;WARLOCK;DEATHKNIGHT;HPET;WPET"} + }; + end + + -- Rogue + if (SMARTBUFF_PLAYERCLASS == "ROGUE") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_STEALTH, -1, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_BLADEFLURRY, 0.165, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_SAD, 0.2, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_HUNGERFORBLOOD, 0.5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_EVASION, 0.2, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_INSTANTPOISON9, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON8, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON7, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON6, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON5, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON4, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON3, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_INSTANTPOISON1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON7, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON6, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON5, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON4, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON3, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WOUNDPOISON1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_MINDPOISON1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON9, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON8, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON7, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON6, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON5, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON4, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON3, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_DEADLYPOISON1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_CRIPPLINGPOISON1, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_ANESTHETICPOISON2, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_ANESTHETICPOISON1, 60, SMARTBUFF_CONST_INV} + }; + end + + -- Paladin + if (SMARTBUFF_PLAYERCLASS == "PALADIN") then + SMARTBUFF_BUFFLIST = { + + {SMARTBUFF_RIGHTEOUSFURY, 30, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_HOLYSHIELD, 0.165, SMARTBUFF_CONST_SELF}, + + {SMARTBUFF_BOW, 5, SMARTBUFF_CONST_GROUP, {14,24,34,44,54,60,65,71,77}, "ROGUE;WARRIOR;HPET;WPET", S.ChainPaladinBOW}, + {SMARTBUFF_GBOW, 15, SMARTBUFF_CONST_GROUP, {54,60,65,71,77}, "ROGUE;WARRIOR;HPET;WPET", S.ChainPaladinBOW, {SMARTBUFF_SYMBOLOFKINGS}}, + {SMARTBUFF_BOM, 5, SMARTBUFF_CONST_GROUP, {4,12,22,32,42,52,60,70,73,79}, "MAGE;PRIEST;WARLOCK;HPET;WPET", S.ChainPaladinBOM}, + {SMARTBUFF_GBOM, 15, SMARTBUFF_CONST_GROUP, {52,60,70,73,79}, "MAGE;PRIEST;WARLOCK;HPET;WPET", S.ChainPaladinBOM, {SMARTBUFF_SYMBOLOFKINGS}}, + {SMARTBUFF_BOK, 5, SMARTBUFF_CONST_GROUP, {20}, "HPET;WPET", S.ChainPaladinBOK}, + {SMARTBUFF_GBOK, 15, SMARTBUFF_CONST_GROUP, {60}, "HPET;WPET", S.ChainPaladinBOK, {SMARTBUFF_SYMBOLOFKINGS}}, + {SMARTBUFF_BOSAL, 5, SMARTBUFF_CONST_GROUP, {26}, "TANK;HPET;WPET", S.ChainPaladinSAL}, + {SMARTBUFF_GBOSAL, 15, SMARTBUFF_CONST_GROUP, {60}, "TANK;HPET;WPET", S.ChainPaladinSAL, {SMARTBUFF_SYMBOLOFKINGS}}, + {SMARTBUFF_BOSAN, 5, SMARTBUFF_CONST_GROUP, {26,40,50,60}, "HPET;WPET", S.ChainPaladinSAN}, + {SMARTBUFF_GBOSAN, 15, SMARTBUFF_CONST_GROUP, {60}, "HPET;WPET", S.ChainPaladinSAN, {SMARTBUFF_SYMBOLOFKINGS}}, + + {SMARTBUFF_SOCOMMAND, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOFURY, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOJUSTICE, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOLIGHT, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SORIGHTEOUSNESS, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOWISDOM, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOTCRUSADER, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOVENGEANCE, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOBLOOD, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOCORRUPTION, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_SOMARTYR, 2, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinSeal}, + {SMARTBUFF_DEVOTIONAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_RETRIBUTIONAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_CONCENTRATIONAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_SHADOWRESISTANCEAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_FROSTRESISTANCEAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_FIRERESISTANCEAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_SANCTITYAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura}, + {SMARTBUFF_CRUSADERAURA, -1, SMARTBUFF_CONST_SELF, nil, nil, nil, S.ChainPaladinAura} + + }; + end + + -- Deathknight + if (SMARTBUFF_PLAYERCLASS == "DEATHKNIGHT") then + SMARTBUFF_BUFFLIST = { + {SMARTBUFF_DANCINGRW, 0.2, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_BLOODPRESENCE, -1, SMARTBUFF_CONST_STANCE, nil, nil, nil, S.ChainDKPresence}, + {SMARTBUFF_FROSTPRESENCE, -1, SMARTBUFF_CONST_STANCE, nil, nil, nil, S.ChainDKPresence}, + {SMARTBUFF_UNHOLYPRESENCE, -1, SMARTBUFF_CONST_STANCE, nil, nil, nil, S.ChainDKPresence}, + {SMARTBUFF_HORNOFWINTER, 60, SMARTBUFF_CONST_SELF, nil, nil, S.LinkAp}, + {SMARTBUFF_BONESHIELD, 5, SMARTBUFF_CONST_SELF}, + {SMARTBUFF_RAISEDEAD, 1, SMARTBUFF_CONST_SELF, nil, S.CheckPet}, + {SMARTBUFF_PATHOFFROST, -1, SMARTBUFF_CONST_SELF} + }; + end + + + -- Stones and oils + SMARTBUFF_WEAPON = { + {SMARTBUFF_LESSERMANAOIL, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_BRILLIANTMANAOIL, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_BRILLIANTWIZARDOIL, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SUPERIORMANAOIL, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SUPERIORWIZARDOIL, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_OILOFIMMOLATION, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SOLIDWSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_SOLIDSSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_ELEMENTALSSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_ADAMANTITEWSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_ADAMANTITESSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_HEAVYWSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_HEAVYSSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_WEIGHSTONE, 60, SMARTBUFF_CONST_INV}, + {SMARTBUFF_FELSHARPENINGSTONE, 60, SMARTBUFF_CONST_INV}, + }; + + -- Tracking + SMARTBUFF_TRACKING = { + {SMARTBUFF_FINDMINERALS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_FINDHERBS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_FINDTREASURE, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKHUMANOIDS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKBEASTS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKUNDEAD, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKHIDDEN, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKELEMENTALS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKDEMONS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKGIANTS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_TRACKDRAGONKIN, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_SENSEDEMONS, -1, SMARTBUFF_CONST_TRACK}, + {SMARTBUFF_SENSEUNDEAD, -1, SMARTBUFF_CONST_TRACK} + }; + + -- Racial + SMARTBUFF_RACIAL = { + {SMARTBUFF_STONEFORM, 0.133, SMARTBUFF_CONST_SELF}, -- Dwarv + --{SMARTBUFF_PRECEPTION, 0.333, SMARTBUFF_CONST_SELF}, -- Human + {SMARTBUFF_BLOODFURY, 0.416, SMARTBUFF_CONST_SELF}, -- Orc + {SMARTBUFF_BERSERKING, 0.166, SMARTBUFF_CONST_SELF}, -- Troll + {SMARTBUFF_WOTFORSAKEN, 0.083, SMARTBUFF_CONST_SELF}, -- Undead + {SMARTBUFF_WarStomp, 0.033, SMARTBUFF_CONST_SELF} -- Tauer + }; + + -- FOOD + SMARTBUFF_FOOD = { + {SMARTBUFF_GOLDENFISHSTICKS_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_FISHERMANSFEAST_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_SKULLFISHSOUP_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_SPICYHOTTALBUK_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_BLACKENEDBASILISK_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_BLACKENEDSPOREFISH_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_BUZZARDBITES_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_CLAMBAR_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_CRUNCHYSERPENT_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_FELTAILDELIGHT_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_GRILLEDMUDFISH_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_HELBOARBACON_ITEM, 15, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_MOKNATHAKSHORTRIBS_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_POACHEDBLUEFISH_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_RAVAGERDOG_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_ROASTEDCLEFTHOOF_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_SPICYCRAWDAD_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_TALBUKSTEAK_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_WARPBURGER_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_CHARREDBEARKABOBS_ITEM, 15, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_ORONOKSTUBERSPELL_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_ORONOKSTUBERAGILITY_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_ORONOKSTUBERHEALS_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_ORONOKSTUBERSTRENGTH_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_HOTAPPLECIDER_ITEM, 30, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_SKYGUARDRATIONS_ITEM, 15, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_DIRGESKICKINCHOPS_ITEM, 15, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_JUICYBEARBURGER_ITEM, 15, SMARTBUFF_CONST_FOOD}, + {SMARTBUFF_NIGHTFINSOUP_ITEM, 10, SMARTBUFF_CONST_FOOD}, + }; + + + -- Scrolls + SMARTBUFF_SCROLL = { + {SMARTBUFF_SOAGILITY5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBAGILITY}, + {SMARTBUFF_SOAGILITY4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBAGILITY}, + {SMARTBUFF_SOAGILITY3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBAGILITY}, + {SMARTBUFF_SOAGILITY2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBAGILITY}, + {SMARTBUFF_SOAGILITY1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBAGILITY}, + + {SMARTBUFF_SOINTELLECT5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBINTELLECT}, + {SMARTBUFF_SOINTELLECT4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBINTELLECT}, + {SMARTBUFF_SOINTELLECT3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBINTELLECT}, + {SMARTBUFF_SOINTELLECT2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBINTELLECT}, + {SMARTBUFF_SOINTELLECT1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBINTELLECT}, + + {SMARTBUFF_SOSTAMINA5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTAMINA}, + {SMARTBUFF_SOSTAMINA4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTAMINA}, + {SMARTBUFF_SOSTAMINA3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTAMINA}, + {SMARTBUFF_SOSTAMINA2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTAMINA}, + {SMARTBUFF_SOSTAMINA1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTAMINA}, + + {SMARTBUFF_SOSPIRIT5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSPIRIT}, + {SMARTBUFF_SOSPIRIT4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSPIRIT}, + {SMARTBUFF_SOSPIRIT3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSPIRIT}, + {SMARTBUFF_SOSPIRIT2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSPIRIT}, + {SMARTBUFF_SOSPIRIT1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSPIRIT}, + + {SMARTBUFF_SOSTRENGHT5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTRENGHT}, + {SMARTBUFF_SOSTRENGHT4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTRENGHT}, + {SMARTBUFF_SOSTRENGHT3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTRENGHT}, + {SMARTBUFF_SOSTRENGHT2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTRENGHT}, + {SMARTBUFF_SOSTRENGHT1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBSTRENGHT}, + + {SMARTBUFF_SOPROTECTION5, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBPROTECTION}, + {SMARTBUFF_SOPROTECTION4, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBPROTECTION}, + {SMARTBUFF_SOPROTECTION3, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBPROTECTION}, + {SMARTBUFF_SOPROTECTION2, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBPROTECTION}, + {SMARTBUFF_SOPROTECTION1, 30, SMARTBUFF_CONST_SCROLL, nil, SMARTBUFF_SBPROTECTION}, + }; + + + --- Burning Crusade Classic Potions / Elixirs / Flasks + + SMARTBUFF_POTION = { + + {SMARTBUFF_ADEPTELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_ADEPTELIXIR_BUFF}, + {SMARTBUFF_MAJORDEFENSE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORDEFENSE_BUFF}, + {SMARTBUFF_MAJORAGILITY_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORAGILITY_BUFF}, + {SMARTBUFF_DRAENICWISDOM_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_DRAENICWISDOM_BUFF}, + {SMARTBUFF_MAJORFROSTPOWER_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORFROSTPOWER_BUFF}, + {SMARTBUFF_EARTHEN_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_EARTHEN_BUFF}, + {SMARTBUFF_MASTERY_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MASTERY_BUFF}, + {SMARTBUFF_CAMOUFLAGE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_CAMOUFLAGE_BUFF}, + {SMARTBUFF_HEALINGPOWER_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_HEALINGPOWER_BUFF}, + {SMARTBUFF_MAJORFORTITUDE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORFORTITUDE_BUFF}, + {SMARTBUFF_MAJORSTRENGTH_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORSTRENGTH_BUFF}, + {SMARTBUFF_ONSLAUGHTELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_ONSLAUGHTELIXIR_BUFF}, + {SMARTBUFF_GREATERARCANE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GREATERARCANE_BUFF}, + {SMARTBUFF_MONGOOSEELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MONGOOSEELIXIR_BUFF}, + {SMARTBUFF_BRUTEFORCE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_BRUTEFORCE_BUFF}, + {SMARTBUFF_SAGESELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_SAGESELIXIR_BUFF}, + {SMARTBUFF_SUPERIORDEFENSE_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_SUPERIORDEFENSE_BUFF}, + {SMARTBUFF_DEMONSLAYING_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_DEMONSLAYING_BUFF}, + {SMARTBUFF_MAJORFIREPOWER_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORFIREPOWER_BUFF}, + {SMARTBUFF_GREATERFIREPOWER_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GREATERFIREPOWER_BUFF}, + {SMARTBUFF_SHADOWPOWER_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_SHADOWPOWER_BUFF}, + {SMARTBUFF_GIANTSELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GIANTSELIXIR_BUFF}, + {SMARTBUFF_GREATERAGILITY_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GREATERAGILITY_BUFF}, + {SMARTBUFF_GIFTOFARTHAS_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GIFTOFARTHAS_BUFF}, + {SMARTBUFF_ARANCEELIXIR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_ARANCEELIXIR_BUFF}, + {SMARTBUFF_GREATERINTELLECT_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_GREATERINTELLECT_BUFF}, + {SMARTBUFF_MAJORNATUREPROT_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORNATUREPROT_BUFF}, + {SMARTBUFF_MAJORMAGEBLOOD_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORMAGEBLOOD_BUFF}, + {SMARTBUFF_MAJORSHADOWPWR_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORSHADOWPWR_BUFF}, + {SMARTBUFF_MAJORIRONSKIN_ITEM, 60, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_MAJORIRONSKIN_BUFF}, + {SMARTBUFF_BLINDINGLIGHTFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_BLINDINGLIGHTFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_FORTIFICATIONFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_FORTIFICATIONFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_RESTORATIONFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_RESTORATIONFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_PUREDEATHFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_PUREDEATHFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_RELENTLESSFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_RELENTLESSFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_CHROMATICFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_CHROMATICFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_DISTILLEDFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_DISTILLEDFLASK_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_HEALINGPOWER_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_HEALINGPOWER_BUFF, S.LinkFlaskTBC}, + {SMARTBUFF_SUPREMEPWRFLASK_ITEM, 120, SMARTBUFF_CONST_POTION, nil, SMARTBUFF_SUPREMEPWRFLASK_BUFF, S.LinkFlaskTBC}, + + } + + SMARTBUFF_AddMsgD(">>>> Spell lists have been initialised."); + +end diff --git a/SmartBuff.globals.lua b/SmartBuff.globals.lua new file mode 100644 index 0000000..2b97256 --- /dev/null +++ b/SmartBuff.globals.lua @@ -0,0 +1,61 @@ +------------------------------------------------------------------------------- +-- SmartBuff +-- Originally created by Aeldra (EU-Proudmoore) +-- Classic versions by Codermik (Mik/Castanova/Amarantine EU-Mirage Raceway) +-- Discord: https://discord.gg/R6EkZ94TKK +-- Cast the most important buffs on you, tanks or party/raid members/pets. +------------------------------------------------------------------------------- + +-- Globals + + +SMARTBUFF_GLOBALS = { }; +local SG = SMARTBUFF_GLOBALS; + +SMARTBUFF_TTC_R = 1; +SMARTBUFF_TTC_G = 1; +SMARTBUFF_TTC_B = 1; +SMARTBUFF_TTC_A = 1; + +SMARTBUFF_OPTIONSFRAME_HEIGHT = 630; +SMARTBUFF_OPTIONSFRAME_WIDTH = 500; + +SMARTBUFF_ACTION_ITEM = "item"; +SMARTBUFF_ACTION_SPELL = "spell"; + +SMARTBUFF_CONST_AUTOSOUND = "Deathbind Sound"; +--SMARTBUFF_CONST_AUTOSOUND = "TaxiNodeDiscovered"; +--SMARTBUFF_CONST_AUTOSOUND = "GLUECREATECHARACTERBUTTON"; + +--[[ +SystemFont +GameFontNormal +GameFontNormalSmall +GameFontNormalLarge +GameFontHighlight +GameFontHighlightSmall +GameFontHighlightSmallOutline +GameFontHighlightLarge +GameFontDisable +GameFontDisableSmall +GameFontDisableLarge +GameFontGreen +GameFontGreenSmall +GameFontGreenLarge +GameFontRed +GameFontRedSmall +GameFontRedLarge +GameFontWhite +GameFontDarkGraySmall +NumberFontNormalYellow +NumberFontNormalSmallGray +QuestFontNormalSmall +DialogButtonHighlightText +ErrorFont +TextStatusBarText +CombatLogFont +NumberFontNormalLarge +NumberFontNormalHuge +]]-- + + diff --git a/SmartBuff.lua b/SmartBuff.lua new file mode 100644 index 0000000..d96b00b --- /dev/null +++ b/SmartBuff.lua @@ -0,0 +1,5043 @@ +------------------------------------------------------------------------------- +-- SmartBuff +-- Originally created by Aeldra (EU-Proudmoore) +-- Classic/Retail versions by Codermik (Mik/Castanova/Amarantine EU-Mirage Raceway or Castanova on EU-Aszune) +-- Discord: https://discord.gg/R6EkZ94TKK +-- Cast the most important buffs on you, tanks or party/raid members/pets. +------------------------------------------------------------------------------- + +SMARTBUFF_DATE = "190722 Dev"; +SMARTBUFF_VERSION = "r21."..SMARTBUFF_DATE; +SMARTBUFF_VERSIONMIN = 11403; -- min version +SMARTBUFF_VERSIONNR = 30400; -- max version +SMARTBUFF_TITLE = "SmartBuff"; +SMARTBUFF_SUBTITLE = "Supports casting buffs on tanks, selected classes in party or raids."; +SMARTBUFF_DESC = "Cast the most important buffs on you, tanks, party or raid members/pets"; +SMARTBUFF_VERS_TITLE = SMARTBUFF_TITLE .. " " .. SMARTBUFF_VERSION; +SMARTBUFF_OPTIONS_TITLE = SMARTBUFF_VERS_TITLE; + +-- addon name +local addonName = ... +local SmartbuffPrefix = "Smartbuff"; +local SmartbuffSession = true; +local SmartbuffVerCheck = false; -- for my use when checking guild users/testers versions :) +local buildInfo = select(4, GetBuildInfo()) +local SmartbuffRevision = 21; +local SmartbuffVerNotifyList = {} + +local LCD = LibStub and LibStub("LibClassicDurations", true) +if LCD then LCD:Register(SMARTBUFF_TITLE) end + +local UnitAuraFull = UnitAura +if LCD and LCD.UnitAura then UnitAuraFull = function(a, b, c) return LCD:UnitAura(a, b, c) end end + + +local SG = SMARTBUFF_GLOBALS; +local OG = nil; -- Options global +local O = nil; -- Options local +local B = nil; -- Buff settings local +local _; + +BINDING_HEADER_SMARTBUFF = "SmartBuff"; +SMARTBUFF_BOOK_TYPE_SPELL = "spell"; + + +local GlobalCd = 1.5; +local maxSkipCoolDown = 3; +local maxRaid = 40; +local maxBuffs = 40; +local maxScrollButtons = 50; +local numBuffs = 0; + +local isLoaded = false; +local isPlayer = false; +local isInit = false; +local isCombat = false; +local isSetBuffs = false; +local isSetZone = false; +local isFirstError = false; +local isMounted = false; +local isCTRA = true; +local isSetUnits = false; +local isKeyUpChanged = false; +local isKeyDownChanged = false; +local isAuraChanged = false; +local isClearSplash = false; +local isRebinding = false; +local isParrot = false; +local isSync = false; +local isSyncReq = false; +local isInitBtn = false; + +local isShapeshifted = false; +local sShapename = ""; + +local tStartZone = 0; +local tTicker = 0; +local tSync = 0; + +local sRealmName = nil; +local sPlayerName = nil; +local sID = nil; +local sPlayerClass = nil; +local iLastSubgroup = 0; +local tLastCheck = 0; +local iGroupSetup = -1; +local iLastBuffSetup = -1; +local sLastTexture = ""; +local iLastGroupSetup = -99; +local sLastZone = ""; +local tAutoBuff = 0; +local tDebuff = 0; +local sMsgWarning = ""; +local iCurrentFont = 1; +local iCurrentList = -1; +local iLastPlayer = -1; + +local isPlayerMoving = false; + +local cGroups = { }; +local cClassGroups = { }; +local cBuffs = { }; +local cBuffIndex = { }; +local cBuffTimer = { }; +local cBlacklist = { }; +local cUnits = { }; +local cBuffsCombat = { }; + +local cScrBtnBO = nil; + +local cAddUnitList = { }; +local cIgnoreUnitList = { }; + +local cClasses = {"DRUID", "HUNTER", "MAGE", "PALADIN", "PRIEST", "ROGUE", "SHAMAN", "WARLOCK", "WARRIOR", "DEATHKNIGHT", "MONK", "DEMONHUNTER", "HPET", "WPET", "DKPET", "TANK", "HEALER", "DAMAGER"}; +local cIgnoreClasses = { 11, 12, 15, 17, 18 }; +local cOrderGrp = {0, 1, 2, 3, 4, 5, 6, 7, 8}; +local cOrderClass = {0, "WARRIOR", "PRIEST", "DRUID", "PALADIN", "SHAMAN", "MAGE", "WARLOCK", "HUNTER", "ROGUE", "TANK", "HPET", "WPET", "DKPET"}; +local cFonts = {"NumberFontNormal", "NumberFontNormalLarge", "NumberFontNormalHuge", "GameFontNormal", "GameFontNormalLarge", "GameFontNormalHuge", "ChatFontNormal", "QuestFont", "MailTextFontNormal", "QuestTitleFont"}; + +local currentUnit = nil; +local currentSpell = nil; +local currentRank = nil; +local currentTemplate = nil; +local currentSpec = nil; + +local imgSB = "Interface\\Icons\\Spell_Nature_Purge"; +local imgIconOn = "Interface\\AddOns\\SmartBuff\\Icons\\MiniMapButtonEnabled"; +local imgIconOff = "Interface\\AddOns\\SmartBuff\\Icons\\MiniMapButtonDisabled"; + +local IconPaths = { + ["Pet"] = "Interface\\Icons\\spell_nature_spiritwolf", + ["Roles"] = "Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES", + ["Classes"] = "Interface\\WorldStateFrame\\Icons-Classes", +}; + +local Icons = { + ["WARRIOR"] = { IconPaths.Classes, 0.00, 0.25, 0.00, 0.25 }, + ["MAGE"] = { IconPaths.Classes, 0.25, 0.50, 0.00, 0.25 }, + ["ROGUE"] = { IconPaths.Classes, 0.50, 0.75, 0.00, 0.25 }, + ["DRUID"] = { IconPaths.Classes, 0.75, 1.00, 0.00, 0.25 }, + ["HUNTER"] = { IconPaths.Classes, 0.00, 0.25, 0.25, 0.50 }, + ["SHAMAN"] = { IconPaths.Classes, 0.25, 0.50, 0.25, 0.50 }, + ["PRIEST"] = { IconPaths.Classes, 0.50, 0.75, 0.25, 0.50 }, + ["WARLOCK"] = { IconPaths.Classes, 0.75, 1.00, 0.25, 0.50 }, + ["PALADIN"] = { IconPaths.Classes, 0.00, 0.25, 0.50, 0.75 }, + ["DEATHKNIGHT"] = { IconPaths.Classes, 0.25, 0.50, 0.50, 0.75 }, + ["MONK"] = { IconPaths.Classes, 0.50, 0.75, 0.50, 0.75 }, + ["DEMONHUNTER"] = { IconPaths.Classes, 0.75, 1.00, 0.50, 0.75 }, + ["PET"] = { IconPaths.Pet, 0.08, 0.92, 0.08, 0.92}, + ["TANK"] = { IconPaths.Roles, 0.0, 19/64, 22/64, 41/64 }, + ["HEALER"] = { IconPaths.Roles, 20/64, 39/64, 1/64, 20/64 }, + ["DAMAGER"] = { IconPaths.Roles, 20/64, 39/64, 22/64, 41/64 }, + ["NONE"] = { IconPaths.Roles, 20/64, 39/64, 22/64, 41/64 }, +}; + +local DebugChatFrame = DEFAULT_CHAT_FRAME; + +-- upvalues +local UnitCastingInfo = _G.UnitCastingInfo or _G.CastingInfo +local UnitChannelInfo = _G.UnitChannelInfo or _G.ChannelInfo +local GetNumSpecGroups = _G.GetNumSpecGroups or function(...) return 1 end +local IsActiveBattlefieldArena = _G.IsActiveBattlefieldArena or function(...) return false end + +-- Popup +StaticPopupDialogs["SMARTBUFF_DATA_PURGE"] = { + text = SMARTBUFF_OFT_PURGE_DATA, + button1 = SMARTBUFF_OFT_YES, + button2 = SMARTBUFF_OFT_NO, + OnAccept = function() SMARTBUFF_ResetAll() end, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 +} + +-- Rounds a number to the given number of decimal places. +local r_mult; +local function Round(num, idp) + r_mult = 10^(idp or 0); + return math.floor(num * r_mult + 0.5) / r_mult; +end + +-- Returns a chat color code string +local function BCC(r, g, b) + return string.format("|cff%02x%02x%02x", (r*255), (g*255), (b*255)); +end + +local BL = BCC(0, 0, 1); +local BLD = BCC(0, 0, 0.7); +local BLL = BCC(0.5, 0.8, 1); +local GR = BCC(0, 1, 0); +local GRD = BCC(0, 0.7, 0); +local GRL = BCC(0.6, 1, 0.6); +local RD = BCC(1, 0, 0); +local RDD = BCC(0.7, 0, 0); +local RDL = BCC(1, 0.3, 0.3); +local YL = BCC(1, 1, 0); +local YLD = BCC(0.7, 0.7, 0); +local YLL = BCC(1, 1, 0.5); +local OR = BCC(1, 0.7, 0); +local ORD = BCC(0.7, 0.5, 0); +local ORL = BCC(1, 0.6, 0.3); +local WH = BCC(1, 1, 1); +local CY = BCC(0.5, 1, 1); + +-- Reorders values in the table +local function treorder(t, i, n) + if (t and type(t) == "table" and t[i]) then + local s = t[i]; + tremove(t, i); + if (i + n < 1) then + tinsert(t, 1, s); + elseif (i + n > #t) then + tinsert(t, s); + else + tinsert(t, i + n, s); + end + end +end + +-- Finds a value in the table and returns the index +local function tfind(t, s) + if (t and type(t) == "table" and s) then + for k, v in pairs(t) do + if (v and v == s) then + return k; + end + end + end + return false; +end + +local function tcontains(t, s) + if (t and type(t) == "table" and s) then + for _, v in ipairs(t) do + if (v == s) then + return true; + end + end + end + return false; +end + +function strim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +local function ChkS(text) + if (text == nil) then + text = ""; + end + return text; +end + +local function IsFlying() + local result = GetShapeshiftForm(false) + -- bugfix 6/7/2022, frost/shadow/sanct aura on paladin was causing the + -- GetShapeshiftForm to return 5 faking the addon into thinking the + -- player was actually flying on a druid. CM + if (result == 5 or result == 6) and sPlayerClass == "DRUID" then + return true + end + return false +end + +local function UnitInVehicle(unit) + return false +end + +local function UnitHasVehicleUI(unit) + return false +end + +local function UnitGroupRolesAssigned(unit) + -- dont bother if we dont have assigned tanks + if cClassGroups then + if cClassGroups["TANK"] then + for n = 1, maxRaid, 1 do + local u = cClassGroups["TANK"][n] + if u and u == unit then + name, rank, subgroup, level, class, classeng, zone, online, isDead, role = GetRaidRosterInfo(n) + if role and role == "MAINTANK" then + return "TANK" + end + end + end + end + end + return "NONE" +end + +local function IsVisibleToPlayer(self) + if (not self) then return false; end + + local w, h = UIParent:GetWidth(), UIParent:GetHeight(); + local x, y = self:GetLeft(), UIParent:GetHeight() - self:GetTop(); + + --print(format("w = %.0f, h = %.0f, x = %.0f, y = %.0f", w, h, x, y)); + if (x >= 0 and x < (w - self:GetWidth()) and y >= 0 and y < (h - self:GetHeight())) then + return true; + end + return false; +end + + +local function CS() + if (currentSpec == nil) then + currentSpec = GetSpecialization(); + end + if (currentSpec == nil) then + currentSpec = 1; + end + return currentSpec; +end + +local function CT() + return currentTemplate; +end + +local function GetBuffSettings(buff) + if (B and buff) then + return B[CS()][CT()][buff]; + end + return nil; +end + +local function InitBuffSettings(cBI, reset) + local buff = cBI.BuffS; + local cBuff = GetBuffSettings(buff); + if (cBuff == nil) then + B[CS()][CT()][buff] = { }; + cBuff = B[CS()][CT()][buff]; + reset = true; + end + + if (reset) then + wipe(cBuff); + cBuff.EnableS = false; + cBuff.EnableG = false; + cBuff.SelfOnly = false; + cBuff.SelfNot = false; + cBuff.CIn = false; + cBuff.COut = true; + cBuff.MH = false; + cBuff.OH = false; + cBuff.RH = false; + cBuff.Reminder = true; + cBuff.RBTime = 0; + cBuff.ManaLimit = 0; + if (cBI.Type == SMARTBUFF_CONST_GROUP or cBI.Type == SMARTBUFF_CONST_ITEMGROUP) then + for n in pairs(cClasses) do + if (cBI.Type == SMARTBUFF_CONST_GROUP and not tcontains(cIgnoreClasses, n) and not string.find(cBI.Params, cClasses[n])) then + cBuff[cClasses[n]] = true; + else + cBuff[cClasses[n]] = false; + end + end + end + end + + -- Upgrades + if (cBuff.RBTime == nil) then cBuff.Reminder = true; cBuff.RBTime = 0; end -- to 1.10g + if (cBuff.ManaLimit == nil) then cBuff.ManaLimit = 0; end -- to 1.12b + if (cBuff.SelfNot == nil) then cBuff.SelfNot = false; end -- to 2.0i + if (cBuff.AddList == nil) then cBuff.AddList = { }; end -- to 2.1a + if (cBuff.IgnoreList == nil) then cBuff.IgnoreList = { }; end -- to 2.1a + if (cBuff.RH == nil) then cBuff.RH = false; end -- to 4.0b + +end + +local function InitBuffOrder(reset) + if (B[CS()].Order == nil) then + B[CS()].Order = { }; + end + + local b; + local i; + local ord = B[CS()].Order; + if (reset) then + wipe(ord); + SMARTBUFF_AddMsgD("Reset buff order"); + end + + -- Remove not longer existing buffs in the order list + for k, v in pairs(ord) do + if (v and cBuffIndex[v] == nil) then + SMARTBUFF_AddMsgD("Remove from buff order: "..v); + tremove(ord, k); + end + end + + i = 1; + while (cBuffs[i] and cBuffs[i].BuffS) do + b = false; + for _, v in pairs(ord) do + if (v and v == cBuffs[i].BuffS) then + b = true; + break; + end + end + -- buff not found add it to order list + if (not b) then + tinsert(ord, cBuffs[i].BuffS); + SMARTBUFF_AddMsgD("Add to buff order: "..cBuffs[i].BuffS); + end + i = i + 1; + end +end + +local function IsMinLevel(minLevel) + if (not minLevel) then + return true; + end + if (minLevel > UnitLevel("player")) then + return false; + end + return true; +end + +local function IsPowerLimitOk(bs) + -- Check for power threshold + if (bs.ManaLimit and bs.ManaLimit > 0) then + local powerType, powerToken = UnitPowerType("player"); + -- if bs.ManaLimit <= 100 and powertype is mana then the ManaLimit is % + if (bs.ManaLimit <= 100 and powerType == 0) then + if (((UnitPower("player", powerType) / UnitPowerMax("player", powerType))) * 100 < bs.ManaLimit) then + --print(powerToken.." is below % threshold!"); + return false; + end + elseif (UnitPower("player", powerType) < bs.ManaLimit) then + --print(powerToken.." is below threshold!"); + return false; + end + end + return true; +end + +local function IsPlayerInGuild() + return IsInGuild() -- and GetGuildInfo("player") +end + +local function SendSmartbuffVersion(player, unit) + -- if ive announced to this player / the player is me then just return. + if player == UnitName("player") then return end + for count,value in ipairs(SmartbuffVerNotifyList) do + if value[1] == player then return end + end + -- not announced, add the player and announce. + tinsert(SmartbuffVerNotifyList, {player, unit, GetTime()}) + C_ChatInfo.SendAddonMessage(SmartbuffPrefix, SmartbuffRevision, "WHISPER", player) + SMARTBUFF_AddMsgD(string.format("%s was sent version information.",player)) +end + +-- SMARTBUFF_OnLoad +function SMARTBUFF_OnLoad(self) + + self:RegisterEvent("ADDON_LOADED"); + self:RegisterEvent("PLAYER_LOGIN"); + self:RegisterEvent("PLAYER_ENTERING_WORLD"); + self:RegisterEvent("UNIT_NAME_UPDATE"); + self:RegisterEvent("GROUP_ROSTER_UPDATE"); + self:RegisterEvent("PLAYER_REGEN_ENABLED"); + self:RegisterEvent("PLAYER_REGEN_DISABLED"); + self:RegisterEvent("PLAYER_STARTED_MOVING"); + self:RegisterEvent("PLAYER_STOPPED_MOVING"); + self:RegisterEvent("SPELLS_CHANGED"); + self:RegisterEvent("ACTIONBAR_HIDEGRID"); + self:RegisterEvent("UNIT_AURA"); + self:RegisterEvent("CHAT_MSG_ADDON"); + self:RegisterEvent("CHAT_MSG_CHANNEL"); + self:RegisterEvent("UPDATE_MOUSEOVER_UNIT"); + self:RegisterEvent("UNIT_SPELLCAST_FAILED"); + self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED"); + + --One of them allows SmartBuff to be closed with the Escape key + tinsert(UISpecialFrames, "SmartBuffOptionsFrame"); + UIPanelWindows["SmartBuffOptionsFrame"] = nil; + + -- setup command line. + SlashCmdList["SMARTBUFF"] = SMARTBUFF_command; + SLASH_SMARTBUFF1 = "/sbo"; + SLASH_SMARTBUFF2 = "/sbuff"; + SLASH_SMARTBUFF3 = "/smartbuff"; + SlashCmdList["SMARTBUFFMENU"] = SMARTBUFF_OptionsFrame_Toggle; + SLASH_SMARTBUFFMENU1 = "/sbm"; + SlashCmdList["SmartReloadUI"] = function(msg) ReloadUI(); end; + SLASH_SmartReloadUI1 = "/rui"; + + SMARTBUFF_InitSpellIDs(); + --DEFAULT_CHAT_FRAME:AddMessage("SB OnLoad"); +end +-- END SMARTBUFF_OnLoad + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SmartBuff Event Handler --------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_OnEvent(self, event, ...) + local arg1, arg2, arg3, arg4, arg5 = ...; + + -- UNIT_NAME_UPDATE / PLAYER_ENTERING_WORLD + if ((event == "UNIT_NAME_UPDATE" and arg1 == "player") or event == "PLAYER_ENTERING_WORLD") then + if IsPlayerInGuild() and event == "PLAYER_ENTERING_WORLD" then + C_ChatInfo.SendAddonMessage(SmartbuffPrefix, SmartbuffRevision, "GUILD") + end + isPlayer = true; + if (event == "PLAYER_ENTERING_WORLD" and isInit and O.Toggle) then + isSetZone = true; + tStartZone = GetTime(); + end + + -- ADDON_LOADED + elseif(event == "ADDON_LOADED" and arg1 == SMARTBUFF_TITLE) then + isLoaded = true; + end + + -- PLAYER_LOGIN + if event == "PLAYER_LOGIN" then + local prefixResult = C_ChatInfo.RegisterAddonMessagePrefix(SmartbuffPrefix) + end + + -- CHAT_MSG_ADDON + if event == "CHAT_MSG_ADDON" then + if arg1 == SmartbuffPrefix then + -- its us. + if arg2 then + arg2 = tonumber(arg2) + if arg2 > SmartbuffRevision and SmartbuffSession then + -- detected a newer version of the addon, lets let the player know. + DEFAULT_CHAT_FRAME:AddMessage(SMARTBUFF_MSG_NEWVER1..SMARTBUFF_VERSION..SMARTBUFF_MSG_NEWVER2..arg2..SMARTBUFF_MSG_NEWVER3) + SmartbuffSession = false + end + -- guild version check - for my use testing the addon with the guild testers. -- + if arg5 and arg5 ~= UnitName("player") and SmartbuffVerCheck then + DEFAULT_CHAT_FRAME:AddMessage("|cff00e0ffSmartbuff : |cffFFFF00"..arg5.." ("..arg3..")|cffffffff has revision |cffFFFF00r"..arg2.."|cffffffff installed.") + end + end + end + end + + -- SMARTBUFF_UPDATE + if (event == "SMARTBUFF_UPDATE" and isLoaded and isPlayer and not isInit and not InCombatLockdown()) then + SMARTBUFF_Options_Init(self); + end + + if (not isInit or O == nil) then + return; + end; + + -- GROUP_ROSTER_UPDATE + if (event == "GROUP_ROSTER_UPDATE") then + isSetUnits = true; + + -- PLAYER_REGEN_DISABLED + elseif (event == "PLAYER_REGEN_DISABLED") then + SMARTBUFF_Ticker(true); + + if (O.Toggle) then + if (O.InCombat) then + for spell, data in pairs(cBuffsCombat) do + if (data and data.Unit and data.ActionType) then + if (data.Type == SMARTBUFF_CONST_SELF or data.Type == SMARTBUFF_CONST_FORCESELF or data.Type == SMARTBUFF_CONST_STANCE or data.Type == SMARTBUFF_CONST_ITEM) then + SmartBuff_KeyButton:SetAttribute("unit", nil); + else + SmartBuff_KeyButton:SetAttribute("unit", data.Unit); + end + SmartBuff_KeyButton:SetAttribute("type", data.ActionType); + SmartBuff_KeyButton:SetAttribute("spell", spell); + SmartBuff_KeyButton:SetAttribute("item", nil); + SmartBuff_KeyButton:SetAttribute("target-slot", nil); + SmartBuff_KeyButton:SetAttribute("target-item", nil); + SmartBuff_KeyButton:SetAttribute("macrotext", nil); + SmartBuff_KeyButton:SetAttribute("action", nil); + SMARTBUFF_AddMsgD("Enter Combat, set button: " .. spell .. " on " .. data.Unit .. ", " .. data.ActionType); + break; + end + end + end + SMARTBUFF_SyncBuffTimers(); + SMARTBUFF_Check(1, true); + end + + -- PLAYER_REGEN_ENABLED + elseif (event == "PLAYER_REGEN_ENABLED") then + SMARTBUFF_Ticker(true); + if (O.Toggle) then + if (O.InCombat) then + SmartBuff_KeyButton:SetAttribute("type", nil); + SmartBuff_KeyButton:SetAttribute("unit", nil); + SmartBuff_KeyButton:SetAttribute("spell", nil); + end + SMARTBUFF_SyncBuffTimers(); + SMARTBUFF_Check(1, true); + end + + -- PLAYER_STARTED_MOVING / PLAYER_STOPPED_MOVING + elseif (event == "PLAYER_STARTED_MOVING") then + isPlayerMoving = true; + + elseif (event == "PLAYER_STOPPED_MOVING") then + isPlayerMoving = false; + + -- SPELLS_CHANGED / ACTIONBAR_HIDEGRID + elseif (event == "SPELLS_CHANGED" or event == "ACTIONBAR_HIDEGRID") then + isSetBuffs = true; + end + + if (not O.Toggle) then + return; + end; + + -- UNIT_AURA + if (event == "UNIT_AURA") then + if (UnitAffectingCombat("player") and (arg1 == "player" or string.find(arg1, "^party") or string.find(arg1, "^raid"))) then + isSyncReq = true; + end + -- checks if aspect of cheetah or pack is active and cancel it if someone gets dazed + if (sPlayerClass == "HUNTER" and O.AntiDaze and (arg1 == "player" or string.find(arg1, "^party") or string.find(arg1, "^raid") or string.find(arg1, "pet"))) then + local _, _, stuntex = GetSpellInfo(1604); --get Dazed icon + if (SMARTBUFF_IsDebuffTexture(arg1, stuntex)) then + buff = nil; + if (arg1 == "player" and SMARTBUFF_CheckBuff(arg1, SMARTBUFF_AOTC)) then + buff = SMARTBUFF_AOTC; + elseif (SMARTBUFF_CheckBuff(arg1, SMARTBUFF_AOTP, true)) then + buff = SMARTBUFF_AOTP; + end + if (buff) then + if (O.ToggleAutoSplash and not SmartBuffOptionsFrame:IsVisible()) then + SmartBuffSplashFrame:Clear(); + SmartBuffSplashFrame:SetTimeVisible(1); + SmartBuffSplashFrame:AddMessage("!!! CANCEL "..buff.." !!!", O.ColSplashFont.r, O.ColSplashFont.g, O.ColSplashFont.b, 1.0); + end + if (O.ToggleAutoChat) then + SMARTBUFF_AddMsgWarn("!!! CANCEL "..buff.." !!!", true); + end + end + end + end + end + + -- UI_ERROR_MESSAGE + if (event == "UI_ERROR_MESSAGE") then + SMARTBUFF_AddMsgD(string.format("Error message: %s",arg1)); + end + + -- UNIT_SPELLCAST_FAILED + if (event == "UNIT_SPELLCAST_FAILED") then + currentUnit = arg1; + SMARTBUFF_AddMsgD(string.format("Spell failed: %s",arg1)); + if (currentUnit and (string.find(currentUnit, "party") or string.find(currentUnit, "raid") or (currentUnit == "target" and O.Debug))) then + if (UnitName(currentUnit) ~= sPlayerName and O.BlacklistTimer > 0) then + cBlacklist[currentUnit] = GetTime(); + if (currentUnit and UnitName(currentUnit)) then + SMARTBUFF_AddMsgWarn(UnitName(currentUnit).." ("..currentUnit..") blacklisted ("..O.BlacklistTimer.."sec)"); + end + end + end + currentUnit = nil; + + -- UNIT_SPELLCAST_SUCCEEDED + elseif (event == "UNIT_SPELLCAST_SUCCEEDED") then + if (arg1 and arg1 == "player") then + local unit = nil; + local spell = nil; + local target = nil; + + if (arg1 and arg2) then + if (not arg3) then arg3 = ""; end + if (not arg4) then arg4 = ""; end + SMARTBUFF_AddMsgD("Spellcast succeeded: " .. arg1 .. ", " .. arg2 .. ", " .. arg3 .. ", " .. arg4) + if (string.find(arg1, "party") or string.find(arg1, "raid")) then + spell = arg2; + end + --SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, imgSB); + end + if (currentUnit and currentSpell and currentUnit ~= "target") then + unit = currentUnit; + spell = currentSpell; + end + if (unit) then + local name = UnitName(unit); + if (cBuffTimer[unit] == nil) then + cBuffTimer[unit] = { }; + end + --if (not SMARTBUFF_IsPlayer(unit)) then + cBuffTimer[unit][spell] = GetTime(); + --end + if (name ~= nil) then + SMARTBUFF_AddMsg(name .. ": " .. spell .. " " .. SMARTBUFF_MSG_BUFFED); + currentUnit = nil; + currentSpell = nil; + currentRank = nil; + end + end + if (isClearSplash) then + isClearSplash = false; + SMARTBUFF_Splash_Clear(); + end + end + end + +end + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_OnUpdate -------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_OnUpdate(self, elapsed) + if not self.Elapsed then + self.Elapsed = 0.2 + end + self.Elapsed = self.Elapsed - elapsed + if self.Elapsed > 0 then + return + end + self.Elapsed = 0.2 + + if (not isInit) then + if (isLoaded and GetTime() > tAutoBuff + 0.5) then + tAutoBuff = GetTime(); + _, tName = GetTalentInfo(1, 1, 1); + if (tName) then + SMARTBUFF_OnEvent(self, "SMARTBUFF_UPDATE"); + end + end + else + if (isSetZone and GetTime() > (tStartZone + 4)) then + SMARTBUFF_CheckLocation(); + end + SMARTBUFF_Ticker(); + SMARTBUFF_Check(1); + end +end + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_Ticker ---------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_Ticker(force) + if (force or GetTime() > tTicker + 1) then + tTicker = GetTime(); + + if (isSetUnits) then + isSetUnits = false; + SMARTBUFF_SetUnits(); + isSyncReq = true; + end + + if (isSyncReq or tTicker > tSync + 10) then + SMARTBUFF_SyncBuffTimers(); + end + + if (isAuraChanged) then + isAuraChanged = false; + --SMARTBUFF_AddMsgD("Force check"); + SMARTBUFF_Check(1, true); + end + + end +end + +------------------------------------------------------------------------------------------------------------------------------------- +-- +-- SMARTBUFF_AddMsg +-- SMARTBUFF_AddMsgErr +-- SMARTBUFF_AddMsgWarn +-- SMARTBUFF_AddMsgD +-- +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_AddMsg(msg, force) + if (DEFAULT_CHAT_FRAME and (force or not O.ToggleMsgNormal)) then + DEFAULT_CHAT_FRAME:AddMessage(YLL .. msg .. "|r"); + end +end + +function SMARTBUFF_AddMsgErr(msg, force) + if (DEFAULT_CHAT_FRAME and (force or not O.ToggleMsgError)) then + DEFAULT_CHAT_FRAME:AddMessage(RDL .. SMARTBUFF_TITLE .. ": " .. msg .. "|r"); + end +end + +function SMARTBUFF_AddMsgWarn(msg, force) + if (DEFAULT_CHAT_FRAME and (force or not O.ToggleMsgWarning)) then + if (isParrot) then + Parrot:ShowMessage(CY .. msg .. "|r"); + else + DEFAULT_CHAT_FRAME:AddMessage(CY .. msg .. "|r"); + end + end +end + +function SMARTBUFF_AddMsgD(msg, r, g, b) + if (r == nil) then r = 0.5; end + if (g == nil) then g = 0.8; end + if (b == nil) then b = 1; end + if (DebugChatFrame and O and O.Debug) then + DebugChatFrame:AddMessage(msg, r, g, b); + end +end + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_SetUnits() +-- Creates a array of units in a party or raid. +------------------------------------------------------------------------------------------------------------------------------------- + +function SMARTBUFF_SetUnits() + --if (not isInit or not O.Toggle) then return; end + if (InCombatLockdown()) then + isSetUnits = true; + return; + end + if (SmartBuffOptionsFrame:IsVisible()) then return; end + + local i = 0; + local n = 0; + local j = 0; + local s = nil; + local psg = 0; + local b = false; + local iBFA = SMARTBUFF_IsActiveBattlefield(); + + if (iBFA > 0) then + SMARTBUFF_CheckLocation(); + end + + -- player + -- pet + -- party1-4 + -- partypet1-4 + -- raid1-40 + -- raidpet1-40 + + iGroupSetup = -1; + if (IsInRaid()) then + iGroupSetup = 3; + elseif (GetNumSubgroupMembers() ~= 0) then + iGroupSetup = 2; + else + iGroupSetup = 1; + end + + if (iGroupSetup ~= iLastGroupSetup) then + iLastGroupSetup = iGroupSetup; + wipe(cBlacklist); + wipe(cBuffTimer); + if (SMARTBUFF_TEMPLATES[iGroupSetup] == nil) then + SMARTBUFF_SetBuffs(); + end + local tmp = SMARTBUFF_TEMPLATES[iGroupSetup]; + if (O.AutoSwitchTemplate and currentTemplate ~= tmp and iBFA == 0) then + SMARTBUFF_AddMsg(SMARTBUFF_OFT_AUTOSWITCHTMP .. ": " .. currentTemplate .. " -> " .. tmp); + currentTemplate = tmp; + SMARTBUFF_SetBuffs(); + end + SMARTBUFF_MiniGroup_Show(); + --SMARTBUFF_AddMsgD("Group type changed"); + end + + wipe(cUnits); + wipe(cGroups); + cClassGroups = nil; + wipe(cAddUnitList); + wipe(cIgnoreUnitList); + + -- Raid Setup + if (iGroupSetup == 3) then + cClassGroups = { }; + local name, server, rank, subgroup, level, class, classeng, zone, online, isDead, role; + local sRUnit = nil; + + j = 1; + for n = 1, maxRaid, 1 do + -- GetRaidRosterInfo role returns "MAINTANK" or "MAINASSIST" + name, rank, subgroup, level, class, classeng, zone, online, isDead, role = GetRaidRosterInfo(n); + if (name) then + server = nil; + i = string.find(name, "-", 1, true); + if (i and i > 0) then + server = string.sub(name, i + 1); + name = string.sub(name, 1, i - 1); + SMARTBUFF_AddMsgD(name .. ", " .. server); + end + sRUnit = "raid"..n; + + -- Debug ---------------------------------------------------------------------------------------- +-- if role then print("Player: ".. name .. ", " .. sRUnit .. ", " .. role); end + + SMARTBUFF_AddUnitToClass("raid", n, role); + SmartBuff_AddToUnitList(1, sRUnit, subgroup); + SmartBuff_AddToUnitList(2, sRUnit, subgroup); + + if (name == sPlayerName and not server) then + psg = subgroup; + end + + if (O.ToggleGrp[subgroup]) then + s = ""; + if (name == UnitName(sRUnit)) then + if (cGroups[subgroup] == nil) then + cGroups[subgroup] = { }; + end + if (name == sPlayerName and not server) then b = true; end + cGroups[subgroup][j] = sRUnit; + j = j + 1; + end + end + -- attempt to announce the addon version (if they have it) + if online then SendSmartbuffVersion(name, sRUnit) end + end + end --end for + + if (not b or B[CS()][currentTemplate].SelfFirst) then + SMARTBUFF_AddSoloSetup(); + iLastSubgroup = psg; + --SMARTBUFF_AddMsgD("Player not in selected groups or buff self first"); + end + + if (iLastSubgroup ~= psg) then + SMARTBUFF_AddMsgWarn(SMARTBUFF_TITLE .. ": " .. SMARTBUFF_MSG_SUBGROUP); + if (O.ToggleSubGrpChanged) then + O.ToggleGrp[psg] = true; + if (SmartBuffOptionsFrame:IsVisible()) then + SMARTBUFF_ShowSubGroupsOptions(); + else + SMARTBUFF_OptionsFrame_Open(); + end + end + iLastSubgroup = psg; + end + + SMARTBUFF_AddMsgD("Raid Unit-Setup finished"); + + -- Party Setup + elseif (iGroupSetup == 2) then + + cClassGroups = { }; + if (B[CS()][currentTemplate].SelfFirst) then + SMARTBUFF_AddSoloSetup(); + end + cGroups[1] = { }; + cGroups[1][0] = "player"; + SMARTBUFF_AddUnitToClass("player", 0, nil); + for j = 1, 4, 1 do + cGroups[1][j] = "party"..j; + SMARTBUFF_AddUnitToClass("party", j, nil); + SmartBuff_AddToUnitList(1, "party"..j, 1); + SmartBuff_AddToUnitList(2, "party"..j, 1); + name, _, _, _, _, _, _, online, _, _ = GetRaidRosterInfo(j); + if name and online then SendSmartbuffVersion(name, "party") end + + -- debug +-- if name then print("Player: ".. name .. ", " .. "party"..j .. "."); end + + + end + SMARTBUFF_AddMsgD("Party Unit-Setup finished"); + + -- Solo Setup + else + SMARTBUFF_AddSoloSetup(); + SMARTBUFF_AddMsgD("Solo Unit-Setup finished"); + end + + collectgarbage(); +end + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_AddUnitToClass -------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_AddUnitToClass(unit, i, proll) + local u = unit; + local up = "pet"; + if (unit ~= "player") then + u = unit..i; + up = unit.."pet"..i; + end + if (UnitExists(u)) then + if (not cUnits[1]) then + cUnits[1] = { }; + end + cUnits[1][i] = u; + SMARTBUFF_AddMsgD("Unit added: " .. UnitName(u) .. ", " .. u); + + local _, uc = UnitClass(u); + if (uc and not cClassGroups[uc]) then + cClassGroups[uc] = { }; + else + if u and uc then + cClassGroups[uc][i] = u; + end + end + + if uc and proll == "MAINTANK" then + if (not cClassGroups["TANK"]) then + cClassGroups["TANK"] = { }; + end + cClassGroups["TANK"][i] = u; + end; + + if (uc and uc == "HUNTER") then + if (not cClassGroups["HPET"]) then + cClassGroups["HPET"] = { }; + end + cClassGroups["HPET"][i] = up; + + elseif (uc and uc == "DEATHKNIGHT") then + if (not cClassGroups["DKPET"]) then + cClassGroups["DKPET"] = { }; + end + cClassGroups["DKPET"][i] = up; + + elseif (uc and (uc == "WARLOCK" or uc == "MAGE")) then + if (not cClassGroups["WPET"]) then + cClassGroups["WPET"] = { }; + end + cClassGroups["WPET"][i] = up; + end + + end +end + +function SMARTBUFF_AddSoloSetup() + cGroups[0] = { }; + cGroups[0][0] = "player"; + cUnits[0] = { }; + cUnits[0][0] = "player"; + if (sPlayerClass == "HUNTER" or sPlayerClass == "WARLOCK" or sPlayerClass == "MAGE") then cGroups[0][1] = "pet"; end + if (B[CS()][currentTemplate]) then + if (not cClassGroups) then + cClassGroups = { }; + end + cClassGroups[0] = { }; + cClassGroups[0][0] = "player"; + end +end +-- END SMARTBUFF_SetUnits + + + + + + + + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_GetSpellID +-- Read available spells / abilities from spell book including spellid's +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_GetSpellID(spellname) + + if (spellname) then spellname = string.lower(spellname); else return nil; end + + local i = 0; + local nSpells = 0; + local id = nil; + local spellN, spellId, skillType; + + -- Get number of spells + for i = 1, GetNumSpellTabs() do + local _, _, _, n = GetSpellTabInfo(i); + nSpells = nSpells + n; + end + + i = 0; + while (i < nSpells) do + i = i + 1; + spellN = GetSpellBookItemName(i, BOOKTYPE_SPELL); + skillType, spellId = GetSpellBookItemInfo(i, BOOKTYPE_SPELL); + --print(spellN.." "..spellId); + + if (skillType == "FLYOUT") then + for j = 1, GetNumFlyouts() do + local fid = GetFlyoutID(j); + local name, description, numSlots, isKnown = GetFlyoutInfo(fid) + if (isKnown) then + for s = 1, numSlots do + local flySpellID, overrideSpellID, isKnown, spellN, slotSpecID = GetFlyoutSlotInfo(fid, s); + if (isKnown and string.lower(spellN) == spellname) then + --print(spellname.." "..spellN.." "..flySpellID); + return flySpellID; + end + end + end + end + end + + if (spellN ~= nil and string.lower(spellN) == spellname) then + id = spellId; + break; + end + end + + if (id) then + if (IsPassiveSpell(id) or skillType == "FUTURESPELL" or not IsSpellKnown(id)) then + id = nil; + i = nil; + end + end + +-- if i and id then print("Spell Name: "..spellname..", id: "..id..", i: " .. i); end; + + return id, i; +end + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_SetBuffs() +-- Setup the buff array +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_SetBuffs() + + if (B == nil) then return; end + + local n = 1; + local buff = nil; + local ct = currentTemplate; + + if (B[CS()] == nil) then + B[CS()] = { }; + end + + SMARTBUFF_InitItemList(); + SMARTBUFF_InitSpellList(); + + if (B[CS()][ct] == nil) then + B[CS()][ct] = { }; + B[CS()][ct].SelfFirst = false; + end + + if (B[CS()][ct].GrpBuffSize == nil) then + B[CS()][ct].GrpBuffSize = 3; + end + + wipe(cBuffs); + wipe(cBuffIndex); + numBuffs = 0; + + for _, buff in pairs(SMARTBUFF_BUFFLIST) do + n = SMARTBUFF_SetBuff(buff, n, true); + end + + for _, buff in pairs(SMARTBUFF_WEAPON) do + n = SMARTBUFF_SetBuff(buff, n); + end + + for _, buff in pairs(SMARTBUFF_RACIAL) do + n = SMARTBUFF_SetBuff(buff, n); + end + + for _, buff in pairs(SMARTBUFF_TRACKING) do + n = SMARTBUFF_SetBuff(buff, n); + end + + for _, buff in pairs(SMARTBUFF_POTION) do + n = SMARTBUFF_SetBuff(buff, n); + end + + for _, buff in pairs(SMARTBUFF_SCROLL) do + n = SMARTBUFF_SetBuff(buff, n); + end + + for _, buff in pairs(SMARTBUFF_FOOD) do + n = SMARTBUFF_SetBuff(buff, n); + end + + wipe(cBuffsCombat); + SMARTBUFF_SetInCombatBuffs(); + + InitBuffOrder(); + + numBuffs = n - 1; + isSetBuffs = false; +end + + +------------------------------------------------------------------------------------------------------------------------------------- +-- SMARTBUFF_SetBuff +------------------------------------------------------------------------------------------------------------------------------------- +function SMARTBUFF_SetBuff(buff, i, ia) + + if (buff == nil or buff[1] == nil or i > maxScrollButtons) then return i; end + + cBuffs[i] = nil; + cBuffs[i] = { }; + cBuffs[i].BuffS = buff[1]; + cBuffs[i].DurationS = ceil(buff[2] * 60); + cBuffs[i].Type = buff[3]; + cBuffs[i].CanCharge = false; + + if (SMARTBUFF_IsSpell(cBuffs[i].Type) or cBuffs[i].Type == SMARTBUFF_CONST_TRACK) then + cBuffs[i].IDS, cBuffs[i].BookID = SMARTBUFF_GetSpellID(cBuffs[i].BuffS); +-- if cBuffs[i].IDS then print("Id: "..cBuffs[i].IDS.." BookId:"..cBuffs[i].BookID); end + end + + if (cBuffs[i].IDS == nil and not(SMARTBUFF_IsItem(cBuffs[i].Type))) then + cBuffs[i] = nil; + return i; + end + + if (buff[4] ~= nil) then cBuffs[i].LevelsS = buff[4] else cBuffs[i].LevelsS = nil end + if (buff[5] ~= nil) then cBuffs[i].Params = buff[5] else cBuffs[i].Params = SG.NIL end + + if (cBuffs[i].IDS ~= nil) then + cBuffs[i].IconS = GetSpellTexture(cBuffs[i].BuffS); + else + if (cBuffs[i].Type == SMARTBUFF_CONST_TRACK) then + + + elseif (cBuffs[i].Type == SMARTBUFF_CONST_ITEMGROUP) then + local _, _, _, _, minLevel, _, _, _, _, texture = GetItemInfo(cBuffs[i].BuffS); + if (not IsMinLevel(minLevel)) then + cBuffs[i] = nil; + return i; + end + cBuffs[i].IconS = texture; + + else + local _, _, _, _, minLevel = GetItemInfo(cBuffs[i].BuffS); + if (not IsMinLevel(minLevel)) then + cBuffs[i] = nil; + return i; + end + + local _, _, count, texture = SMARTBUFF_FindItem(cBuffs[i].BuffS, cBuffs[i].Chain); + if (count <= 0) then + cBuffs[i] = nil; + return i; + end + cBuffs[i].IconS = texture; + end + end + + -- debug +-- print("Add "..buff[1]); + + cBuffs[i].Links = buff[6]; + cBuffs[i].Chain = buff[7]; + cBuffs[i].BuffG = buff[8]; + + cBuffs[i].IDG = SMARTBUFF_GetSpellID(cBuffs[i].BuffG); + if (cBuffs[i].IDG ~= nil) then + cBuffs[i].IconG = GetSpellTexture(cBuffs[i].BuffG); + else + cBuffs[i].IconG = nil; + end + if (buff[9] ~= nil) then cBuffs[i].DurationG = ceil(buff[9] * 60); else cBuffs[i].DurationG = nil; end + if (buff[10] ~= nil) then cBuffs[i].LevelsG = buff[10]; else cBuffs[i].LevelsG = nil; end + if (buff[11] ~= nil) then cBuffs[i].ReagentG = buff[11]; else cBuffs[i].ReagentG = nil; end + + cBuffIndex[cBuffs[i].BuffS] = i; + if (cBuffs[i].IDG ~= nil) then + cBuffIndex[cBuffs[i].BuffG] = i; + end + + InitBuffSettings(cBuffs[i]); + + return i + 1; +end + + +function SMARTBUFF_SetInCombatBuffs() + local ct = currentTemplate; + if (ct == nil or B[CS()] == nil or B[CS()][ct] == nil) then + return; + end + for name, data in pairs(B[CS()][ct]) do + --SMARTBUFF_AddMsgD(name .. ", type = " .. type(data)); + if (type(data) == "table" and cBuffIndex[name] and (B[CS()][ct][name].EnableS or B[CS()][ct][name].EnableG) and B[CS()][ct][name].CIn) then + if (cBuffsCombat[name]) then + wipe(cBuffsCombat[name]); + else + cBuffsCombat[name] = { }; + end + cBuffsCombat[name].Unit = "player"; + cBuffsCombat[name].Type = cBuffs[cBuffIndex[name]].Type; + cBuffsCombat[name].ActionType = "spell"; + SMARTBUFF_AddMsgD("Set combat spell: " .. name); + --break; + end + end +end +-- END SMARTBUFF_SetBuffs + + +function SMARTBUFF_IsTalentFrameVisible() + return PlayerTalentFrame and PlayerTalentFrame:IsVisible(); +end + + +-- Main Check functions +function SMARTBUFF_PreCheck(mode, force) + if (not isInit) then return false end + + if (not isInitBtn) then + SMARTBUFF_InitActionButtonPos(); + end + + if (not O.Toggle) then + if (mode == 0) then + SMARTBUFF_AddMsg(SMARTBUFF_MSG_DISABLED); + end + return false; + end + + if (mode == 1 and not force) then + if ((GetTime() - tLastCheck) < O.AutoTimer) then + return false; + end + end + + tLastCheck = GetTime(); + SMARTBUFF_ShowSAButton(); + --end + + SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, imgSB); + if (SmartBuffOptionsFrame:IsVisible()) then return false; end + + -- check for mount-spells + if (sPlayerClass == "PALADIN" and (IsMounted() or IsFlying()) and not SMARTBUFF_CheckBuff("player", SMARTBUFF_CRUSADERAURA)) then + return true; + end + + if ((mode == 1 and not O.ToggleAuto) or IsMounted() or IsFlying() or LootFrame:IsVisible() + or UnitOnTaxi("player") or UnitIsDeadOrGhost("player") or UnitIsCorpse("player") + or (mode ~= 1 and (SMARTBUFF_IsPicnic("player") or SMARTBUFF_IsFishing("player"))) + or (UnitInVehicle("player") or UnitHasVehicleUI("player")) + --or (mode == 1 and (O.ToggleAutoRest and IsResting()) and not UnitIsPVP("player")) + or (not O.BuffInCities and IsResting() and not UnitIsPVP("player"))) then + + if (UnitIsDeadOrGhost("player")) then + SMARTBUFF_CheckBuffTimers(); + end + + return false; + end + + if (UnitAffectingCombat("player")) then + isCombat = true; + --SMARTBUFF_AddMsgD("In combat"); + else + isCombat = false; + --SMARTBUFF_AddMsgD("Out of combat"); + end + + if (not isCombat and isSetBuffs) then + SMARTBUFF_SetBuffs(); + isSyncReq = true; + end + + sMsgWarning = ""; + isFirstError = true; + + return true; +end + + +-- Bufftimer check functions +function SMARTBUFF_CheckBuffTimers() + local n = 0; + local ct = currentTemplate; + local cGrp = cUnits; + for subgroup in pairs(cGrp) do + n = 0; + if (cGrp[subgroup] ~= nil) then + for _, unit in pairs(cGrp[subgroup]) do + if (unit) then + if (SMARTBUFF_CheckUnitBuffTimers(unit)) then + n = n + 1; + end + end + end + if (cBuffTimer[subgroup]) then + cBuffTimer[subgroup] = nil; + SMARTBUFF_AddMsgD("Group " .. subgroup .. ": group timer reseted"); + end + end + end +end +-- END SMARTBUFF_CheckBuffTimers + +-- if unit is dead, remove all timers +function SMARTBUFF_CheckUnitBuffTimers(unit) + if (UnitExists(unit) and UnitIsConnected(unit) and UnitIsFriend("player", unit) and UnitIsPlayer(unit) and UnitIsDeadOrGhost(unit)) then + local _, uc = UnitClass(unit); + local fd = nil; + if (uc == "HUNTER") then + fd = SMARTBUFF_IsFeignDeath(unit); + end + if (not fd) then + if (cBuffTimer[unit]) then + cBuffTimer[unit] = nil; + SMARTBUFF_AddMsgD(UnitName(unit) .. ": unit timer reset"); + end + if (cBuffTimer[uc]) then + cBuffTimer[uc] = nil; + SMARTBUFF_AddMsgD(uc .. ": class timer reset"); + end + return true; + end + end +end +-- END SMARTBUFF_CheckUnitBuffTimers + + +-- Reset the buff timers and set them to running out soon +function SMARTBUFF_ResetBuffTimers() + if (not isInit) then return; end + + local ct = currentTemplate; + local t = GetTime(); + local rbTime = 0; + local i = 0; + local d = 0; + local tl = 0; + local buffS = nil; + local buff = nil; + local unit = nil; + local obj = nil; + local uc = nil; + + local cGrp = cGroups; + for subgroup in pairs(cGrp) do + n = 0; + if (cGrp[subgroup] ~= nil) then + + for _, unit in pairs(cGrp[subgroup]) do + if (unit and UnitExists(unit) and UnitIsConnected(unit) and UnitIsFriend("player", unit) and UnitIsPlayer(unit) and not UnitIsDeadOrGhost(unit)) then + _, uc = UnitClass(unit); + i = 1; + while (cBuffs[i] and cBuffs[i].BuffS) do + d = -1; + buff = nil; + rbTime = 0; + buffS = cBuffs[i].BuffS; + + rbTime = B[CS()][ct][buffS].RBTime; + if (rbTime <= 0) then + rbTime = O.RebuffTimer; + end + + if (cBuffs[i].BuffG and B[CS()][ct][buffS].EnableG and cBuffs[i].IDG ~= nil and cBuffs[i].DurationG > 0) then + d = cBuffs[i].DurationG; + buff = cBuffs[i].BuffG; + obj = subgroup; + end + + if (d > 0 and buff) then + if (not cBuffTimer[obj]) then + cBuffTimer[obj] = { }; + end + cBuffTimer[obj][buff] = t - d + rbTime - 1; + end + + buff = nil; + if (buffS and B[CS()][ct][buffS].EnableS and cBuffs[i].IDS ~= nil and cBuffs[i].DurationS > 0 + and uc and B[CS()][ct][buffS][uc]) then + d = cBuffs[i].DurationS; + buff = buffS; + obj = unit; + end + + if (d > 0 and buff) then + if (not cBuffTimer[obj]) then + cBuffTimer[obj] = { }; + end + cBuffTimer[obj][buff] = t - d + rbTime - 1; + end + + i = i + 1; + end + end + end + end + end + --isAuraChanged = true; + SMARTBUFF_Check(1, true); +end + +function SMARTBUFF_ShowBuffTimers() + if (not isInit) then return; end + + local ct = currentTemplate; + local t = GetTime(); + local rbTime = 0; + local i = 0; + local d = 0; + local tl = 0; + local buffS = nil; + + for unit in pairs(cBuffTimer) do + for buff in pairs(cBuffTimer[unit]) do + if (unit and buff and cBuffTimer[unit][buff]) then + + d = -1; + buffS = nil; + if (cBuffIndex[buff]) then + i = cBuffIndex[buff]; + if (cBuffs[i].BuffS == buff and cBuffs[i].DurationS > 0) then + d = cBuffs[i].DurationS; + buffS = cBuffs[i].BuffS; + elseif (cBuffs[i].BuffG == buff and cBuffs[i].DurationG > 0) then + d = cBuffs[i].DurationG; + buffS = cBuffs[i].BuffS; + end + i = i + 1; + end + + if (buffS and B[CS()][ct][buffS] ~= nil) then + if (d > 0) then + rbTime = B[CS()][ct][buffS].RBTime; + if (rbTime <= 0) then + rbTime = O.RebuffTimer; + end + tl = cBuffTimer[unit][buff] + d - t; + if (tl >= 0) then + local s = ""; + if (string.find(unit, "^party") or string.find(unit, "^raid") or string.find(unit, "^player") or string.find(unit, "^pet")) then + local un = UnitName(unit); + if (un) then + un = " (" .. un .. ")"; + else + un = ""; + end + s = "Unit " .. unit .. un; + elseif (string.find(unit, "^%d$")) then + s = "Grp " .. unit; + else + s = "Class " .. unit; + end + -- SMARTBUFF_AddMsg(string.format("%s: %s, time left: %.0f, rebuff time: %.0f", s, buff, tl, rbTime)); + else + cBuffTimer[unit][buff] = nil; + end + else + --SMARTBUFF_AddMsgD("Removed: " .. buff); + cBuffTimer[unit][buff] = nil; + end + end + + end + end + end + +end +-- END SMARTBUFF_ResetBuffTimers + + +-- Synchronize the internal buff timers with the UI timers +function SMARTBUFF_SyncBuffTimers() + if (not isInit or isSync or isSetBuffs or SMARTBUFF_IsTalentFrameVisible()) then return; end + isSync = true; + tSync = GetTime(); + + local ct = currentTemplate; + local rbTime = 0; + local i = 0; + local buffS = nil; + local unit = nil; + local uc = nil; + + local cGrp = nil; + if (sPlayerClass == "PALADIN" and cClassGroups) then + cGrp = cClassGroups; + else + cGrp = cGroups; + end + + for subgroup in pairs(cGrp) do + n = 0; + if (cGrp[subgroup] ~= nil) then + for _, unit in pairs(cGrp[subgroup]) do + if (unit and UnitExists(unit) and UnitIsConnected(unit) and UnitIsFriend("player", unit) and UnitIsPlayer(unit) and not UnitIsDeadOrGhost(unit)) then + _, uc = UnitClass(unit); + i = 1; + while (cBuffs[i] and cBuffs[i].BuffS) do + rbTime = 0; + buffS = cBuffs[i].BuffS; + + rbTime = B[CS()][ct][buffS].RBTime; + if (rbTime <= 0) then + rbTime = O.RebuffTimer; + end + + if (cBuffs[i].BuffG and B[CS()][ct][buffS].EnableG and cBuffs[i].IDG ~= nil and cBuffs[i].DurationG > 0) then + SMARTBUFF_SyncBuffTimer(unit, subgroup, cBuffs[i], true); + end + + if (buffS and B[CS()][ct][buffS].EnableS and cBuffs[i].IDS ~= nil and cBuffs[i].DurationS > 0) then + if (cBuffs[i].Type ~= SMARTBUFF_CONST_SELF or (cBuffs[i].Type == SMARTBUFF_CONST_SELF and SMARTBUFF_IsPlayer(unit))) then + --and uc and B[CS()][ct][buffS][uc]) then + --SMARTBUFF_AddMsgD("Buff timer sync check: " .. buffS); + SMARTBUFF_SyncBuffTimer(unit, unit, cBuffs[i], false); + end + end + + i = i + 1; + end -- END while + end + end -- END for + end + end -- END for + + isSync = false; + isSyncReq = false; +end + + +function SMARTBUFF_SyncBuffTimer(unit, grp, cBuff, isGrpBuff) + if (not unit or not grp or not cBuff) then return end + + local buff, d; + if (isGrpBuff) then + d = cBuff.DurationG; + buff = cBuff.BuffG; + else + d = cBuff.DurationS; + buff = cBuff.BuffS; + end + + if (d and d > 0 and buff) then + local t = GetTime(); + local ret, _, _, timeleft = SMARTBUFF_CheckUnitBuffs(unit, buff, cBuff.Type, cBuff.Links, cBuff.Chain); + if (ret == nil and timeleft ~= nil) then + if (not cBuffTimer[grp]) then cBuffTimer[grp] = { } end + st = Round(t - d + timeleft, 2); + if (not cBuffTimer[grp][buff] or (cBuffTimer[grp][buff] and cBuffTimer[grp][buff] ~= st)) then + cBuffTimer[grp][buff] = st; + if (timeleft > 60) then + SMARTBUFF_AddMsgD("Buff timer sync: " .. grp .. ", " .. buff .. ", " .. string.format("%.1f", timeleft/60) .. "min"); + else + SMARTBUFF_AddMsgD("Buff timer sync: " .. grp .. ", " .. buff .. ", " .. string.format("%.1f", timeleft) .. "sec"); + end + end + end + end +end + + +-- check if the player is shapeshifted +function SMARTBUFF_IsShapeshifted() + if (sPlayerClass == "SHAMAN") then + if (GetShapeshiftForm(true) > 0) then + return true, "Ghost Wolf"; + end + elseif (sPlayerClass == "DRUID") then + local i; + for i = 1, GetNumShapeshiftForms(), 1 do + local icon, active, castable, spellId = GetShapeshiftFormInfo(i); + local name = GetSpellInfo(spellId); + if (active and castable and name ~= SMARTBUFF_DRUID_TREANT) then + return true, name; + end + end + end + return false, nil; +end +-- END SMARTBUFF_IsShapeshifted + + +local IsChecking = false; +function SMARTBUFF_Check(mode, force) + if (IsChecking or not SMARTBUFF_PreCheck(mode, force)) then return; end + + IsChecking = true; + + local ct = currentTemplate; + local unit = nil; + local units = nil; + local unitsGrp = nil; + local unitB = nil; + local unitL = nil; + local unitU = nil; + local uLevel = nil; + local uLevelL = nil; + local uLevelU = nil; + local idL = nil; + local idU = nil; + local subgroup = 0; + local i; + local j; + local n; + local m; + local rc; + local rank; + local reagent; + local nGlobal = 0; + local tmpDisabled = { }; + + local buffs = nil; + if (SMARTBUFF_Buffs[CS()]) then + buffs = SMARTBUFF_Buffs[CS()][ct]; + end + + SMARTBUFF_checkBlacklist(); + + -- 1. check in combat buffs + if (InCombatLockdown()) then -- and O.InCombat + for spell in pairs(cBuffsCombat) do + if (spell) then + local ret, actionType, spellName, slot, unit, buffType = SMARTBUFF_BuffUnit("player", 0, mode, spell) + --SMARTBUFF_AddMsgD("Check combat spell: " .. spell .. ", ret = " .. ret); + if (ret and ret == 0) then + IsChecking = false; + return; + end + end + end + end + + -- 2. buff target, if enabled + if ((mode == 0 or mode == 5) and O.BuffTarget) then + local actionType, spellName, slot, buffType, rankText; + i, actionType, spellName, slot, _, buffType, rankText = SMARTBUFF_BuffUnit("target", 0, mode); + if (i <= 1) then + if (i == 0) then + --tLastCheck = GetTime() - O.AutoTimer + GlobalCd; + end + IsChecking = false; + return i, actionType, spellName, slot, "target", buffType, rankText; + end + end + + -- 3. check groups + local cGrp = nil; + local cOrd = nil; + cGrp = cGroups; + cOrd = cOrderGrp; + + isMounted = IsMounted() or IsFlying(); + + for _, subgroup in pairs(cOrd) do + --SMARTBUFF_AddMsgD("Checking subgroup " .. subgroup .. ", " .. GetTime()); + if (cGrp[subgroup] ~= nil or (type(subgroup) == "number" and subgroup == 1)) then + + if (cGrp[subgroup] ~= nil) then + units = cGrp[subgroup]; + else + units = nil; + end + + if (cUnits and type(subgroup) == "number" and subgroup == 1) then + unitsGrp = cUnits[1]; + else + unitsGrp = units; + end + + -- check group buff + if (buffs and unitsGrp and not isMounted) then + + i = 1; + local rbTime = 0; + while (cBuffs[i] and cBuffs[i].BuffS) do + local cBuff = cBuffs[i]; + local buffnS = cBuff.BuffS; + local buffnG = cBuff.BuffG; + local bs = buffs[buffnS]; + + if (buffnG and tmpDisabled[buffnG] == nil and bs and bs.EnableG and cBuff.IDG ~= nil + and ((isCombat and bs.CIn) or (not isCombat and bs.COut)) and IsPowerLimitOk(bs) + --and UnitMana("player") >= bs.ManaLimit + and (sPlayerClass ~= "PALADIN" or not cClassGroups or (sPlayerClass == "PALADIN" and (bs[subgroup] or (type(subgroup) == "number" and subgroup == 0))))) then + + local tmpUnits = { }; + local btl = 9999; + local bExp = false; + local target = ""; + + if (sPlayerClass == "PALADIN" and cClassGroups) then + for _, unit in pairs(units) do + local u = UnitClass(unit); + if (u) then + target = SMARTBUFF_MSG_CLASS .. " " .. u; + SMARTBUFF_AddMsgD(target); + break; + end + end + else + --target = SMARTBUFF_MSG_GROUP .. " " .. subgroup; + target = SMARTBUFF_MSG_GROUP; + end + + if (type(subgroup) == "number" and subgroup == 0) then + target = sPlayerName; + end + + rbTime = bs.RBTime; + if (rbTime <= 0) then + rbTime = SMARTBUFF_Options.RebuffTimer; + end + + if (cBuffTimer[subgroup] ~= nil and cBuffTimer[subgroup][buffnG] ~= nil) then + btl = cBuff.DurationG - (GetTime() - cBuffTimer[subgroup][buffnG]); + if (rbTime > 0 and rbTime >= btl) then + bExp = true; + if (mode == 1) then + -- clean up buff timer, if expired + if (btl < 0) then + cBuffTimer[subgroup][buffnG] = nil; + --SMARTBUFF_AddMsgD("Group " .. subgroup .. ": " .. buffnS .. " timer reset"); + tLastCheck = GetTime() - SMARTBUFF_Options.AutoTimer + 0.5; + return; + end + end + end + end + + SMARTBUFF_AddMsgD("Checking0 " .. buffnG); + n = 0; + m = 0; + j = 0; + uLevelL = 100; + uLevelU = 0; + unitL = nil; + unitU = nil; + unitB = nil; + for _, unit in pairs(unitsGrp) do + j = j + 1; + SMARTBUFF_AddMsgD("Checking1 " .. buffnG .. " " .. unit); + + --if (unit and (UnitIsPlayer(unit) or (sPlayerClass == "PALADIN" and (UnitPlayerOrPetInParty(unit) or UnitPlayerOrPetInRaid(unit)))) and not SMARTBUFF_IsInList(unit, UnitName(unit), SMARTBUFF_Buffs[CS()][ct][buffnS].IgnoreList)) then + if (unit and UnitIsPlayer(unit) and not SMARTBUFF_IsInList(unit, UnitName(unit), bs.IgnoreList)) then + + SMARTBUFF_AddMsgD("Checking2 " .. buffnG .. " " .. unit); + n = n + 1; + --if (UnitExists(unit) and not UnitIsDeadOrGhost(unit) and not UnitIsCorpse(unit) and UnitIsConnected(unit) and UnitIsVisible(unit) and not UnitOnTaxi(unit) and (SMARTBUFF_IsPlayer(unit) or not SMARTBUFF_Options.AdvGrpBuffRange or not SpellHasRange(cBuff.BuffG) or (IsSpellInRange(cBuff.BuffG, unit) == 1))) then + + if (UnitExists(unit) and not UnitIsDeadOrGhost(unit) and not UnitIsCorpse(unit) and UnitIsConnected(unit) and UnitIsVisible(unit) and not UnitOnTaxi(unit) and UnitInRange(unit) == 1) then + --if (sPlayerClass ~= "PALADIN") + tmpUnits[n] = unit; + uLevel = UnitLevel(unit); + if (uLevel < uLevelL) then + uLevelL = uLevel; + unitL = unit; + end + if (uLevel > uLevelU) then + uLevelU = uLevel; + unitU = unit; + unitB = unit; + end + local ret, idx, buffname; + ret, idx, buffname = SMARTBUFF_CheckUnitBuffs(unit, nil, buffnG); + if (ret ~= nil or bExp) then + m = m + 1; + end + end + end + + end -- end for units + + if (mode == 1 and m >= buffs.GrpBuffSize and n >= buffs.GrpBuffSize) then + SMARTBUFF_SetMissingBuffMessage(target, buffnG, false, 1, btl, bExp, false); + SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, cBuff.IconG); + return; + end + + if (unitL ~= nil and unitU ~=nil and unitB ~= nil and cBuff.IDG ~= nil) then + idU, rank = SMARTBUFF_CheckUnitLevel(unitU, cBuff.IDG, cBuff.LevelsG); + idL, rank = SMARTBUFF_CheckUnitLevel(unitL, cBuff.IDG, cBuff.LevelsG); + + if (idL ~= nil and idU ~= nil and idL == idU and rank > 0 and m >= buffs.GrpBuffSize and n >= buffs.GrpBuffSize) then + + reagent = cBuff.ReagentG[rank]; + if (reagent and mode ~= 1) then + rc = SMARTBUFF_CountReagent(reagent); + if (rc > 0) then + currentUnit = nil; + currentSpell = nil; + + SMARTBUFF_AddMsgD("Buffing group (" .. unitB .. ") " .. subgroup .. ", " .. idU .. ", " .. j .. ", "); + j = SMARTBUFF_doCast(unitB, idU, buffnG, nil, SMARTBUFF_CONST_ALL) + + if (j == 0) then + SMARTBUFF_AddMsg(target .. ": " .. buffnG .. " " .. SMARTBUFF_MSG_BUFFED); + SMARTBUFF_AddMsg(SMARTBUFF_MSG_STOCK .. " " .. reagent .. " = " .. (rc - 1)); + + if (sPlayerClass == "PALADIN") then + local _, uc = UnitClass(unitB); + if (cBuffTimer[uc] == nil) then + cBuffTimer[uc] = { }; + end + cBuffTimer[uc][buffnG] = GetTime(); + else + if (cBuffTimer[subgroup] == nil) then + cBuffTimer[subgroup] = { }; + end + cBuffTimer[subgroup][buffnG] = GetTime(); + end + + -- cleanup single buff timer + for _, unit in pairs(tmpUnits) do + if (cBuffTimer[unit] and cBuffTimer[unit][buffnS]) then + cBuffTimer[unit][buffnS] = nil; + end + end + + --tLastCheck = GetTime() - SMARTBUFF_Options.AutoTimer + GlobalCd; + return 0, SMARTBUFF_ACTION_SPELL, buffnG, -1, unitB, cBuff.Type; + end + else + SMARTBUFF_AddMsgWarn(SMARTBUFF_MSG_NOREAGENT .. " " .. reagent .. "! " .. buffnG .. " " .. SMARTBUFF_MSG_DEACTIVATED); + tmpDisabled[buffnG] = true; + --tinsert(tmpDisabled, buffnG); + --bs.EnableG = false; + end + elseif (reagent and mode == 1) then + SMARTBUFF_SetMissingBuffMessage(target, buffnG, false, 1, btl, bExp, false); + SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, cBuff.IconG); + return; + else + --SMARTBUFF_AddMsgD("Reagent = nil"); + end + end + end + end + + i = i + 1; + end -- END while buffs + end + + -- check buffs + if (units) then + for _, unit in pairs(units) do + if (isSetBuffs) then break; end + + local spellName, actionType, slot, buffType, rankText; + i, actionType, spellName, slot, _, buffType, rankText = SMARTBUFF_BuffUnit(unit, subgroup, mode); + + if (i <= 1) then + if (i == 0 and mode ~= 1) then + --tLastCheck = GetTime() - O.AutoTimer + GlobalCd; + if (actionType == SMARTBUFF_ACTION_ITEM) then + --tLastCheck = tLastCheck + 2; + end + end + IsChecking = false; + return i, actionType, spellName, slot, unit, buffType, rankText; + end + end + end + + end + end -- for groups + + if (mode == 0) then + if (sMsgWarning == "" or sMsgWarning == " ") then + SMARTBUFF_AddMsg(SMARTBUFF_MSG_NOTHINGTODO); + else + SMARTBUFF_AddMsgWarn(sMsgWarning); + sMsgWarning = ""; + end + end + --tLastCheck = GetTime(); + IsChecking = false; +end +-- END SMARTBUFF_Check + + +-- Buffs a unit +function SMARTBUFF_BuffUnit(unit, subgroup, mode, spell) + local bs = nil; + local buff = nil; + local buffname = nil; + local buffnS = nil; + local uc = nil; + local ur = "NONE"; + local un = nil; + local uct = nil; + local ucf = nil; + local r; + local rankText; + local i; + local bt = 0; + local cd = 0; + local cds = 0; + local charges = 0; + local handtype = ""; + local bExpire = false; + local isPvP = false; + local bufftarget = nil; + local rbTime = 0; + local bUsable = false; + local time = GetTime(); + local cBuff = nil; + local iId = nil; + local iSlot = -1; + + if (UnitIsPVP("player")) then isPvP = true end + + SMARTBUFF_CheckUnitBuffTimers(unit); + + --SMARTBUFF_AddMsgD("Checking " .. unit); + + if (UnitExists(unit) and UnitIsFriend("player", unit) and not UnitIsDeadOrGhost(unit) and not UnitIsCorpse(unit) + and UnitIsConnected(unit) and UnitIsVisible(unit) and not UnitOnTaxi(unit) and not cBlacklist[unit] + and ((not UnitIsPVP(unit) and (not isPvP or O.BuffPvP)) or (UnitIsPVP(unit) and (isPvP or O.BuffPvP)))) then + --and not SmartBuff_UnitIsIgnored(unit) + + _, uc = UnitClass(unit); + un = UnitName(unit); + ur = UnitGroupRolesAssigned(unit); + uct = UnitCreatureType(unit); + ucf = UnitCreatureFamily(unit); + if (uct == nil) then uct = ""; end + if (ucf == nil) then ucf = ""; end + +-- if (un) then SMARTBUFF_AddMsgD("Grp "..subgroup.." checking "..un.." ("..unit.."/"..uc.."/"..ur.."/"..uct.."/"..ucf..")", 0, 1, 0.5); end + + isShapeshifted, sShapename = SMARTBUFF_IsShapeshifted(); + --while (cBuffs[i] and cBuffs[i].BuffS) do + for i, buffnS in pairs(B[CS()].Order) do + if (isSetBuffs or SmartBuffOptionsFrame:IsVisible()) then break; end + cBuff = cBuffs[cBuffIndex[buffnS]]; + --buffnS = cBuff.BuffS; + bs = GetBuffSettings(buffnS); + bExpire = false; + handtype = ""; + charges = -1; + bufftarget = nil; + bUsable = false; + iId = nil; + iSlot = -1; + + if (not cBuff or not bs) then bUsable = false end + if (cBuff and bs) then bUsable = bs.EnableS end + + if (bUsable and spell and spell ~= buffnS) then + bUsable = false; + --SMARTBUFF_AddMsgD("Exclusive check on " .. spell .. ", current spell = " .. buffnS); + end + + if (bUsable and cBuff.Type == SMARTBUFF_CONST_SELF and not SMARTBUFF_IsPlayer(unit)) then bUsable = false end + if (bUsable and not cBuff.Type == SMARTBUFF_CONST_TRACK and not SMARTBUFF_IsItem(cBuff.Type) and not IsUsableSpell(buffnS)) then bUsable = false end + if (bUsable and bs.SelfNot and SMARTBUFF_IsPlayer(unit)) then bUsable = false end + if (bUsable and cBuff.Params == SG.CheckFishingPole and SMARTBUFF_IsFishingPoleEquiped()) then bUsable = false end + + -- Check for power threshold + if (bUsable) then + bUsable = IsPowerLimitOk(bs); + end + + -- Check for buffs which depends on a pet + if (bUsable and cBuff.Params == SG.CheckPet and UnitExists("pet")) then bUsable = false end + if (bUsable and cBuff.Params == SG.CheckPetNeeded and not UnitExists("pet")) then bUsable = false end + + -- Check for mount auras + isMounted = false; + if (bUsable and sPlayerClass == "PALADIN") then + isMounted = IsMounted() or IsFlying(); + if ((buffnS ~= SMARTBUFF_CRUSADERAURA and isMounted) or (buffnS == SMARTBUFF_CRUSADERAURA and not isMounted)) then + bUsable = false; + end + end + + + if (bUsable and not (cBuff.Type == SMARTBUFF_CONST_TRACK or SMARTBUFF_IsItem(cBuff.Type))) then + -- check if you have enough mana/rage/energy to cast + local isUsable, notEnoughMana = IsUsableSpell(buffnS); + if (notEnoughMana) then + bUsable = false; + --SMARTBUFF_AddMsgD("Buff " .. cBuff.BuffS .. ", not enough mana!"); + elseif (mode ~= 1 and isUsable == nil and buffnS ~= SMARTBUFF_PWS) then + bUsable = false; + --SMARTBUFF_AddMsgD("Buff " .. cBuff.BuffS .. " is not usable!"); + end + end + + if (bUsable and bs.EnableS and (cBuff.IDS ~= nil or SMARTBUFF_IsItem(cBuff.Type) or cBuff.Type == SMARTBUFF_CONST_TRACK) + and ((mode ~= 1 and ((isCombat and bs.CIn) or (not isCombat and bs.COut))) + or (mode == 1 and bs.Reminder and ((not isCombat and bs.COut) + or (isCombat and (bs.CIn or O.ToggleAutoCombat)))))) then + + --print("Check: "..buffnS) + + if (not bs.SelfOnly or (bs.SelfOnly and SMARTBUFF_IsPlayer(unit))) then + -- get current spell cooldown + cd = 0; + cds = 0; + if (cBuff.IDS) then + cds, cd = GetSpellCooldown(buffnS); + cd = (cds + cd) - time; + if (cd < 0) then + cd = 0; + end + --SMARTBUFF_AddMsgD(buffnS.." cd = "..cd); + end + + -- check if spell has cooldown + if (cd <= 0 or (mode == 1 and cd <= 1.5)) then + if (cBuff.IDS and sMsgWarning == SMARTBUFF_MSG_CD) then + sMsgWarning = " "; + end + + rbTime = bs.RBTime; + if (rbTime <= 0) then + rbTime = O.RebuffTimer; + end + + --SMARTBUFF_AddMsgD(uc.." "..CT()); + if (not SMARTBUFF_IsInList(unit, un, bs.IgnoreList) and (((cBuff.Type == SMARTBUFF_CONST_GROUP or cBuff.Type == SMARTBUFF_CONST_ITEMGROUP) + and (bs[ur] + or (bs.SelfOnly and SMARTBUFF_IsPlayer(unit)) + or (bs[uc] and (UnitIsPlayer(unit) or uct == SMARTBUFF_HUMANOID or (uc == "DRUID" and (uct == SMARTBUFF_BEAST or uct == SMARTBUFF_ELEMENTAL)))) + or (bs["HPET"] and uct == SMARTBUFF_BEAST and uc ~= "DRUID") + or (bs["DKPET"] and utc == SMARTBUFF_UNDEAD) + or (bs["WPET"] and (uct == SMARTBUFF_DEMON or (uc ~= "DRUID" and uct == SMARTBUFF_ELEMENTAL)) and ucf ~= SMARTBUFF_DEMONTYPE))) + or (cBuff.Type ~= SMARTBUFF_CONST_GROUP and SMARTBUFF_IsPlayer(unit)) + or SMARTBUFF_IsInList(unit, un, bs.AddList))) then + buff = nil; + + --Tracking ability ------------------------------------------------------------------------ + + if (cBuff.Type == SMARTBUFF_CONST_TRACK) then + if buildInfo >= 20502 then + -- assume we are TBC Classic + local count = (GetNumTrackingTypes())+1; -- GetNumTrackingTypes doesnt count "none" so add one to include it. + local trackingFound; + for n = 1, count do + local trackN, trackT, trackA, trackC = GetTrackingInfo(n); + if trackN == buffnS and trackA then + trackingFound = true; + break; + else + trackingFound = false; + end + end + if not trackingFound then + if (sPlayerClass ~= "DRUID" or ((not isShapeshifted and buffnS ~= SMARTBUFF_DRUID_TRACK) or (isShapeshifted and buffnS ~= SMARTBUFF_DRUID_TRACK) or (isShapeshifted and buffnS == SMARTBUFF_DRUID_TRACK and sShapename == SMARTBUFF_DRUID_CAT))) then + buff = buffnS; + end + end + else + -- we are below the minimal tbc build, assume its classic era / season of mastery. + local iconTrack = GetTrackingTexture(); + if (iconTrack ~= nil) then + SMARTBUFF_AddMsgD("Track already enabled: " .. iconTrack); + else + if (sPlayerClass ~= "DRUID" or ((not isShapeshifted and buffnS ~= SMARTBUFF_DRUID_TRACK) or (isShapeshifted and buffnS ~= SMARTBUFF_DRUID_TRACK) or (isShapeshifted and buffnS == SMARTBUFF_DRUID_TRACK and sShapename == SMARTBUFF_DRUID_CAT))) then + buff = buffnS; + SMARTBUFF_AddMsgD("Missing tracking: "..buffnS); + end + end + end + + -- Food, Scroll, Potion or conjured items ------------------------------------------------------------------------ + + elseif (cBuff.Type == SMARTBUFF_CONST_FOOD or cBuff.Type == SMARTBUFF_CONST_SCROLL or cBuff.Type == SMARTBUFF_CONST_POTION or + cBuff.Type == SMARTBUFF_CONST_ITEM or cBuff.Type == SMARTBUFF_CONST_ITEMGROUP) then + + if (cBuff.Type == SMARTBUFF_CONST_ITEM) then + bt = nil; + buff = nil; + if (cBuff.Params ~= SG.NIL) then + local cr = SMARTBUFF_CountReagent(cBuff.Params, cBuff.Chain); + --SMARTBUFF_AddMsgD(cr.." "..cBuff.Params.." found"); + if (cr == 0) then + buff = cBuff.Params; + end + end + + -- only prompt / apply food when I am not moving - this would constantly use food + -- in your bags if you were moving - bugfix 03/12/2021. + + elseif (cBuff.Type == SMARTBUFF_CONST_FOOD and isPlayerMoving == false) then + if (not SMARTBUFF_IsPicnic(unit)) then + buff, index, buffname, bt, charges = SMARTBUFF_CheckUnitBuffs(unit, SMARTBUFF_FOOD_AURA, cBuff.Type, cBuff.Links, cBuff.Chain); + end + + else + if (cBuff.Params ~= SG.NIL) then + if (cBuff.Links and cBuff.Links == SG.CheckFishingPole) then + if (SMARTBUFF_IsFishingPoleEquiped()) then + buff, index, buffname, bt, charges = SMARTBUFF_CheckUnitBuffs(unit, cBuff.Params, cBuff.Type); + else + buff = nil; + end + else + buff, index, buffname, bt, charges = SMARTBUFF_CheckUnitBuffs(unit, cBuff.Params, cBuff.Type, cBuff.Links, cBuff.Chain); + end + --SMARTBUFF_AddMsgD("Buff time ("..cBuff.Params..") = "..tostring(bt)); + else + buff = nil; + end + end + + if (buff == nil and cBuff.DurationS >= 1 and rbTime > 0) then + if (charges == nil) then charges = -1; end + if (charges > 1) then cBuff.CanCharge = true; end + bufftarget = nil; + end + + if (bt and bt <= rbTime) then + buff = buffnS; + bExpire = true; + end + + if (buff) then + if (cBuff.Type ~= SMARTBUFF_CONST_ITEM) then + local cr, iid = SMARTBUFF_CountReagent(buffnS, cBuff.Chain); + if (cr > 0) then + buff = buffnS; + if (cBuff.Type == SMARTBUFF_CONST_ITEMGROUP or cBuff.Type == SMARTBUFF_CONST_SCROLL) then + cds, cd = GetItemCooldown(iid); + cd = (cds + cd) - time; + --SMARTBUFF_AddMsgD(cr.." "..buffnS.." found, cd = "..cd); + if (cd > 0) then + buff = nil; + end + end + --SMARTBUFF_AddMsgD(cr .. " " .. buffnS .. " found"); + else + --SMARTBUFF_AddMsgD("No " .. buffnS .. " found"); + buff = nil; + bExpire = false; + end + end + end + + -- Weapon buff ------------------------------------------------------------------------ + + elseif (cBuff.Type == SMARTBUFF_CONST_WEAPON or cBuff.Type == SMARTBUFF_CONST_INV) then + --SMARTBUFF_AddMsgD("Check weapon Buff"); + local bMh, tMh, cMh, idMh, bOh, tOh, cOh, idOh = GetWeaponEnchantInfo(); + + if (bs.MH) then + iSlot = 16; + iId = GetInventoryItemID("player", iSlot); + if (iId and SMARTBUFF_CanApplyWeaponBuff(buffnS, iSlot)) then + if (bMh) then + if (rbTime > 0 and cBuff.DurationS >= 1) then + --if (tMh == nil) then tMh = 0; end + tMh = floor(tMh/1000); + charges = cMh; + if (charges == nil) then charges = -1; end + if (charges > 1) then cBuff.CanCharge = true; end + --SMARTBUFF_AddMsgD(un .. " (WMH): " .. buffnS .. string.format(" %.0f sec left", tMh) .. ", " .. charges .. " charges left"); + if (tMh <= rbTime or (O.CheckCharges and cBuff.CanCharge and charges > 0 and charges <= O.MinCharges)) then + buff = buffnS; + bt = tMh; + bExpire = true; + end + end + else + handtype = "main"; + buff = buffnS; + end + else + --SMARTBUFF_AddMsgD("Weapon Buff cannot be cast, no mainhand weapon equipped or wrong weapon/stone type"); + end + end + + if (bs.OH and not bExpire and handtype == "") then + iSlot = 17; + iId = GetInventoryItemID("player", iSlot); + if (iId and SMARTBUFF_CanApplyWeaponBuff(buffnS, iSlot)) then + if (bOh) then + if (rbTime > 0 and cBuff.DurationS >= 1) then + --if (tOh == nil) then tOh = 0; end + tOh = floor(tOh/1000); + charges = cOh; + if (charges == nil) then charges = -1; end + if (charges > 1) then cBuff.CanCharge = true; end + --SMARTBUFF_AddMsgD(un .. " (WOH): " .. buffnS .. string.format(" %.0f sec left", tOh) .. ", " .. charges .. " charges left"); + if (tOh <= rbTime or (O.CheckCharges and cBuff.CanCharge and charges > 0 and charges <= O.MinCharges)) then + buff = buffnS; + bt = tOh; + bExpire = true; + end + end + else + handtype = "off"; + buff = buffnS; + end + else + --SMARTBUFF_AddMsgD("Weapon Buff cannot be cast, no offhand weapon equipped or wrong weapon/stone type"); + end + end + + if (buff and cBuff.Type == SMARTBUFF_CONST_INV) then + local cr = SMARTBUFF_CountReagent(buffnS, cBuff.Chain); + if (cr > 0) then + --SMARTBUFF_AddMsgD(cr .. " " .. buffnS .. " found"); + else + --SMARTBUFF_AddMsgD("No " .. buffnS .. " found"); + buff = nil; + end + end + + -- Normal buff ------------------------------------------------------------------------ + + else + local index = nil; + + -- check timer object + buff, index, buffname, bt, charges = SMARTBUFF_CheckUnitBuffs(unit, buffnS, cBuff.Type, cBuff.Links, cBuff.Chain); + if (charges == nil) then charges = -1; end + if (charges > 1) then cBuff.CanCharge = true; end + + if (unit ~= "target" and buff == nil and cBuff.DurationS >= 1 and rbTime > 0) then + if (SMARTBUFF_IsPlayer(unit)) then + if (cBuffTimer[unit] ~= nil and cBuffTimer[unit][buffnS] ~= nil) then + local tbt = cBuff.DurationS - (time - cBuffTimer[unit][buffnS]); + if (not bt or bt - tbt > rbTime) then + bt = tbt; + end + end + bufftarget = nil; + --SMARTBUFF_AddMsgD(un .. " (P): " .. index .. ". " .. GetPlayerBuffTexture(index) .. "(" .. charges .. ") - " .. buffnS .. string.format(" %.0f sec left", bt)); + elseif (cBuffTimer[unit] ~= nil and cBuffTimer[unit][buffnS] ~= nil) then + bt = cBuff.DurationS - (time - cBuffTimer[unit][buffnS]); + bufftarget = nil; + --SMARTBUFF_AddMsgD(un .. " (S): " .. buffnS .. string.format(" %.0f sec left", bt)); + elseif (cBuff.BuffG ~= nil and cBuffTimer[subgroup] ~= nil and cBuffTimer[subgroup][cBuff.BuffG] ~= nil) then + bt = cBuff.DurationG - (time - cBuffTimer[subgroup][cBuff.BuffG]); + if (type(subgroup) == "number") then + bufftarget = SMARTBUFF_MSG_GROUP .. " " .. subgroup; + else + bufftarget = SMARTBUFF_MSG_CLASS .. " " .. UnitClass(unit); + end + --SMARTBUFF_AddMsgD(bufftarget .. ": " .. cBuff.BuffG .. string.format(" %.0f sec left", bt)); + elseif (cBuff.BuffG ~= nil and cBuffTimer[uc] ~= nil and cBuffTimer[uc][cBuff.BuffG] ~= nil) then + bt = cBuff.DurationG - (time - cBuffTimer[uc][cBuff.BuffG]); + bufftarget = SMARTBUFF_MSG_CLASS .. " " .. UnitClass(unit); + --SMARTBUFF_AddMsgD(bufftarget .. ": " .. cBuff.BuffG .. string.format(" %.0f sec left", bt)); + else + bt = nil; + end + + if ((bt and bt <= rbTime) or (O.CheckCharges and cBuff.CanCharge and charges > 0 and charges <= O.MinCharges)) then + if (buffname) then + buff = buffname; + else + buff = buffnS; + end + bExpire = true; + end + end + + -- check if the group buff is active, in this case it is not possible to cast the single buff + if (buffname and mode ~= 1 and buffname ~= buffnS) then + buff = nil; + --SMARTBUFF_AddMsgD("Group buff is active, single buff canceled!"); + --print("Group buff is active, single buff canceled!"); + end + + end -- END normal buff + + -- check if shapeshifted and cancel buff if it is not possible to cast it + if (buff and cBuff.Type ~= SMARTBUFF_CONST_TRACK and cBuff.Type ~= SMARTBUFF_CONST_FORCESELF) then + --isShapeshifted = true; + --sShapename = "Moonkingestalt"; + if (isShapeshifted) then + if (string.find(cBuff.Params, sShapename)) then + --SMARTBUFF_AddMsgD("Cast " .. buff .. " while shapeshifted"); + else + if(cBuff.Params == SMARTBUFF_DRUID_CAT) then + buff = nil; + end + if (buff and mode ~= 1 and not O.InShapeshift and (sShapename ~= SMARTBUFF_DRUID_MOONKIN and sShapename ~= SMARTBUFF_DRUID_TREANT)) then + --sMsgWarning = SMARTBUFF_MSG_SHAPESHIFT .. ": " .. sShapename; + buff = nil; + end + end + else + if(cBuff.Params == SMARTBUFF_DRUID_CAT) then + buff = nil; + end + end + end + + if (buff) then + + -- Cast mode --------------------------------------------------------------------------------------- + if (mode == 0 or mode == 5) then + currentUnit = nil; + currentSpell = nil; + + --try to apply weapon buffs on main/off hand + if (cBuff.Type == SMARTBUFF_CONST_INV) then + if (iSlot and (handtype ~= "" or bExpire)) then + local bag, slot, count = SMARTBUFF_FindItem(buffnS, cBuff.Chain); + if (count > 0) then + sMsgWarning = ""; + return 0, SMARTBUFF_ACTION_ITEM, buffnS, iSlot, "player", cBuff.Type; + end + end + r = 50; + elseif (cBuff.Type == SMARTBUFF_CONST_WEAPON) then + if (iId and (handtype ~= "" or bExpire)) then + sMsgWarning = ""; + return 0, SMARTBUFF_ACTION_SPELL, buffnS, iSlot, "player", cBuff.Type; + --return 0, SMARTBUFF_ACTION_SPELL, buffnS, iId, "player", cBuff.Type; + end + r = 50; + + -- eat food or use scroll or potion + elseif (cBuff.Type == SMARTBUFF_CONST_FOOD or cBuff.Type == SMARTBUFF_CONST_SCROLL or cBuff.Type == SMARTBUFF_CONST_POTION) then + local bag, slot, count = SMARTBUFF_FindItem(buffnS, cBuff.Chain); + if (count > 0 or bExpire) then + sMsgWarning = ""; + return 0, SMARTBUFF_ACTION_ITEM, buffnS, 0, "player", cBuff.Type; + end + r = 20; + + -- use item on a unit + elseif (cBuff.Type == SMARTBUFF_CONST_ITEMGROUP) then + local bag, slot, count = SMARTBUFF_FindItem(buffnS, cBuff.Chain); + if (count > 0) then + sMsgWarning = ""; + return 0, SMARTBUFF_ACTION_ITEM, buffnS, 0, unit, cBuff.Type; + end + r = 20; + + -- create item + elseif (cBuff.Type == SMARTBUFF_CONST_ITEM) then + r = 20; + local bag, slot, count = SMARTBUFF_FindItem(buff, cBuff.Chain); + if (count == 0) then + r = SMARTBUFF_doCast(unit, cBuff.IDS, buffnS, cBuff.LevelsS, cBuff.Type); + if (r == 0) then + currentUnit = unit; + currentSpell = buffnS; + end + end + + -- cast spell + else + r, _, rankText = SMARTBUFF_doCast(unit, cBuff.IDS, buffnS, cBuff.LevelsS, cBuff.Type); + if (r == 0) then + currentUnit = unit; + currentSpell = buffnS; + end + end + + -- Check mode --------------------------------------------------------------------------------------- + elseif (mode == 1) then + currentUnit = nil; + currentSpell = nil; + if (bufftarget == nil) then bufftarget = un; end + + if (SMARTBUFF_CheckUnitLevel(unit, cBuff.IDS, cBuff.LevelsS) ~= nil or cBuff.IDS ~= nil or SMARTBUFF_IsItem(cBuff.Type) or cBuff.Type == SMARTBUFF_CONST_TRACK) then + -- clean up buff timer, if expired + if (bt and bt < 0 and bExpire) then + bt = 0; + if (cBuffTimer[unit] ~= nil and cBuffTimer[unit][buffnS] ~= nil) then + cBuffTimer[unit][buffnS] = nil; + --SMARTBUFF_AddMsgD(un .. " (S): " .. buffnS .. " timer reset"); + end + if (cBuff.IDG ~= nil) then + if (cBuffTimer[subgroup] ~= nil and cBuffTimer[subgroup][cBuff.BuffG] ~= nil) then + cBuffTimer[subgroup][cBuff.BuffG] = nil; + --SMARTBUFF_AddMsgD("Group " .. subgroup .. ": " .. buffnS .. " timer reset"); + end + if (cBuffTimer[uc] ~= nil and cBuffTimer[uc][cBuff.BuffG] ~= nil) then + cBuffTimer[uc][cBuff.BuffG] = nil; + --SMARTBUFF_AddMsgD("Class " .. uc .. ": " .. cBuff.BuffG .. " timer reset"); + end + end + tLastCheck = time - O.AutoTimer + 0.5; + return 0; + end + + SMARTBUFF_SetMissingBuffMessage(bufftarget, buff, cBuff.IconS, cBuff.CanCharge, charges, bt, bExpire); + SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, cBuff.IconS); + return 0; + end + end + + if (r == 0) then + -- target buffed + -- Message will printed in the "SPELLCAST_STOP" event + sMsgWarning = ""; + return 0, SMARTBUFF_ACTION_SPELL, buffnS, -1, unit, cBuff.Type, rankText; + elseif (r == 1) then + -- spell cooldown + if (mode == 0) then SMARTBUFF_AddMsgWarn(buffnS .. " " .. SMARTBUFF_MSG_CD); end + return 1; + elseif (r == 2) then + -- can not target + if (mode == 0 and ucf ~= SMARTBUFF_DEMONTYPE) then SMARTBUFF_AddMsgD("Can not target " .. un); end + elseif (r == 3) then + -- target oor + if (mode == 0) then SMARTBUFF_AddMsgWarn(un .. " " .. SMARTBUFF_MSG_OOR); end + break; + elseif (r == 4) then + -- spell cooldown > maxSkipCoolDown + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " " .. SMARTBUFF_MSG_CD .. " > " .. maxSkipCoolDown); end + elseif (r == 5) then + -- target to low + if (mode == 0) then SMARTBUFF_AddMsgD(un .. " is to low to get buffed with " .. buffnS); end + elseif (r == 6) then + -- not enough mana/rage/energy + sMsgWarning = SMARTBUFF_MSG_OOM; + elseif (r == 7) then + -- tracking ability is already active + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " not used, other ability already active"); end + elseif (r == 8) then + -- actionslot is not defined + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " has no actionslot"); end + elseif (r == 9) then + -- spell ID not found + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " spellID not found"); end + elseif (r == 10) then + -- target could not buffed + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " could not buffed on " .. un); end + elseif (r == 20) then + -- item not found + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " could not used"); end + elseif (r == 50) then + -- weapon buff could not applied + if (mode == 0) then SMARTBUFF_AddMsgD(buffnS .. " could not applied"); end + else + -- no spell selected + if (mode == 0) then SMARTBUFF_AddMsgD(SMARTBUFF_MSG_CHAT); end + end + else + -- finished + if (mode == 0) then SMARTBUFF_AddMsgD(un .. " nothing to buff"); end + end + else + -- target does not need this buff + if (mode == 0) then SMARTBUFF_AddMsgD(un .. " does not need " .. buffnS); end + end + else + -- cooldown + if (sMsgWarning == "") then + sMsgWarning = SMARTBUFF_MSG_CD; + end + --SMARTBUFF_AddMsgD("Spell on cd: "..buffnS); + end + end -- group or self + end + --i = i + 1; + end -- for buff + + end + return 3; +end +-- END SMARTBUFF_BuffUnit + + +function SMARTBUFF_IsInList(unit, unitname, list) + if (list ~= nil) then + for un in pairs(list) do + if (un ~= nil and UnitIsPlayer(unit) and un == unitname) then + return true; + end + end + end + return false; +end + + +function SMARTBUFF_SetMissingBuffMessage(target, buff, icon, bCanCharge, nCharges, tBuffTimeLeft, bExpire) + local f = SmartBuffSplashFrame; + -- show splash buff message + if (f and O.ToggleAutoSplash and not SmartBuffOptionsFrame:IsVisible()) then + local s; + local sd = O.SplashDuration; + local si = ""; + + if (OG.SplashIcon and icon) then + local n = O.SplashIconSize; + if (n == nil or n <= 0) then + n = O.CurrentFontSize; + end + si = string.format("\124T%s:%d:%d:1:0\124t ", icon, n, n) or ""; + end + if (OG.SplashMsgShort and si == "") then si = buff end + if (O.AutoTimer < 4) then + sd = 1; + f:Clear(); + end + + f:SetTimeVisible(sd); + if (not nCharges) then nCharges = 0; end + if (O.CheckCharges and bCanCharge and nCharges > 0 and nCharges <= O.MinCharges and bExpire) then + if (OG.SplashMsgShort) then + s = target.." > "..si.." < "..format(SMARTBUFF_ABBR_CHARGES_OL, nCharges); + else + s = target.."\n"..SMARTBUFF_MSG_REBUFF.." "..si..buff..": "..format(ITEM_SPELL_CHARGES, nCharges).." "..SMARTBUFF_MSG_LEFT; + end + elseif (bExpire) then + if (OG.SplashMsgShort) then + s = target.." > "..si.." < "..format(SECOND_ONELETTER_ABBR, tBuffTimeLeft); + else + s = target.."\n"..SMARTBUFF_MSG_REBUFF.." "..si..buff..": "..format(SECONDS_ABBR, tBuffTimeLeft).." "..SMARTBUFF_MSG_LEFT; + end + else + if (OG.SplashMsgShort) then + s = target.." > "..si; + else + s = target.." "..SMARTBUFF_MSG_NEEDS.." "..si..buff; + end + end + f:AddMessage(s, O.ColSplashFont.r, O.ColSplashFont.g, O.ColSplashFont.b, 1.0); + end + + -- show chat buff message + if (O.ToggleAutoChat) then + if (O.CheckCharges and bCanCharge and nCharges > 0 and nCharges <= O.MinCharges and bExpire) then + SMARTBUFF_AddMsgWarn(target..": "..SMARTBUFF_MSG_REBUFF.." "..buff..", "..format(ITEM_SPELL_CHARGES, nCharges).." ".. SMARTBUFF_MSG_LEFT, true); + elseif (bExpire) then + SMARTBUFF_AddMsgWarn(target..": "..SMARTBUFF_MSG_REBUFF.." "..buff..format(SECONDS_ABBR, tBuffTimeLeft).." "..SMARTBUFF_MSG_LEFT, true); + else + SMARTBUFF_AddMsgWarn(target.." "..SMARTBUFF_MSG_NEEDS.." "..buff, true); + end + end + + -- play sound + if (O.ToggleAutoSound) then + PlaySound(1141); + end +end + + +local cWeaponStandard = {0, 1, 4, 5, 6, 7, 8, 10, 13, 15, 16}; -- "Daggers", "Axes", "Swords", "Maces", "Staves", "Fist Weapons", "Polearms", "Thrown" +local cWeaponBlunt = {4, 5, 10, 13}; -- "Maces", "Staves", "Fist Weapons" +local cWeaponSharp = {0, 1, 6, 7, 8, 15}; -- "Daggers", "Axes", "Swords", "Polearms" + +-- check if a spell/reagent could applied on a weapon +function SMARTBUFF_CanApplyWeaponBuff(buff, slot) + local cWeaponTypes = nil; + if (string.find(buff, SMARTBUFF_WEAPON_SHARP_PATTERN)) then + cWeaponTypes = cWeaponSharp; + elseif (string.find(buff, SMARTBUFF_WEAPON_BLUNT_PATTERN)) then + cWeaponTypes = cWeaponBlunt; + else + cWeaponTypes = cWeaponStandard; + end + + local itemLink = GetInventoryItemLink("player", slot); + if (itemLink == nil) then return false end + + local itemType, itemSubType, _, _, _, _, classId, subclassId = select(6, GetItemInfo(itemLink)); + --if (itemType and itemSubType) then + -- SMARTBUFF_AddMsgD("Type: "..itemType..", Subtype: "..itemSubType); + --end + + if (tcontains(cWeaponTypes, subclassId)) then + return true, itemSubType; + end + + return false; +end +-- END SMARTBUFF_CanApplyWeaponBuff + + +-- Check the unit blacklist +function SMARTBUFF_checkBlacklist() + local t = GetTime(); + for unit in pairs(cBlacklist) do + if (t > (cBlacklist[unit] + O.BlacklistTimer)) then + cBlacklist[unit] = nil; + end + end +end +-- END SMARTBUFF_checkBlacklist + + +-- Casts a spell +function SMARTBUFF_doCast(unit, id, spellName, levels, type) + if (id == nil) then return 9; end + + if (type == SMARTBUFF_CONST_TRACK) then + local iconTrack = GetTrackingTexture(); + if (iconTrack ~= nil and iconTrack ~= "Interface\\Minimap\\Tracking\\None") then + SMARTBUFF_AddMsgD("Track already enabled: "..iconTrack); + return 7; + end + end + + -- check if spell has cooldown + local _, cd = GetSpellCooldown(spellName) + if (not cd) then + -- move on + elseif (cd > maxSkipCoolDown) then + return 4; + elseif (cd > 0) then + return 1; + end + + -- Rangecheck + if (type == SMARTBUFF_CONST_GROUP or type == SMARTBUFF_CONST_ITEMGROUP) then + + if (SpellHasRange(spellName)) then + if (IsSpellInRange(spellName, unit) ~= 1) then + return 3; + end + else + if (UnitInRange(unit) ~= 1) then + return 3; + end + end + + end + + -- check if target is to low for this spell + local newId, rank, rankText = SMARTBUFF_CheckUnitLevel(unit, id, levels); + if (newId == nil) then + return 5; + end + + -- check if you have enough mana/energy/rage to cast + local isUsable, notEnoughMana = IsUsableSpell(spellName); + if (notEnoughMana) then + return 6; + end + + return 0, rank, rankText; +end +-- END SMARTBUFF_doCast + + +-- checks if the unit is the player +function SMARTBUFF_IsPlayer(unit) + if (unit and UnitIsUnit("player", unit)) then + return true; + end + return false; +end +-- END SMARTBUFF_IsPlayer + + +function UnitBuffByBuffName(target,buffname,filter) + for i = 1,40 do + name = UnitBuff(target, i, filter); + if not name then return end + if name == buffname then + return UnitBuff(target, i, filter); + end + end +end + +-- +-- SMARTBUFF_CheckUnitBuffs +-- Function to return the name of the buff to cast. +-- +function SMARTBUFF_CheckUnitBuffs(unit, buffN, buffT, buffL, buffC) + if (not unit or (not buffN and not buffL)) then return end + + local i, n, v; + local buff = nil; + local defBuff = nil; + local timeleft = nil; + local duration = nil; + local caster = nil; + local count = nil; + local icon = nil; + local time = GetTime(); + local uname = UnitName(unit) or "?"; + + if (buffN) then + defBuff = buffN; + else + defBuff = buffL[1]; + end + + -- Stance/Presence/Seal check, these are not in the aura list + n = cBuffIndex[defBuff]; + if (cBuffs[n] and cBuffs[n].Type == SMARTBUFF_CONST_STANCE) then + if (defBuff and buffC and #buffC >= 1) then + local t = B[CS()].Order; + if (t and #t >= 1) then + for i = 1, #t, 1 do + if (t[i] and tfind(buffC, t[i])) then + v = GetBuffSettings(t[i]); + if (v and v.EnableS) then + for n = 1, GetNumShapeshiftForms(), 1 do + local _, name, active, castable = GetShapeshiftFormInfo(n); + if (name and not active and castable and name == t[i]) then + return defBuff, nil, nil, nil, nil; + elseif (name and active and castable and name == t[i]) then + return nil, i, defBuff, 1800, -1; + end + end + end + end + end + end + end + return defBuff, nil, nil, nil, nil; + end + + -- Check linked buffs + if (buffL) then + if (not O.LinkSelfBuffCheck and buffT == SMARTBUFF_CONST_SELF) then + -- Do not check linked self buffs + elseif (not O.LinkGrpBuffCheck and buffT == SMARTBUFF_CONST_GROUP) then + -- Do not check linked group buffs + else + for n, v in pairs(buffL) do + if (v and v ~= defBuff) then + SMARTBUFF_AddMsgD("Check linked buff ("..uname.."): "..v); + buff, icon, count, _, duration, timeleft, caster = UnitBuffByBuffName(unit, v); + if (buff) then + timeleft = timeleft - time; + SMARTBUFF_AddMsgD("Linked buff found: "..buff..", "..timeleft..", "..icon); + return nil, n, defBuff, timeleft, count; + end + end + end + end + end + + -- Check chained buffs + if (defBuff and buffC and #buffC > 1) then + local t = B[CS()].Order; + if (t and #t > 1) then + for i = 1, #t, 1 do + if (t[i] and tfind(buffC, t[i])) then + v = GetBuffSettings(t[i]); + if (v and v.EnableS) then + local b, tl, im = SMARTBUFF_CheckBuff(unit, t[i]); + if (b and im) then + if (SMARTBUFF_CheckBuffLink(unit, t[i], v.Type, v.Links)) then + return nil, i, defBuff, tl, -1; + end + elseif (not b and t[i] == defBuff) then + return defBuff, nil, nil, nil, nil; + end + end + end + end + end + end + + -- Check default buff + if (defBuff) then + buff, icon, count, _, duration, timeleft, caster = UnitBuffByBuffName(unit, defBuff); + if (buff) then +-- print("Found buff: "..buff.. " on unit: "..unit) + timeleft = timeleft - time; + if (SMARTBUFF_IsPlayer(caster)) then + SMARTBUFF_UpdateBuffDuration(defBuff, duration); + end + SMARTBUFF_AddMsgD("Default buff found: "..buff..", "..timeleft..", "..icon); + return nil, 0, defBuff, timeleft, count; + else +-- print("Not Found Buff: "..defBuff.. " on unit: "..unit) + end + end + + -- Buff not found, return default buff + return defBuff, nil, nil, nil, nil; + +end + + +-- Will return the lower Id of the spell, if the unit level is lower +function SMARTBUFF_CheckUnitLevel(unit, spellId, spellLevels) + if (spellLevels == nil or spellId == nil) then + return spellId; + end + + local Id = spellId; + local uLevel = UnitLevel(unit); + local spellName, _, icon, castTime, minRange, maxRange = GetSpellInfo(Id); + local sRank = GetSpellSubtext(Id); + if (sRank == nil or sRank == "") then + return Id; + end + + local _, _, spellRank = string.find(sRank, "(%d+)"); + if (spellRank == nil) then + return Id; + end + + spellRank = tonumber(spellRank); + local i = spellRank; + + --SMARTBUFF_AddMsgD(spellName .. sRank .. ":" .. spellRank .. ", " .. spellLevels[i]); + + while (i >= 1) do + if (uLevel >= (spellLevels[i] - 10)) then + break; + end + i = i - 1; + end + + if (i == spellRank) then + return Id; + end + + local rankText; + if (i > 0) then + local n = spellRank - i; + Id = Id - n; + rankText = "("..string.gsub(sRank, "(%d+)", n)..")"; + --SMARTBUFF_AddMsgD(uLevel .. " " .. spellName .. " Rank " .. i .. " - ID = " .. Id); + else + Id = nil; + --SMARTBUFF_AddMsgD(spellName .. ": no rank available for this level"); + end; + + return Id, i, rankText; +end +-- END SMARTBUFF_CheckUnitLevel + + + +function SMARTBUFF_CheckBuffLink(unit, defBuff, buffT, buffL) + -- Check linked buffs + if (buffL) then + if (not O.LinkSelfBuffCheck and buffT == SMARTBUFF_CONST_SELF) then + -- Do not check linked self buffs + elseif (not O.LinkGrpBuffCheck and buffT == SMARTBUFF_CONST_GROUP) then + -- Do not check linked group buffs + else + for n, v in pairs(buffL) do + if (v and v ~= defBuff) then + SMARTBUFF_AddMsgD("Check linked buff ("..uname.."): "..v); + buff, icon, count, _, duration, timeleft, caster = UnitBuffByBuffName(unit, v); + if (buff) then + timeleft = timeleft - time; + SMARTBUFF_AddMsgD("Linked buff found: "..buff..", "..timeleft..", "..icon); + return nil, n, defBuff, timeleft, count; + end + end + end + end + end + return defBuff; +end + +function SMARTBUFF_CheckBuffChain(unit, buff, chain) + local i; + if (buff and chain and #chain > 1) then + local t = B[CS()].Order; + if (t and #t > 1) then + SMARTBUFF_AddMsgD("Check chained buff: "..buff); + for i = 1, #t, 1 do + if (t[i] and t[i] ~= buff and tfind(chain, t[i])) then + local b, tl, im = SMARTBUFF_CheckBuff(unit, t[i], true); + if (b and im) then + SMARTBUFF_AddMsgD("Chained buff found: "..t[i]); + return nil, i, buff, tl, -1; + end + end + end + end + end + return buff; +end + + +function SMARTBUFF_UpdateBuffDuration(buff, duration) + local i = cBuffIndex[buff]; + if (i ~= nil and cBuffs[i] ~= nil and buff == cBuffs[i].BuffS) then + if (cBuffs[i].DurationS ~= nil and cBuffs[i].DurationS > 0 and cBuffs[i].DurationS ~= duration) then + SMARTBUFF_AddMsgD("Updated buff duration: "..buff.." = "..duration.."sec, old = "..cBuffs[i].DurationS); + cBuffs[i].DurationS = duration; + end + end +end + + +function UnitAuraBySpellName(target, spellname, filter) + for i = 1,40 do + name = UnitAura(target, i, filter); + if not name then return end + if name == spellname then + return UnitAuraFull(target, i, filter); + end + end +end + +function SMARTBUFF_CheckBuff(unit, buffName, isMine) + if (not unit or not buffName) then + return false, 0; + end + local buff, _, _, _, _, timeleft, caster = UnitAuraBySpellName(unit, buffName, "HELPFUL"); + if (buff) then + SMARTBUFF_AddMsgD(UnitName(unit).." buff found: "..buff, 0, 1, 0.5); + if (buff == buffName) then + timeleft = timeleft - GetTime(); + if (isMine and caster) then + if (SMARTBUFF_IsPlayer(caster)) then + return true, timeleft, caster; + end + return false, 0, nil; + end + return true, timeleft, SMARTBUFF_IsPlayer(caster); + end + end + return false, 0; +end +-- END SMARTBUFF_CheckUnitBuffs + + +-- Will return the name/description of the buff +function SMARTBUFF_GetBuffName(unit, buffIndex, line) + local i = buffIndex; + local name = nil; + if (i < 0 or i > maxBuffs) then + return nil; + end + --SmartBuffTooltip:SetOwner(SmartBuffFrame, "ANCHOR_NONE"); + SmartBuffTooltip:ClearLines(); + SmartBuffTooltip:SetUnitBuff(unit, i); + local obj = _G["SmartBuffTooltipTextLeft" .. line]; + if (obj) then + name = obj:GetText(); + end + return name; +end +-- END SMARTBUFF_GetBuffName + + +-- IsFeignDeath(unit) +function SMARTBUFF_IsFeignDeath(unit) + return UnitIsFeignDeath(unit); +end +-- END SMARTBUFF_IsFeignDeath + + +-- IsPicnic(unit) +function SMARTBUFF_IsPicnic(unit) + if (not SMARTBUFF_CheckUnitBuffs(unit, SMARTBUFF_FOOD_SPELL, SMARTBUFF_CONST_FOOD, {SMARTBUFF_FOOD_SPELL, SMARTBUFF_DRINK_SPELL})) then + return true; + end + return false; +end +-- END SMARTBUFF_IsPicnic + + +-- IsFishing(unit) +function SMARTBUFF_IsFishing(unit) + -- spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitChannelInfo("unit") + local spell = UnitChannelInfo(unit); + if (spell ~= nil and SMARTBUFF_FISHING ~= nil and spell == SMARTBUFF_FISHING) then + --SMARTBUFF_AddMsgD("Channeling "..SMARTBUFF_FISHING); + return true; + end + return false; +end + +function SMARTBUFF_IsFishingPoleEquiped() + if (not SG or not SG.FishingPole) then return false end + + local link = GetInventoryItemLink("player", GetInventorySlotInfo("MainHandSlot")); + if (not link) then return false end + + local _, _, _, _, _, _, subType = GetItemInfo(link); + if (not subType) then return false end + + --print(SG.FishingPole.." - "..subType); + if (SG.FishingPole == subType) then return true end + + return false; +end +-- END SMARTBUFF_IsFishing + +-- SMARTBUFF_IsSpell(sType) +function SMARTBUFF_IsSpell(sType) + return sType == SMARTBUFF_CONST_GROUP or sType == SMARTBUFF_CONST_GROUPALL or sType == SMARTBUFF_CONST_SELF or sType == SMARTBUFF_CONST_FORCESELF or sType == SMARTBUFF_CONST_WEAPON or sType == SMARTBUFF_CONST_STANCE or sType == SMARTBUFF_CONST_ITEM; +end +-- END SMARTBUFF_IsSpell + +-- SMARTBUFF_IsItem(sType) +function SMARTBUFF_IsItem(sType) + return sType == SMARTBUFF_CONST_INV or sType == SMARTBUFF_CONST_FOOD or sType == SMARTBUFF_CONST_SCROLL or sType == SMARTBUFF_CONST_POTION or sType == SMARTBUFF_CONST_ITEMGROUP; +end +-- END SMARTBUFF_IsItem + + +-- Loops through all of the debuffs currently active looking for a texture string match +function SMARTBUFF_IsDebuffTexture(unit, debufftex) + local active = false; + local i = 1; + local name, icon; + -- name,rank,icon,count,type = UnitDebuff("unit", id or "name"[,"rank"]) + while (UnitDebuff(unit, i)) do + name, icon, _, _ = UnitDebuff(unit, i); + --SMARTBUFF_AddMsgD(i .. ". " .. name .. ", " .. icon); + if (string.find(icon, debufftex)) then + active = true; + break + end + i = i + 1; + end + return active; +end +-- END SMARTASPECT_IsDebuffTex + + +-- Returns the number of a reagent currently in player's bag +function SMARTBUFF_CountReagent(reagent, chain) + if (reagent == nil) then + return -1, nil; + end + + local toy = SG.Toybox[reagent]; + if (toy) then + return 1, toy[1]; + end + + local n = 0; + local id = nil; + local bag = 0; + local slot = 0; + local itemLink, itemName, count; + if (chain == nil) then chain = { reagent }; end + for bag = 0, NUM_BAG_FRAMES do + for slot = 1, GetContainerNumSlots(bag) do + itemLink = GetContainerItemLink(bag, slot); + if (itemLink ~= nil) then + itemName = string.match(itemLink, "%[.-%]"); + --print(bag, slot, itemName); + for i = 1, #chain, 1 do + --print(chain[i]); + if (chain[i] and string.find(itemName, chain[i], 1, true)) then + --if (chain[i] and string.find(itemLink, "["..chain[i].."]", 1, true)) then + --print("Item found: "..chain[i]); + _, count = GetContainerItemInfo(bag, slot); + id = GetContainerItemID(bag, slot); + n = n + count; + end + end + end + end + end + return n, id; +end + +function SMARTBUFF_FindItem(reagent, chain) + if (reagent == nil) then + return nil, nil, -1, nil; + end + + --local toy = SG.Toybox[reagent]; + --if (toy) then + -- return 999, toy[1], 1, toy[2]; + --end + + local n = 0; + local bag = 0; + local slot = 0; + local itemLink, itemName, texture, count; + if (chain == nil) then chain = { reagent }; end + for bag = 0, NUM_BAG_FRAMES do + for slot = 1, GetContainerNumSlots(bag) do + itemLink = GetContainerItemLink(bag, slot); + if (itemLink ~= nil) then + --itemName = string.match(itemLink, "item[%-?%d:]+"); + --itemName = string.match(itemLink, "|h%[.*%]|h"); + itemName = string.match(itemLink, "%[.-%]"); + --print(bag, slot, itemName); + --SMARTBUFF_AddMsgD("Reagent found: " .. itemLink); + for i = 1, #chain, 1 do + --print(chain[i]); + if (chain[i] and string.find(itemName, chain[i], 1, true)) then + --if (chain[i] and string.find(itemLink, "["..chain[i].."]", 1, true)) then + --print("Item found: "..chain[i]); + texture, count = GetContainerItemInfo(bag, slot); + return bag, slot, count, texture; + end + end + end + end + end + return nil, nil, 0, nil; +end +-- END Reagent functions + + +--------------------------------------------------------------------------------------------------- +-- check the current zone and set buff template +--------------------------------------------------------------------------------------------------- +function SMARTBUFF_CheckLocation() + if (not O.AutoSwitchTemplate and not O.AutoSwitchTemplateInst) then return; end + + local zone = GetRealZoneText(); + if (zone == nil) then + SMARTBUFF_AddMsgD("No zone found, try again..."); + tStartZone = GetTime(); + isSetZone = true; + return; + end + + isSetZone = false; + local tmp = nil; + local b = false; + + SMARTBUFF_AddMsgD("Current zone: "..zone..", last zone: "..sLastZone); + if (zone ~= sLastZone) then + sLastZone = zone; + if (IsActiveBattlefieldArena()) then + tmp = SMARTBUFF_TEMPLATES[5]; + elseif (SMARTBUFF_IsActiveBattlefield(zone) == 1) then + tmp = SMARTBUFF_TEMPLATES[4]; + else + if (O.AutoSwitchTemplateInst) then + local i = 1; + for _ in pairs(SMARTBUFF_INSTANCES) do + if (string.find(string.lower(zone), string.lower(SMARTBUFF_INSTANCES[i]))) then + b = true; + break; + end + i = i + 1; + end + tmp = nil; + if (b) then + if (SMARTBUFF_TEMPLATES[i + 5] ~= nil) then + tmp = SMARTBUFF_TEMPLATES[i + 5] + end + end + end + end + --SMARTBUFF_AddMsgD("Current tmpl: " .. currentTemplate .. " - new tmpl: " .. tmp); + if (tmp and currentTemplate ~= tmp) then + SMARTBUFF_AddMsg(SMARTBUFF_OFT_AUTOSWITCHTMP .. ": " .. currentTemplate .. " -> " .. tmp); + currentTemplate = tmp; + SMARTBUFF_SetBuffs(); + end + end +end + + + +-- checks if the player is inside a battlefield +function SMARTBUFF_IsActiveBattlefield(zone) + local i, status, map, instanceId, teamSize; + for i = 1, GetMaxBattlefieldID() do + status, map, instanceId, _, _, teamSize = GetBattlefieldStatus(i); + if (status and status ~= "none") then + SMARTBUFF_AddMsgD("Battlefield status = "..ChkS(status)..", Id = "..ChkS(instanceId)..", TS = "..ChkS(teamSize)..", Map = "..ChkS(map)..", Zone = "..ChkS(zone)); + else + SMARTBUFF_AddMsgD("Battlefield status = none"); + end + if (status and status == "active" and map) then + if (teamSize and type(teamSize) == "number" and teamSize > 0) then + return 2; + end + return 1; + end + end + return 0; +end +-- END IsActiveBattlefield + + +-- Helper functions --------------------------------------------------------------------------------------- +function SMARTBUFF_toggleBool(b, msg) + if (not b or b == nil) then + b = true; + SMARTBUFF_AddMsg(SMARTBUFF_TITLE .. ": " .. msg .. GR .. "On", true); + else + b = false + SMARTBUFF_AddMsg(SMARTBUFF_TITLE .. ": " .. msg .. RD .."Off", true); + end + return b; +end + +function SMARTBUFF_BoolState(b, msg) + if (b) then + SMARTBUFF_AddMsg(SMARTBUFF_TITLE .. ": " .. msg .. GR .. "On", true); + else + SMARTBUFF_AddMsg(SMARTBUFF_TITLE .. ": " .. msg .. RD .."Off", true); + end +end + +function SMARTBUFF_Split(msg, char) + local arr = { }; + while (string.find(msg, char)) do + local iStart, iEnd = string.find(msg, char); + tinsert(arr, strsub(msg, 1, iStart - 1)); + msg = strsub(msg, iEnd + 1, strlen(msg)); + end + if (strlen(msg) > 0) then + tinsert(arr, msg); + end + return arr; +end +-- END Bool helper functions + + +-- Init the SmartBuff variables --------------------------------------------------------------------------------------- +function SMARTBUFF_Options_Init(self) + if (isInit) then return; end + + self:UnregisterEvent("CHAT_MSG_CHANNEL"); + self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT"); + + --DebugChatFrame:AddMessage("Starting init SB"); + + _, sPlayerClass = UnitClass("player"); + sRealmName = GetRealmName(); + sPlayerName = UnitName("player"); + sID = sRealmName .. ":" .. sPlayerName; + --AutoSelfCast = GetCVar("autoSelfCast"); + + SMARTBUFF_PLAYERCLASS = sPlayerClass; + + + if (not SMARTBUFF_Buffs) then SMARTBUFF_Buffs = { }; end + B = SMARTBUFF_Buffs; + if (not SMARTBUFF_Options) then SMARTBUFF_Options = { }; end + O = SMARTBUFF_Options; + + SMARTBUFF_BROKER_SetIcon(); -- bug fix, credit: SunNova + + if (O.Toggle == nil) then O.Toggle = true; end + if (O.ToggleAuto == nil) then O.ToggleAuto = true; end + if (O.AutoTimer == nil) then O.AutoTimer = 5; end + if (O.BlacklistTimer == nil) then O.BlacklistTimer = 5; end + if (O.ToggleAutoCombat == nil) then O.ToggleAutoCombat = false; end + if (O.ToggleAutoChat == nil) then O.ToggleAutoChat = false; end + if (O.ToggleAutoSplash == nil) then O.ToggleAutoSplash = true; end + if (O.ToggleAutoSound == nil) then O.ToggleAutoSound = true; end + if (O.CheckCharges == nil) then O.CheckCharges = true; end + --if (O.ToggleAutoRest == nil) then O.ToggleAutoRest = true; end + if (O.RebuffTimer == nil) then O.RebuffTimer = 20; end + if (O.SplashDuration == nil) then O.SplashDuration = 2; end + if (O.SplashIconSize == nil) then O.SplashIconSize = 12; end + + if (O.BuffTarget == nil) then O.BuffTarget = false; end + if (O.BuffPvP == nil) then O.BuffPvP = false; end + if (O.BuffInCities == nil) then O.BuffInCities = true; end + if (O.LinkSelfBuffCheck == nil) then O.LinkSelfBuffCheck = true; end + if (O.LinkGrpBuffCheck == nil) then O.LinkGrpBuffCheck = true; end + if (O.AntiDaze == nil) then O.AntiDaze = true; end + + if (O.ScrollWheel ~= nil and O.ScrollWheelUp == nil) then O.ScrollWheelUp = O.ScrollWheel; end + if (O.ScrollWheel ~= nil and O.ScrollWheelDown == nil) then O.ScrollWheelDown = O.ScrollWheel; end + if (O.ScrollWheelUp == nil) then O.ScrollWheelUp = true; end + if (O.ScrollWheelDown == nil) then O.ScrollWheelDown = true; end + + if (O.InCombat == nil) then O.InCombat = true; end + if (O.AutoSwitchTemplate == nil) then O.AutoSwitchTemplate = true; end + if (O.AutoSwitchTemplateInst == nil) then O.AutoSwitchTemplateInst = true; end + if (O.InShapeshift == nil) then O.InShapeshift = true; end + + if (O.ToggleGrp == nil) then O.ToggleGrp = {true, false, false, false, false, false, false, false}; end + if (O.ToggleSubGrpChanged == nil) then O.ToggleSubGrpChanged = false; end + + if (O.ToggleMsgNormal == nil) then O.ToggleMsgNormal = true; end + if (O.ToggleMsgWarning == nil) then O.ToggleMsgWarning = false; end + if (O.ToggleMsgError == nil) then O.ToggleMsgError = false; end + + if (O.HideMmButton == nil) then O.HideMmButton = false; end + if (O.HideSAButton == nil) then O.HideSAButton = false; end + + if (O.MinCharges == nil) then + if (sPlayerClass == "SHAMAN" or sPlayerClass == "PRIEST") then + O.MinCharges = 1; + else + O.MinCharges = 3; + end + end + + if (O.ShowMiniGrp == nil) then + if (sPlayerClass == "DRUID" or sPlayerClass == "MAGE" or sPlayerClass == "PRIEST") then + O.ShowMiniGrp = true; + else + O.ShowMiniGrp = false; + end + end + + if (not O.AddList) then O.AddList = { }; end + if (not O.IgnoreList) then O.IgnoreList = { }; end + + if (O.LastTemplate == nil) then O.LastTemplate = SMARTBUFF_TEMPLATES[1]; end + local b = false; + while (SMARTBUFF_TEMPLATES[i] ~= nil) do + if (SMARTBUFF_TEMPLATES[i] == O.LastTemplate) then + b = true; + break; + end + i = i + 1; + end + if (not b) then + O.LastTemplate = SMARTBUFF_TEMPLATES[1]; + end + + currentTemplate = O.LastTemplate; + --currentSpec = GetSpecialization(); + currentSpec = 1; + + if (O.OldWheelUp == nil) then O.OldWheelUp = ""; end + if (O.OldWheelDown == nil) then O.OldWheelDown = ""; end + + SMARTBUFF_InitActionButtonPos(); + + if (O.SplashX == nil) then O.SplashX = 100; end + if (O.SplashY == nil) then O.SplashY = -100; end + if (O.CurrentFont == nil) then O.CurrentFont = 9; end + if (O.ColSplashFont == nil) then + O.ColSplashFont = { }; + O.ColSplashFont.r = 1.0; + O.ColSplashFont.g = 1.0; + O.ColSplashFont.b = 1.0; + end + iCurrentFont = O.CurrentFont; + + if (O.Debug == nil) then O.Debug = false; end + + -- Cosmos support + if(EarthFeature_AddButton) then + EarthFeature_AddButton( + { id = SMARTBUFF_TITLE; + name = SMARTBUFF_TITLE; + subtext = SMARTBUFF_TITLE; + tooltip = ""; + icon = imgSB; + callback = SMARTBUFF_OptionsFrame_Toggle; + test = nil; + } ) + elseif (Cosmos_RegisterButton) then + Cosmos_RegisterButton(SMARTBUFF_TITLE, SMARTBUFF_TITLE, SMARTBUFF_TITLE, imgSB, SMARTBUFF_OptionsFrame_Toggle); + end + + if (IsAddOnLoaded("Parrot")) then + isParrot = true; + end + + SMARTBUFF_FindItem("ScanBagsForSBInit"); + + SMARTBUFF_AddMsg(SMARTBUFF_VERS_TITLE .. " " .. SMARTBUFF_MSG_LOADED, true); + SMARTBUFF_AddMsg("/sbm - " .. SMARTBUFF_OFT_MENU, true); + isInit = true; + + SMARTBUFF_CheckMiniMapButton(); + SMARTBUFF_MinimapButton_OnUpdate(SmartBuff_MiniMapButton); + SMARTBUFF_ShowSAButton(); + SMARTBUFF_Splash_Hide(); + + if (O.UpgradeToDualSpec == nil) then + for n = 1, GetNumSpecGroups(), 1 do + if (B[n] == nil) then + B[n] = { }; + end + for k, v in pairs(SMARTBUFF_TEMPLATES) do + SMARTBUFF_AddMsgD(v); + if (B[v] ~= nil) then + B[n][v] = B[v]; + end + end + end + for k, v in pairs(SMARTBUFF_TEMPLATES) do + if (B[v] ~= nil) then + wipe(B[v]); + B[v] = nil; + end + end + O.UpgradeToDualSpec = true; + SMARTBUFF_AddMsg("Upgraded to dual spec", true); + end + + for k, v in pairs(cClasses) do + if (SMARTBUFF_CLASSES[k] == nil) then + SMARTBUFF_CLASSES[k] = v; + end + end + + if (O.VersionNr == nil or O.VersionNr < SMARTBUFF_VERSIONNR) then + O.VersionNr = SMARTBUFF_VERSIONNR; + SMARTBUFF_SetBuffs(); + InitBuffOrder(true); + --print("Upgrade SmartBuff to "..SMARTBUFF_VERSION); + end + + if (SMARTBUFF_OptionsGlobal == nil) then SMARTBUFF_OptionsGlobal = { }; end + OG = SMARTBUFF_OptionsGlobal; + if (OG.SplashIcon == nil) then OG.SplashIcon = true; end + if (OG.SplashMsgShort == nil) then OG.SplashMsgShort = false; end + if (OG.FirstStart == nil) then OG.FirstStart = "V0"; end + + SMARTBUFF_Splash_ChangeFont(0); + if (OG.FirstStart ~= SMARTBUFF_VERSION) then + OG.FirstStart = SMARTBUFF_VERSION; + SMARTBUFF_OptionsFrame_Open(true); + + if (OG.Tutorial == nil) then + OG.Tutorial = SMARTBUFF_VERSIONNR; + SMARTBUFF_ToggleTutorial(); + end + + SmartBuffWNF_lblText:SetText(SMARTBUFF_WHATSNEW); + SmartBuffWNF:Show(); + else + SMARTBUFF_SetBuffs(); + end + + if (not IsVisibleToPlayer(SmartBuff_KeyButton)) then + SmartBuff_KeyButton:ClearAllPoints(); + SmartBuff_KeyButton:SetPoint("CENTER", UIParent, "CENTER", 0, 100); + end + + SMARTBUFF_SetUnits(); + SMARTBUFF_RebindKeys(); + isSyncReq = true; + + -- finally, client version check + if buildInfo > SMARTBUFF_VERSIONNR or buildInfo < SMARTBUFF_VERSIONMIN then + DEFAULT_CHAT_FRAME:AddMessage("|cff00e0ffSmartbuff : |cffff6060This version was NOT intended for client version ("..buildInfo..") - you may encounter lua errors or other issues so please check for an update! - Join Discord for all the latest information at |cffFFFF00https://discord.gg/R6EkZ94TKK.") + end + +end +-- END SMARTBUFF_Options_Init + +function SMARTBUFF_InitActionButtonPos() + if (InCombatLockdown()) then return end + + isInitBtn = true; + if (O.ActionBtnX == nil) then + SMARTBUFF_SetButtonPos(SmartBuff_KeyButton); + else + SmartBuff_KeyButton:ClearAllPoints(); + SmartBuff_KeyButton:SetPoint("TOPLEFT", UIParent, "TOPLEFT", O.ActionBtnX, O.ActionBtnY); + end + --print(format("x = %.0f, y = %.0f", O.ActionBtnX, O.ActionBtnY)); +end + +function SMARTBUFF_ResetAll() + wipe(SMARTBUFF_Buffs); + wipe(SMARTBUFF_Options); + ReloadUI(); +end + +function SMARTBUFF_SetButtonPos(self) + local x, y = self:GetLeft(), self:GetTop() - UIParent:GetHeight(); + O.ActionBtnX = x; + O.ActionBtnY = y; + --print(format("x = %.0f, y = %.0f", x, y)); +end + +function SMARTBUFF_RebindKeys() + local i; + isRebinding = true; + for i = 1, GetNumBindings(), 1 do + local s = ""; + local command, key1, key2 = GetBinding(i); + + --if (command and key1) then + -- SMARTBUFF_AddMsgD(i .. " = " .. command .. " - " .. key1; + --end + + if (key1 and key1 == "MOUSEWHEELUP" and command ~= "SmartBuff_KeyButton") then + O.OldWheelUp = command; + --SMARTBUFF_AddMsgD("Old wheel up: " .. command); + elseif (key1 and key1 == "MOUSEWHEELDOWN" and command ~= "SmartBuff_KeyButton") then + O.OldWheelDown = command; + --SMARTBUFF_AddMsgD("Old wheel down: " .. command); + end + + if (command and command == "SMARTBUFF_BIND_TRIGGER") then + --s = i .. " = " .. command; + if (key1) then + --s = s .. ", key1 = " .. key1 .. " rebound"; + SetBindingClick(key1, "SmartBuff_KeyButton"); + end + if (key2) then + --s = s .. ", key2 = " .. key2 .. " rebound"; + SetBindingClick(key2, "SmartBuff_KeyButton"); + end + --SMARTBUFF_AddMsgD(s); + break; + end + end + + if (O.ScrollWheelUp) then + isKeyUpChanged = true; + SetOverrideBindingClick(SmartBuffFrame, false, "MOUSEWHEELUP", "SmartBuff_KeyButton", "MOUSEWHEELUP"); + --SMARTBUFF_AddMsgD("Set wheel up"); + else + if (isKeyUpChanged) then + isKeyUpChanged = false; + SetOverrideBinding(SmartBuffFrame, false, "MOUSEWHEELUP"); + --SMARTBUFF_AddMsgD("Set old wheel up: " .. O.OldWheelUp); + end + end + + if (O.ScrollWheelDown) then + isKeyDownChanged = true; + SetOverrideBindingClick(SmartBuffFrame, false, "MOUSEWHEELDOWN", "SmartBuff_KeyButton", "MOUSEWHEELDOWN"); + --SMARTBUFF_AddMsgD("Set wheel down"); + else + if (isKeyDownChanged) then + isKeyDownChanged = false; + SetOverrideBinding(SmartBuffFrame, false, "MOUSEWHEELDOWN"); + --SMARTBUFF_AddMsgD("Set old wheel down: " .. O.OldWheelDown); + end + end + isRebinding = false; +end + +function SMARTBUFF_ResetBindings() + if (not isRebinding) then + isRebinding = true; + if (O.OldWheelUp == "SmartBuff_KeyButton") then + SetBinding("MOUSEWHEELUP", "CAMERAZOOMIN"); + else + SetBinding("MOUSEWHEELUP", O.OldWheelUp); + end + if (O.OldWheelDown == "SmartBuff_KeyButton") then + SetBinding("MOUSEWHEELDOWN", "CAMERAZOOMOUT"); + else + SetBinding("MOUSEWHEELDOWN", O.OldWheelDown); + end + SaveBindings(GetCurrentBindingSet()); + SMARTBUFF_RebindKeys(); + end +end + + +-- SmartBuff commandline menu --------------------------------------------------------------------------------------- +function SMARTBUFF_command(msg) + if (not isInit) then + SMARTBUFF_AddMsgWarn(SMARTBUFF_VERS_TITLE.." not initialized correctly!", true); + return; + end + + if(msg == "toggle" or msg == "t") then + SMARTBUFF_OToggle(); + SMARTBUFF_SetUnits(); + elseif (msg == "menu") then + SMARTBUFF_OptionsFrame_Toggle(); + elseif (msg == "rbt") then + SMARTBUFF_ResetBuffTimers(); + elseif (msg == "sbt") then + SMARTBUFF_ShowBuffTimers(); + elseif (msg == "target") then + if (SMARTBUFF_PreCheck(0)) then + SMARTBUFF_checkBlacklist(); + SMARTBUFF_BuffUnit("target", 0, 0); + end + elseif (msg == "debug") then + O.Debug = SMARTBUFF_toggleBool(O.Debug, "Debug active = "); + elseif (msg == "open") then + SMARTBUFF_OptionsFrame_Open(true); + elseif (msg == "sync") then + SMARTBUFF_SyncBuffTimers(); + elseif (msg == "rb") then + SMARTBUFF_ResetBindings(); + SMARTBUFF_AddMsg("SmartBuff key and mouse bindings reset.", true); + elseif (msg == "rafp") then + SmartBuffSplashFrame:ClearAllPoints(); + SmartBuffSplashFrame:SetPoint("CENTER", UIParent, "CENTER"); + SmartBuff_MiniMapButton:ClearAllPoints(); + SmartBuff_MiniMapButton:SetPoint("TOPLEFT", Minimap, "TOPLEFT"); + SmartBuff_KeyButton:ClearAllPoints(); + SmartBuff_KeyButton:SetPoint("CENTER", UIParent, "CENTER"); + SmartBuffOptionsFrame:ClearAllPoints(); + SmartBuffOptionsFrame:SetPoint("CENTER", UIParent, "CENTER"); + SmartBuff_MiniGroup:ClearAllPoints(); + SmartBuff_MiniGroup:SetPoint("CENTER", UIParent, "CENTER"); + elseif (msg == "tmg") then + --SMARTBUFF_OToggleMiniGrp(); + O.ShowMiniGrp = SMARTBUFF_toggleBool(O.ShowMiniGrp, "MiniGrp active = "); + SMARTBUFF_MiniGroup_Show(); + + elseif (msg == "test") then + + -- Test Code ****************************************** + -- **************************************************** + + --SMARTBUFF_WEAPON_SHARP_PATTERN + --Schwerer Gewichtsstein + --Schwerer Wetzstein + --local a, b = SMARTBUFF_CanApplyWeaponBuff("Schwerer Wetzstein", 16); + --print(a); + --print(b); + + --local spellname = "Mind--numbing Poison"; + --SMARTBUFF_AddMsg("Original: " .. spellname, true); + --if (string.find(spellname, "%-%-") ~= nil) then + -- spellname = string.gsub(spellname, "%-%-", "%-"); + --end + --SMARTBUFF_AddMsg("Modified: " .. spellname, true); + -- **************************************************** + -- **************************************************** + + else + --SMARTBUFF_Check(0); + SMARTBUFF_AddMsg(SMARTBUFF_VERS_TITLE, true); + SMARTBUFF_AddMsg("Syntax: /sbo [command] or /sbuff [command] or /smartbuff [command]", true); + SMARTBUFF_AddMsg("toggle - " .. SMARTBUFF_OFT, true); + SMARTBUFF_AddMsg("menu - " .. SMARTBUFF_OFT_MENU, true); + SMARTBUFF_AddMsg("target - " .. SMARTBUFF_OFT_TARGET, true); + SMARTBUFF_AddMsg("rbt - " .. "Reset buff timers", true); + SMARTBUFF_AddMsg("sbt - " .. "Show buff timers", true); + SMARTBUFF_AddMsg("rafp - " .. "Reset all frame positions", true); + SMARTBUFF_AddMsg("sync - " .. "Sync buff timers with UI", true); + SMARTBUFF_AddMsg("rb - " .. "Reset key/mouse bindings", true); + end +end +-- END SMARTBUFF_command + + +-- SmartBuff options toggle --------------------------------------------------------------------------------------- +function SMARTBUFF_OToggle() + if (not isInit) then return; end + O.Toggle = SMARTBUFF_toggleBool(O.Toggle, "Active = "); + SMARTBUFF_CheckMiniMapButton(); + if (O.Toggle) then + SMARTBUFF_MiniGroup_Show(); + SMARTBUFF_SetUnits(); + else + if (SmartBuff_MiniGroup:IsVisible()) then + SmartBuff_MiniGroup:Hide(); + end + end +end + +function SMARTBUFF_OToggleAuto() + O.ToggleAuto = not O.ToggleAuto; +end +function SMARTBUFF_OToggleAutoCombat() + O.ToggleAutoCombat = not O.ToggleAutoCombat; +end +function SMARTBUFF_OToggleAutoChat() + O.ToggleAutoChat = not O.ToggleAutoChat; +end +function SMARTBUFF_OToggleAutoSplash() + O.ToggleAutoSplash = not O.ToggleAutoSplash; +end +function SMARTBUFF_OToggleAutoSound() + O.ToggleAutoSound = not O.ToggleAutoSound; +end + +--function SMARTBUFF_OToggleCheckCharges() +-- O.ToggleCheckCharges = not O.ToggleCheckCharges; +--end +--function SMARTBUFF_OToggleAutoRest() +-- O.ToggleAutoRest = not O.ToggleAutoRest; +--end + +function SMARTBUFF_OAutoSwitchTmp() + O.AutoSwitchTemplate = not O.AutoSwitchTemplate; +end +function SMARTBUFF_OAutoSwitchTmpInst() + O.AutoSwitchTemplateInst = not O.AutoSwitchTemplateInst; +end + +function SMARTBUFF_OBuffTarget() + O.BuffTarget = not O.BuffTarget; +end + +function SMARTBUFF_OBuffPvP() + O.BuffPvP = not O.BuffPvP; +end + +function SMARTBUFF_OBuffInCities() + O.BuffInCities = not O.BuffInCities; +end + +function SMARTBUFF_OLinkSelfBuffCheck() + O.LinkSelfBuffCheck = not O.LinkSelfBuffCheck; +end +function SMARTBUFF_OLinkGrpBuffCheck() + O.LinkGrpBuffCheck = not O.LinkGrpBuffCheck; +end +function SMARTBUFF_OAntiDaze() + O.AntiDaze = not O.AntiDaze; +end + +function SMARTBUFF_OScrollWheelUp() + O.ScrollWheelUp = not O.ScrollWheelUp; + isKeyUpChanged = true; +end +function SMARTBUFF_OScrollWheelDown() + O.ScrollWheelDown = not O.ScrollWheelDown; + isKeyDownChanged = true; +end +function SMARTBUFF_OInShapeshift() + O.InShapeshift = not O.InShapeshift; +end +function SMARTBUFF_OInCombat() + O.InCombat = not O.InCombat; +end + +function SMARTBUFF_OToggleGrp(i) + O.ToggleGrp[i] = not O.ToggleGrp[i]; + if (SmartBuff_MiniGroup:IsVisible()) then + SMARTBUFF_SetUnits(); + end +end +function SMARTBUFF_OToggleMiniGrp() + O.ShowMiniGrp = not O.ShowMiniGrp; +end +function SMARTBUFF_OToggleSubGrpChanged() + O.ToggleSubGrpChanged = not O.ToggleSubGrpChanged; +end + +function SMARTBUFF_OToggleMsgNormal() + O.ToggleMsgNormal = not O.ToggleMsgNormal; +end +function SMARTBUFF_OToggleMsgWarning() + O.ToggleMsgWarning = not O.ToggleMsgWarning; +end +function SMARTBUFF_OToggleMsgError() + O.ToggleMsgError = not O.ToggleMsgError; +end + +function SMARTBUFF_OHideMmButton() + O.HideMmButton = not O.HideMmButton; + SMARTBUFF_CheckMiniMapButton(); +end +function SMARTBUFF_OHideSAButton() + O.HideSAButton = not O.HideSAButton; + SMARTBUFF_ShowSAButton(); +end + +function SMARTBUFF_OToggleBuff(s, i) + local bs = GetBuffSettings(cBuffs[i].BuffS); + if (bs == nil) then + return; + end + + if (s == "S") then + bs.EnableS = not bs.EnableS; + if (bs.IDG ~= nil) then + bs.EnableG = bs.EnableS; + else + bs.EnableG = false; + end + SMARTBUFF_AddMsgD("OToggleBuff = "..cBuffs[i].BuffS..", "..tostring(bs.EnableS)..", "..tostring(bs.EnableG)); + + if (bs.EnableS) then + SmartBuff_BuffSetup_Show(i); + else + SmartBuff_BuffSetup:Hide(); + iLastBuffSetup = -1; + SmartBuff_PlayerSetup:Hide(); + end + elseif (s == "G") then + bs.EnableG = not bs.EnableG; + end + +end + +function SMARTBUFF_OToggleDebug() + O.Debug = not O.Debug; +end + +function SMARTBUFF_OptionsFrame_Toggle() + if (not isInit) then return; end + + if(SmartBuffOptionsFrame:IsVisible()) then + if(iLastBuffSetup > 0) then + SmartBuff_BuffSetup:Hide(); + iLastBuffSetup = -1; + SmartBuff_PlayerSetup:Hide(); + end + SmartBuffOptionsFrame:Hide(); + else + SmartBuffOptionsCredits_lblText:SetText(SMARTBUFF_CREDITS); + SmartBuffOptionsFrame:Show(); + SmartBuff_PlayerSetup:Hide(); + end + + SMARTBUFF_MinimapButton_CheckPos(); +end + +function SMARTBUFF_OptionsFrame_Open(force) + if (not isInit) then return; end + if(not SmartBuffOptionsFrame:IsVisible() or force) then + SmartBuffOptionsCredits_lblText:SetText(SMARTBUFF_CREDITS); + SmartBuffOptionsFrame:Show(); + end +end + +function SmartBuff_BuffSetup_Show(i) + local icon1 = cBuffs[i].IconS; + local icon2 = cBuffs[i].IconG; + local name = cBuffs[i].BuffS; + local btype = cBuffs[i].Type; + local hidden = true; + local n = 0; + local bs = GetBuffSettings(name); + + if (name == nil or btype == SMARTBUFF_CONST_TRACK) then + SmartBuff_BuffSetup:Hide(); + iLastBuffSetup = -1; + SmartBuff_PlayerSetup:Hide(); + return; + end + + if(SmartBuff_BuffSetup:IsVisible() and i == iLastBuffSetup) then + SmartBuff_BuffSetup:Hide(); + iLastBuffSetup = -1; + SmartBuff_PlayerSetup:Hide(); + return; + else + if (btype == SMARTBUFF_CONST_GROUP or btype == SMARTBUFF_CONST_ITEMGROUP) then + hidden = false; + end + + if (icon2 and bs.EnableG) then + SmartBuff_BuffSetup_BuffIcon2:SetNormalTexture(icon2); + SmartBuff_BuffSetup_BuffIcon2:Show(); + else + SmartBuff_BuffSetup_BuffIcon2:Hide(); + end + if (icon1) then + SmartBuff_BuffSetup_BuffIcon1:SetNormalTexture(icon1); + if (icon2 and bs.EnableG) then + SmartBuff_BuffSetup_BuffIcon1:SetPoint("TOPLEFT", 44, -30); + else + SmartBuff_BuffSetup_BuffIcon1:SetPoint("TOPLEFT", 64, -30); + end + SmartBuff_BuffSetup_BuffIcon1:Show(); + else + SmartBuff_BuffSetup_BuffIcon1:SetPoint("TOPLEFT", 24, -30); + SmartBuff_BuffSetup_BuffIcon1:Hide(); + end + + local obj = SmartBuff_BuffSetup_BuffText; + if (name) then + obj:SetText(name); + --SMARTBUFF_AddMsgD(name); + else + obj:SetText(""); + end + + SmartBuff_BuffSetup_cbSelf:SetChecked(bs.SelfOnly); + SmartBuff_BuffSetup_cbSelfNot:SetChecked(bs.SelfNot); + SmartBuff_BuffSetup_cbCombatIn:SetChecked(bs.CIn); + SmartBuff_BuffSetup_cbCombatOut:SetChecked(bs.COut); + SmartBuff_BuffSetup_cbMH:SetChecked(bs.MH); + SmartBuff_BuffSetup_cbOH:SetChecked(bs.OH); + SmartBuff_BuffSetup_cbRH:SetChecked(bs.RH); + SmartBuff_BuffSetup_cbReminder:SetChecked(bs.Reminder); + SmartBuff_BuffSetup_txtManaLimit:SetNumber(bs.ManaLimit); + + --SMARTBUFF_AddMsgD("Test Buff setup show 1"); + if (cBuffs[i].DurationS > 0) then + SmartBuff_BuffSetup_RBTime:SetMinMaxValues(0, cBuffs[i].DurationS); + _G[SmartBuff_BuffSetup_RBTime:GetName().."High"]:SetText(cBuffs[i].DurationS); + if (cBuffs[i].DurationS <= 60) then + SmartBuff_BuffSetup_RBTime:SetValueStep(1); + elseif (cBuffs[i].DurationS <= 180) then + SmartBuff_BuffSetup_RBTime:SetValueStep(5); + elseif (cBuffs[i].DurationS <= 600) then + SmartBuff_BuffSetup_RBTime:SetValueStep(10); + else + SmartBuff_BuffSetup_RBTime:SetValueStep(30); + end + SmartBuff_BuffSetup_RBTime:SetValue(bs.RBTime); + _G[SmartBuff_BuffSetup_RBTime:GetName().."Text"]:SetText(bs.RBTime .. "\nsec"); + SmartBuff_BuffSetup_RBTime:Show(); + else + SmartBuff_BuffSetup_RBTime:Hide(); + end + --SMARTBUFF_AddMsgD("Test Buff setup show 2"); + + SmartBuff_BuffSetup_txtManaLimit:Hide(); + if (cBuffs[i].Type == SMARTBUFF_CONST_INV or cBuffs[i].Type == SMARTBUFF_CONST_WEAPON) then + SmartBuff_BuffSetup_cbMH:Show(); + SmartBuff_BuffSetup_cbOH:Show(); + SmartBuff_BuffSetup_cbRH:Hide(); + else + SmartBuff_BuffSetup_cbMH:Hide(); + SmartBuff_BuffSetup_cbOH:Hide(); + SmartBuff_BuffSetup_cbRH:Hide(); + if (cBuffs[i].Type ~= SMARTBUFF_CONST_FOOD and cBuffs[i].Type ~= SMARTBUFF_CONST_SCROLL and cBuffs[i].Type ~= SMARTBUFF_CONST_POTION) then + SmartBuff_BuffSetup_txtManaLimit:Show(); + --SMARTBUFF_AddMsgD("Show ManaLimit"); + end + end + + if (cBuffs[i].Type == SMARTBUFF_CONST_GROUP or cBuffs[i].Type == SMARTBUFF_CONST_ITEMGROUP) then + SmartBuff_BuffSetup_cbSelf:Show(); + SmartBuff_BuffSetup_cbSelfNot:Show(); + SmartBuff_BuffSetup_btnPriorityList:Show(); + SmartBuff_BuffSetup_btnIgnoreList:Show(); + else + SmartBuff_BuffSetup_cbSelf:Hide(); + SmartBuff_BuffSetup_cbSelfNot:Hide(); + SmartBuff_BuffSetup_btnPriorityList:Hide(); + SmartBuff_BuffSetup_btnIgnoreList:Hide(); + SmartBuff_PlayerSetup:Hide(); + end + + local cb = nil; + local btn = nil; + n = 0; + --SMARTBUFF_AddMsgD("Test Buff setup show 3"); + for _ in pairs(cClasses) do + n = n + 1; + cb = _G["SmartBuff_BuffSetup_cbClass"..n]; + btn = _G["SmartBuff_BuffSetup_ClassIcon"..n]; + if (hidden or tcontains(cIgnoreClasses, n)) then + cb:Hide(); + btn:Hide(); + else + cb:SetChecked(bs[cClasses[n]]); + cb:Show(); + btn:Show(); + end + end + iLastBuffSetup = i; + --SMARTBUFF_AddMsgD("Test Buff setup show 4"); + SmartBuff_BuffSetup:Show(); + + if (SmartBuff_PlayerSetup:IsVisible()) then + SmartBuff_PS_Show(iCurrentList); + end + end +end + +function SmartBuff_BuffSetup_ManaLimitChanged(self) + local i = iLastBuffSetup; + if (i <= 0) then + return; + end + local ct = currentTemplate; + local name = cBuffs[i].BuffS; + B[CS()][ct][name].ManaLimit = self:GetNumber(); +end + +function SmartBuff_BuffSetup_OnClick() + local i = iLastBuffSetup; + local ct = currentTemplate; + if (i <= 0) then + return; + end + local name = cBuffs[i].BuffS; + local cBuff = GetBuffSettings(name); + + cBuff.SelfOnly = SmartBuff_BuffSetup_cbSelf:GetChecked(); + cBuff.SelfNot = SmartBuff_BuffSetup_cbSelfNot:GetChecked(); + cBuff.CIn = SmartBuff_BuffSetup_cbCombatIn:GetChecked(); + cBuff.COut = SmartBuff_BuffSetup_cbCombatOut:GetChecked(); + cBuff.MH = SmartBuff_BuffSetup_cbMH:GetChecked(); + cBuff.OH = SmartBuff_BuffSetup_cbOH:GetChecked(); + cBuff.RH = SmartBuff_BuffSetup_cbRH:GetChecked(); + cBuff.Reminder = SmartBuff_BuffSetup_cbReminder:GetChecked(); + + cBuff.RBTime = SmartBuff_BuffSetup_RBTime:GetValue(); + _G[SmartBuff_BuffSetup_RBTime:GetName().."Text"]:SetText(cBuff.RBTime .. "\nsec"); + + if (cBuffs[i].Type == SMARTBUFF_CONST_GROUP or cBuffs[i].Type == SMARTBUFF_CONST_ITEMGROUP) then + local n = 0; + local cb = nil; + for _ in pairs(cClasses) do + n = n + 1; + cb = _G["SmartBuff_BuffSetup_cbClass"..n]; + if (tcontains(cIgnoreClasses, n)) then + cBuff[cClasses[n]] = false; + else + cBuff[cClasses[n]] = cb:GetChecked(); + end + end + end + --SMARTBUFF_AddMsgD("Buff setup saved"); +end + +function SmartBuff_BuffSetup_ToolTip(mode) + local i = iLastBuffSetup; + if (i <= 0) then + return; + end + local ids = cBuffs[i].IDS; + local idg = cBuffs[i].IDG; + local btype = cBuffs[i].Type + + GameTooltip:ClearLines(); + if (SMARTBUFF_IsItem(btype)) then + local bag, slot, count, texture = SMARTBUFF_FindItem(cBuffs[i].BuffS, cBuffs[i].Chain); + if (bag and slot) then + if (bag == 999) then -- Toy + GameTooltip:SetToyByItemID(slot); + else + GameTooltip:SetBagItem(bag, slot); + end + end + else + if (mode == 1 and ids) then + GameTooltip:SetHyperlink("spell:" .. ids); + elseif (mode == 2 and idg) then + GameTooltip:SetHyperlink("spell:" .. idg); + end + end + GameTooltip:Show(); +end +-- END SmartBuff options toggle + + +-- Options frame functions --------------------------------------------------------------------------------------- +function SMARTBUFF_Options_OnLoad(self) +end + +function SMARTBUFF_Options_OnShow() + -- Check if the options frame is out of screen area + local top = GetScreenHeight() - math.abs(SmartBuffOptionsFrame:GetTop()); + local bottom = GetScreenHeight() - math.abs(SmartBuffOptionsFrame:GetBottom()); + local left = SmartBuffOptionsFrame:GetLeft(); + local right = SmartBuffOptionsFrame:GetRight(); + + --SMARTBUFF_AddMsgD("X: " .. GetScreenWidth() .. ", " .. left .. ", " .. right); + --SMARTBUFF_AddMsgD("Y: " .. GetScreenHeight() .. ", " .. top .. ", " .. bottom); + + if (GetScreenWidth() < left + 20 or GetScreenHeight() < top + 20 or right < 20 or bottom < 20) then + SmartBuffOptionsFrame:SetPoint("TOPLEFT", UIParent, "CENTER", -SmartBuffOptionsFrame:GetWidth() / 2, SmartBuffOptionsFrame:GetHeight() / 2); + end + + SmartBuff_ShowControls("SmartBuffOptionsFrame", true); + + SmartBuffOptionsFrame_cbSB:SetChecked(O.Toggle); + SmartBuffOptionsFrame_cbAuto:SetChecked(O.ToggleAuto); + SmartBuffOptionsFrameAutoTimer:SetValue(O.AutoTimer); + SmartBuff_SetSliderText(SmartBuffOptionsFrameAutoTimer, SMARTBUFF_OFT_AUTOTIMER, O.AutoTimer, INT_SPELL_DURATION_SEC); + SmartBuffOptionsFrame_cbAutoCombat:SetChecked(O.ToggleAutoCombat); + SmartBuffOptionsFrame_cbAutoChat:SetChecked(O.ToggleAutoChat); + SmartBuffOptionsFrame_cbAutoSplash:SetChecked(O.ToggleAutoSplash); + SmartBuffOptionsFrame_cbAutoSound:SetChecked(O.ToggleAutoSound); + --SmartBuffOptionsFrame_cbCheckCharges:SetChecked(O.ToggleCheckCharges); + --SmartBuffOptionsFrame_cbAutoRest:SetChecked(O.ToggleAutoRest); + SmartBuffOptionsFrame_cbAutoSwitchTmp:SetChecked(O.AutoSwitchTemplate); + SmartBuffOptionsFrame_cbAutoSwitchTmpInst:SetChecked(O.AutoSwitchTemplateInst); + SmartBuffOptionsFrame_cbBuffPvP:SetChecked(O.BuffPvP); + SmartBuffOptionsFrame_cbBuffTarget:SetChecked(O.BuffTarget); + SmartBuffOptionsFrame_cbBuffInCities:SetChecked(O.BuffInCities); + SmartBuffOptionsFrame_cbInShapeshift:SetChecked(O.InShapeshift); + + SmartBuffOptionsFrame_cbAntiDaze:SetChecked(O.AntiDaze); + SmartBuffOptionsFrame_cbLinkGrpBuffCheck:SetChecked(O.LinkGrpBuffCheck); + SmartBuffOptionsFrame_cbLinkSelfBuffCheck:SetChecked(O.LinkSelfBuffCheck); + + SmartBuffOptionsFrame_cbScrollWheelUp:SetChecked(O.ScrollWheelUp); + SmartBuffOptionsFrame_cbScrollWheelDown:SetChecked(O.ScrollWheelDown); + SmartBuffOptionsFrame_cbInCombat:SetChecked(O.InCombat); + SmartBuffOptionsFrame_cbMsgNormal:SetChecked(O.ToggleMsgNormal); + SmartBuffOptionsFrame_cbMsgWarning:SetChecked(O.ToggleMsgWarning); + SmartBuffOptionsFrame_cbMsgError:SetChecked(O.ToggleMsgError); + SmartBuffOptionsFrame_cbHideMmButton:SetChecked(O.HideMmButton); + SmartBuffOptionsFrame_cbHideSAButton:SetChecked(O.HideSAButton); + + SmartBuffOptionsFrameRebuffTimer:SetValue(O.RebuffTimer); + SmartBuff_SetSliderText(SmartBuffOptionsFrameRebuffTimer, SMARTBUFF_OFT_REBUFFTIMER, O.RebuffTimer, INT_SPELL_DURATION_SEC); + SmartBuffOptionsFrameBLDuration:SetValue(O.BlacklistTimer); + SmartBuff_SetSliderText(SmartBuffOptionsFrameBLDuration, SMARTBUFF_OFT_BLDURATION, O.BlacklistTimer, INT_SPELL_DURATION_SEC); + + SMARTBUFF_ShowSubGroupsOptions(); + SMARTBUFF_SetCheckButtonBuffs(0); + + SMARTBUFF_Splash_Show(); + + SMARTBUFF_AddMsgD("Option frame updated: " .. currentTemplate); +end + +function SMARTBUFF_ShowSubGroupsMini() + SMARTBUFF_ShowSubGroups("SmartBuff_MiniGroup", O.ToggleGrp); +end + +function SMARTBUFF_ShowSubGroupsOptions() + SMARTBUFF_ShowSubGroups("SmartBuffOptionsFrame", O.ToggleGrp); +end + +function SMARTBUFF_ShowSubGroups(frame, grpTable) + local i; + for i = 1, 8, 1 do + obj = _G[frame.."_cbGrp"..i]; + if (obj) then + obj:SetChecked(grpTable[i]); + end + end +end + +function SMARTBUFF_Options_OnHide() + if (SmartBuffWNF:IsVisible()) then + SmartBuffWNF:Hide(); + end + SMARTBUFF_ToggleTutorial(true); + SmartBuffOptionsFrame:SetHeight(SMARTBUFF_OPTIONSFRAME_HEIGHT); + --SmartBuff_BuffSetup:SetHeight(SMARTBUFF_OPTIONSFRAME_HEIGHT); + wipe(cBuffsCombat); + SMARTBUFF_SetInCombatBuffs(); + SmartBuff_BuffSetup:Hide(); + SmartBuff_PlayerSetup:Hide(); + SMARTBUFF_SetUnits(); + SMARTBUFF_Splash_Hide(); + SMARTBUFF_RebindKeys(); + --collectgarbage(); +end + +function SmartBuff_ShowControls(sName, bShow) + local children = {_G[sName]:GetChildren()}; + for i, child in pairs(children) do + --SMARTBUFF_AddMsgD(i .. ": " .. child:GetName()); + if (i > 1 and string.find(child:GetName(), "^"..sName..".+")) then + if (bShow) then + child:Show(); + else + child:Hide(); + end + end + end +end + +function SmartBuffOptionsFrameSlider_OnLoad(self, low, high, step, labels) + _G[self:GetName().."Text"]:SetFontObject(GameFontNormalSmall); + if (labels) then + if (self:GetOrientation() ~= "VERTICAL") then + _G[self:GetName().."Low"]:SetText(low); + else + _G[self:GetName().."Low"]:SetText(""); + end + _G[self:GetName().."High"]:SetText(high); + else + _G[self:GetName().."Low"]:SetText(""); + _G[self:GetName().."High"]:SetText(""); + end + self:SetMinMaxValues(low, high); + self:SetValueStep(step); + self:SetStepsPerPage(step); + + if (step < 1) then return; end + + self.GetValueBase = self.GetValue; + self.GetValue = function() + local n = self:GetValueBase(); + if (n) then + local r = Round(n); + if (r ~= n) then + self:SetValue(n); + end + return r; + end + return low; + end; +end + +function SmartBuff_SetSliderText(self, text, value, valformat, setval) + if (not self or not value) then return end + local s; + if (setval) then self:SetValue(value) end + if (valformat) then + s = string.format(valformat, value); + else + s = tostring(value); + end + getglobal(self:GetName().."Text"):SetText(text.." "..WH..s.."|r"); +end + +function SmartBuff_BuffSetup_RBTime_OnValueChanged(self) + _G[SmartBuff_BuffSetup_RBTime:GetName().."Text"]:SetText(WH..format("%.0f", self:GetValue()).."\nsec|r"); +end + +function SMARTBUFF_SetCheckButtonBuffs(mode) + local objS; + local objG; + local i = 1; + local ct = currentTemplate; + + if (mode == 0) then + SMARTBUFF_SetBuffs(); + end + + SmartBuffOptionsFrame_cbAntiDaze:Hide(); + + if (sPlayerClass == "HUNTER" or sPlayerClass == "ROGUE" or sPlayerClass == "WARRIOR") then + SmartBuffOptionsFrameBLDuration:Hide(); + if (sPlayerClass == "HUNTER") then + SmartBuffOptionsFrame_cbLinkGrpBuffCheck:Hide(); + SmartBuffOptionsFrame_cbAntiDaze:Show(); + end + end + + if (sPlayerClass == "DRUID" or sPlayerClass == "SHAMAN") then + SmartBuffOptionsFrame_cbInShapeshift:Show(); + else + SmartBuffOptionsFrame_cbInShapeshift:Hide(); + end + + SMARTBUFF_BuffOrderOnScroll(); +end + + +function SMARTBUFF_DropDownTemplate_OnShow(self) + local i = 0; + for _, tmp in pairs(SMARTBUFF_TEMPLATES) do + i = i + 1; + --SMARTBUFF_AddMsgD(i .. "." .. tmp); + if (tmp == currentTemplate) then + break; + end + end + UIDropDownMenu_Initialize(self, SMARTBUFF_DropDownTemplate_Initialize); + UIDropDownMenu_SetSelectedValue(SmartBuffOptionsFrame_ddTemplates, i); + UIDropDownMenu_SetWidth(SmartBuffOptionsFrame_ddTemplates, 135); +end + +function SMARTBUFF_DropDownTemplate_Initialize() + local info = UIDropDownMenu_CreateInfo(); + info.text = ALL; + info.value = -1; + info.func = SMARTBUFF_DropDownTemplate_OnClick; + for k, v in pairs(SMARTBUFF_TEMPLATES) do + info.text = SMARTBUFF_TEMPLATES[k]; + info.value = k; + info.func = SMARTBUFF_DropDownTemplate_OnClick; + info.checked = nil; + UIDropDownMenu_AddButton(info); + end +end + +function SMARTBUFF_DropDownTemplate_OnClick(self) + local i = self.value; + local tmp = nil; + UIDropDownMenu_SetSelectedValue(SmartBuffOptionsFrame_ddTemplates, i); + tmp = SMARTBUFF_TEMPLATES[i]; + --SMARTBUFF_AddMsgD("Selected/Current Buff-Template: " .. tmp .. "/" .. currentTemplate); + if (currentTemplate ~= tmp) then + SmartBuff_BuffSetup:Hide(); + iLastBuffSetup = -1; + SmartBuff_PlayerSetup:Hide(); + + currentTemplate = tmp; + SMARTBUFF_Options_OnShow(); + O.LastTemplate = currentTemplate; + end +end +-- END Options frame functions + + +-- Splash screen functions --------------------------------------------------------------------------------------- +function SMARTBUFF_Splash_Show() + if (not isInit) then return; end + SMARTBUFF_Splash_ChangeFont(1); + SmartBuffSplashFrame:EnableMouse(true); + SmartBuffSplashFrame:Show(); + SmartBuffSplashFrame:SetTimeVisible(60); + SmartBuffSplashFrameOptions:Show(); +end + +function SMARTBUFF_Splash_Hide() + if (not isInit) then return; end + SMARTBUFF_Splash_Clear(); + SMARTBUFF_Splash_ChangePos(); + SmartBuffSplashFrame:EnableMouse(false); + SmartBuffSplashFrame:SetFadeDuration(O.SplashDuration); + SmartBuffSplashFrame:SetTimeVisible(O.SplashDuration); + SmartBuffSplashFrameOptions:Hide(); +end + +function SMARTBUFF_Splash_Clear() + SmartBuffSplashFrame:Clear(); +end + +function SMARTBUFF_Splash_ChangePos() + local x, y = SmartBuffSplashFrame:GetLeft(), SmartBuffSplashFrame:GetTop() - UIParent:GetHeight(); + if (O) then + O.SplashX = x; + O.SplashY = y; + end +end + +function SMARTBUFF_Splash_ChangeFont(mode) + local f = SmartBuffSplashFrame; + + if (mode > 1) then + SMARTBUFF_Splash_ChangePos(); + iCurrentFont = iCurrentFont + 1; + end + if (not cFonts[iCurrentFont]) then + iCurrentFont = 1; + end + O.CurrentFont = iCurrentFont; + f:ClearAllPoints(); + f:SetPoint("TOPLEFT", O.SplashX, O.SplashY); + + local fo = f:GetFontObject(); + local fName, fHeight, fFlags = _G[cFonts[iCurrentFont]]:GetFont(); + if (mode > 1 or O.CurrentFontSize == nil) then + O.CurrentFontSize = fHeight; + end + fo:SetFont(fName, O.CurrentFontSize, fFlags); + SmartBuffSplashFrameOptions.size:SetValue(O.CurrentFontSize); + + f:SetInsertMode("TOP"); + f:SetJustifyV("MIDDLE"); + if (mode > 0) then + local si = ""; + if (OG.SplashIcon) then + local n = O.SplashIconSize; + if (n == nil or n <= 0) then + n = O.CurrentFontSize; + end + si = string.format(" \124T%s:%d:%d:1:0\124t", "Interface\\Icons\\INV_Misc_QuestionMark", n, n) or ""; + else + si = " BuffXYZ"; + end + SMARTBUFF_Splash_Clear(); + if (OG.SplashMsgShort) then + f:AddMessage(cFonts[iCurrentFont].." >"..si.."\ndrag'n'drop to move", O.ColSplashFont.r, O.ColSplashFont.g, O.ColSplashFont.b, 1.0); + else + f:AddMessage(cFonts[iCurrentFont].." "..SMARTBUFF_MSG_NEEDS..si.."\ndrag'n'drop to move", O.ColSplashFont.r, O.ColSplashFont.g, O.ColSplashFont.b, 1.0); + end + end +end +-- END Splash screen events + + +-- Playerlist functions --------------------------------------------------------------------------------------- +function SmartBuff_PlayerSetup_OnShow() +end + +function SmartBuff_PlayerSetup_OnHide() +end + +function SmartBuff_PS_GetList() + if (iLastBuffSetup <= 0) then return { } end + + local name = cBuffs[iLastBuffSetup].BuffS; + if (name) then + if (iCurrentList == 1) then + return B[CS()][currentTemplate][name].AddList; + else + return B[CS()][currentTemplate][name].IgnoreList; + end + end +end + +function SmartBuff_PS_GetUnitList() + if (iCurrentList == 1) then + return cAddUnitList; + else + return cIgnoreUnitList; + end +end + +function SmartBuff_UnitIsAdd(unit) + if (unit and cAddUnitList[unit]) then return true end + return false; +end + +function SmartBuff_UnitIsIgnored(unit) + if (unit and cIgnoreUnitList[unit]) then return true end + return false; +end + +function SmartBuff_PS_Show(i) + iCurrentList = i; + iLastPlayer = -1; + local obj = SmartBuff_PlayerSetup_Title; + if (iCurrentList == 1) then + obj:SetText("Additional list"); + else + obj:SetText("Ignore list"); + end + obj:ClearFocus(); + SmartBuff_PlayerSetup_EditBox:ClearFocus(); + SmartBuff_PlayerSetup:Show(); + SmartBuff_PS_SelectPlayer(0); +end + +function SmartBuff_PS_AddPlayer() + local cList = SmartBuff_PS_GetList(); + local un = UnitName("target"); + if (un and UnitIsPlayer("target") and (UnitInRaid("target") or UnitInParty("target") or O.Debug)) then + if (not cList[un]) then + cList[un] = true; + SmartBuff_PS_SelectPlayer(0); + end + end +end + +function SmartBuff_PS_RemovePlayer() + local n = 0; + local cList = SmartBuff_PS_GetList(); + for player in pairs(cList) do + n = n + 1; + if (n == iLastPlayer) then + cList[player] = nil; + break; + end + end + SmartBuff_PS_SelectPlayer(0); +end + +function SmartBuff_AddToUnitList(idx, unit, subgroup) + iCurrentList = idx; + local cList = SmartBuff_PS_GetList(); + local cUnitList = SmartBuff_PS_GetUnitList(); + if (unit and subgroup) then + local un = UnitName(unit); + if (un and cList[un]) then + cUnitList[unit] = subgroup; + --print("Added to UnitList:" .. un .. "(" .. unit .. ")"); + end + end +end + +function SmartBuff_PS_SelectPlayer(iOp) + local idx = iLastPlayer + iOp; + local cList = SmartBuff_PS_GetList(); + local s = ""; + + local tn = 0; + for player in pairs(cList) do + tn = tn + 1; + s = s .. player .. "\n"; + end + + -- update list in textbox + if (iOp == 0) then + SmartBuff_PlayerSetup_EditBox:SetText(s); + --SmartBuff_PlayerSetup_EditBox:ClearFocus(); + end + + -- highlight selected player + if (tn > 0) then + if (idx > tn) then idx = tn; end + if (idx < 1) then idx = 1; end + iLastPlayer = idx; + --SmartBuff_PlayerSetup_EditBox:ClearFocus(); + local n = 0; + local i = 0; + local w = 0; + for player in pairs(cList) do + n = n + 1; + w = string.len(player); + if (n == idx) then + SmartBuff_PlayerSetup_EditBox:HighlightText(i + n - 1, i + n + w); + break; + end + i = i + w; + end + end +end + +function SmartBuff_PS_Resize() + local h = SmartBuffOptionsFrame:GetHeight(); + local b = true; + + if (h < 200) then + SmartBuffOptionsFrame:SetHeight(SMARTBUFF_OPTIONSFRAME_HEIGHT); + --SmartBuff_BuffSetup:SetHeight(SMARTBUFF_OPTIONSFRAME_HEIGHT); + b = true; + else + SmartBuffOptionsFrame:SetHeight(40); + --SmartBuff_BuffSetup:SetHeight(40); + b = false; + end + SmartBuff_ShowControls("SmartBuffOptionsFrame", b); + if (b) then + SMARTBUFF_SetCheckButtonBuffs(1); + end +end +-- END Playerlist functions + + +-- Mini group functions --------------------------------------------------------------------------------------- +function SMARTBUFF_MiniGroup_OnShow() + SmartBuff_MiniGroup_Title:SetText(SMARTBUFF_TITLE.." - "..currentTemplate); + SMARTBUFF_ShowSubGroupsMini(); +end + +function SMARTBUFF_MiniGroup_OnHide() +end + +function SMARTBUFF_MiniGroup_Show() + --if (O.ShowMiniGrp) then + if (O.ShowMiniGrp and iGroupSetup == 3) then + SmartBuff_MiniGroup:Show(); + else + if (SmartBuff_MiniGroup:IsVisible()) then + SmartBuff_MiniGroup:Hide(); + end + end +end +-- END Mini group functions + + +-- Secure button functions, NEW TBC --------------------------------------------------------------------------------------- +function SMARTBUFF_ShowSAButton() + if (not InCombatLockdown()) then + if (O.HideSAButton) then + SmartBuff_KeyButton:Hide(); + else + SmartBuff_KeyButton:Show(); + end + end +end + +local sScript; +function SMARTBUFF_OnClick(obj) + SMARTBUFF_AddMsgD("OnClick"); +end + + +local lastBuffType = ""; +function SMARTBUFF_OnPreClick(self, button, down) + if (not isInit) then return end + + local mode = 0; + if (button) then + if (button == "MOUSEWHEELUP" or button == "MOUSEWHEELDOWN") then + mode = 5; + end + end + + if (not InCombatLockdown()) then + self:SetAttribute("type", nil); + self:SetAttribute("unit", nil); + self:SetAttribute("spell", nil); + self:SetAttribute("item", nil); + self:SetAttribute("macrotext", nil); + self:SetAttribute("target-slot", nil); + self:SetAttribute("target-item", nil); + self:SetAttribute("action", nil); + end + + --sScript = self:GetScript("OnClick"); + --self:SetScript("OnClick", SMARTBUFF_OnClick); + + local td; + if (lastBuffType == "") then + td = 0.8; + else + td = GlobalCd; + end + --SMARTBUFF_AddMsgD("Last buff type: " .. lastBuffType .. ", set cd: " .. td); + + + -- *** TODO: Check for classic ********************************************************************************** + local casting = UnitCastingInfo("player") or UnitChannelInfo("player"); + --print(casting); + if (casting ~= nil) then + --print("Casting", casting, "-> Reset AutoBuff timer"); + tAutoBuff = GetTime() + 0.7; + return; + end + + if (GetTime() < (tAutoBuff + td)) then return end + + --SMARTBUFF_AddMsgD("next buff check"); + tAutoBuff = GetTime(); + lastBuffType = ""; + currentUnit = nil; + currentSpell = nil; + currentRank = nil; + + if (not InCombatLockdown()) then + local ret, actionType, spellName, slot, unit, buffType, rankText = SMARTBUFF_Check(mode); + if (ret and ret == 0 and actionType and spellName and unit) then + lastBuffType = buffType; + self:SetAttribute("type", actionType); + self:SetAttribute("unit", unit); + if (actionType == SMARTBUFF_ACTION_SPELL) then + if (slot and slot > 0 and unit == "player") then + self:SetAttribute("type", "macro"); + self:SetAttribute("macrotext", string.format("/use %s\n/use %i\n/click StaticPopup1Button1", spellName, slot)); + --self:SetAttribute("target-item", slot); + SMARTBUFF_AddMsgD("Weapon buff "..spellName..", "..slot); + else + --rankText = "(Rang 1)"; + local name = spellName; + if (rankText ~= nil) then + name = spellName..rankText; + end + SMARTBUFF_AddMsgD("SetAttribute 'spell' = "..name); + self:SetAttribute("spell", name); + end + + if (cBuffIndex[spellName]) then + currentUnit = unit; + currentSpell = spellName; + end + + elseif (actionType == SMARTBUFF_ACTION_ITEM and slot) then + --if (spellname ~= nil and string.find(spellname, "%-%-") ~= nil) then + -- spellname = string.gsub(spellname, "%-%-", "%-"); + --end + self:SetAttribute("item", spellName); + if (slot > 0) then + --self:SetAttribute("target-slot", slot); + + self:SetAttribute("type", "macro"); + self:SetAttribute("macrotext", string.format("/use %s\n/use %i\n/click StaticPopup1Button1", spellName, slot)); + end + elseif (actionType == "action" and slot) then + self:SetAttribute("action", slot); + else + SMARTBUFF_AddMsgD("Preclick: not supported actiontype -> " .. actionType); + end + + --isClearSplash = true; + tLastCheck = GetTime() - O.AutoTimer + GlobalCd; + end + end +end + +function SMARTBUFF_OnPostClick(self, button, down) + if (not isInit) then return end + + if (button) then + if (button == "MOUSEWHEELUP") then + CameraZoomIn(1); + elseif (button == "MOUSEWHEELDOWN") then + CameraZoomOut(1); + end + end + + if (InCombatLockdown()) then return end + + --[[ + if (O.Toggle) then + if (O.InCombat) then + for spell, data in pairs(cBuffsCombat) do + if (data and data.Unit and data.ActionType) then + SmartBuff_KeyButton:SetAttribute("unit", data.Unit); + SmartBuff_KeyButton:SetAttribute("type", data.ActionType); + SmartBuff_KeyButton:SetAttribute("spell", spell); + SmartBuff_KeyButton:SetAttribute("item", nil); + SmartBuff_KeyButton:SetAttribute("target-slot", nil); + SmartBuff_KeyButton:SetAttribute("action", nil); + SMARTBUFF_AddMsgD("Enter Combat, set button: " .. spell .. " on " .. data.Unit .. ", " .. data.ActionType); + break; + end + end + end + end + ]]-- + + --local posX, posY = GetPlayerMapPosition("player"); + --SMARTBUFF_AddMsgD("X = " .. posX .. ", Y = " .. posY); + --if (UnitCreatureType("target")) then + -- SMARTBUFF_AddMsgD(UnitCreatureType("target")); + --end + + --[[ + local r = IsSpellInRange("Nachwachsen", "target") + if(r and r == 1) then + SMARTBUFF_AddMsgD("Spell in range"); + elseif(r and r == 0) then + SMARTBUFF_AddMsgD("OOR"); + end + ]]-- + + --[[ + local s = ""; + local button = SecureStateChild_GetEffectiveButton(self); + local type = SecureButton_GetModifiedAttribute(self, "type", button, ""); + local unit = SecureButton_GetModifiedAttribute(self, "unit", button, ""); + local spell = SecureButton_GetModifiedAttribute(self, "spell", button, ""); + if (type and unit and spell) then + s = s .. type .. ", " .. unit .. ", " .. spell; + end + ]]-- + + self:SetAttribute("type", nil); + self:SetAttribute("unit", nil); + self:SetAttribute("spell", nil); + self:SetAttribute("item", nil); + self:SetAttribute("target-slot", nil); + self:SetAttribute("target-item", nil); + self:SetAttribute("macrotext", nil); + self:SetAttribute("action", nil); + + SMARTBUFF_SetButtonTexture(SmartBuff_KeyButton, imgSB); + --SMARTBUFF_AddMsgD("Button reseted, " .. button); + --self:SetScript("OnClick", sScript); +end + +function SMARTBUFF_SetButtonTexture(button, texture, text) + --if (InCombatLockdown()) then return; end + + if (button and texture and texture ~= sLastTexture) then + sLastTexture = texture; + button:SetNormalTexture(texture); + --SMARTBUFF_AddMsgD("Button slot texture set -> " .. texture); + if (text) then + --button.title:SetText(spell); + end + end +end +-- END secure button functions + + +-- Minimap button functions --------------------------------------------------------------------------------------- +-- Sets the correct icon on the minimap button +function SMARTBUFF_CheckMiniMapButton() + if (O.Toggle) then + SmartBuff_MiniMapButton:SetNormalTexture(imgIconOn); + else + SmartBuff_MiniMapButton:SetNormalTexture(imgIconOff); + end + + if (O.HideMmButton) then + SmartBuff_MiniMapButton:Hide(); + else + SmartBuff_MiniMapButton:Show(); + end + + -- Update the Titan Panel icon + if (TitanPanelBarButton and TitanPanelSmartBuffButton_SetIcon ~= nil) then + TitanPanelSmartBuffButton_SetIcon(); + end + + -- Update the FuBar icon + if (IsAddOnLoaded("FuBar") and IsAddOnLoaded("FuBar_SmartBuffFu") and SMARTBUFF_Fu_SetIcon ~= nil) then + SMARTBUFF_Fu_SetIcon(); + end + + -- Update the Broker icon + if (IsAddOnLoaded("Broker_SmartBuff") and SMARTBUFF_BROKER_SetIcon ~= nil) then + SMARTBUFF_BROKER_SetIcon(); + end + +end + +function SMARTBUFF_MinimapButton_CheckPos() + if (not isInit or not SmartBuff_MiniMapButton) then return; end + local x = SmartBuff_MiniMapButton:GetLeft(); + local y = SmartBuff_MiniMapButton:GetTop(); + if (x == nil or y == nil) then return; end + x = x - Minimap:GetLeft(); + y = y - Minimap:GetTop(); + if (math.abs(x) < 180 and math.abs(y) < 180) then + O.MMCPosX = x; + O.MMCPosY = y; + --SMARTBUFF_AddMsgD("x = " .. O.MMCPosX .. ", y = " .. O.MMCPosY); + end +end + +-- Function to move the minimap button arround the minimap +function SMARTBUFF_MinimapButton_OnUpdate(self, move) + if (not isInit or self == nil or not self:IsVisible()) then + return; + end + + local xpos, ypos; + self:ClearAllPoints(); + if (move or O.MMCPosX == nil) then + local pos, r + local xmin, ymin = Minimap:GetLeft(), Minimap:GetBottom(); + xpos, ypos = GetCursorPosition(); + xpos = xmin-xpos/Minimap:GetEffectiveScale()+70; + ypos = ypos/Minimap:GetEffectiveScale()-ymin-70; + pos = math.deg(math.atan2(ypos,xpos)); + r = math.sqrt(xpos*xpos + ypos*ypos); + --SMARTBUFF_AddMsgD("x = " .. xpos .. ", y = " .. ypos .. ", r = " .. r .. ", pos = " .. pos); + + if (r < 75) then + r = 75; + elseif(r > 105) then + r = 105; + end + + xpos = 52-r*cos(pos); + ypos = r*sin(pos)-52; + O.MMCPosX = xpos; + O.MMCPosY = ypos; + --SMARTBUFF_AddMsgD("Update minimap button position"); + else + xpos = O.MMCPosX; + ypos = O.MMCPosY; + --SMARTBUFF_AddMsgD("Load minimap button position"); + end + self:ClearAllPoints(); + self:SetPoint("TOPLEFT", "Minimap", "TOPLEFT", xpos, ypos); + --SMARTBUFF_AddMsgD("x = " .. O.MMCPosX .. ", y = " .. O.MMCPosY); + --SmartBuff_MiniMapButton:SetUserPlaced(true); + --SMARTBUFF_AddMsgD("Update minimap button"); +end +-- END Minimap button functions + + + +-- Scroll frame functions --------------------------------------------------------------------------------------- +local ScrBtnSize = 20; +local ScrLineHeight = 18; +local function SetPosScrollButtons(parent, cBtn) + local btn; + local name; + for i = 1, #cBtn, 1 do + btn = cBtn[i]; + btn:ClearAllPoints(); + btn:SetPoint("TOPLEFT", parent, "TOPLEFT", 2, -2 - ScrLineHeight*(i-1)); + end +end + +local StartY, EndY; +local function CreateScrollButton(name, parent, cBtn, onClick, onDragStop) + local btn = CreateFrame("CheckButton", name, parent, "OptionsCheckButtonTemplate"); + btn:SetWidth(ScrBtnSize); + btn:SetHeight(ScrBtnSize); + --btn:RegisterForClicks("LeftButtonUp"); + btn:RegisterForClicks("AnyUp"); + btn:SetScript("OnClick", onClick); + --btn:SetScript("OnMouseUp", onClick); + + if (onDragStop ~= nil) then + btn:SetMovable(true); + btn:RegisterForDrag("LeftButton"); + btn:SetScript("OnDragStart", function(self, b) + StartY = self:GetTop(); + self:StartMoving(); + end + ); + btn:SetScript("OnDragStop", function(self, b) + EndY = self:GetTop(); + local i = tonumber(self:GetID()) + FauxScrollFrame_GetOffset(parent); + local n = math.floor((StartY-EndY) / ScrLineHeight); + self:StopMovingOrSizing(); + SetPosScrollButtons(parent, cBtn); + onDragStop(i, n); + end + ); + end + + local text = btn:CreateFontString(nil, nil, "GameFontNormal"); + text:SetJustifyH("LEFT"); + --text:SetAllPoints(btn); + text:SetPoint("TOPLEFT", btn, "TOPLEFT", ScrBtnSize, 0); + text:SetWidth(parent:GetWidth()-ScrBtnSize); + text:SetHeight(ScrBtnSize); + btn:SetFontString(text); + btn:SetHighlightFontObject("GameFontHighlight"); + + local highlight = btn:CreateTexture(); + --highlight:SetAllPoints(btn); + highlight:SetPoint("TOPLEFT", btn, "TOPLEFT", 0, -2); + highlight:SetWidth(parent:GetWidth()); + highlight:SetHeight(ScrLineHeight-3); + + highlight:SetTexture("Interface/QuestFrame/UI-QuestTitleHighlight"); + btn:SetHighlightTexture(highlight); + + return btn; +end + + +local function CreateScrollButtons(self, cBtn, sBtnName, onClick, onDragStop) + local btn, i; + for i = 1, maxScrollButtons, 1 do + btn = CreateScrollButton(sBtnName..i, self, cBtn, onClick, onDragStop); + btn:SetID(i); + cBtn[i] = btn; + end + SetPosScrollButtons(self, cBtn); +end + + +local function OnScroll(self, cData, sBtnName) + local num = #cData; + local n, numToDisplay; + + if (num <= maxScrollButtons) then + numToDisplay = num-1; + else + numToDisplay = maxScrollButtons; + end + + FauxScrollFrame_Update(self, num, numToDisplay, ScrLineHeight); + local t = B[CS()][CT()]; + for i = 1, maxScrollButtons, 1 do + n = i + FauxScrollFrame_GetOffset(self); + btn = _G[sBtnName..i]; + if (btn) then + if (n <= num) then + btn:SetNormalFontObject("GameFontNormalSmall"); + btn:SetHighlightFontObject("GameFontHighlightSmall"); + btn:SetText(cData[n]); + btn:SetChecked(t[cData[n]].EnableS); + btn:Show(); + else + btn:Hide(); + end + end + end +end + + +function SMARTBUFF_BuffOrderOnScroll(self, arg1) + if (not self) then + self = SmartBuffOptionsFrame_ScrollFrameBuffs; + end + + local name = "SMARTBUFF_BtnScrollBO"; + if (not cScrBtnBO and self) then + cScrBtnBO = { }; + CreateScrollButtons(self, cScrBtnBO, name, SMARTBUFF_BuffOrderBtnOnClick, SMARTBUFF_BuffOrderBtnOnDragStop); + end + + if (B[CS()].Order == nil) then + B[CS()].Order = { }; + end + + local t = { }; + for _, v in pairs(B[CS()].Order) do + if (v) then + tinsert(t, v); + end + end + OnScroll(self, t, name); +end + +function SMARTBUFF_BuffOrderBtnOnClick(self, button) + local n = self:GetID() + FauxScrollFrame_GetOffset(self:GetParent()); + local i = cBuffIndex[B[CS()].Order[n]]; + --SMARTBUFF_AddMsgD("Buff OnClick = "..n..", "..button); + if (button == "LeftButton") then + SMARTBUFF_OToggleBuff("S", i); + else + local b = not self:GetChecked(); + self:SetChecked(b); + SmartBuff_BuffSetup_Show(i); + end +end + +function SMARTBUFF_BuffOrderBtnOnDragStop(i, n) + treorder(B[CS()].Order, i, n); + SMARTBUFF_BuffOrderOnScroll(); +end + +function SMARTBUFF_BuffOrderReset() + InitBuffOrder(true); + SMARTBUFF_BuffOrderOnScroll(); +end + + +-- Help plate functions --------------------------------------------------------------------------------------- + +local HelpPlateList = { + FramePos = { x = 20, y = -20 }, + FrameSize = { width = 480, height = 500 }, + [1] = { ButtonPos = { x = 344, y = -80 }, HighLightBox = { x = 260, y = -50, width = 204, height = 410 }, ToolTipDir = "DOWN", ToolTipText = "Spell list\nDrag'n'Drop to change the priority order" }, + [2] = { ButtonPos = { x = 105, y = -110 }, HighLightBox = { x = 10, y = -30, width = 230, height = 125 }, ToolTipDir = "DOWN", ToolTipText = "Buff reminder options" }, + [3] = { ButtonPos = { x = 105, y = -250 }, HighLightBox = { x = 10, y = -165, width = 230, height = 135 }, ToolTipDir = "DOWN", ToolTipText = "Character based options" }, + [4] = { ButtonPos = { x = 200, y = -320 }, HighLightBox = { x = 10, y = -300, width = 230, height = 90 }, ToolTipDir = "RIGHT", ToolTipText = "Additional UI options" }, +} + +function SMARTBUFF_ToggleTutorial(close) +end +--[[function SMARTBUFF_ToggleTutorial(close) + local helpPlate = HelpPlateList; + if (not helpPlate) then return end; + + local b = HelpPlate_IsShowing(helpPlate); + if (close) then + HelpPlate_Hide(false); + return; + end + + if (not b) then + HelpPlate_Show(helpPlate, SmartBuffOptionsFrame, SmartBuffOptionsFrame_TutorialButton, true); + else + HelpPlate_Hide(true); + end +end--]] diff --git a/SmartBuff.toc b/SmartBuff.toc new file mode 100644 index 0000000..dc42e7d --- /dev/null +++ b/SmartBuff.toc @@ -0,0 +1,20 @@ +## Interface: 20504 +## Title: SmartBuff |cffffffff(Classic TBC)|r by |cff00ff00Codermik & Aeldra|r +## Version: 21.20504 +## Author: |cff20d2ffCodermik (Mik / Castanova on EU-Mirage Raceway) & Aeldra|r (EU-Proudmoore) +## Notes: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## DefaultState: Enabled +## LoadOnDemand: 0 +## Notes-deDE: Castet die wichtigsten Buffs auf dich selbst, Gruppe/Raid Mitglieder/Pets. Benutze /sbm um das Men� zu �ffnen +## Notes-frFR: Cast the most important buffs on you or party/raid members/pets. Use /sbm for options menu. +## SavedVariables: SMARTBUFF_OptionsGlobal +## SavedVariablesPerCharacter: SMARTBUFF_Options, SMARTBUFF_Buffs + +lib\LibStub\LibStub.lua +lib\CallbackHandler-1.0\CallbackHandler-1.0.lua +lib\LibClassicDurations\LibClassicDurations.xml +SmartBuff.globals.lua +SmartBuff.xml + +lib\Broker_SmartBuff\LibDataBroker-1.1.lua +lib\Broker_SmartBuff\Broker_SmartBuff.lua diff --git a/SmartBuff.xml b/SmartBuff.xml new file mode 100644 index 0000000..adcabeb --- /dev/null +++ b/SmartBuff.xml @@ -0,0 +1,3299 @@ + +