From b740289e9dd9f6ce258722734ac9ff2d7286d07b Mon Sep 17 00:00:00 2001 From: OEVG <950+oevg@noreply.octowow.st> Date: Fri, 30 Oct 2026 16:59:08 +0000 Subject: [PATCH] Apply Patch --- Bindings.xml | 32 + BossTrash.lua | 34 + Documentation/FutureFeatures.txt | 14 + Documentation/Images/Background.jpg | Bin 0 -> 26832 bytes Documentation/Images/Minimap.jpg | Bin 0 -> 52505 bytes Documentation/Images/NewOutfit.jpg | Bin 0 -> 94793 bytes Documentation/Images/OutfitterIcon.jpg | Bin 0 -> 25233 bytes Documentation/Images/OutfitterUI.jpg | Bin 0 -> 136164 bytes Documentation/Images/QuickSlots.jpg | Bin 0 -> 53186 bytes Documentation/RevisionHistory.txt | 490 ++ Documentation/UsersManual.html | 201 + Libs/AceEvent-2.0/AceEvent-2.0.lua | 973 ++++ Libs/AceLibrary/AceLibrary.lua | 757 +++ Libs/AceOO-2.0/AceOO-2.0.lua | 1006 ++++ Outfitter.lua | 7387 ++++++++++++++++++++++++ Outfitter.toc | 25 + Outfitter.xml | 1774 ++++++ OutfitterClientMods.lua | 157 + OutfitterStrings.lua | 411 ++ OutfitterStrings_cn.lua | 0 OutfitterStrings_de.lua | 339 ++ OutfitterStrings_fr.lua | 349 ++ OutfitterStrings_kr.lua | 368 ++ OutfitterStrings_tw.lua | 0 Textures/ButtonBarBackground.blp | Bin 0 -> 6684 bytes Textures/CheckboxUnknown.blp | Bin 0 -> 2564 bytes Textures/DialogBox-Background.blp | Bin 0 -> 6660 bytes Textures/GuildLogo.blp | Bin 0 -> 88580 bytes Textures/GuildLogo2.blp | Bin 0 -> 88580 bytes Textures/Icon.blp | Bin 0 -> 6660 bytes Textures/MinimapButton.blp | Bin 0 -> 2564 bytes Textures/Outfitter-Button-pfUI.blp | Bin 0 -> 6676 bytes Textures/Outfitter-Button.blp | Bin 0 -> 6660 bytes Textures/OutfitterFrame-Bottom.blp | Bin 0 -> 44900 bytes Textures/OutfitterFrame-Top.blp | Bin 0 -> 88580 bytes Textures/QuickSlotsBackground.blp | Bin 0 -> 12132 bytes Textures/RepairBags.blp | Bin 0 -> 3916 bytes Textures/ScrollbarTrench.blp | Bin 0 -> 6684 bytes UI.xsd | 663 +++ 39 files changed, 14980 insertions(+) create mode 100644 Bindings.xml create mode 100644 BossTrash.lua create mode 100644 Documentation/FutureFeatures.txt create mode 100644 Documentation/Images/Background.jpg create mode 100644 Documentation/Images/Minimap.jpg create mode 100644 Documentation/Images/NewOutfit.jpg create mode 100644 Documentation/Images/OutfitterIcon.jpg create mode 100644 Documentation/Images/OutfitterUI.jpg create mode 100644 Documentation/Images/QuickSlots.jpg create mode 100644 Documentation/RevisionHistory.txt create mode 100644 Documentation/UsersManual.html create mode 100644 Libs/AceEvent-2.0/AceEvent-2.0.lua create mode 100644 Libs/AceLibrary/AceLibrary.lua create mode 100644 Libs/AceOO-2.0/AceOO-2.0.lua create mode 100644 Outfitter.lua create mode 100644 Outfitter.toc create mode 100644 Outfitter.xml create mode 100644 OutfitterClientMods.lua create mode 100644 OutfitterStrings.lua create mode 100644 OutfitterStrings_cn.lua create mode 100644 OutfitterStrings_de.lua create mode 100644 OutfitterStrings_fr.lua create mode 100644 OutfitterStrings_kr.lua create mode 100644 OutfitterStrings_tw.lua create mode 100644 Textures/ButtonBarBackground.blp create mode 100644 Textures/CheckboxUnknown.blp create mode 100644 Textures/DialogBox-Background.blp create mode 100644 Textures/GuildLogo.blp create mode 100644 Textures/GuildLogo2.blp create mode 100644 Textures/Icon.blp create mode 100644 Textures/MinimapButton.blp create mode 100644 Textures/Outfitter-Button-pfUI.blp create mode 100644 Textures/Outfitter-Button.blp create mode 100644 Textures/OutfitterFrame-Bottom.blp create mode 100644 Textures/OutfitterFrame-Top.blp create mode 100644 Textures/QuickSlotsBackground.blp create mode 100644 Textures/RepairBags.blp create mode 100644 Textures/ScrollbarTrench.blp create mode 100644 UI.xsd diff --git a/Bindings.xml b/Bindings.xml new file mode 100644 index 0000000..c3b2715 --- /dev/null +++ b/Bindings.xml @@ -0,0 +1,32 @@ + + + Outfitter_WearBoundOutfit(1); + + + Outfitter_WearBoundOutfit(2); + + + Outfitter_WearBoundOutfit(3); + + + Outfitter_WearBoundOutfit(4); + + + Outfitter_WearBoundOutfit(5); + + + Outfitter_WearBoundOutfit(6); + + + Outfitter_WearBoundOutfit(7); + + + Outfitter_WearBoundOutfit(8); + + + Outfitter_WearBoundOutfit(9); + + + Outfitter_WearBoundOutfit(10); + + diff --git a/BossTrash.lua b/BossTrash.lua new file mode 100644 index 0000000..a96b2bb --- /dev/null +++ b/BossTrash.lua @@ -0,0 +1,34 @@ +gBossTrashNames = { + --MC-- + ["Core Rager"] = true, + ["Firesworn"] = true, + ["Flamewaker"] = true, + ["Flamewaker Protector"] = true, + ["Flamewaker Healer"] = true, + ["Flamewaker Elite"] = true, + ["Flamewaker Priest"] = true, + + --ZG-- + ["Razzashi Cobra"] = true, + ["Zealot Zath"] = true, + ["Zealot Lor'Khan"] = true, + ["Witherbark Speaker"] = true, + ["Vilebranch Speaker"] = true, + + --BWL-- + ["Grethok the Controller"] = true, + ["Blackwing Guardsman"] = true, + + --AQ-- + ["Sartura's Royal Guard"] = true, + + --NAXX-- + ["Crypt Guard"] = true, + ["Deathknight Understudy"] = true, + ["Naxxramas Combat Dummy"] = true, + ["Naxxramas Follower"] = true, + ["Naxxramas Worshipper"] = true, + ["Soldier of the Frozen Wastes"] = true, + ["Soul Weaver"] = true, + ["Unstoppable Abomination"] = true, +} diff --git a/Documentation/FutureFeatures.txt b/Documentation/FutureFeatures.txt new file mode 100644 index 0000000..60d1fcf --- /dev/null +++ b/Documentation/FutureFeatures.txt @@ -0,0 +1,14 @@ +Version 2.0: + +- Outfit analyzer displays complete statistics for the current outfit +- Generate outfits to maximize TankPoints and HealPoints +- Unequipping items will attempt to return them to their original bag +- Dining outfit will automatically unequip once health and mana reach 100% +- Enhanced tooltips in the character window explaining how each stat affects other attributes +- Mage Evocate outfit +- Hunter aspects +- Create custom Special Occassion outfits for particular zones/areas +- Scriptable special occassion outfits with custom event triggers and code +- Shows info in item tooltips stating whether that item would be an upgrade for you +- Show info in item tooltips listing the outfits in which the item is used +- Ability to update an outfit with the currently equipped items diff --git a/Documentation/Images/Background.jpg b/Documentation/Images/Background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2d3f8ca263ec38b81e886386b84f98ab7bc3caf GIT binary patch literal 26832 zcmeHwd011|*7rFXfP^`T69NWEfI}HFLJ|fU!jKTAB#zZ8kN{C8LlA7O6^sgw5F!F1 zCb4u`>eh8+UuLsLBstP1(AiSGzf}|gS;RJvVhEC5`+a54E`Y4 z0m2(;2ugvczoeJIo})4tAj5<}3ORyP4YQ0i1<+g8t03HHT?4qDfr!snLy(8vi))x7 zCq+q3%*fH?Ks+JBBvk^Vlfz80h1|Uv8l`e0fQ;va)1g5y9*w(Z5QT+ zei+(?9ive}aG1f^QCYL`?SP%f+5x+dZwJ6+)Lz&Z^HR5Y*oZn5EfkTF>+pCiQ67rr zJ;=(~rbQ8P5IlSzvN7f$#cH(X@MTB~Sy@qNV*LTPrKuNmI$>No4X= zdn@BHdKt;Qp2F6amew}bb~ZM46dM~G3YyqZMylBV6$Qh`A$tpG7r+a4g)sIo)*c?d z3YtwEZiimAX)-l9I`;%ZgZLl=9slg}c!vNn2Cc9CdMbggIR&8|;6On#Y~o@bMaVVTD`~ z*|taHKjrMKACwP2(SF&Je{CqrLvL7nU|ajS>pwRhJkdMwXm;B2b(KwrPM*Kz`r#&-MKRot^LmMkuoOY!ZoWl{jZokj+_lsBFdb=^+!U74un?7^6dnkB) z|BdpL+Q;$SdYoSCFM1fyFU}|Y!nWhZ9Fl1DyXyNIYMncg1-P2P#+G`U&ZpgU&z+<- zq}pSeq@W+$#Pae7NxdDjTpNOPGHSnFgJNf4Ldg6^va<+D;q=7BN7b~1+W%0snX1>9 z>`b=bfP>_hbk!&8#Ef@xWnE?cz=*R$iTRQz%SC(s)lz!pJy-D@m!P)f8@0K*s!zkK zobRLs$@#!`N%M7gNW00;|~#M9yS#pH2tSX5iiM781yyC=iK%3ffy? zK*$EX#a&(Hb9o1mQ7DcPN%}m_$Ne9{KDzD$EpEnfyMR7cB*+sg~A@REgYhH{fr(TK7;OGyOg%A$M zw_MQ-B_&@E7tcY=^!J?!OC4yZvQXx%%!d7&$zxSXW(nD`8a^E!%EY#_Cg&dsem^#8Kv{T{{ZvZ74#a zzP+_XBzfGmWmlL?)g#d1HM*ote?AV|iOjHdqP zn$?2nnsQcUH9Ilh6|)xT9cGw*-5BxshXZ2)Dm-@7O&Hl+v8nYh7wwy8mKF!(vsDC_J3bW zqK6h+tvoCJGGT*m(;Wj>BuUs1mT+osdx0o6ysApS=SGEgRIh3zvqlRbyguNLimPdL14szX~L~5l4q{pvvAeV`p-XtIaL?l>ikVbYeKXu&wchS zAqz4zE^AgCKyqbE5hUeeiL}`5%VW#8;!a9sq`)M&)15IE<>;d|E0#~%G`Uk1br7scV| z#^;WmF&&qnW!QV8Wg`z_bOD1tkYQszcVn5&Se2Qpp%IPNMjrZLcQ#5+do_<8GUf@! z6eRFSEut|G9`|S+uw+3GqVe&MQW&E>k5Cd=;g^;MN-{wT78>AyM>)HzYhH3#M*e(| zzL4P>IX+_?qt2%w4?($LG4Y27_7+P|J5|i?ATy!_)iM4sDji{<DN9m8ZnT~>Rl@{1)WIM*SjA@MWT&GvdPtOMn(_H?O-|NG zex$NAJ!7=om^aJIRHZ8OW@k$BKxO!q`{0dbfK39YxiKRWj?- zvX$BSDArbyGE{qlkq7eD$@!X`Xl1riovcwR00WY*$W@LC6Gwzm4q770N~eO$f4lwI ze08Qga;_ZQY7|@){8u?~dFjemIA+P28hLX1D?FQ2C8(z?)QIw8`NZF1wKIR1*)HGKp(~|QuQ6D2LSE@CCAU^vA`&Dtvl=O(4%pCPN zaP3F*hey9G09By)oNN?pf+i<7AzzcH9Pc>9OyEer<65QUXn;fgj&BLNIOBD3<0$n+ zZvAkz!bjmM@J zAkzzw=>^F20%Uptn&=DA$dlIvJWwI9;ssAy^igXIg+U6is7(P&S}K$XmcTh+VVeWx z8L3<#LH=JPs9@nNgGOFAjL-a$HMY6&Ne=EY+%NbjL!-$R`1xh$`6i?Pg7r;I)@v_h|7&oW~gG`Rx4$1$IDaS zUYg2RxXuhA1{DelvvRYPnq+EWR%UjdpfK3gs9XSOl3&Q;pYO+D`LS3&K*A?)MYbln&?h_3 zZA8fnJwjz(s#=w+QRQS)QN77v&8`V{bwzLV@)$KSIX5ou<*oh@jjSxcKdPChkt)ZG z{KJ}g=z`Brs?5vDSEnk0_?Vr*j35AaT%16dlbWBU%+`p6A^G_#g@DcD2pOy}Hjm4V z5QZ_CVUhk!eq%as@}*AxU(-3R-tTk@m1@;; zr6Nk5lVt=oH(8yhL>n0F`l5v|dtn6RAR|Nq)oaEG`TqXQa8|^>Z{Y9hjTwXDHd3s3 z4Y$9lc3izNwJ$*(YoyUF(cAf^cdR% zUW34^Scvgwkw5<7XIzs;g-7-L$GSq1`m!f-!TY9hZc(KADKnMmNX!G1Ak*)a-cY0p z(sI;U$(j&VR&u)1Z%M8)J;-m2`=2&2_r(ulFYSC~f_YhNoUUK7^ktF2_+|+@RT%>2 zj6Y(J>z%RU7*(DoN4>)Dg_olvV60RW5s|3QNmFGiL-M52;Z#v%1el%t{e4)z%<(rF zC-4hm!0Ty#py%s0vhfU(D5_%YFR zwCecc*Q?I^^Qz;EU#~h=b5^!W6T%w3+iUFCYsG_REmsOv>B>A%hwJan;s$_|2Tr~> z%b(@V3gCbf@OT_=E}H>PCZGYI$M$CN{k_=?rZ=0(11H~`%K|5x1$aPD00W#rHUQ0Y zK{+_t95yR3T*wRHafQMtjz6F0@6Qtk0QrE3$f$@2W(1oNFlzWKmW`VI9~;9;@Qd{y zj}Elt_kMtK1&OLcW#(L=3Jmi+)E59;L4JQ&G7jaj@_GNZ=D3pAYZ}L)46LV=sOuS( zjbpto{R(Dmf1W?bo5SGyGmI(drvN5vBxM;nBPkp3xy%t6jyGB>z?gzQ1^op$AO#!_ zkIOKopg#c(dK09e{{z^-JJ1x!gOrb^JRk{D^j>V>D`<+|1*}etDX0r*V_o1u93}^p zqA9Qzq$8XFBh5ooKCly{Mj1XA&;cxz9{{`!q`)UROg<0g19vi}Xk9)JmErSH89v`A z!)F?4R2$!@jn7B#$T#Zbqn5B3On-0Sx8A_lz5Trdym{VyZvYLG>CI$$GuhrujyLdQ zAjAyt22RfcvS28HkpKn>7mOF+?qFm9hYw@}PYz)4m;qto92PH}$Bkh7`wPQ_!T=sW zB7zTwr?E3%>9Ifc@)6$$t6Z>F_ItTl9yimDtegHT>6oAWSJaOvHQi)F;F{nv!8IWS zCM0a~E)!f6LSRC|Chs!AH6a8hBy9376I>HQU_!zs?=rzPAp|BQZ1OG>ToXcILc%8R zGQl+=1STYG@-7ox6GC7@!Y1!B!8IWSCM0a~E)!f6LSRC|Chs!AH6a8hBy9376I>HQ zU_!zs?=rzPAp|BQZ1OG>ToXcILc%8RGQl+=1STYG@-7ox6GC7@!Y1!B!8IWSCM0a~ zE)!f6LSRC|Chs!AH6a8hB>bn|MI76Hs>}v^P7A>1(%~Ph=7LQ{ixQ;?Q6fpCai^?R zj6{{4g8^|`va&U5bUV`AdGo2}-+(wR1Q1pRL}W=$&C89GMWMk&Ah1=5itbrL>Cpr1 zwtaklB+N*UPfQ|}`l8@3UhPwJ)gT-QoCxIE3b5%E&{{xe7HD!&J{n$wlCl(~F=${7 ziW(RQ=&2~3K0>3>G$<(}bSO$Iva&%W77S{0t|Ci;((QmQS)PwZXu(PVy>7WmSpevB zfTm^UXQ=><1`VQQDU(6e7#te9gQiiYW&oN2Xe+f`8Ug4a5dOp}eH@)Kj@E!sDL@vA z$jMz{3?4%DOhu?*YXy%Qqb$f&YBWBHU{7$eT0xD-$;wU6UI9TPZANQBq~GlaGqOjL zKP?<5_h%&9whro2|DP+4Gi#h3-e8-uQmq7=hpDrHm#MPTL3d{>RL0HJs_a*G{EgG_f2=l6 z14@qgH6X}_-yq5&U&!uT3WU9P8p4q+A?$)WPy)Z~Hwj@j*c}f+b7tHe@q0jna%1{R zg4qhPm^_s+ei0NQl~Ysm)yqdjaOedO!g|?46lfac47ov`AgB}z3V;HkP$&`-LkS?n z)I8`d5P~WL$^s#%3ZRux5ws542$ezGpc<$iGC(cR2hhjRVdyic6*>uh1>&6cLYJXF zXaM>V8iXE0&p<>?bJ!Xt!_(jyFdcpaX2Co-1dfCyuoRvLFNV|MY&aiY39o@S!aBGH z-VL|FAHhfAR=5-HhA+bX@NM`Z{3`~FvBFR=P8fHLABKks!^C3bn1z^h%reZ|7%gTC zrV7)5`5WdCrWNxQrWezP`4RI7gg~{#PR6=meXu-i1U3OXADf0%V^?7}U@Nf=*blJB zupQVQY#;V6_7|KPj*O$?d~kud7~CveDsCBW6>bx*2DcY?2-lA5!S&+?alhfM@s9X6 z@B+LDKNp{lFTk(ESK^!S2k|HHz4!tAV>2_e$z~pA0cJ5~^URi*y<@h?Y^T|Nv*Tvn zX4lLfnVXwWGk?Q8*gU~J*<543&b-?EZ{}Z^pEVyae`;ZAF~fpo5oIyoBHN1OXv|pdhRuY$X^7#|YmN1_;lH_Cyb2Fi}oiLM$Ry5kDZFAYLI3 zSz21UTJkNEELE1PEvqa)v^-_mZ~2QA$;!(r!fJt4zSS11W~<{?7p;b@t*zayL#^jq zYpl0ew^)B^{k`>58?ueBjmSn}^PbHPn?p8dZSLC=Z0WXPwr|<&@GXA51wr<;m3PQ$wdJr*4?Ke`@d4U#C&0MNV5ft$f?`pt_C4%--;d@u->=-S!|yi+myyXZFfKDmOfj>V zd5rmx<;6;6?O>f_TeG9s@3D`tA8_8_C^>bU@3>@c9Ctmpjr%YE0Drar2mZGMXaS1@ zY6C9tD7-}8Cf+GNo*&MCkN+9}7lFS(BluYGQ=m`a(!hOzw}L!^ltG4|Yr(F;$-%pW z`$DK8i$ivW^v!gcnLM*$<`1E6p^DI^(3@dM*pjfnh20Nlgsa03hChiAM7$euT!-2+kaaZE$@!9c*6QBf9LPf&WM32N}iJvB!B_$^9NV*|qN>@rd zWMtVQ**@80dANM5{PHZ%S^2ZtX4}qQFuP^;lR3gUx;cGw{pP+q_p5mh^HlSW%r~Du zdw$dWM{h>Hx$Vt?1>6Pe7Mx$`v9NGq=UWbMWxn-~MYfBQ7k#oAzj)5#eT$zbCnPr{ zKS~j$)TRukMx<^}{ZSFB&?{~$gOxhv&9vY&UD~bm;Pi_0+Zi)6Dl_h?B2+c12TNj> z)Gv9mG+}A;(&5ZGnftRWvKD6@%_e0p&2GU_&F^0xvV6z#rv%q~2=!fQq8ikojoz1{c@?w!K>->eAmfC^mF$WNfV5_~(MJu2sZU9MV(u8}vVKTePjSl2ci~owz-Jdta5L>PR)Mx~%$n zO-4=cj_@7(YaMG#YoF{?>^xf+TK7S{Q~k#JUw5f?eYZP$_n`*&hRQu=dzSCHVVG^` zXyi4vG&wYFZ2DJoc5~le>E8C1fR>hhj{CO0k9j};{o8+A@V7I67ykXo2RP6P6+p)l7 z2S4@wwD~ia&vyJ{(m%F-PW)W^`S2HSfAQ#e?(w^=>8;n=7PVdea_*Ps+LPM9IT3r} z)XAumUv`9bd~quH)MuT7&ZAwtuESsXe|6|I_w>Q9xnCdr#{Zi`-v)ep6yM#tn0fKRrRA5NU0!_!e`Ui}yQ`Jo zJAU8rPvoEb`~3U<(J$;j{e$d>%hyt`{dhg^`tt$p4eJ|~H)q^zxy8Em+3l#?XYRat zXW+-&AD`V_chCM_?S0St2Yw3u>Ga^-!GQ_~ikqnUL1lRfLbJ8eou=bnp7Ia)&07q)6n_mZ;N<7if#qLq+1Plm{-HH4ULB zOOf#KH!I4K-E==z!_Bs;lJIv#2(n`#A|R%5R@b(P=NWQqcT&s+h@GzLhyjzduWYrh zGM+TRBOrxIo8?=H!2@)5Qto-_mFg38AEc`UX%o*ioHfj^+Dt;@c2BYB4UF05!I?C9 z=sHPyzu%?LkU|L;FOnZ8HYdIa%_lq<Wo`^54Buf?}&TzD{@u`Kbv;o82?LRwQC4yhyCa%wd_dcF3; zF1Klpdk>zK8y*M@O+pVxcQZ}m6*?pSZM>QbmRva+B$7qHVD5 zN)-s4o_2`1BKCkyr~Oqr%RJH?iK@8BK7t^nG3thBs;30_a%peSDTz+cNoWXTl62d<-P+5mY_P)o6{9t05= zNzE{;Wdvl+mM?HcqB9~lZ6~tocBe#kODa7|#NBCj@VwVc_a+z11m-h1I+^b(QL6+J zuhdBg4K6nFR#EJyiP{yyAWslUTtw4J_1f^#7(Shr=^@x=eaW!!3Gg~NI@HBCKjs!m z+P=5(hK$xY?e5N&t%TNYI=ci3S3T?L6vaN=aV)nSM2_wq3MDPO8?uD@6s#SQ#Wmdc zm83Hnx@}0i=T34q2=?8UayuzTuWxiOl}x9{6q}VIi956pU4$Uqb>W3hUN4oKaKMHn z9kANQ-jx_cYb>&>krpAqfrMRg+RhFFQWk$pLP8K3>|>$t6pLq<9!O{qAsJ#!X>~kF zdi7^1p4p9P_2rHH3v2D9zHDPuaa!|Xg-#@?$f%m+35HLxKD@G&qW`c&TS8dg&C7hK ztIRkrUH*fMn55O0NLueUld4Lj86vTR$CV0wGMyFVd8{I*t)9ev?qb*d*M0bT{3#Gna1$*DnmQ+cu~*v0A-B+q}9k9wU}YtMu)Lrf|w(m*U1Q@uFObT+)aj5wqO45wr)v zq?A{Y-5n)$xTDjXwR|OiT+$syTS<}@zv~jMy?jstP7+gjdV}UPHJt5D0UKw zcB>h7!G`OqT7mOyV_>p&(>;%9Pn<2cqj<>mr`xt7rzBEoCuDE|pAnb|W;e*HMO__} ztJ~IA*vom^3}yjeNmJi$fuRxMJWc}m4n&Gq%B9jx2*)Dvq0rurBrUOP!0E%`#5Huf z?`@)M^n(OJc>3v3;8>d}N(M`IvIWswNbXUz?o?W14Ot*-CnW3^#k8`T@_UY@KnU8U zt6g04yQB5()p~vB&6xY^8M6Bogj1k^O{lFPs&$q2NXc`l_BJ}T#qFZB7uPneCP~34 z`?Q6l)gKMdTioSeyBAEM417?bXSsPid9zrYBr&W!mrVC;VYF?CY|qf?V!T2#*7bPh z0WqI74Y|a+tF*n~%K=qFkC-KNfp~$PLs{|qPiOhp-A2kul++JpH?{2$NoH}L6atIs z)b6WvMpYbLa^VSWzMD{g+}%wWdX*gFN|NEJ=|Xl_nMgFft&p&~JI?q)17=HnZ3)2; zE>0x$3#W##48S*7l`TK(OSSseFXu^m_EnUuoxE8pWA7^xmJpfy#PdF^xa=xjUMBS; zAZZ6~m2eU>Pd|>AR1pweshz%6d#Q9tB#Efl+Evxw+)wv@bN>m^9{J_<#JFy{-}O4q zTIW>+vH*ObAiioUA-m^mx^GM(ol~`z3_eZ~Ex_16-xr;@8)s;=GkmA-k~o0x4Y*eO zh#rDL+cOj(cK(Ez#~||vqS#+Nat`ZTeWlW8y6S;QUod4|smmwSxsu~s5cdJ6f&@hq zUjpFmJ~^!IEA5f9kxP9Xk%&S_I4U$W?wKoP><|I3?%Rs%KfbrAmrm2` zBlJZg@!j3mZZy4zH(x<(yhJW5>u2iq9|_!Hfe1-#I=_0)RT15C*%2XT9U_{9DO?yusb0xuRF*qAxOkpuS6jyY%H4FNeeY&*c`u`z z&Vt?cO3Fmyr_GQ@sY5gNWAQxXnNEXulFEFgFz3!rU{&uBE7@J&p)VFI7VK=26PN80 zNjBu|N~G11a8E?Bl=U?tivB=HD-Y3nfG>LlyF_*qFqLcR%*_-@SM`kIjXPYW(i-`3 z$;sPDJD5A2h|;QuI`IPiub$0h1SxYcJZK1QlX-N~8Cv}&JVk#*Os5r#(_DD0-6vbJ zMX|b&foVviTbuYTj~@&;+}H79@q6IY3BJ<1wOmh8th4+`l4A>)bQ>}f8WzwRH$gk} z*F|FB_UGl=meAOb#cv+VD6a3Tx~1Dbz^KQ`Eii(BnI&2?SlwB4S67{}OMW~l$k3>BXx6SPMV6f`E!8&q J5P>-t{|Avo-Vp!* literal 0 HcmV?d00001 diff --git a/Documentation/Images/Minimap.jpg b/Documentation/Images/Minimap.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b06794993cdc5c22dd0ea2b13bc81290c60fbeb GIT binary patch literal 52505 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 literal 0 HcmV?d00001 diff --git a/Documentation/Images/NewOutfit.jpg b/Documentation/Images/NewOutfit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7037b9746ff65e2db45bf501815433d3332782cc GIT binary patch literal 94793 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 literal 0 HcmV?d00001 diff --git a/Documentation/Images/OutfitterIcon.jpg b/Documentation/Images/OutfitterIcon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2d4fc3be2ba52087435383d9549f3f0c2d7bae76 GIT binary patch literal 25233 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

*pKR1?&1i8&FSXLMfG1R%_b(z)m%&m0^P=eho1T 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 KMi%NP{{H}B5r9|# literal 0 HcmV?d00001 diff --git a/Documentation/Images/QuickSlots.jpg b/Documentation/Images/QuickSlots.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89f4eba8df8f0c9cadf6f25a02f8cd260ab104ef GIT binary patch literal 53186 zcmeFacUTlnvo}0TlpIAtiGqOSoIx^6R6w#KEK88E2rN-R0mV!X0)i+(vg9OS0z@R| zoRpk%+XjqXK{0_5r{P!#}z1p(B+ ze*k)nqDeb3Yu1%QPGT8ndN6FwfU$e{_$0+cwQ1vgo!a0Ty#QDZE4uiLgP#A-R_5)iJa zcM|3*yuyZuF#!L($cJ{&h*zhql&^@o!N-4^@LyZN{>ub(KR}FqSSJM_2dpXRD=kjK z)flUIq}-tzRJ~lDXA*iywVn>pxy}!iC?<@|`-PI)=VD zG?0g#xvkS%d3roSevV1DeS_LpDYwqM)Y?$XB6*K~;mr)Y^~y}S<)mBBdUKwNFilfb zS%6|{T6ca`)zeKs`xvB+?wm~y>RFQGZrSYfih7!dTJWTosTIXV-+SD@_-1d+p}f&R zR}WRE;El?x2|OwP)M;Jwz1ot+A(TzN!3UR{b*n1@BmpeEHDA2Xc#S=Vg`M6$aqg0p zZR37I85)3269qhY!{i-&+dpJQ^V*W!=L*U-3yJ)T1LK#fS<~8hC_{VIA9!65;>0W4 zVZM>t80kUvAvW8iOH+`%izD!?m)^-cedHo)qLe8n{9QbmK6)Q6SQN{4iAR>Cq@!Ec zE|QV^jmH*k;xAs+03J_cEK9vq_vu*>6(q znm6@MiOrl>(Up2v|Fs@931#w7!okWO3*ai$8hBn*RL|e^HrR3Z+Cq(%`AnX*BJEWp z;j7kiF9sZ|zS_Faz3MFO%yVk$EppR3s^4L2LQ`(*uU zHT^CP>e1liCrV+hCwpJAg;PkWUw*I}`8?Y{lcXdf%yIqlwWhJ?@J5E-EpOBMbjud^ zGt0YC!gU`8xcDgPc|`MH?Itz$e;@Gcp5vXf92gWtWmiO$m4Bu7wyuGbU?X0|T;02| zDYS4B4M-to8y|gc$VBBpUw6xx29pSto|^^c10V9(@~ZHFEYcRh&^c856YU3Zd?1B2E)Q* z&s4HPa?vTrzGZ*&G8uEsmK zI_E2ATv;N}RlI=)`df5RZD>F|o^Hfo?pobEjrYAY@kJh|wwdm0{t128>JYm1#!8-d z(_!Cc*0m!#B-5l;9fnle6>sFE4G_`EX@uDgnR3);O(Xo*O8iALWM9-PYp!Q!_YXik zUJrGV&knYaRU$IbfD>jqlNMZ;H3a zYGwU0@{e20!eF(vwUY#4<;|?=_8+;P*!9;yZL_Ga?(1ar_N;&LepE0zWd3^IS|lX@ z&6LoPs8e5l{P0%KuFkRs8S6d7N$IyF*nt`+B8Xk%`4E*`a|R!B7ozY& z&9#;`^N`)I*Oz)W`KCvvlMEeZx4)Le^fLHf+$8M3c#^!wc+O}x6K<|LRO6qu%c!{S zSCG-;tyRUFX7XXr{$}sqbzzc^>+YS#3w^W28$LB{D4Q(Zw%y9^6|N7~Bs3*&qXoaL zUhruoi65Q{*1fhn<0C3l^J3&m(n?Jer?1s#{M6pYxJj9J{P@BGsgqw4Mhc%4?THHQ z#LcW{ST|uv0*Q1`MZm`X)kXKiGT{zr8ezzvX$&{$!P@ z5NGdmIr8tuMq79SEgq}G3rX^o4;@~`+?x~7MIUw^z03UywJ&oo_ySl~F2Xv@5F1c*Znzp}5VUM$HLUWie~8 z1iQLuli9N8)Rnh!jxcWa^X#X+(m0J2nuooo(LiBAsgK!wd{ws-8o+DWuGO21={~=~ zrK-cqSg5rGg!d;g+E~jlHVoLj-t>nZummm%Nx!e9hf&Rn=1wZ z%re#0yhgLZ>tsuh;%6B_?+z+(2}lSt;tN$ zYxOm`iR?Kgd0pbArF)Z()9O%VRg3p<;J~txoPh|kreTmB)$1~{ZxGD2-@3-@FS0+g z${2xeA2olV?9pSMJ;!zPQDXn+zO3qywd!<|T|zJM=Q5GSy<63d8d-kYi^ zO#@e_ePndnP)UsIsF;4o;-t3endC*h?DWFU+&YMLU3rd|o6M4Z!lugiXPXY@>ghGi zUGZmFCEp-XDg&~?8*%Yi#PXEmE1BlultGVe7zjwl_4Evw>XFe`k;YP2^P`H^%5z{E zB?o8D?B}f~ExVcfBwrVk$}#NdgWdHyMOT}ydJ%WSL}Q@3R3fl5A1+39W@xu=w646F zNTH5ogMj5^4#aTeOhEf2@JQiJa&j1|}J)ntm3Y)!!j z9-6hz+VLF-H4HHo5uGt?Jvf=TX;$DpqGqGj{4O`9*EsIoly|dZQ1_mx%1~2MS_g^* z4Q#eg^Y7w!b3a;Yp5v*AGv#F!{uF)B+*f?TKYJjzcI5sp8qnF*kW;j2&43>`H0H5q zxuthD#pYzjtw6{pOr4za5R)<`_&qZy%V6qBE2XAg#P_l8{xTamXKW!JzV|t3Kx{_3 zDrh?{eMOW54K%&=)!wup)A!S$`J~Fp<6k*`FjA)}=h?V75@c5DMwbY6onu|wrP!LW zyuDi-l2`S{t^M_Wbj}mK)U8|QmD>$JMAO{}6K7oK*io#$pyOc_S6mOd^2Y5BsM(;5 zpnb2JZ)o2txAub?&8cqUXj;s%z)&yg&nl@hC^V`pi}-h`#@H*Bh!Is?CqA z2-zuzlHh$Adx_Id8i*>x$o6;N8NCp4Kv$yYM8B@&(%alxlO477xZaMjfLC>YFx}pC zmVdt0FNj_md{o5j_rJ929SKfF0~rR@qn^*D!)2|~N%c+{^=!{9DZ zZ$x?07RN9a>K-h(5_u#wpYfp29a^}&hi}AfFLoN{&X2fn+hcFKml3;i|Duxp)mwc+ z@GU{wuB*tZnx#0;%0AfOsQh|P_^3*1?!mXOjSaRQWm3+-A`ph}Q9J_8oZy%IeAAUX z5J#=Zd8~M1PfL-WQQEFJX)0(_m|cwHrbR~+8rTuBNwYGwMoK+L(S>TK$@}hxGe|RDIn-1EYkTaEi}NTIS<#l?)&17i*qiVk9SKXn(GrkM3M^xaF5* z&F|YM`{dm-3p=;l_5-D`tEKBsl{2XEC!H4g8wvIYjxGI@G@%zEp)+zCJ_%@G&(R$X zWPamYv!uBa~|ae;=cT43oVc|cP*#bB=Bi6w21~f&_Lk9g+;!ZUJ0@dzT^=92YZ#w zPoK2cEONlR7>1Q6yKYR+`_a%a&$&VMUTdNNP0*690+##yznarP{{TOXNmusD$V zp6NlswVc~gQiMedobNQuanQgVC#NlTg`ZC<1E+0x)S8A4SryMM%AV2is8uKr*2Tz6 z0o#Mv166@nQ$ktk-!0mdzdeWKO%Llt&`4BBJh6`*w=5N|YH=4*J@`DbYi_t+-7+O3 z{0+M~!-3+g=j+sal(EkkUe6moXiXClE{@Ac14!|QldgSHPDOX+ZKV#>tX#7S?{YEM zB9!+EfHH4T)Niq#ieY`2ba^qUVzo0|Z&tBpH!{9uD~|`tCY$0#XztPAWdg;OO$k5D zg??E56s9)|_2k3krw+RAQ$00|W(`O}_n{YP+@1Ou+NYDyCYilsa0ZhS24R}C)aFUFBy?T z4$m*nq0Vja8UUQZXw1Jou%|KE|27N#|0VAbnG+b@0H&>AyRj}Foj*`y0J*?neCY@u zI?N@u4VWCY2XhHvVpmugd}#qg00EwQ01R*eoWM_8@Y)S92lxR&@Du}2QSb^w3jqRv zFnAu;iqZ170~4|OabPt6jE?=q{MjWx86fea2^f|W(!l}zzy$d4ED=a2D_0%M8!+(d zhhklr8>VWEdjR@i5YGYOglW{_p$WHk`~6zM4dHlnePo8NjqQ*8!$#w|I@rPBt_BX8 zu3&M<-|E3V%mdk!;E8{D0af}zi^2y5pJME{R^K6>|)!0iXYye9GHp#V(^5>Eg#ZH z_aY`*edNMNV?b4ibYPAP})<{)6v-x?qFD6(D(NZ1a;RJqq%mwh z7N$cHH+vZtAzlGq0UiMX0Tx+8CMG6n7b|N?T_u$tCBZ8hmLDd1czE!72=O9ZZ1@Bu zBqaFw1^EO8c|ZvsS1%_w3r`*=*K5K|bmaSYC0*Tg;lGUhwtpMUznguvPh(zm886cytur8sDOxqgt(HtfPlOL=0Crnu%NPpsEU$`G^U&WUhY@B ze&~ccxw=_6!Qel2%Kv9Ne=GMdI+frqcJ6R16&Hl#A*jw4F0OD)17%qLYT?gbI09Mv z5F$yte;OnHe>3J^%Kb71gWFNI)jx6j57quw?w8u1p#Ey)p<80AD>wi0;CVtz`?!!O9gFQ)(3PicAh#U=Uq4=w*)^0!7|bZ8;0 z?5w^16CJ-v{!<5d?^;>7S^P&@ewY1+p2PNlVPr6rEqnN@+JFDM;oq9{L->cD|FN#H zg8l3XXE0uWIJQ{9_}~t3%$?{84uS%Ff9nk^n4~qr#nHk|*3Qww2F`cG8EzxZ_lx^K zZJ_gCzo-6b=idgHpV^1Q_1`T0nI(A`nFl)+E-NI>_wU%h_0F$sH9J=~go_v7UtW&6 z1AgT~6%{YJAgt{i;Igi|stQa{Wkpc|2~klVL0*C1EBQ_Ce;OJ$JL~^q*u~`hDxh=Hd#cuH^!iVAWIiV1@!$P*Xl z77^kHPXUky`Qk#{f)b+KLi_^ULIUF8DZwow2%bWMAP>|d#t)vLtQh861k49dAz>jw zDHS1c0q_CEFRUyipeP_Hrl24%s;H=_EUX|TA}^q%@Wb%GS@y&1|FL@*4o-OZ_jd;- z=U@E*!b=LvT(QnCYYb61QnhzN;E^ZnbL-%$RQZ~UvIkPzq$|2F5JB@gdIJ@9=B zj&Z%iBEPZzDg8Ihgha(fg}H_KB}DlTQ?Q@J1O$&#!9&hbDg^RH1de2cxiO{04pXpC z!Ttg{Ugg z6f6s-hh;$z5*82!b1^AsEtnp0#13h3Oez7|38sfK5+WciCWzsSf!+qDpic@5NPs#q zDWWBcs|YG7hzKYsOYrk6iSUa`i2l`?f9tXT*2|B4AAHLN-d^l5#_%!AlTlmRV`wbQ+IrM3pn)KL8bjM0 z(cFhJNAyJuZRO|$u4IRWvDw+m(F#L<0_pqiNX!a%*qR`H&)p900n(iy&FX-3v;%3( zl8Mxga0_tNJsix^XRK~;m@P>2gEX;=zOEujOM}bD5!?JmTmDA7flJMSvVbDO+3Rre zH6{)iClffeLYzqr?%@D;bK|)L&Iz_~v0_q0I67N6c>%ytn=z#T%72*;cE~zQDfZCiFAa9`tuou1pI8;Ocw%Orgen0z7lfVF+9S;D8j8jK`kI`^+ zHy=_z6RZ%B#B#MeT>lYJ)YWH#Azj>$vT-mUxZt9uWB@g|U?&4`4&VTIz`65cfD~{M zPzKZi9Y7y22CjjNc-jJv;6k1rz%Aeoa1VF{gaT1O9FPR002x3oPymzyZ-Mtf9nc7F zlhXwZ0HeTnU=COYHi12GLl%4p34{tl3t@z?LAW4-5OIhsL>Zz9(S;a8u0w1fP7oyI z79-Nf?73c`Ad6^r!}D;ui>>pfN@Ru|SN)*RLbxPuN6HVrm2HV?Kqwj#C;wh6X1 zwhOi&_CxGw?3dWN*cI6I*d5rT*z?#sICwZzI7~P^I8r!jI9G6BI5%=9BB zvJ=V>>J#1|yh9jEm`hkoI7qlgL`1|wBtdkU$d2eXQ7q9LqR&KQL_5Tk#21JaiOqk&J+h zjZB{G8ksj)G+7~83)wt50r`1yMRE&rKk|6;a`GPX4GJm>0SX-oM~cT3nG_8a)0Fs> z=P8vbttf*iUr~OfoS?#{I!C2Q1)~b2N};Ny`c92U%}x!azCrznI)}QMdif;fN#Tu5 zw9I^#S&bRVoXp(JyvM@Ma)l*;C68t39N{_fbJph~&wV(z%*x2B#d?c1i?yGPfK8mu zmMw;@o^9(q`+39j!RJfQPqUw9hq8OKXR!}*kZ{Ox+~j!4(aDL&Db8un`JA)$0@ekQ z3$_>HFSKxBafx!-aXsg1TY5~@Tc$(2v7>B3j_#M2&@WT5QGWF3w8>T2&oA93zZ422y+R;g%gE)MW{ry zM1n;=h#ZKDiMoj9iq43!id`2=5bF`A7QZC^Sp2gDu7rYwzr$ zd#OyRX=!$8xO9s2gba&}g-o){s4SE0b=eoPqjJo07IH7;#xI_`Xmv5|;*>n6{0;eR z`9%eO1s8>4g)K!%MPJ2tO4v%ON)MHql_{04D90%etFWlpsAQ=utBR=lsJ>IfRnt%l zQ|p1!Lt)Si=(4()y07{t4Pp&FjW~^Q%?p|?niX1DTIyO6T7%kb+D_V~I)DyTCqifF z68oi_mntvgUA}ZV{_>=*fbK2bdOa#VbG=NxO??IZ5dDEG99NK6J{XW0m>FakY#AyU zh8vC=@frCVH5$_y+ZmUc;F}njq?v4(Dw{@`em4^_yJyyYmHn#c)rM56t^ZLGpj>Suh4NItHg5@$y5f%fRv$|*%X*C0vfrrDVtYxgjt*32dY$9xC zY~^gDZRhP2?c(fKZm8Wzy0K-iW1nu1b})3vb3EaA-Lc$>(#hWG6M_NZiD+}?a=zz0 zdQ z74K9Z93Pm^hg;0I?%W#lmG@2dgZNqceegf$ALRf2w(9NIcL?v;-)Rcq4+sxf4>Sy{ z2%-RxUP7G_`HO(2@evso?AU{PrR6zn?#@VC~5bF-HYC2)#Q?w=U+y@ z!h7ZZYBI$jr9M?WH6x8K?NQo6x>Ne-Yu(qMGQ=`6GS6m)WMO3?vu3i*vRiYMa>{af za+C9D@*ceb-XP!1=3me6F3>3WP$*uQTf|nBP)t?)umn=#RkB=aTRK{1T-H{uUjCs% zs-n1(w=(@L^V|5UlT{(rgw;XS=o;^ujd#xP=HJ`ApZH+@Vc?_D$IefeKQ-5C)PAm0 zsry(jUtjZC=JVSI$%gVT;$KP|MH@@LihM0@5@{-K7HuwR5o;-Hm1wPKlWwbSmur9D zq0~{=3GHm`((Y>OzS7;>W7ad;Yt=j5=g_y(@7}*RaC;DU@Zk{oQ1tNG;g=(vBYC5u zqg7){V_(Ph#s?-~6La5OzwLhynk1Qwo?@KJm=>IVJEJnwI%_)nea?AqZ~oo_#X`a& z$70da#ig&yM$6wPX-s0_lc8fP7bxO|k0(D)bpcIZW*3{D3 z1lr5Y&%XG-u=HuGbE3~~ zHn6W4u9qA>cwSgG>jgRX$NtI2cUy!d_)_amSLinlX<5a$lk~Q`v-M{)?B{*7Vj6NP z-?^H|cb&R14Y#2>>Z36e?P zDmE{CLg}EuU6WEe7z;=&YQVjAR*4Gb4789-z8f0CBmG2IzRt5t(0q(@V5XLc;ul?4?Xwx$Sx-XJO8%b`OD~nqigp zivx?j8E_%mJ`#5>`b)PKbKS`7OQhQUD+kKYyr^IB0EiT43giWSZk-G@Nu8YufhGaz zErir)K)B_$UaZMS8>YpS@W}Sd3LvLlH*z3A{VE$RffH0Sy+Qc(=M^nZ&V;nVWKMN; zxU5}zlW-b)6PsYfc-$@ZpuoWt_mni#x9#D{=f>7F%|=3o!=Hsq>uW?>dt$Gq=IsTs zM(gT1$ubLXM{K2@tHtGL_!hB>TCb*KV-`+HMcJuoai$Vo;p0pdPKiqOZAfLJy7waW zMG97|tuEvwKgk98jEc|NMmN>_Egu8R11ns2V&U+zg+ZyYF3_)Oo-Ffy|bb&m8QcV z9(@;aTAQl=$=Cg-R|rcV9f19`@^wE1s#Pk;%`J(F4BYChFwa^iyYf!djczBK_(tgl z;jDXQ9&ntnYxWBUR@t7>;nKliH@ ze0ziFOsvM~iS>7}rqqUQBj&TH=Xc)7q?{u63kylf`EIfP_5x9EgZL87q7or>2*f;7z; z+ljuW7WA(U<<6S|wbf62dPmhDttS3bN$Kl`G7)VYj&(h6-)@qS%Qd@HcG3E4e})Y= z(k)x3^{!Z{1R?e(Ut7Z^zgmwN?fR>EGUDpRzL)mPr(h6L3|e;_YYgF0ir|I#`r6Zx)yjU6IBwwJGi!`>i_0F_h-G2hdwSc2&Rw#Q_l_UGhlDy$ zt!aF%Vq;&|+{TspEL>F`Ve^i2(ZUql=JaCAO)WMR)A3h4GG92X^>p5=_D7b!XA>M8 zp>A(~q3+nUM8KI)ZA+jLXNG)+Jia z$#&zKx>c$mO;mei170L`hGxp?6uR(OyeOtxeyR_`Y0Md8l5U{|&@ssiCX{zMw8LXl z@Neq|=mtd=I43~*IG`G;pyOegq@*fbN~B6j6BrM73*gX&cHE-W4Ogdnj|MJn_>-LIrdNuG-R0~51tK9pWyCGM7V~n3AEL|JLwuQZ< z8evmb77ybvBHc@OXarni zKk^B^)(gI0Z|vJb3^QSEkki=X(10W=N=aWOTP#o&hTT^QCjDgib8!TK?CP z8iVNFF6lDu0JD*W{F|OJ!X17y>n0FZ)XpvmVs*GHql=r5u|OcH;H`T|={I@qGZ&qj zO)J-v;!%_%;Ff}c#jd`puk#LrfR|P#q4~GSBp{AbUZY_}GcqkQyuuF3A+H|Uo(a>0~(Oq@VB z7LW6y4g=>Hs{llu>ci#nhtWYVIPFHkkuTy?`h9J%iehP;-Bbcjt7W}u$_JoBKD>Mu z+^R<%mg%+}#ve`-RIZZ=<%BBejYd*Fj3Q8gj^T1Y=g<-8W8=xZq&FL`?vHL?V9{a^C8jJj?6 z%{;M9&rad{%B2>owl{mU)fcwt`Y%1K_A_O$B+fRpt|PTS4=9Oiq1O8RTXeFXtEBaG z^`D(Z-F-raqtkw-kFRfMIBDi|x@vbwrV+P~x8CeWpZ7FYy9TDW7}GAeX64x@?PrPd z3bnSNfwB@bkl?>c@PzhYC1mHeNWuRnjAmvb8X)O_qy z=d7DPkG_>J%8l{3ku>jj`@uC%v1b^<)a(Nvv}1+zRot1N>s!b`1E1M8d2{8@(e$33 z^ua-rLNrc`?b z2Q@J&YiEF0H!ZF^@s8)ZSzyHgS;%N~s{|V-F2{CCs*fs!QzpPvH*h>W3YV{pt==t_ zNH;v_fmWtL)VdaDI8-A|2UoT;vR;2I6)LF?!|Y7@oQ(%poSu4Cd@q41Q?(DJAU^m4txv7$=TPcqCT%bp_L40?tTQh3jME z5s4$zkwskMH!Peo@ca?6wV)Es>In7;n|91DduKj~z5tN(Qtnxe$r)2r42uqL=bOo7n5gZnbI1fyR_) zmZUa`$ee~o^ApCc?@z)MO|AR;^4~R&Nh&N>r1{}F8KpkW{4%^U-Dj$Hi=uLHf-z~{ z|8;)B%FWrE+}T)CWs7niAwKl7Dq<}7nUd>NYy z8~3?IAz3Ar*O5tY7hVsMQ*<-5TU9*5xsAVwnk8bIEd1yLzHW>cx8EBsTcoF!o=Fer zeENbBKm79rUF>A$!MvT4nLemO`TD@JuF3m){h(CVaNTy@E--Ci*U*myAC9b%7;j3z zi7fEc2DHOZ-%bRy!K)&6h@_{ohJq)QHSz_PCsgj!K?A2PL3>EJCjql9r$Q(L!K=ye zC<40%ofWN@>iR+H4U)D{jR18Mmr#Pul+)_aGI@J@F5;vdd?2yeO zjLcYW#(Hrs{LV!0jq@cE!%J-kj8o)8<_7k8c6c}a6F0?lJks})-WGAq_U5IhTN#;# zM0L1en_l7Z9C~cV3qFNXwyq#@*1^3INu!=CCng!aKw?dVZW=2Wy7$~GZx$}?n-yrz zZA#qqHgD9ga~K6IW>3;G(0bPxpQiQp@AAu!xhI1Lq9pK8FSuyJm7Vx|;s%P6*d5fa zCfbY6%>?42;@tx$7am#f4@WmgMcsMg$zAdAsx}(9+U;FjQOTS6&UEvJ*XMP==BA_> z#FgD#ZP_cDg=eJNUtGRolTKmFgLH&Bz)Y_?)#ZnjC)sVt=**$QB&9!nyC|MY4madz z{Jy?EhAKsg1_E+w^mNa@&YqSq93R{)@7<(J+~lV@CAMWY+ka>CZQcmuWGNb8DUr=b zGCc3pDzO|iGLEvZmCqw7Gg(;px+T=-O1n#R#$#Jf2ZZIsn=xo(vuiD_)q@~#9HaP{ zc^(J@dZC-ye<>>Rw$W~wed21{l3X6|;OmKi1rGPe&SekS*1L1bsnpMJ2+9e-6{b-+ z*5hui18b6Z&*3dhNTqp;nj*8i($D(kO^bCSS_>D7z5RQ1b8N4>y-oOPFliniawh~{ zWBu~$?dgKv;Yp$S^=p#_X;q2EoAYT^vq(4DG`?AId&`bHdmMM7_wSY6Hd|3VW8P=` zrJ!k3YR!0^;^zF!bB&jl>-*UyZUf$a%H90^joh%A&(yo|+B}9beZq2Qre%r+NAz}T zEe_oGn@c+jm%Zb?WsLd2cV%Ny!%OR#Bbz3I;HKUsB?BkpV4a7 zJ9zVaF3&5qd=-3vJAtCB`Me%Fcpaa^X`;Jle>Nuh;M&XqTesl;lrk|73F$7c*Opl4 zLAUMOnKV8$kjJ>28ROr|xLJ|&LiD=9!mBbnA9FOIJezAlmBdI>B3UVYC-$2}1Qv{$ zIot1sv;d!BcLiwt%r{GO!+u8|{MMWtXOjI9J^%bHp){myL>KQKFW0K1yJAD1%2;vR z-jf41r%jaQsAMiO^6f(Cp33;rgS*dzyAX9>a+lX;4MsOBkfivo>VgfjLYL2;+qatd zww%E9>@z%+)j$5h0Ru37t_M$?)B6Rm`Y#Y%khwViKw*M)gYf_ zrXpH+t@F_pPV0%3zV^&lRu4tg*d=FYwN?)9VYy;Db7`?)SyNl;Q&Me^@u{SJ z3ghX4tKDSoyJXLHxCDB=#CQC>(10h(>A=6KbTs9a`I_T4Cy&k9Ed7QJ9q<*aq2q(P z38fAJ_%;@_48HHDM%+sQAEN2C;*qy8`73GQ_XY5qg3gCa;gN}y5Z2I?aF7pWO;Aub zjoeLT=0!r)+c*iJ%Nly$!lPs%tgj|RPh_a565P@S2ei@X4EEa(qr0T-GcRHJzXxB? z+`@w*U#sCHvqn}pN~H&ctLwKwIOsdl?)0(oLHGhLC0elZENbZQCb|*WhMS|i*4!HQ z&dYOAe^I?l9a;V0yC9U)Efq|8mZ?Dkf-EXRYpXo@Dc7VYzM5?#fV{NgaZhffI$3L!|uXM~B$vxk=Sd-cl;hLM9tzP>AUt;N`)W&1J$t@qb zbrW^FicGs%zbCvtbFj@|Q}Yy*%y6pI;`(5ZkAK4DPbhHw*zWdI<*G8xEX+c-#n#DW z4_wtkrbzZY%yeX^)`(v~Zh8BqKD@`ApxQ2y-!1aa3-}f};2aYx-H(*(&Oo98eeYNN zLMD5UMVk65--MIZ?8pvmPbAAJyW*`~b@DW`1dW}f*R zmSw~5t({IxLQ^@&S$PYqh^6h3q;5+Kc!Py~|$8k;d z+Rq=JS+GehloM5BbRC&85_>+MC?&6xbIr)!-Ot@yrR`=l);qWsGwffM5u-gC}Kge^>^ zqikU_+9xV>LamRz-1`C=h)2AK+8k8!rrn;u45)czBs0j#pWiSYv?yz0M+u<;eiH_i z+^}oa$rGr;7 zXyB&m0eCCNo)-VVWNTHs7;$@5^4b`H-8X1m}C>q+-E)NmfTn?EJdG?=59uQ^0zEYw~v<^`^fm zJjjV;@(m@JSOnf-@>=IQ}gvLni-e-(~`-&-{pnbn`v?WW7&_K}-``%g}IRT2f zL*2l9;nuT|0)iXjomsN4?L)7En-#J|$WZg$as4r6)xLBoz1n!#t9rG>XLr((5@?uqDVMnO^tW`TKvYJb5GZFDu7u?{RqdjRj+xOsP zV9{IIi*l2!LO33?AbwVRmM`sAz~Q=(wjd$D87;S?i?n1f(zObk(kb!|1g6h*hK|pPsvqu(d&m z(o7k>#`y#(#OFM&^W9y_ZkHN^%kC`|Z+^F!-;!GMRgNv%<-=nRkwES#&qbWJEW8*Q&g$a*aFhfJIERWd;otta{7o zigtw{i>=yxi5;Kj_TP=%oA!-G<+!)`K0*2PuJe|5X3o-Hsic3JcZ%|1{!QhuS-M$@ z*{cP{vjec~;wGEcT>{P*fMJEX2EF{wx$cv`F*N(HnZnV4Lg~m%q3yt8-_GKdRiWI^ zxtWRmabNJdz1_M@L-rkux*PM{lg8%rO{br2_lkb6VUm8dyn6H5Op*9fb^64cN}t(- zGrn3aP)$^xn^3oF-{ZaNMtNUkU#Mw~eXh^Vl{rVBtPMuTO|gNRof?CYWpx>$WGf_B z!I{e}kM(GJyCv(xHR7)bPjpo@7V!0=0rhCq#8y?5!QRQ{I~x&a(ke+4vgz{b>%LmU z7V$<*U5VVwpIB?l%7kRZSK$q}XpEo%0?Rh41`mZI0rj72yE$VFm8j#YgY4=zadok_=qYov$ zeUE0lxn`^DRZ{2Ntc)qmm%syV?;CZng*)(oG>45``>QaME!0$oP5QMu?}ztH>wa+abw3LYihjRhlJ;3=)#qHHi2}R=Q4j-l43>MXN-I?F5 zt3vvz-vo(^rxfT$wIY0PGw!u9ZVt2`B%DKC!Xeuhd$As3C?}h6kzj+K^y$Z1kCykl zm2Ge0-L+H(=I=#K8 zj1OmbBj&z-^pi3T(fZy>*X_X2vCunF-QuwkLv^*gl)1B4#Exk{jN+5ljhEIUHc=t* z9eJnAb=9O|Rm*ej_Geq#w3L@#55+D!ei^)AzaU9J0`4WAy6%7TlyE%#eR@9JTykWG zt6LXIr0{6<>t3ySI#=?S2{)8TAB{U;8S8gf1Y7lY8||GCH4ps=OGE?Bj@*o+@p3wA zoocT`$G^JQBMPd?MnhWTxMxqFlo|w|3Q8+Yjcq~#oTcpZMQ=ofd3&csD*Qasddfvr zUim^Z^^q}T7PW|Y)ZKBqLI3&jn!O0|_K}pqn_vttkMX@nxrf^zp`mb8T9DTChjt(0w<)ItG7h zk1h7x1gWzZ;M>Dlk417*n{ak|w_#VZ{MDx@MXT#imA`t!u2PC<@6WIzB;vMph%Qll z+fk+-+WYZIxN(Hy8Kl!LTX@6%5ZD?5)2PfW?6W3zFY{rg!m{C86>fvwr8^b=Hx2Cv z_h`$TS-VMRgx1gIfI+k?odVoNr%GzH27Jgzv}#{ZJV*#qnSvL@oM10l%Ilzl3%_9; z{^W@Us*_`2u^p$uCqP*q>ieM8`o7_m)wgfo7iQeaE(d9p1}j#b_gi@4?R}ykEitD3 zb?$@Pd*2st4$MMb{X?^K;%cADzO<1cQB+ew11h>nGxdAf`R~J3I}~KT*PtFQuR&YI z7|n?d(SVCi=8F@asSzXdd5l|K!#xHX9^cG284@_LeRH#82xLc;YZ5n}g;^WGX``;X z7Q}ryP=6GMoti?kK*BI`Y<#$%wW-Yoh(J%?9j=o@V;fFf7dSQ#o3b;Z^K}|1y&SknT-v| zXE+g3X4bc|zF%v^ernDB%7k+KzRUp5l_$#9vnv@xtb$)2jo@GH7WbteiLIrG3Eb=T z-y{A0yz@~~M8ND-LvOBw(t2PeA!p+^4F5@cQ~Cf#?NfQm_7u zNQFI|#H;Ae8F)R4b7Zt8I>Z{@4Zk9w#=BX#&rI$Y=`Y%{EzGT}Xfmqyh)!72Uo?q; zlDhyF7AemX5@@~0QD4|mW|6kEYR>yZcG3l6r7<`&e=G=K%7JQ|p zTWa=LJ!Nd(mHTuSH)=ieS}R+(M8LTn?6po>ug9J!FGCHkSF{@6X?A7`(ord7DiTU2*-Lwojz<0Tpu6?t6AN)J+v{V#6KpOX2@{Q*0htJQf zG}<~{VR`)6kUqDdVzdZsMDU17lGYbr3Agd?R<1@K$D*||+Nm9_{VpBi^2g;bK5Cd~ zsNxTI*`!4$<^=RO@zRKrIof!XKnec?023wX|M$+bQ!9H?pez#xbvd8X0itJQod=6 z1_(#iz+h3R&Xs2+z5Q7gJ+k$9#mS4E5hQ1`WK_vAMy-j(tR$!2igd}wGfWyWu9N8H zH*ficfZr#?V{IsyDOD-(E_$lEEytCl_tlJ@LD_@9cOYn%R-J()`sQ_@0t8-ViS!gz z&(xxP1{Y+8lMZyTlM=aT;(6DHUR^U=NZFB~_&+^-XIK+mv~>_fQHp|s(v>DvL3&9< zYCu4P^rq5@p*KMY3W_4l5PFI9-a7~Z6+-X5BR%vEfrM{-?|1LdJWnRsGjq;9d#|nnY7J$p?{<~ZgSb(26{@pBR;%GZ$zTg6+FgpVP zlbUV#w{CWLAxE1@4s(`iXWvO(Gmr0fxnl)H7LM|vHWga0Y@p+YbbA5esCh|>Bdq~M z>2mrYL0i>E&`nJCllPq?lOrFYHosEq5_SNDJe*k`)iv)mK9kh7$jRsl92)n8Ki&)0 z$xwLY3U^HkV4SSP^`a&mhu1zRcq{ynbNXrjHO<0aFayDR?3 zWv3GJz4Ix75Ukma)WB0%5BeG(MeZFb6g%ZdM27)SSfb0d7r;%nPw*EYu1MW%==4$4 z-#sMrh`Fy$VcIaRZ}C)~WISZoa;EPl0M|^}r?F$m)kS`1heNdZh6}RZ$d0~sD-*H@ zG}e!<2KzniF;jcCTC1QHBRWJW)^>lzkC!36z^%8o$BO{j`KFoS2jGw3tj1P@=tR4T zF0=ZiW7X}0LWBqDFy^u4&Bv{Nhpa9bRS9lV6ni!J*L}qtTO$*e3(#GQRrrgCuH{0l zUa*d`7((3Hk%7G(r!;7qG`9_(YQZhBjc<9a(A)m4B5bK73wLFqjF;Ovk0Km@4R>1_ zJGHybSpPxkv_Lp|7(3t0U{9wYfmnRPcVCmR*RQ9U^sOTJJT)#rD=x^qZ9-N~?cgUn zCxXKvYdo#e!ya7@wD90#{^p*Rj=Em$x)jY6GFkt`)e4d3*#*ALYsnE>qt9_1F4i>m z3JpC|>r5%j0A^YQ@%A@)jxprOw2xdJ?LB^J!)k)6VO}LjC?Lsm{3956Vx`0EYu@sm zN&1?W)`i`RxOeCy!c4jOVb^K7$dr=t>q^PKaf4j3)q=k0-pXT&ReZs*LitRhPW|Lr zZu;G?HAR0L#*7h#8KMJpb3a;NI&YNJhp|dOW*<(E|74NoM(_t!?6Minvr&n!5$ZDf->9d4zwYAFN#UY*L66JTF1x~u)Dbv56PC(NgbBKdWh3Ou#i*-Qxk z%qL7tHDM!&iBTW_{)17YsKMPwqVPL29l7xKD~6P%7DP=ZZnpRcjMoc^%CW<#31PQs ziWCJ|oocrR3IFrXmUp2zoZkXl@BL$@vFo-6Z~c7Zx#`fas6S;-=O@YXzD*O`M&Z%%S_WN#A0HEmsbT4z9z&>39Qv+;|swlex6Fo0hK z?UFSo_~yM>)2IAeB64O||vkM*{j#pc* z34Fa{>171Rmg}72H>#ZPlEWqu!e^xFxS)?U?U z`#MaBXQmZ$+A(T9BGA#ZR%>{2l;Dae?9LnK48FN}?C*3K`-s0d^Wd%HH}p1a)y?!o zj&&v01b+85!Nf}_Nq)vzxyPtyNsUSj!w4BnSYzOPqaEb9o2)Cjl{zHS{nKvkb_FK( zw9u&Ft$FV{T}N>v>#w$B*xz5u>vxxg*l+&mQPiX4RW2e}5G?zb%lwd?s=xOxEjBeA7f3wI*yc0+dCH zDEX&9Rfx>*T+Y7VB$bH7YB%?+j|>0#mHV45g7Q4p;SMWO{kV6`ue!JK5@a)HtP*G(Q%|Vbb0kxpED6%JQZ~EmdiPZ##_XjDYG@r zuEdH#-nq`2?d6uIFHNkhC$3f&MrEe;turIbRjNc;`EGPywJd+|oi#SYnmCp%$=?|p z-wXTX^827h=NPN`b-zm^qR^~|r^oF_&2eA8VUu5cHa3szyyXT?pJ0ge@#c!$zAbQP zw!E}I*Bj{4t=~Qws}{UflkU&cQKOYXM|OH?t1*wL?{}?qk!;D&H1B0~`52*=>9kt!tk6&~EF63nUO%#e zO~I7lPW4(6dUQh8(nG3tv&G!qah-)qOXjX*94|zpeJt6MWyc0gD53X}0`sKCTHN|& zExy&cWO*vT^}MwP9S&X`jCN8GJU-}^XuxxL)NDKQTpEBVUH067El)iZ2#tr%i;P7pWwer(UpT_(Uf{&-lr*l5_;pKle&HHBf5 zbw5Gm?*e5s!_vHri+bV(sCFLhja=#Wj=vOGY5T%9d*s30#iZb}4q*Tg{9k5!EAM}p zZC$KXW_hOds|9l!&wkC^+4Z_!{b~d2VZ-bG-8wSt5kLNs(}pUFkGCRA@iC~-gLx*Q z_pDL?`1TUxe8h6|sGd!ik3%5KC@gvH`GdUj!7mkzbycNRqJ>4(mWH^Q-U>oW_94I{ zhaG;)IUuDW${GLu>dH42pz%ih8g+8Ctxf5S>+Lg~#5NQBBTiI;(CO^@Hy_=H5%qS? zvDv@hn_~<*(jyc5e5%cv)DGcNbXlKgHb1IlkwViZ0 z7?t4{yw29;>thRBjcb4iiY80WV7_~VN|trrA-G-!XZ;S->-AKjYbDSjo>dQ#Tui&y z&7_L`hg<7*2gjpgwasZpE0;1}n8krp493U5Bb=()drc;F0R*nr;}&|u!#_1Fe%N{Z z%Yq}AR>II@O3}W2z_NOJ4Lj2c9>os8iKLj8WI%vA`;QpD2QWX-{Dt#tyblkUP6!2% zK$LE-D%M_JbHySIu7j@^AXbb{=ieEnr+}Y+FFuUXXZc$6cMY{RngZWdX+5;-&O1sL z^fmPdouTI#z8H9lIruaN$Gh#8I+Z^&sLP_NQ7ZfFB)km(R4Eg}lLt9aLU|*DwzUP1g%RQQMX^RN&pao9 z5)*M#!T#m%Ox@_gl1==FaK@oKeqyx0O$x^S-U&01=#CpdI%W^J6y|f}9-Oj4c(xda zB*YCzYDwR)k(*e6kmzC3J@mr&AT?;~y(V()65*w(A6w%O^Wml|+t$&ToqVS3ese|+ zqXMJ)8w;jy?dD@D=UxX(GZ1VaBTv7ozbHwqDt;VMbJs3vHG&W;JezCwGzBvZZ`@8V zk$lfn?{xvPb^VQVQ_a`}M_GR8H2a%xWi=j-7b?IrL-2+eT6zbsW==~Hj)V+pcO$|4 z@P!w?b_7a~yD_kd0=lY%X=}96^TWG!ziUV2UQdmtmCIXGCkoV_^oI`^O8eptLZ%=E zhq!~{LP^VsQPI{k>OaZZgl;pw2_LDKlfDnnD77%pl!q2pI23K%Ak^J-FLkgH8N1&e zkw}mPnhn+?86R6ht!FH;cU#OU3kRF}`N*Wk$fGdIa*`$8qRVyIQ)km;HbKZqJN;(8 zePL4Xa%mw!gdh<4XT1yIxj<?XSEB=u>Cym5FWp(H47$MQWlzjKltKoMI_FVvyIAGbPP0Tu$ zs+2iAEIiCPzgVvhRAtY-qhK>0200N}d*u4K6e@kj`pjqOXAGWly35!9Q-Xh#n*o#W z(GrT9jq|)?O|&lAsGE`S5x|ktElpp?0R3($(7aS(&v~5A59uJCo!nf~;R38;ENlB> z3rwNxqo)mmJ}a=&Aisc$@ax+JbOfFeWS`O9Ma*zI2}SQ?M!s0?LsC_of8lE-`P%^sxW zj;u9cMmVC~IfVFO2Magl4&4)L3|^7zywo|}GQq$~$sh04<&T-I(y0dH7{PvOl1Q0o zK5&6SH8YAi#d-~niiq?xX^COVYH5| zaLa4Leg6A*%nUExUb;!)ljLi1S}AHuz>U(B3MT)_K>j-OFl;AqCxde z5XfR7yBc~vs9Z-^Z4ygx^lFj840kdrfWH1M{w0#7l2W9iGtK49&K7c8uHjmcuUFXn zqwKmB*5%5+>zI4#k)Xv3kdcCjU0Nhu?zw91IdG3WUL5yO{-Q7RTeW`<=ADSROUBU(I=Jx;u1r< zY{)|HD1OZl6Jpr9o693SPaZv>-jUFsX_yY7DYW9*mjX3j-jQMRDUHeO$T1L91sFVB{nZ_t%>fb`& zvz>Fl+-3CM7Cp{DpMB$%;Hygv$ItoQE4UY2;wr&P(GLR!cr>vFHbXv&CTuyj)z5GcO!Llvlb~?M@|5bW24<&e((I>pa8h>i}Gx*5s z{OEOo@qt%K{LBv-uXQ`odG)`xkJ@qgmar^c+Em%y_mT7Cr@&H;kPs1thi$cJ1C|YE zOD}10=p!kGr2+@6g<`uGtf$GZ^5sk%;>$M1+>(im zx3@X4onL%Y)s>*l3s*3Gzq~D;u+-)I%@0yhd8iO!UE#ytcmdjRP|(eQWItw{_j_kJ zUYY2!o$pOcWbYu7!xetD3b&t z9ct(*iVYeLOmUR|G%;6|v{ZQZHso6%D|wiX(^{fl^tfKwI9%urpen|1b@u`QSxO?bOk!-=I1+Kec2+KTahjMMtWc~5_6lOHD z6cPxi5;BK;Ja5Zb_q2H)1tYA5W5OmJfh0WPI>w=gr=>Z2;Qn<=_&wQqI@K;ZVBiTI zqfor)pP_EXFa_9#^SoAZf!rEpLjsQIr#P+k2eobv9ZK#3G#dEv)wp|!Jr5?R8P);C zQE^_S@$%>S0E>K^6+GRF^Vjx!KNpTlQ!Hbd<3WpZlGT3qbz1(r?uy7401!~R0BMTE zW1gGOU2Ort&Q;)Z?WNv4?}LWn=|H+mugt8z1N8~lOk_J(MKdACO}=(QacL8P0vXu~ z3+t}^{vay5HQ`qu-C274cX9X|U4=riuw`{%1u~G}xV`ZdpA0UbZY^i*g;k#=u+lC^ zde+sOoW}|f#p;uXOa?@P|Vd@RZ#Tl_QF76Qf-H ziFen)gwN5FCeTQT=w?i9jMVY%)L^@)GwCgPIk&}k5w4NApHg;ff8K4CV`d2U{~Hl2 zcC3hY@(6zH#-5l>Dr8HBNPh0LZ!fGv2Dv4e=DgDC*thwg({mTRylL88b(}17wYRoiEH|BtX_TulXHJL^Rb*C+RWZDwdnPw_lK@A4|T9yT$Y^)9N-K|ogW}*p2gS(0nW(DHw;fDF4&mwx)75aFcXq5w1%sr7;Bm2cXV)vY0fpBocf-%* z5LLUdY>SsP+4%#lBZG;$(r{2|`kCnN(5I0hLPSeFn2R5&0 zY>v7BIsdmZ8Z8c~rl;VoqBL?nEqe%GvP%E#x?5lcn zzyDsgbSnA_*#3b?T zY_I#GjB6JYNykHJl2Sh9F*^alP#jEOs zY_>Bk6O`!)n$KQY_0;HqReDK4_5B*Sk(vK{*}0@OgZhZ$Km(@CMI)txD>I`v%^cZB zwHtwo8UVToB8v4HRt-xyj(b6VoPzS;!Yrm-BWwCs=8 zC4fnRe>pdO^XzwIiNDlP0|)qxk? zG@K>n#Jd%NB1QBgddSJMzkx@GOw2MfM~&8}rX0d7?0n&tclC7q*w3(Yk^W_if0vfN z?e0Hlj3HCy6_I;Llg^G^hP&;%>`Ez2R%2~*@n-9WWnpp1RgQo1QzCC{elY11ki6!A ziol*fQOw?kYgM`uJQ{yjTapmU>f}?E!aoMN%6xXl@Y_1|eK&#-OW#w571X~*pO z=EL*h#BW5J->rb|`+;9pmgsNxbd%{+-{hJPQ&JPd@>-%1!Fj!Hi|7NS{wm|4#gmGJ582^yW21DH1NzWg@uCzK9-oj6t6KrePVNWF!>)8xQkAdwPBj0m;L5GL8 z_h($=s7kT>qZ_mna0DVb?vSXEpS*r5ePV?8o!9?8?(DK~&a;X($Cb+6N=!|@s@f~+ zpNNp#757?*@U4SswT*Edg!lLYi@P*)I6jmFucoVbgC$MBfoL}2DUYNSmI;3nwp=bx z>MT3imW}wYkChTWRW0aGd176BDN1S}gKrzFBGPx81+(s6&d_O{s9XV3E6zT^2(AxruCqsZOnP*42v5`MCjJTh434SfK;7LY<`g^HTy5xDj|Ci$Z=h8vxusT`nlHP`Ad zeb5|tX2et^tnb!jB&?Dh`d-(!eiayxh@|2vc1wfu!_b+jTPYx@=6l^=FnVC1@tETy zbcsg@MzNDZ-_I=wOSs~`_nzS#rqPFaf~QOsYoLu_vly3jXUi~sQ6Wq$rWs5m_;b}FWk%8r3MbKsPR zn->*=0p=C=2Xme7R$$^uOLQgrdhZjcEA#dU&=hYZ%C^-pS0vqywKX8h2LbNS#I ztCN1c>f=vZZX2GW)kAP*<53fW0k{}AnwGK2&%-Tm(&O~DtY79n$Kf1tYrNi3+pt9Lqd4TqsURp zCTB2^9Hf&w!QYMCOsqafQOXQ!G^O3r5%hiFF8^ahZa8ZK1TV}DlbZl>WWFv9gHLRy zZO$s{-AQJ6cZG|~b{V4;b?noY+m4E(T{oORcru`>s`xm2bsR_h`9oAzksxJ`ECI4c zI!ZT*-T?D;uu0Cb!kc~sd0p@4hk^Kk26~*&My%NKhkGllCF=y^f{1Jq;6v5XDoP}~ z0EGf0?ZxAUEtv9plITBi=SE|yW@E+B>x}J+u=7g-F7Sv$Flx=e=5R_RMd(laEWU1T z-TYbYCfual8Udc3OuhhJhAop)8953LYge2ar?Z}n4vHQ$U{?e!OzJ$rIJ2@{R;1kguydQXjhSQa{)vO}P8;W5=8x8_W8^{8e?Hev zZdOkk3``QVfIj*}f)T2$^!YY^P)i(D)V4v~bz3Xw@8P7&uU7Y!`^dGVV zzrtfbg+j9;1+?YgdOn`QY__vEbsKmg;=vsdS4=7?+Gg%W;NZ@^~A-g`1^Pj$^-ME$Lx6Mzh4mj(4o?#on)us{+g>q{i|S@hPReN zedfx87aJjF%B{Qds+e1IRovMzt)-V`rRd+XmzoN(sRh!{QDG*W1lyoZ&{wJ#8+t0w z(K0er+`$(^xucIg7g-)@<3)J7Iw2ZVk4+$3;9j8IrvqfiMuyI$u#s}M(_zVw_s!D? z%;{zbPWQwwWdIaU#K%Pkevz^AGeGks7X0a zW8I`{6bUlTQEKW5jQ8gWGEm7j4yXId0PyRCh}9s5-h2NG<=-pN`A`QNX* ztZ9n`9p|X7yuD=oA$$xR)7>fBpd`MI{|;6KCX#)?w`4;b?rK$*B<3+@%Gyn!U&%O3@O`g8 z0*~urG*nGHqiFI>oINc%$_QqSEF2g$2r{3)JR)A^8^Fd-jmNqpC-t&zR26E;jv59i zBr-s=_<-ItR7w=y(`&qL+UUxFi=?#5pAdkT>`pXYJvuYnI4XY9wo2s4n^L%PZHt0M zwEF6OKY%hR2`f6f02OL>l!^SgLGaU+&Z4rZ#MLzescg?a7uHI6&a7hiy?aHLp` z7oh?4lbuH;HcP~Dqx(NA0io34xlSINXuNh+^$kNW1Fgg#Y+Qc+y)Q!DkOMxRP6n93 z@F!(`vrm&v=MM_qpl;+qyL#|^#lP4j_A9Y$cIg5%`49QYlBqfZ*3rK|QJTcPyfRn5 zm2r)pe3d{qQk0BIcKKOD?Mb|$!|X>%a-e(CnBBtmv~Q$uz?c>EsLyM>RwD8bxkl zNs}A|v&ZERiKEC#OWcVml0~it!aZL?5%xsW zW#dQZ^`xU3kl|`y*GKY%txNXtoaFz8MbuE6k?s^y-GD3O5(f{LsBGLuoI(>w(&Iv_7Wu8;NLYdy0IxE=ujL#(X1^IpVFF zfKMhnKWoNJVDb54eAIb;2@QB!f@3O+rD!2nLqlDYJ7V-Gh5Ih54q8E_u4N3^Bn?Bf ze*gJ}LlhJb{QBWjEYdf&Gi#e`d!i|fthPN77-bqQH$(ZUowaWEQY3rCIussS6v(`D z@;{@UlzGKxN4{@7J8ftr6)gJuk5G>VbxkYO$#bhs^^TZwM_1bB+!8SlKl`P17*xh0 zbepoG9x)Tq*l|>T`Y*d(Cs^rwBz!=gYG4OIqco>%UnaKG7fa&A?5Z|G4HBmMl)lVW z1dK||CZ2XmgdK}xZbEzpoM-ZLJ&d>3-iZ@yjMq&}jFczVCM_-MoE&Gl*L8<{uFR6Y&#v4`m4m@1w}4Esy&qzpIlIPo9L@It zjjqo1BB&vgbP2H$JK=z4Hf#PqOxKbTH=+6VaYY6Bti_VB$j3H(FI>ihZgC$M($&m< z>>Vo!-m8?odjS%vA#Kt@zSHLUbbOGg(s`9l_O!6I>Zp%jao2dhT>zc=KvOv~m#+-w z%l8Zf)fmc1ij4Wd!_S?;r=kJnWax7K7!&jn_T3Am@j`>aNryWl^MDmS$WNKw$DPS@ zb65RFiZKdJrrv>=0j7~*KQd5IerI$BJ@gt1ovluR&eebgRX{bB_fi3Rf#Mf5_6ghMOp@2W;Kq{>;J){6L1t zcZGJ4k9GmngS|42CWtb@_D8Jaf%p1qX^%BRV$>TJo7&W8tkf?pj+ zH{XGzhHS#ilIxK>5LhL2+`HE|X&37D)h)?^ISN>$75R{^crXvwF9CP|$#7-IEXwa| z0DhOpQ1+(ikEv^N)PwgbUhFG=pyVvsqu2zxpP$_=?(f|bScGIjxT^2$Te8{b0Ukc-K`*D$8hLN z4R7)?7(HLhEq-wd6jVbe4LShpOP2hq4%O_i2U9I(^79*KQt5;kb7$Ip9}J4h$gGsl zhKkU`sJaVrJ?3! zg|2mYu6xNBk46Kxk~jqmimYR4U{)&docLYoG8ff*^quEL_d|~lL6^9%wU!slBl#t5 zJ{5f_hgu|S8f(28o4Z~WF#ltzM^1Yf?Z)2WRyux-l=;bbjc^ts#f% z9irpBNBm?bx!bvvAR})%4`x!zC7E(dU z1I1xN`J}09bL$Gy$j=>TlK^t0?oq&hY-JU50(_YtRv?bFTEy&B0A)v*=8>w-Hc(MI zUd~p7{cf0qmp_OnUz5TfF-#9#<_?}kaq2AZK+3|HD_pK;Km6Y>Q(&#E{fQPwa|Xd? zIF6%iK~e-sMP_~MkJ>~T7MLwqe6IC5cq0@u3j{*t-`)<$qYQ{Ox0esQo^x6)21pYi zr?+OScClO9Iz*21keB)P{_SnRmvo3Vw=O_$tee1v%z!FF!briAtW|4V0Sn~x`x!IU zUq&78-hJ}tS@j1ZI#-_=Sy~1((YpVl=NOlPtO)=E-n;glz80s~|4e^Wv{)|1B7f?APfG7%wi@-~lROilzAwC+^#=c3DxNyaaaSa@ z@b=4709l$3@ayJ>Y5;q%oeT{9tJ}1Nio+#5y~3PpKhBND!8~9=1F=;6&rwR<(g5ty zKmLFRLIwEuAYOh@Ps?J?rk6m^Y4}~bW-={{z5w0I@YDvnw`Ng>aaj|TE?Y?o{ZxXf zx61XMWHs}(Lq);tYhp1C15Xz-sVV^9NX_h`Dwc%3K67bz2e5-!w(bO*$Ro;(6wZ6X zAxZ;(6I`6lV&8@2(^~>3WS%MF&?GVWds2rf9%Gp-WF;V3G;UDq>LNul1I zkdr_fhxYR%`BxU|ZY&ib@&pQy+E&CgaX5ISsAh8YWp{sNj|99Sn`8<@uJn}P%6op!uAOH>q)m~jUAlse#dK#bJ za#v7peT}$RnX~zRrx>TGU*(fX-GxpShM|{20#Ytnt??TJPDucC)VG&`GUMq^&pC)& z-AcvSw9s}pm&Hh)=3KF|?vGiPIo_JYBf*{V2CGDc5TRPXau#Ow{@B&uXR~6ft=qrT zyECc@E1GGc^8Tq6qE#<~&EDpw+m|d1`)kFsAQRn=&mh0dFF?9PW{lqNw2-=e6_4%K z9$Zni=!euo2z+KDaqA!-nbq6B^#Yd|6r_G-*y3P!0kCV>=3cme4v8gp_GHw(FA5Hh z9j&XB_-?Y=CWLFw9xUv&e>lB*J=x6hz_a?$2PkQX>+!yHf0}DqQsKTQE`$kK@_MwjDpR0%Kov#nw9)Tbfxa==6-` zTepegzI^lu1>Ta8G!TEC?U!2>0MsG5$gg@eW*pp6wCe*feESCN4&PeHB9063??OU}`e%!ac>Wx4? zZ^5;djwcHj`%R9qn0?H?=6YF#)@^*Pb~b(X{P>*y#q#crt9-`9yZ*74H7rgXC0Jc) z1vHiNU%h!%eK*?3I(Aw`hA~*2Qryf$91;*m8%sY;^yl=u4Zko zKPIJqdtTvX)IgJ2F{ZP^c#~wwh-tB(BRPPzZICP0%T-BFof)peV5LH+=L}x}#{gsi zR2T-U)JFeH3l2#Xdw_3X-t!dWIKa5_-3#T5HV z29#ep3pjcZDjF1-_vCr5@&jl2;YKnyy2O50)8Ud8htf6((BsBjBER6ygJ z2?`xq8`KAw5%P$-T&r)Y>Ni78{9y`H-Cj(u`OtM9?M24-1kCX%7U$J}|he)Y_x@wHqaW}^<)!gaOPo@vrx%WWZugw#Bmil>uv(#LlAwcJL;flx?~@=oNX$tC8MfpK;UO?h zW?CEVq7+h9>Rw^~+z;R+70xSJ2-VNq z&vXi3c}>1WjI+1Wj6C+oof%33igDXMV{8cvDHzCE#DIT-i2+ygX!5s8=P!sBXKlzY z#r_cNNo{)JAzh_O+=~ABw}L|p_*(8CLy1GdS)&8&x<^qD6>q3G<45&7eVGmNCv89X9}A9msi$m zq(ABqNUqoYi%)?1Lp^VWI{Y(Jj%;}8p-RbPrHnw7Yz*AKH8UpWG0j#riye&{``)O+ zW@$R`WUg4O%$}RdC;beq7Co-_%`ZfkG`$t83c)*-NUe(IJfVN(ps}hpd~}>miuztE zd$*VqoTs|HV+y5#U}<&2?}9*|XahKxKQAket`69He-R$L3K??fr$JLcQ?+~)pqaE^ zyQR=kQX#6`dh?3&e-v(pB#$>$db0>DQhw+g(?|4EM9+?fhJNM}zdBzGV0r}%BBW^; zJ!0oS;BSIz@}zkKSWBvK?jS&v^gkd+SJSrh!{oAnsvRgn&>0!rfN@n!oX$N_vIkWB z?im#Stg@=dL{5H?lx7@iuB544+>+x zXkXWq4%gKPW$1{!nrfWE!@b52O9nb!fQ>Gup|V2 zlmn;$r>-3xu>BJt0~X3rX=v!~YhMY`c*#Qrw9!GR1@r(ab|U5jcPftnY*?D?{@lly z;RhPl+%F5k{PW62*<*?Byz$Uy4XKj5b0{QA!^DMu83q_ugL47=y8S&v^FM3~ zlyb?B{^>{P*Bz}qs5wKHdWXi#UqJ7z7UC}rbnkm9#<$)8z0J>*rwCnqiabpB#;uP} z>7jyc|J-7qSLF^mL{jnl!2pD-F&Ajz&>9H(uR0an(Ldhn-V}gpsGB$_<}PM-Kwkz8 zz`kh101gb5L=mF?#*2gd$4RaO?8Dqgi;KZxD!a7r#zjgB^pR=aP@aeUgA_@q*cmwo zbo6b&*74Sl_pogu9?Ea0L9dO9)sSakXW&TCu&$KnX1Im^$sN!A@@FP}9DvmawGU=w zJ<<(GmWFC_qnuG_`YC#^YyA8%xz2IC{QQ3HjzR6*nZy?PTl4o(G0!xd8aPq0^eNXA zfkPtV789sym~@AI6f=wHwQ6%7o + + Outfitter User's Manual + + + + Outfitter Instructions +

Contents

+ +

Installing Outfitter

+

Outfitter is installed just like any other addon. If World of Warcraft is + running you should exit from the game before installing. Extract the contents + of the Outfitter.zip file and then copy the resulting Outfitter folder to your + World of Warcraft's Addons folder located inside the Interface folder.

+

Windows users: + The Addons folder can normally be found at + C:\Program + Files\World of Warcraft\Interface\Addons

+

MacOS users:The Addons folder can + normally be found inside the Interface folder which is located inside the World + of Warcraft application folder

+

IMPORTANT: Depending on your unzipping application, you may end up with the + addon folder inside another folder. Look inside the Outfitter folder and verify + that there's a file named Outfitter.toc. If you don't see this file and see + another folder instead, open that folder and look for the file. The folder + containing the .toc file is the one which should be copied to your World of + Warcraft addons folder.

+

The addon is now installed and you can now launch World of Warcraft.

+

Accessing Outfitter

+

To open Outfitter simply open World of Warcrafts character window (usually the + 'c' key on your keyboard. You can open Outfitter from the Character window by + click the button with a robe icon in the top right corner of the window.

+
+

Outfit categories and ready-made outfits

+

One of the first things you will notice is that Outfitter has created several + outfits for you and that these outfits are in categories named Complete + Wardrobes, Mix-n-match, Accessories, and Special Occassions.

+

Complete Wardrobes + are outfits which contain an item for every slot of your inventory. Whenever + you wear a complete wardrobe you will replace any other outfits you're wearing + at the time. The first time you use Outfitter it will create two complete + wardrobes for you. The Normal wardrobe is whatever gear you happened to be + wearing when Outfitter was first run. The Birthday Suit outfit is a naked + outfit which will remove all of your gear when you wear it.

+

Mix-n-match + outfits on the other hand don't have items in every slot. These outfits are + used to overlay special sets of items, such as Fire Resist gear or PvP items, + over a complete wardrobe. Any time you select a Mix-n-match outfit you will + replace all other outfits you're wearing, except for the selected Complete + Wardrobe which will act as a base outfit for the overlay. The first time you + use Outfitter it will attempt to create a set of resistance gear (Fire, Nature, + etc.) for you. If you don't have any items which give you a particular + resistance then Outfitter won't create that outfit automatically.

+

Accessories, like Mix-n-match, are also + only partial outfits. The difference is that you can combine as many accessory + outfits as you like. These outfits can be used for equipping special items such + as Jumper Cables, Lei of Lilies, fishing poles, or other items which you don't + normally have as part of another outfit. The first time you use Outfitter it + will search your bags for tradeskill items, such as fishing poles, gloves with + herbalism, mining or skinning enchants, etc. and create Accessory outfits for + those.

+

The last category is + Special Occassion + outfits which are worn automatically for you at the appropriate time. There are + several of these outfits, some are created for every class and others are only + created for specific classes

+

The + Argent Dawn + outfit will be worn whenever you're in the plaguelands, Scholomance or + Stratholme and will automatically be setup with your Argent Dawn trinket if you + have one.

+

The + Riding + outfit will be worn whenever you are mounted and will automatically be setup + with your Carrot on a Stick, boots with Mithril Spurs, and gloves with the + Riding Skill enchantment if you have those. Note that by default the riding + outfit is setup so that it won't equip when you are in a battleground. You can + change this setting using the menu to the right of the outfit.

+

The + Dining + outfit will be worn whenever you start eating or drinking. This outfit is + initially "transparent" (meaning it has no inventory slots enabled) but can be + edited to include items which boost your spirit or health and mana regen in + order to lower your down time. Choosing items for this outfit can be tricky + though since you don't want to swap in items which reduce your stamina or + intellect.

+

The + Battlegrounds + outfit will be worn whenever you're in one of the three battlegrounds and can + be used to automatically equip your PvP gear.

+

There are also class-specific outfits for priests (shadowform), rogues + (stealth), warriors (all three stances), and druids (all four shapeshift + forms). These outfits are set to transparent by default, so they have no + effect.

+

Any of the Special Occassion outfits can be disabled by using the menu to the + right of the outfit. This is useful if you only temporarily want to prevent + that outfit from auto-equipping.

+

Creating an outfit

+

To create an outfit click the New Outfit button at the bottom of the window. + This will open the New Outfit window where you can name your new outfit and + specify how you want it initially setup.

+
+

By default the Optimize menu will be set to use current outfit. This will create + the new outfit as a Complete Wardrobe using whatever items you currently have + equipped.

+

You may choose Create Empty Outfit which will create an outfit with no slots + enabled.

+

If you want to have Outfitter generate an outfit for you which maximizes some + attribute, you can choose that attribute from the various sub-menus of the + Optimize menu. You can maximize stamina, nature resistance, spell damage, and + many other attributes using this feature. Outfitter will scan your bags and + inventory and choose an item for each slot which has the maximum value for that + attribute. If you don't have any items for a slot which contain that attribute + then that slot will not be enabled in your new outfit.

+

Updating an outfit

+

You can change the contents of an outfit at any time by opening Outfitter and + selecting the outfit from your list of outfits. The selected outfit will equip + and the enabled slots for that outfit will have checkmarks in them. Just equip + an item and it will be added to the selected outfit. If you no longer want that + outfit to include a particular slot just uncheck the box for that slot.

+

When an outfit is selected you will also see two new buttons at the top of your + character window "Enable all" and "Enable none" These buttons can be used to + quickly enable all item slots or disable all item slots to make it easier to + create your outfit.

+

The minimap button

+

The minimap button will initially be located at the center of the left side of + your minimap. If you are using other addons which place buttons around the + minimap you may have to temporarily move them out of the way in order to see + Outfitters button.

+
+

To change the position of Outfitter button just drag it to where you'd like it. + This position will be remembered and set for you each time you start World of + Warcraft.

+

To bring up Outfitters minimap menu click the button. From here you can open the + Outfitter UI in order to edit outfits or you can quickly select an outfit to + wear.

+

QuickSlots

+

QuickSlots are automatically added to your character window for each item slot. + They allow you to quickly find items which go into that slot without having to + dig through all your bags. To access the QuickSlot just click a slot in your + character window. A row of inventory slots will appear containing every item + you have which can go into that slot. An empty slot is also provided so you can + quickly unequip an item without having to open your bags.

+
+

Commands

+

Commands to equip or unequip outfits can be included in macros. Outfitter + supports these commands:

+

+ /outfitter wear outfitname + Equips the outfit named outfitname
+ /outfitter unwear outfitname + Unequips the outfit named outfitname
+ /outfitter toggle outfitname + Toggles the outfit named outfitname (if it is currently equipped it's removed, + otherwise it's equipped
+

+

Key Bindings

+

Outfits can be attached to a key so that they can be equipped or removed using a + key press. Outfitter supports up to 10 outfits being attached to keys. To + attach an outfit to a key on your keyboard, do the following:

+

First, use the menu next to the outfit to choose which of the 10 key bindings + you want to use for your outfit.

+

Next open World of Warcraft's Key Binding settings window and scroll down to the + Outfitter section. In that section you will see the 10 key binding outfits + listed and you can associate a key combination with that outfit.

+ + diff --git a/Libs/AceEvent-2.0/AceEvent-2.0.lua b/Libs/AceEvent-2.0/AceEvent-2.0.lua new file mode 100644 index 0000000..c654568 --- /dev/null +++ b/Libs/AceEvent-2.0/AceEvent-2.0.lua @@ -0,0 +1,973 @@ +--[[ +Name: AceEvent-2.0 +Revision: $Rev: 17803 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceEvent-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0 +Description: Mixin to allow for event handling, scheduling, and inter-addon + communication. +Dependencies: AceLibrary, AceOO-2.0 +]] + +local MAJOR_VERSION = "AceEvent-2.0" +local MINOR_VERSION = "$Revision: 17803 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end + +local AceOO = AceLibrary:GetInstance("AceOO-2.0") +local Mixin = AceOO.Mixin +local AceEvent = Mixin { + "RegisterEvent", + "RegisterAllEvents", + "UnregisterEvent", + "UnregisterAllEvents", + "TriggerEvent", + "ScheduleEvent", + "ScheduleRepeatingEvent", + "CancelScheduledEvent", + "CancelAllScheduledEvents", + "IsEventRegistered", + "IsEventScheduled", + "RegisterBucketEvent", + "UnregisterBucketEvent", + "UnregisterAllBucketEvents", + "IsBucketEventRegistered", + } + +local table_setn +do + local version = GetBuildInfo() + if string.find(version, "^2%.") then + -- 2.0.0 + table_setn = function() end + else + table_setn = table.setn + end +end + +local weakKey = {__mode="k"} +local new, del +do + local list = setmetatable({}, weakKey) + function new() + local t = next(list) + if t then + list[t] = nil + return t + else + return {} + end + end + + function del(t) + setmetatable(t, nil) + for k in pairs(t) do + t[k] = nil + end + list[t] = true + end +end + +local FAKE_NIL +local RATE + +local eventsWhichHappenOnce = { + PLAYER_LOGIN = true, + AceEvent_FullyInitialized = true, + VARIABLES_LOADED = true, + PLAYER_LOGOUT = true, +} + +local registeringFromAceEvent +function AceEvent:RegisterEvent(event, method, once) + AceEvent:argCheck(event, 2, "string") + if self == AceEvent and not registeringFromAceEvent then + AceEvent:argCheck(method, 3, "function") + self = method + else + AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number") + if type(method) == "boolean" or type(method) == "number" then + AceEvent:argCheck(once, 4, "nil") + once, method = method, event + end + end + AceEvent:argCheck(once, 4, "number", "boolean", "nil") + if eventsWhichHappenOnce[event] then + once = true + end + local throttleRate + if type(once) == "number" then + throttleRate, once = once + end + if not method then + method = event + end + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + else + assert(type(method) == "function" or type(method) == "string") + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[event] then + AceEvent_registry[event] = new() + AceEvent.frame:RegisterEvent(event) + end + + local remember = true + if AceEvent_registry[event][self] then + remember = false + end + AceEvent_registry[event][self] = method + + local AceEvent_onceRegistry = AceEvent.onceRegistry + if once then + if not AceEvent_onceRegistry then + AceEvent.onceRegistry = new() + AceEvent_onceRegistry = AceEvent.onceRegistry + end + if not AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event] = new() + end + AceEvent_onceRegistry[event][self] = true + else + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if throttleRate then + if not AceEvent_throttleRegistry then + AceEvent.throttleRegistry = new() + AceEvent_throttleRegistry = AceEvent.throttleRegistry + end + if not AceEvent_throttleRegistry[event] then + AceEvent_throttleRegistry[event] = new() + end + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self]) + end + AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey) + local t = AceEvent_throttleRegistry[event][self] + t[RATE] = throttleRate + else + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self]) + end + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + end + + if remember then + AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event) + end +end + +local ALL_EVENTS + +function AceEvent:RegisterAllEvents(method) + if self == AceEvent then + AceEvent:argCheck(method, 1, "function") + self = method + else + AceEvent:argCheck(method, 1, "string", "function") + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register all events to method %q, it does not exist", method) + end + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[ALL_EVENTS] then + AceEvent_registry[ALL_EVENTS] = new() + AceEvent.frame:RegisterAllEvents() + end + + AceEvent_registry[ALL_EVENTS][self] = method +end + +local _G = getfenv(0) +local memstack, timestack = {}, {} +local memdiff, timediff +function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then + return + end + local _G_event = _G.event + _G.event = event + local lastEvent = AceEvent.currentEvent + AceEvent.currentEvent = event + + local AceEvent_onceRegistry = AceEvent.onceRegistry + local AceEvent_debugTable = AceEvent.debugTable + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + local tmp = new() + for obj, method in pairs(AceEvent_onceRegistry[event]) do + tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil + end + local obj = next(tmp) + while obj do + local mem, time + if AceEvent_debugTable then + if not AceEvent_debugTable[event] then + AceEvent_debugTable[event] = new() + end + if not AceEvent_debugTable[event][obj] then + AceEvent_debugTable[event][obj] = new() + AceEvent_debugTable[event][obj].mem = 0 + AceEvent_debugTable[event][obj].time = 0 + AceEvent_debugTable[event][obj].count = 0 + end + if memdiff then + table.insert(memstack, memdiff) + table.insert(timestack, timediff) + end + memdiff, timediff = 0, 0 + mem, time = gcinfo(), GetTime() + end + local method = tmp[obj] + AceEvent.UnregisterEvent(obj, event) + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + elseif method then -- function + method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + if AceEvent_debugTable then + local dmem, dtime = memdiff, timediff + mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff + AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem + AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time + AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 + + memdiff, timediff = table.remove(memstack), table.remove(timestack) + if memdiff then + memdiff = memdiff + mem + dmem + timediff = timediff + time + dtime + end + end + tmp[obj] = nil + obj = next(tmp) + end + del(tmp) + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] + if AceEvent_registry[event] then + local tmp = new() + for obj, method in pairs(AceEvent_registry[event]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + local continue = false + if throttleTable and throttleTable[obj] then + local a1 = a1 + if a1 == nil then + a1 = FAKE_NIL + end + if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then + throttleTable[obj][a1] = GetTime() + else + continue = true + end + end + if not continue then + local mem, time + if AceEvent_debugTable then + if not AceEvent_debugTable[event] then + AceEvent_debugTable[event] = new() + end + if not AceEvent_debugTable[event][obj] then + AceEvent_debugTable[event][obj] = new() + AceEvent_debugTable[event][obj].mem = 0 + AceEvent_debugTable[event][obj].time = 0 + AceEvent_debugTable[event][obj].count = 0 + end + if memdiff then + table.insert(memstack, memdiff) + table.insert(timestack, timediff) + end + memdiff, timediff = 0, 0 + mem, time = gcinfo(), GetTime() + end + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + elseif method then -- function + method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + if AceEvent_debugTable then + local dmem, dtime = memdiff, timediff + mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff + AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem + AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time + AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 + + memdiff, timediff = table.remove(memstack), table.remove(timestack) + if memdiff then + memdiff = memdiff + mem + dmem + timediff = timediff + time + dtime + end + end + end + tmp[obj] = nil + obj = next(tmp) + end + del(tmp) + end + if AceEvent_registry[ALL_EVENTS] then + local tmp = new() + for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + local mem, time + if AceEvent_debugTable then + if not AceEvent_debugTable[event] then + AceEvent_debugTable[event] = new() + end + if not AceEvent_debugTable[event][obj] then + AceEvent_debugTable[event][obj] = new() + AceEvent_debugTable[event][obj].mem = 0 + AceEvent_debugTable[event][obj].time = 0 + AceEvent_debugTable[event][obj].count = 0 + end + if memdiff then + table.insert(memstack, memdiff) + table.insert(timestack, timediff) + end + memdiff, timediff = 0, 0 + mem, time = gcinfo(), GetTime() + end + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + elseif method then -- function + method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + end + if AceEvent_debugTable then + local dmem, dtime = memdiff, timediff + mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff + AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem + AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time + AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 + + memdiff, timediff = table.remove(memstack), table.remove(timestack) + if memdiff then + memdiff = memdiff + mem + dmem + timediff = timediff + time + dtime + end + end + tmp[obj] = nil + obj = next(tmp) + end + del(tmp) + end + _G.event = _G_event + AceEvent.currentEvent = lastEvent +end + +-- local accessors +local getn = table.getn +local tinsert = table.insert +local tremove = table.remove +local floor = math.floor +local GetTime = GetTime +local next = next +local pairs = pairs +local unpack = unpack + +local delayRegistry +local tmp = {} +local function OnUpdate() + local t = GetTime() + for k,v in pairs(delayRegistry) do + tmp[k] = true + end + for k in pairs(tmp) do + local v = delayRegistry[k] + if v then + local v_time = v.time + if not v_time then + delayRegistry[k] = del(v) + elseif v_time <= t then + local v_repeatDelay = v.repeatDelay + if v_repeatDelay then + -- use the event time, not the current time, else timing inaccuracies add up over time + v.time = v_time + v_repeatDelay + end + local event = v.event + local mem, time + if AceEvent_debugTable then + mem, time = gcinfo(), GetTime() + end + if type(event) == "function" then + event(unpack(v)) + else + AceEvent:TriggerEvent(event, unpack(v)) + end + if AceEvent_debugTable then + mem, time = gcinfo() - mem, GetTime() - time + v.mem = v.mem + mem + v.timeSpent = v.timeSpent + time + v.count = v.count + 1 + end + if not v_repeatDelay then + local x = delayRegistry[k] + if x and x.time == v_time then -- check if it was manually reset + delayRegistry[k] = del(v) + end + end + end + end + end + for k in pairs(tmp) do + tmp[k] = nil + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end +end + +local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + local id + if type(event) == "string" or type(event) == "table" then + if type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 + AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(delay, 4, "number") + self:CancelScheduledEvent(id) + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + if not delayRegistry then + AceEvent.delayRegistry = new() + delayRegistry = AceEvent.delayRegistry + AceEvent.frame:SetScript("OnUpdate", OnUpdate) + end + local t + if type(id) == "table" then + for k in pairs(id) do + id[k] = nil + end + t = id + else + t = new() + end + t[1] = a1 + t[2] = a2 + t[3] = a3 + t[4] = a4 + t[5] = a5 + t[6] = a6 + t[7] = a7 + t[8] = a8 + t[9] = a9 + t[10] = a10 + t[11] = a11 + t[12] = a12 + t[13] = a13 + t[14] = a14 + t[15] = a15 + t[16] = a16 + t[17] = a17 + t[18] = a18 + t[19] = a19 + t[20] = a20 + table_setn(t, 20) + t.event = event + t.time = GetTime() + delay + t.self = self + t.id = id or t + t.repeatDelay = repeating and delay + if AceEvent_debugTable then + t.mem = 0 + t.count = 0 + t.timeSpent = 0 + end + delayRegistry[t.id] = t + AceEvent.frame:Show() + return t.id +end + +function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + if type(event) == "string" or type(event) == "table" then + if type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(a1, 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) +end + +function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + if type(event) == "string" or type(event) == "table" then + if type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(a1, 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) +end + +function AceEvent:CancelScheduledEvent(t) + AceEvent:argCheck(t, 2, "string", "table") + if delayRegistry then + local v = delayRegistry[t] + if v then + delayRegistry[t] = del(v) + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + return true + end + end + return false +end + +function AceEvent:IsEventScheduled(t) + AceEvent:argCheck(t, 2, "string", "table") + if delayRegistry then + local v = delayRegistry[t] + if v then + return true, v.time - GetTime() + end + end + return false, nil +end + +function AceEvent:UnregisterEvent(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[event] and AceEvent_registry[event][self] then + AceEvent_registry[event][self] = nil + local AceEvent_onceRegistry = AceEvent.onceRegistry + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self]) + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + if not next(AceEvent_registry[event]) then + AceEvent_registry[event] = del(AceEvent_registry[event]) + if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent.frame:UnregisterEvent(event) + end + end + else + if self == AceEvent then + error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2) + else + AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self) + end + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) +end + +function AceEvent:UnregisterAllEvents() + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then + AceEvent_registry[ALL_EVENTS][self] = nil + if not next(AceEvent_registry[ALL_EVENTS]) then + del(AceEvent_registry[ALL_EVENTS]) + AceEvent.frame:UnregisterAllEvents() + for k,v in pairs(AceEvent_registry) do + if k ~= ALL_EVENTS then + AceEvent.frame:RegisterEvent(k) + end + end + AceEvent_registry[event] = nil + end + end + local first = true + for event, data in pairs(AceEvent_registry) do + if first then + if AceEvent_registry.AceEvent_EventUnregistered then + event = "AceEvent_EventUnregistered" + else + first = false + end + end + local x = data[self] + data[self] = nil + if x and event ~= ALL_EVENTS then + if not next(data) then + del(data) + if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent.frame:UnregisterEvent(event) + end + AceEvent_registry[event] = nil + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) + end + if first then + event = nil + end + end + if AceEvent.onceRegistry then + for event, data in pairs(AceEvent.onceRegistry) do + data[self] = nil + end + end +end + +function AceEvent:CancelAllScheduledEvents() + if delayRegistry then + for k,v in pairs(delayRegistry) do + if v.self == self then + delayRegistry[k] = del(v) + end + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + end +end + +function AceEvent:IsEventRegistered(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if self == AceEvent then + return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false + end + if AceEvent_registry[event] and AceEvent_registry[event][self] then + return true, AceEvent_registry[event][self] + end + return false, nil +end + +local bucketfunc +function AceEvent:RegisterBucketEvent(event, delay, method) + AceEvent:argCheck(event, 2, "string", "table") + if type(event) == "table" then + for k,v in pairs(event) do + if type(k) ~= "number" then + AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.") + elseif type(v) ~= "string" then + AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.") + end + end + end + AceEvent:argCheck(delay, 3, "number") + if AceEvent == self then + AceEvent:argCheck(method, 4, "function") + self = method + else + if type(event) == "string" then + AceEvent:argCheck(method, 4, "string", "function", "nil") + if not method then + method = event + end + else + AceEvent:argCheck(method, 4, "string", "function") + end + + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + end + end + if not AceEvent.buckets then + AceEvent.buckets = new() + end + if not AceEvent.buckets[event] then + AceEvent.buckets[event] = new() + end + if not AceEvent.buckets[event][self] then + AceEvent.buckets[event][self] = new() + AceEvent.buckets[event][self].current = new() + AceEvent.buckets[event][self].self = self + else + AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id) + end + local bucket = AceEvent.buckets[event][self] + bucket.method = method + + local func = function(arg1) + bucket.run = true + if arg1 then + bucket.current[arg1] = true + end + end + AceEvent.buckets[event][self].func = func + if type(event) == "string" then + AceEvent.RegisterEvent(self, event, func) + else + for _,v in ipairs(event) do + AceEvent.RegisterEvent(self, v, func) + end + end + if not bucketfunc then + bucketfunc = function(bucket) + local current = bucket.current + local method = bucket.method + local self = bucket.self + if bucket.run then + if type(method) == "string" then + self[method](self, current) + elseif method then -- function + method(current) + end + for k in pairs(current) do + current[k] = nil + k = nil + end + bucket.run = false + end + end + end + bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket) +end + +function AceEvent:IsBucketEventRegistered(event) + AceEvent:argCheck(event, 2, "string", "table") + return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self] +end + +function AceEvent:UnregisterBucketEvent(event) + AceEvent:argCheck(event, 2, "string", "table") + if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then + AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self) + end + + local bucket = AceEvent.buckets[event][self] + + if type(event) == "string" then + AceEvent.UnregisterEvent(self, event) + else + for _,v in ipairs(event) do + AceEvent.UnregisterEvent(self, v) + end + end + AceEvent:CancelScheduledEvent(bucket.id) + + del(bucket.current) + AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self]) + if not next(AceEvent.buckets[event]) then + AceEvent.buckets[event] = del(AceEvent.buckets[event]) + end +end + +function AceEvent:UnregisterAllBucketEvents() + if not AceEvent.buckets or not next(AceEvent.buckets) then + return + end + for k,v in pairs(AceEvent.buckets) do + if v == self then + AceEvent.UnregisterBucketEvent(self, k) + k = nil + end + end +end + +function AceEvent:OnEmbedDisable(target) + self.UnregisterAllEvents(target) + + self.CancelAllScheduledEvents(target) + + self.UnregisterAllBucketEvents(target) +end + +function AceEvent:EnableDebugging() + if not self.debugTable then + self.debugTable = new() + + if delayRegistry then + for k,v in pairs(self.delayRegistry) do + if not v.mem then + v.mem = 0 + v.count = 0 + v.timeSpent = 0 + end + end + end + end +end + +function AceEvent:IsFullyInitialized() + return self.postInit or false +end + +function AceEvent:IsPostPlayerLogin() + return self.playerLogin or false +end + +function AceEvent:activate(oldLib, oldDeactivate) + AceEvent = self + + if oldLib then + self.onceRegistry = oldLib.onceRegistry + self.throttleRegistry = oldLib.throttleRegistry + self.delayRegistry = oldLib.delayRegistry + self.buckets = oldLib.buckets + self.registry = oldLib.registry + self.frame = oldLib.frame + self.debugTable = oldLib.debugTable + self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true + self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true + self.ALL_EVENTS = oldLib.ALL_EVENTS + self.FAKE_NIL = oldLib.FAKE_NIL + self.RATE = oldLib.RATE + end + if not self.registry then + self.registry = {} + end + if not self.frame then + self.frame = CreateFrame("Frame", "AceEvent20Frame") + end + if not self.ALL_EVENTS then + self.ALL_EVENTS = {} + end + if not self.FAKE_NIL then + self.FAKE_NIL = {} + end + if not self.RATE then + self.RATE = {} + end + ALL_EVENTS = self.ALL_EVENTS + FAKE_NIL = self.FAKE_NIL + RATE = self.RATE + local inPlw = false + local blacklist = { + UNIT_INVENTORY_CHANGED = true, + BAG_UPDATE = true, + ITEM_LOCK_CHANGED = true, + ACTIONBAR_SLOT_CHANGED = true, + } + self.frame:SetScript("OnEvent", function() + local event = event + if event == "PLAYER_ENTERING_WORLD" then + inPlw = false + elseif event == "PLAYER_LEAVING_WORLD" then + inPlw = true + end + if event and (not inPlw or not blacklist[event]) then + self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + end + end) + if self.delayRegistry then + delayRegistry = self.delayRegistry + self.frame:SetScript("OnUpdate", OnUpdate) + end + + self:UnregisterAllEvents() + self:CancelAllScheduledEvents() + + registeringFromAceEvent = true + self:RegisterEvent("LOOT_OPENED", function() + SendAddonMessage("LOOT_OPENED", "", "RAID") + end) + registeringFromAceEvent = nil + + if not self.playerLogin then + registeringFromAceEvent = true + self:RegisterEvent("PLAYER_LOGIN", function() + self.playerLogin = true + end, true) + registeringFromAceEvent = nil + end + + if not self.postInit then + local isReload = true + local function func() + self.postInit = true + self:TriggerEvent("AceEvent_FullyInitialized") + if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then + self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") + end + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + self:UnregisterEvent("MEETINGSTONE_CHANGED") + end + if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then + self:UnregisterEvent("MINIMAP_ZONE_CHANGED") + end + if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then + self:UnregisterEvent("LANGUAGE_LIST_CHANGED") + end + end + registeringFromAceEvent = true + local f = function() + self.playerLogin = true + self:ScheduleEvent("AceEvent_FullyInitialized", func, 1) + end + self:RegisterEvent("MEETINGSTONE_CHANGED", f, true) + self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function() + self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05) + end) + self:RegisterEvent("LANGUAGE_LIST_CHANGED", function() + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + registeringFromAceEvent = true + self:UnregisterEvent("MEETINGSTONE_CHANGED") + self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true) + registeringFromAceEvent = nil + end + end) + self:ScheduleEvent("AceEvent_FullyInitialized", func, 10) + registeringFromAceEvent = nil + end + + self.super.activate(self, oldLib, oldDeactivate) + if oldLib then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate) +AceEvent = AceLibrary(MAJOR_VERSION) diff --git a/Libs/AceLibrary/AceLibrary.lua b/Libs/AceLibrary/AceLibrary.lua new file mode 100644 index 0000000..0f2b237 --- /dev/null +++ b/Libs/AceLibrary/AceLibrary.lua @@ -0,0 +1,757 @@ +--[[ +Name: AceLibrary +Revision: $Rev: 17722 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Iriel (iriel@vigilance-committee.org) + Tekkub (tekkub@gmail.com) + Revision: $Rev: 17722 $ +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceLibrary +SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary +Description: Versioning library to handle other library instances, upgrading, + and proper access. + It also provides a base for libraries to work off of, providing + proper error tools. It is handy because all the errors occur in the + file that called it, not in the library file itself. +Dependencies: None +]] + +local ACELIBRARY_MAJOR = "AceLibrary" +local ACELIBRARY_MINOR = "$Revision: 17722 $" + +if loadstring("return function(...) return ... end") and AceLibrary and AceLibrary:HasInstance(ACELIBRARY_MAJOR) then return end -- lua51 check +local table_setn +do + local version = GetBuildInfo() + if string.find(version, "^2%.") then + -- 2.0.0 + table_setn = function() end + else + table_setn = table.setn + end +end + +local string_gfind = string.gmatch or string.gfind + +local _G = getfenv(0) +local previous = _G[ACELIBRARY_MAJOR] +if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end + +local function safecall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) + local success, err = pcall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) + if not success then geterrorhandler()(err) end +end + +-- @table AceLibrary +-- @brief System to handle all versioning of libraries. +local AceLibrary = {} +local AceLibrary_mt = {} +setmetatable(AceLibrary, AceLibrary_mt) + +local tmp +local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + if type(self) ~= "table" then + _G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2) + end + if not tmp then + tmp = {} + else + for k in pairs(tmp) do tmp[k] = nil end + table_setn(tmp, 0) + end + + table.insert(tmp, a1) + table.insert(tmp, a2) + table.insert(tmp, a3) + table.insert(tmp, a4) + table.insert(tmp, a5) + table.insert(tmp, a6) + table.insert(tmp, a7) + table.insert(tmp, a8) + table.insert(tmp, a9) + table.insert(tmp, a10) + table.insert(tmp, a11) + table.insert(tmp, a12) + table.insert(tmp, a13) + table.insert(tmp, a14) + table.insert(tmp, a15) + table.insert(tmp, a16) + table.insert(tmp, a17) + table.insert(tmp, a18) + table.insert(tmp, a19) + table.insert(tmp, a20) + + local stack = debugstack() + if not message then + local _,_,second = string.find(stack, "\n(.-)\n") + message = "error raised! " .. second + else + for i = 1,table.getn(tmp) do + tmp[i] = tostring(tmp[i]) + end + for i = 1,10 do + table.insert(tmp, "nil") + end + message = string.format(message, unpack(tmp)) + end + + if getmetatable(self) and getmetatable(self).__tostring then + message = string.format("%s: %s", tostring(self), message) + elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then + message = string.format("%s: %s", self:GetLibraryVersion(), message) + elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then + message = string.format("%s: %s", self.class:GetLibraryVersion(), message) + end + + local first = string.gsub(stack, "\n.*", "") + local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1") + file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + + local i = 0 + for s in string_gfind(stack, "\n([^\n]*)") do + i = i + 1 + if not string.find(s, file .. "%.lua:%d+:") then + file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1") + file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + break + end + end + local j = 0 + for s in string_gfind(stack, "\n([^\n]*)") do + j = j + 1 + if j > i and not string.find(s, file .. "%.lua:%d+:") then + _G.error(message, j + 1) + return + end + end + _G.error(message, 2) + return +end + +local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + if not condition then + if not message then + local stack = debugstack() + local _,_,second = string.find(stack, "\n(.-)\n") + message = "assertion failed! " .. second + end + error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + return + end + return condition +end + +local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) + if type(num) ~= "number" then + error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) + elseif type(kind) ~= "string" then + error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) + end + local errored = false + arg = type(arg) + if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then + local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])") + if not func then + _,_,func = string.find(debugstack(), "([`<].-['>])") + end + if kind5 then + error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) + elseif kind4 then + error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) + elseif kind3 then + error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) + elseif kind2 then + error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) + else + error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) + end + end +end + +local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + if not a1 then + error(self, string.gsub(a2, ".-%.lua:%d-: ", "")) + else + return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 + end +end + +local recurse = {} +local function addToPositions(t, major) + if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then + rawset(t, recurse, true) + AceLibrary.positions[t] = major + for k,v in pairs(t) do + if type(v) == "table" and not rawget(v, recurse) then + addToPositions(v, major) + end + if type(k) == "table" and not rawget(k, recurse) then + addToPositions(k, major) + end + end + local mt = getmetatable(t) + if mt and not rawget(mt, recurse) then + addToPositions(mt, major) + end + rawset(t, recurse, nil) + end +end + +local function svnRevisionToNumber(text) + if type(text) == "string" then + if string.find(text, "^%$Revision: (%d+) %$$") then + return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1"))) + elseif string.find(text, "^%$Rev: (%d+) %$$") then + return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1"))) + elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then + return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1"))) + end + elseif type(text) == "number" then + return text + end + return nil +end + +local crawlReplace +do + local recurse = {} + local function func(t, to, from) + if recurse[t] then + return + end + recurse[t] = true + local mt = getmetatable(t) + setmetatable(t, nil) + rawset(t, to, rawget(t, from)) + rawset(t, from, nil) + for k,v in pairs(t) do + if v == from then + t[k] = to + elseif type(v) == "table" then + if not recurse[v] then + func(v, to, from) + end + end + + if type(k) == "table" then + if not recurse[k] then + func(k, to, from) + end + end + end + setmetatable(t, mt) + if mt then + if mt == from then + setmetatable(t, to) + elseif not recurse[mt] then + func(mt, to, from) + end + end + end + function crawlReplace(t, to, from) + func(t, to, from) + for k in pairs(recurse) do + recurse[k] = nil + end + end +end + +-- @function destroyTable +-- @brief remove all the contents of a table +-- @param t table to destroy +local function destroyTable(t) + setmetatable(t, nil) + for k,v in pairs(t) do t[k] = nil end + table_setn(t, 0) +end + +local function isFrame(frame) + return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" +end + +local new, del +do + local tables = setmetatable({}, {__mode = "k"}) + + function new() + local t = next(tables) + if t then + tables[t] = nil + return t + else + return {} + end + end + + function del(t, depth) + if depth and depth > 0 then + for k,v in pairs(t) do + if type(v) == "table" and not isFrame(v) then + del(v, depth - 1) + end + end + end + destroyTable(t) + tables[t] = true + end +end + +-- @function copyTable +-- @brief Create a shallow copy of a table and return it. +-- @param from The table to copy from +-- @return A shallow copy of the table +local function copyTable(from) + local to = new() + for k,v in pairs(from) do to[k] = v end + table_setn(to, table.getn(from)) + setmetatable(to, getmetatable(from)) + return to +end + +-- @function deepTransfer +-- @brief Fully transfer all data, keeping proper previous table +-- backreferences stable. +-- @param to The table with which data is to be injected into +-- @param from The table whose data will be injected into the first +-- @param saveFields If available, a shallow copy of the basic data is saved +-- in here. +-- @param list The account of table references +-- @param list2 The current status on which tables have been traversed. +local deepTransfer +do + -- @function examine + -- @brief Take account of all the table references to be shared + -- between the to and from tables. + -- @param to The table with which data is to be injected into + -- @param from The table whose data will be injected into the first + -- @param list An account of the table references + local function examine(to, from, list, major) + list[from] = to + for k,v in pairs(from) do + if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then + if from[k] == to[k] then + list[from[k]] = to[k] + elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then + list[from[k]] = from[k] + elseif not list[from[k]] then + examine(to[k], from[k], list, major) + end + end + end + return list + end + + function deepTransfer(to, from, saveFields, major, list, list2) + setmetatable(to, nil) + local createdList + if not list then + createdList = true + list = new() + list2 = new() + examine(to, from, list, major) + end + list2[to] = to + for k,v in pairs(to) do + if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then + if saveFields then + saveFields[k] = v + end + to[k] = nil + elseif v ~= _G then + if saveFields then + saveFields[k] = copyTable(v) + end + end + end + for k in pairs(from) do + if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then + if not list2[to[k]] then + deepTransfer(to[k], from[k], nil, major, list, list2) + end + to[k] = list[to[k]] or list2[to[k]] + else + rawset(to, k, from[k]) + end + end + table_setn(to, table.getn(from)) + setmetatable(to, getmetatable(from)) + local mt = getmetatable(to) + if mt then + if list[mt] then + setmetatable(to, list[mt]) + elseif mt.__index and list[mt.__index] then + mt.__index = list[mt.__index] + end + end + destroyTable(from) + if createdList then + del(list) + del(list2) + end + end +end + +-- @method TryToLoadStandalone +-- @brief Attempt to find and load a standalone version of the requested library +-- @param major A string representing the major version +-- @return If library is found, return values from the call to LoadAddOn are returned +-- If the library has been requested previously, nil is returned. +local function TryToLoadStandalone(major) + if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end + if AceLibrary.scannedlibs[major] then return end + + AceLibrary.scannedlibs[major] = true + + local name, _, _, enabled, loadable = GetAddOnInfo(major) + if loadable then + return LoadAddOn(name) + end + + for i=1,GetNumAddOns() do + if GetAddOnMetadata(i, "X-AceLibrary-"..major) then + local name, _, _, enabled, loadable = GetAddOnInfo(i) + if loadable then + return LoadAddOn(name) + end + end + end +end + +-- @method IsNewVersion +-- @brief Obtain whether the supplied version would be an upgrade to the +-- current version. This allows for bypass code in library +-- declaration. +-- @param major A string representing the major version +-- @param minor An integer or an svn revision string representing the minor version +-- @return whether the supplied version would be newer than what is +-- currently available. +function AceLibrary:IsNewVersion(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) + end + end + argCheck(self, minor, 3, "number") + local data = self.libs[major] + if not data then + return true + end + return data.minor < minor +end + +-- @method HasInstance +-- @brief Returns whether an instance exists. This allows for optional support of a library. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return Whether an instance exists. +function AceLibrary:HasInstance(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) + end + end + argCheck(self, minor, 3, "number") + if not self.libs[major] then + return + end + return self.libs[major].minor == minor + end + return self.libs[major] and true +end + +-- @method GetInstance +-- @brief Returns the library with the given major/minor version. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return The library with the given major/minor version. +function AceLibrary:GetInstance(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + local data = self.libs[major] + if not data then + _G.error(string.format("Cannot find a library instance of %s.", major), 2) + return + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) + end + end + argCheck(self, minor, 2, "number") + if data.minor ~= minor then + _G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2) + return + end + end + return data.instance +end + +-- Syntax sugar. AceLibrary("FooBar-1.0") +AceLibrary_mt.__call = AceLibrary.GetInstance + +local donothing + +local AceEvent + +-- @method Register +-- @brief Registers a new version of a given library. +-- @param newInstance the library to register +-- @param major the major version of the library +-- @param minor the minor version of the library +-- @param activateFunc (optional) A function to be called when the library is +-- fully activated. Takes the arguments +-- (newInstance [, oldInstance, oldDeactivateFunc]). If +-- oldInstance is given, you should probably call +-- oldDeactivateFunc(oldInstance). +-- @param deactivateFunc (optional) A function to be called by a newer library's +-- activateFunc. +-- @param externalFunc (optional) A function to be called whenever a new +-- library is registered. +function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) + argCheck(self, newInstance, 2, "table") + argCheck(self, major, 3, "string") + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) + end + end + argCheck(self, minor, 4, "number") + if math.floor(minor) ~= minor or minor < 0 then + error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) + end + argCheck(self, activateFunc, 5, "function", "nil") + argCheck(self, deactivateFunc, 6, "function", "nil") + argCheck(self, externalFunc, 7, "function", "nil") + if not deactivateFunc then + if not donothing then + donothing = function() end + end + deactivateFunc = donothing + end + local data = self.libs[major] + if not data then + -- This is new + local instance = copyTable(newInstance) + crawlReplace(instance, instance, newInstance) + destroyTable(newInstance) + if AceLibrary == newInstance then + self = instance + AceLibrary = instance + end + self.libs[major] = { + instance = instance, + minor = minor, + deactivateFunc = deactivateFunc, + externalFunc = externalFunc, + } + rawset(instance, 'GetLibraryVersion', function(self) + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + addToPositions(instance, major) + if activateFunc then + safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil + end + + if externalFunc then + for k,data in pairs(self.libs) do + if k ~= major then + safecall(externalFunc, instance, k, data.instance) + end + end + end + + for k,data in pairs(self.libs) do + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end + if major == "AceEvent-2.0" then + AceEvent = instance + end + if AceEvent then + AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) + end + + return instance + end + local instance = data.instance + if minor <= data.minor then + -- This one is already obsolete, raise an error. + _G.error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2) + return + end + -- This is an update + local oldInstance = new() + + addToPositions(newInstance, major) + local isAceLibrary = (AceLibrary == newInstance) + local old_error, old_assert, old_argCheck, old_pcall + if isAceLibrary then + self = instance + AceLibrary = instance + + old_error = instance.error + old_assert = instance.assert + old_argCheck = instance.argCheck + old_pcall = instance.pcall + + self.error = error + self.assert = assert + self.argCheck = argCheck + self.pcall = pcall + end + deepTransfer(instance, newInstance, oldInstance, major) + crawlReplace(instance, instance, newInstance) + local oldDeactivateFunc = data.deactivateFunc + data.minor = minor + data.deactivateFunc = deactivateFunc + data.externalFunc = externalFunc + rawset(instance, 'GetLibraryVersion', function(self) + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + if isAceLibrary then + for _,v in pairs(self.libs) do + local i = type(v) == "table" and v.instance + if type(i) == "table" then + if not rawget(i, 'error') or i.error == old_error then + rawset(i, 'error', error) + end + if not rawget(i, 'assert') or i.assert == old_assert then + rawset(i, 'assert', assert) + end + if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then + rawset(i, 'argCheck', argCheck) + end + if not rawget(i, 'pcall') or i.pcall == old_pcall then + rawset(i, 'pcall', pcall) + end + end + end + end + if activateFunc then + safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) + else + safecall(oldDeactivateFunc, oldInstance) + end + del(oldInstance) + + if externalFunc then + for k,data in pairs(self.libs) do + if k ~= major then + safecall(externalFunc, instance, k, data.instance) + end + end + end + + return instance +end + +local iter +function AceLibrary:IterateLibraries() + if not iter then + local function iter(t, k) + k = next(t, k) + if not k then + return nil + else + return k, t[k].instance + end + end + end + return iter, self.libs, nil +end + +-- @function Activate +-- @brief The activateFunc for AceLibrary itself. Called when +-- AceLibrary properly registers. +-- @param self Reference to AceLibrary +-- @param oldLib (optional) Reference to an old version of AceLibrary +-- @param oldDeactivate (optional) Function to deactivate the old lib +local function activate(self, oldLib, oldDeactivate) + if not self.libs then + if oldLib then + self.libs = oldLib.libs + self.scannedlibs = oldLib.scannedlibs + end + if not self.libs then + self.libs = {} + end + if not self.scannedlibs then + self.scannedlibs = {} + end + end + if not self.positions then + if oldLib then + self.positions = oldLib.positions + end + if not self.positions then + self.positions = setmetatable({}, { __mode = "k" }) + end + end + + -- Expose the library in the global environment + _G[ACELIBRARY_MAJOR] = self + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +if not previous then + previous = AceLibrary +end +if not previous.libs then + previous.libs = {} +end +AceLibrary.libs = previous.libs +if not previous.positions then + previous.positions = setmetatable({}, { __mode = "k" }) +end +AceLibrary.positions = previous.positions +AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate) diff --git a/Libs/AceOO-2.0/AceOO-2.0.lua b/Libs/AceOO-2.0/AceOO-2.0.lua new file mode 100644 index 0000000..1bbf52c --- /dev/null +++ b/Libs/AceOO-2.0/AceOO-2.0.lua @@ -0,0 +1,1006 @@ +--[[ +Name: AceOO-2.0 +Revision: $Rev: 17638 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceOO-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 +Description: Library to provide an object-orientation framework. +Dependencies: AceLibrary +]] + +local MAJOR_VERSION = "AceOO-2.0" +local MINOR_VERSION = "$Revision: 17639 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check +local table_setn +do + local version = GetBuildInfo() + if string.find(version, "^2%.") then + -- 2.0.0 + table_setn = function() end + else + table_setn = table.setn + end +end + +local AceOO = { + error = AceLibrary.error, + argCheck = AceLibrary.argCheck +} + +-- @function getuid +-- @brief Obtain a unique string identifier for the object in question. +-- @param t The object to obtain the uid for. +-- @return The uid string. +local function pad(cap) + return string.rep('0', 8 - string.len(cap)) .. cap +end +local function getuid(t) + local mt = getmetatable(t) + setmetatable(t, nil) + local str = tostring(t) + setmetatable(t, mt) + local _,_,cap = string.find(str, '[^:]*: 0x(.*)$') + if cap then return pad(cap) end + _,_,cap = string.find(str, '[^:]*: (.*)$') + if cap then return pad(cap) end +end + +local function getlibrary(o) + if type(o) == "table" then + return o + elseif type(o) == "string" then + if not AceLibrary:HasInstance(o) then + AceOO:error("Library %q does not exist.", o) + end + return AceLibrary(o) + end +end + +-- @function Factory +-- @brief Construct a factory for the creation of objects. +-- @param obj The object whose init method will be called on the new factory +-- object. +-- @param newobj The object whose init method will be called on the new +-- objects that the Factory creates, to initialize them. +-- @param (a1..a20) Arguments which will be passed to obj.init() in addition +-- to the Factory object. +-- @return The new factory which creates a newobj when its new method is called, +-- or when it is called directly (__call metamethod). +local Factory +do + local function new(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + local t = {} + local uid = getuid(t) + local l = getlibrary + obj:init(t, l(a1), l(a2), l(a3), l(a4), l(a5), l(a6), l(a7), + l(a8), l(a9), l(a10), l(a11), l(a12), l(a13), + l(a14), l(a15), l(a16), l(a17), l(a18), l(a19), + l(a20)) + t.uid = uid + return t + end + + local function createnew(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, + a19, a20) + local o = self.prototype + local l = getlibrary + return new(o, l(a1), l(a2), l(a3), l(a4), l(a5), l(a6), l(a7), + l(a8), l(a9), l(a10), l(a11), l(a12), l(a13), + l(a14), l(a15), l(a16), l(a17), l(a18), l(a19), + l(a20)) + end + + function Factory(obj, newobj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, + a19, a20) + local t = new(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + t.prototype = newobj + t.new = createnew + getmetatable(t).__call = t.new + return t + end +end + + +local function objtostring(self) + if self.ToString then + return self:ToString() + elseif self.GetLibraryVersion then + return (self:GetLibraryVersion()) + elseif self.super then + local s = "Sub-" .. tostring(self.super) + local first = true + if self.interfaces then + for interface in pairs(self.interfaces) do + if first then + s = s .. "(" .. tostring(interface) + first = false + else + s = s .. ", " .. tostring(interface) + end + end + end + if self.mixins then + for mixin in pairs(self.mixins) do + if first then + s = s .. tostring(mixin) + first = false + else + s = s .. ", " .. tostring(mixin) + end + end + end + if first then + if self.uid then + return s .. ":" .. self.uid + else + return s + end + else + return s .. ")" + end + else + return self.uid and 'Subclass:' .. self.uid or 'Subclass' + end +end + +-- @table Object +-- @brief Base of all objects, including Class. +-- +-- @method init +-- @brief Initialize a new object. +-- @param newobject The object to initialize +-- @param class The class to make newobject inherit from +local Object +do + Object = {} + function Object:init(newobject, class) + local parent = class or self + if not rawget(newobject, 'uid') then + newobject.uid = getuid(newobject) + end + local mt = { + __index = parent, + __tostring = objtostring, + } + setmetatable(newobject, mt) + end + Object.uid = getuid(Object) + setmetatable(Object, { __tostring = function() return 'Object' end }) +end + +local Interface + +local function validateInterface(object, interface) + if not object.class and object.prototype then + object = object.prototype + end + for k,v in pairs(interface.interface) do + if tostring(type(object[k])) ~= v then + return false + end + end + if interface.superinterfaces then + for superinterface in pairs(interface.superinterfaces) do + if not validateInterface(object, superinterface) then + return false + end + end + end + if type(object.class) == "table" and rawequal(object.class.prototype, object) then + if not object.class.interfaces then + rawset(object.class, 'interfaces', {}) + end + object.class.interfaces[interface] = true + elseif type(object.class) == "table" and type(object.class.prototype) == "table" then + validateInterface(object.class.prototype, interface) + -- check if class is proper, thus preventing future checks. + end + return true +end + +-- @function inherits +-- @brief Return whether an Object or Class inherits from a given +-- parent. +-- @param object Object or Class to check +-- @param parent Parent to test inheritance from +-- @return whether an Object or Class inherits from a given +-- parent. +local function inherits(object, parent) + object = getlibrary(object) + if type(parent) == "string" then + if not AceLibrary:HasInstance(parent) then + return false + else + parent = AceLibrary(parent) + end + end + AceOO:argCheck(parent, 2, "table") + if type(object) ~= "table" then + return false + end + local current + if object.class then + current = object.class + else + current = object + end + if type(current) ~= "table" then + return false + end + if rawequal(current, parent) then + return true + end + if parent.class then + while true do + if rawequal(current, Object) then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if rawequal(mixin, parent) then + return true + end + end + end + if current.interfaces then + for interface in pairs(current.interfaces) do + if rawequal(interface, parent) then + return true + end + end + end + current = current.super + if type(current) ~= "table" then + break + end + end + + local isInterface = false + local curr = parent.class + while true do + if rawequal(curr, Object) then + break + elseif rawequal(curr, Interface) then + isInterface = true + break + end + curr = curr.super + if type(curr) ~= "table" then + break + end + end + return isInterface and validateInterface(object, parent) + else + while true do + if rawequal(current, parent) then + return true + elseif rawequal(current, Object) then + return false + end + current = current.super + if type(current) ~= "table" then + return false + end + end + end +end + +-- @table Class +-- @brief An object factory which sets up inheritence and supports +-- 'mixins'. +-- +-- @metamethod Class call +-- @brief Call ClassFactory:new() to create a new class. +-- +-- @method Class new +-- @brief Construct a new object. +-- @param (a1..a20) Arguments to pass to the object init function. +-- @return The new object. +-- +-- @method Class init +-- @brief Initialize a new class. +-- @param parent Superclass. +-- @param (a1..a20) Mixins. +-- +-- @method Class ToString +-- @return A string representing the object, in this case 'Class'. +local initStatus +local Class +local Mixin +local autoEmbed = false +local function traverseInterfaces(bit, total) + if bit.superinterfaces then + for interface in pairs(bit.superinterfaces) do + if not total[interface] then + total[interface] = true + traverseInterfaces(interface, total) + end + end + end +end +local class_new +do + Class = Factory(Object, setmetatable({}, {__index = Object}), Object) + Class.super = Object + + local function protostring(t) + return '<' .. tostring(t.class) .. ' prototype>' + end + local function classobjectstring(t) + if t.ToString then + return t:ToString() + elseif t.GetLibraryVersion then + return (t:GetLibraryVersion()) + else + return '<' .. tostring(t.class) .. ' instance>' + end + end + local function classobjectequal(self, other) + if type(self) == "table" and self.Equals then + return self:Equals(other) + elseif type(other) == "table" and other.Equals then + return other:Equals(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) == 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) == 0 + else + return rawequal(self, other) + end + end + local function classobjectlessthan(self, other) + if type(self) == "table" and self.IsLessThan then + return self:IsLessThan(other) + elseif type(other) == "table" and other.IsLessThanOrEqualTo then + return not other:IsLessThanOrEqualTo(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) < 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) > 0 + elseif type(other) == "table" and other.IsLessThan and other.Equals then + return other:Equals(self) or other:IsLessThan(self) + else + AceOO:error("cannot compare two objects") + end + end + local function classobjectlessthanequal(self, other) + if type(self) == "table" and self.IsLessThanOrEqualTo then + return self:IsLessThanOrEqualTo(other) + elseif type(other) == "table" and other.IsLessThan then + return not other:IsLessThan(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) <= 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) >= 0 + elseif type(self) == "table" and self.IsLessThan and self.Equals then + return self:Equals(other) or self:IsLessThan(other) + else + AceOO:error("cannot compare two incompatible objects") + end + end + local function classobjectadd(self, other) + if type(self) == "table" and self.Add then + return self:Add(other) + else + AceOO:error("cannot add two incompatible objects") + end + end + local function classobjectsub(self, other) + if type(self) == "table" and self.Subtract then + return self:Subtract(other) + else + AceOO:error("cannot subtract two incompatible objects") + end + end + local function classobjectunm(self, other) + if type(self) == "table" and self.UnaryNegation then + return self:UnaryNegation(other) + else + AceOO:error("attempt to negate an incompatible object") + end + end + local function classobjectmul(self, other) + if type(self) == "table" and self.Multiply then + return self:Multiply(other) + else + AceOO:error("cannot multiply two incompatible objects") + end + end + local function classobjectdiv(self, other) + if type(self) == "table" and self.Divide then + return self:Divide(other) + else + AceOO:error("cannot divide two incompatible objects") + end + end + local function classobjectpow(self, other) + if type(self) == "table" and self.Exponent then + return self:Exponent(other) + else + AceOO:error("cannot exponentiate two incompatible objects") + end + end + local function classobjectconcat(self, other) + if type(self) == "table" and self.Concatenate then + return self:Concatenate(other) + else + AceOO:error("cannot concatenate two incompatible objects") + end + end + function class_new(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + if self.virtual then + AceOO:error("Cannot instantiate a virtual class.") + end + + local o = self.prototype + local newobj = {} + if o.class and o.class.instancemeta then + setmetatable(newobj, o.class.instancemeta) + else + Object:init(newobj, o) + end + + if self.interfaces and not self.interfacesVerified then + -- Verify the interfaces + + for interface in pairs(self.interfaces) do + for field,kind in pairs(interface.interface) do + if tostring(type(newobj[field])) ~= kind then + AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) + end + end + end + self.interfacesVerified = true + end + local tmp = initStatus + initStatus = newobj + newobj:init(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + if initStatus then + initStatus = tmp + AceOO:error("Initialization not completed, be sure to call the superclass's init method.") + return + end + initStatus = tmp + return newobj + end + local classmeta = { + __tostring = objtostring, + __call = function(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + return self:new(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20) + end, + } + function Class:init(newclass, parent, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20) + parent = parent or self + + local total + + if parent.class then + total = { + parent, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20 + } + parent = self + else + total = { + a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20 + } + end + if not inherits(parent, Class) then + AceOO:error("Classes must inherit from a proper class") + end + if parent.sealed then + AceOO:error("Cannot inherit from a sealed class") + end + for i,v in ipairs(total) do + if inherits(v, Mixin) and v.class then + if not newclass.mixins then + newclass.mixins = {} + end + if newclass.mixins[v] then + AceOO:error("Cannot explicitly inherit from the same mixin twice") + end + newclass.mixins[v] = true + elseif inherits(v, Interface) and v.class then + if not newclass.interfaces then + newclass.interfaces = {} + end + if newclass.interfaces[v] then + AceOO:error("Cannot explicitly inherit from the same interface twice") + end + newclass.interfaces[v] = true + else + AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") + end + end + if parent.interfaces then + if newclass.interfaces then + for interface in pairs(parent.interfaces) do + newclass.interfaces[interface] = true + end + else + newclass.interfaces = parent.interfaces + end + end + for k in pairs(total) do + total[k] = nil + end + table_setn(total, 0) + + newclass.super = parent + + newclass.prototype = setmetatable(total, { + __index = parent.prototype, + __tostring = protostring, + }) + total = nil + + newclass.instancemeta = { + __index = newclass.prototype, + __tostring = classobjectstring, + __eq = classobjectequal, + __lt = classobjectlessthan, + __le = classobjectlessthanequal, + __add = classobjectadd, + __sub = classobjectsub, + __unm = classobjectunm, + __mul = classobjectmul, + __div = classobjectdiv, + __pow = classobjectpow, + __concat = classobjectconcat, + } + + setmetatable(newclass, classmeta) + + newclass.new = class_new + + if newclass.mixins then + -- Fold in the mixins + local err, msg + for mixin in pairs(newclass.mixins) do + local ret + autoEmbed = true + ret, msg = pcall(mixin.embed, mixin, newclass.prototype) + autoEmbed = false + if not ret then + err = true + break + end + end + + if err then + local pt = newclass.prototype + for k,v in pairs(pt) do + pt[k] = nil + end + + -- method conflict + AceOO:error(msg) + end + end + + newclass.prototype.class = newclass + + if newclass.interfaces then + for interface in pairs(newclass.interfaces) do + traverseInterfaces(interface, newclass.interfaces) + end + end + if newclass.mixins then + for mixin in pairs(newclass.mixins) do + if mixin.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(mixin.interfaces) do + newclass.interfaces[interface] = true + end + end + end + end + end + function Class:ToString() + if type(self.GetLibraryVersion) == "function" then + return (self:GetLibraryVersion()) + else + return "Class" + end + end + + local tmp + function Class.prototype:init() + if rawequal(self, initStatus) then + initStatus = nil + else + AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) + end + self.uid = getuid(self) + local current = self.class + while true do + if current == Class then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnInstanceInit) == "function" then + mixin:OnInstanceInit(self) + end + end + end + current = current.super + end + end +end + + +-- @object ClassFactory +-- @brief A factory for creating classes. Rarely used directly. +local ClassFactory = Factory(Object, Class, Object) + +function Class:new(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20) + local x = ClassFactory:new(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20) + if AceOO.classes then + AceOO.classes[x] = true + end + return x +end +getmetatable(Class).__call = Class.new + +-- @class Mixin +-- @brief A class to create mixin objects, which contain methods that get +-- "mixed in" to class prototypes. +-- +-- @object Mixin prototype +-- @brief The prototype that mixin objects inherit their methods from. +-- +-- @method Mixin prototype embed +-- @brief Mix in the methods of our object which are listed in our interface +-- to the supplied target table. +-- +-- @method Mixin prototype init +-- @brief Initialize the mixin object. +-- @param newobj The new object we're initializing. +-- @param interface The interface we implement (the list of methods our +-- prototype provides which should be mixed into the target +-- table by embed). +do + Mixin = Class() + function Mixin:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Mixin' + end + end + local function _Embed(state, field, target) + field = next(state.export, field) + if field == nil then + return + end + + if rawget(target, field) or (target[field] and target[field] ~= state[field]) then + AceOO:error("Method conflict in attempt to mixin. Field %q", field) + end + + target[field] = state[field] + + local ret,msg = pcall(_Embed, state, field, target) + if not ret then + -- Mix in the next method according to the defined interface. If that + -- fails due to a conflict, re-raise to back out the previous mixed + -- methods. + + target[field] = nil + AceOO:error(msg) + end + end + function Mixin.prototype:embed(target) + local mt = getmetatable(target) + setmetatable(target, nil) + local err, msg = pcall(_Embed, self, nil, target) + if not err then + setmetatable(target, mt) + AceOO:error(msg) + return + end + if type(self.embedList) == "table" then + self.embedList[target] = true + end + if type(target.class) ~= "table" then + target[self] = true + end + if not autoEmbed and type(self.OnManualEmbed) == "function" then + if not target.modules then + self:OnManualEmbed(target) + end + end + setmetatable(target, mt) + end + + function Mixin.prototype:activate(oldLib, oldDeactivate) + if oldLib and oldLib.embedList then + for target in pairs(oldLib.embedList) do + local mt = getmetatable(target) + setmetatable(target, nil) + for field in pairs(oldLib.export) do + target[field] = nil + end + setmetatable(target, mt) + end + self.embedList = oldLib.embedList + for target in pairs(self.embedList) do + self:embed(target) + end + else + self.embedList = setmetatable({}, {__mode="k"}) + end + end + + function Mixin.prototype:init(export, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, + a17, a18, a19, a20) + AceOO:argCheck(export, 2, "table") + for k,v in pairs(export) do + if type(k) ~= "number" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + end + end + local num = table.getn(export) + for i = 1, num do + local v = export[i] + export[i] = nil + export[v] = true + end + table_setn(export, 0) + local interfaces + if a1 then + local l = getlibrary + interfaces = { l(a1), l(a2), l(a3), l(a4), l(a5), l(a6), l(a7), l(a8), + l(a9), l(a10), l(a11), l(a12), l(a13), l(a14), l(a15), l(a16), + l(a17), l(a18), l(a19), l(a20) } + for _,v in ipairs(interfaces) do + if not v.class or not inherits(v, Interface) then + AceOO:error("Mixins can inherit only from interfaces") + end + end + local num = table.getn(interfaces) + for i = 1, num do + local v = interfaces[i] + interfaces[i] = nil + interfaces[v] = true + end + table_setn(interfaces, 0) + for interface in pairs(interfaces) do + traverseInterfaces(interface, interfaces) + end + for interface in pairs(interfaces) do + for field,kind in pairs(interface.interface) do + if kind ~= "nil" then + local good = false + for bit in pairs(export) do + if bit == field then + good = true + break + end + end + if not good then + AceOO:error("Mixin does not fully accommodate field %q", field) + end + end + end + end + end + self.super = Mixin.prototype + Mixin.super.prototype.init(self) + self.export = export + self.interfaces = interfaces + end +end + +-- @class Interface +-- @brief A class to create interfaces, which contain contracts that classes +-- which inherit from this must comply with. +-- +-- @object Interface prototype +-- @brief The prototype that interface objects must adhere to. +-- +-- @method Interface prototype init +-- @brief Initialize the mixin object. +-- @param interface The interface we contract (the hash of fields forced). +-- @param (a1..a20) Superinterfaces +do + Interface = Class() + function Interface:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Instance' + end + end + function Interface.prototype:init(interface, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + Interface.super.prototype.init(self) + AceOO:argCheck(interface, 2, "table") + for k,v in pairs(interface) do + if type(k) ~= "string" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then + AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') + end + end + local l = getlibrary + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = l(a1), l(a2), l(a3), l(a4), l(a5), l(a6), l(a7), l(a8), l(a9), l(a10), l(a11), l(a12), l(a13), l(a14), l(a15), l(a16), l(a17), l(a18), l(a19), l(a20) + if a1 then + self.superinterfaces = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20} + for k,v in ipairs(self.superinterfaces) do + if not inherits(v, Interface) or not v.class then + AceOO:error('Cannot provide a non-Interface to inherit from') + end + end + local num = table.getn(self.superinterfaces) + for i = 1, num do + local v = self.superinterfaces[i] + self.superinterfaces[i] = nil + self.superinterfaces[v] = true + end + table_setn(self.superinterfaces, 0) + end + self.interface = interface + end +end + +-- @function Classpool +-- @brief Obtain a read only class from our pool of classes, indexed by the +-- superclass and mixins. +-- @param sc The superclass of the class we want. +-- @param (m1..m20) Mixins of the class we want's objects. +-- @return A read only class from the class pool. +local Classpool +do + local pool = setmetatable({}, {__mode = 'v'}) + local function newindex(k, v) + AceOO:error('Attempt to modify a read-only class.') + end + local function protonewindex(k, v) + AceOO:error('Attempt to modify a read-only class prototype.') + end + local function ts(bit) + if type(bit) ~= "table" then + return tostring(bit) + elseif getmetatable(bit) and bit.__tostring then + return tostring(bit) + elseif type(bit.GetLibraryVersion) == "function" then + return bit:GetLibraryVersion() + else + return tostring(bit) + end + end + local t + local function getcomplexuid(sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, + m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20) + if not t then t = {} end + if sc then if sc.uid then table.insert(t, sc.uid) else AceOO:error("%s is not an appropriate class/mixin", ts(sc)) end + if m1 then if m1.uid then table.insert(t, m1.uid) else AceOO:error("%s is not an appropriate mixin", ts(m1)) end + if m2 then if m2.uid then table.insert(t, m2.uid) else AceOO:error("%s is not an appropriate mixin", ts(m2)) end + if m3 then if m3.uid then table.insert(t, m3.uid) else AceOO:error("%s is not an appropriate mixin", ts(m3)) end + if m4 then if m4.uid then table.insert(t, m4.uid) else AceOO:error("%s is not an appropriate mixin", ts(m4)) end + if m5 then if m5.uid then table.insert(t, m5.uid) else AceOO:error("%s is not an appropriate mixin", ts(m5)) end + if m6 then if m6.uid then table.insert(t, m6.uid) else AceOO:error("%s is not an appropriate mixin", ts(m6)) end + if m7 then if m7.uid then table.insert(t, m7.uid) else AceOO:error("%s is not an appropriate mixin", ts(m7)) end + if m8 then if m8.uid then table.insert(t, m8.uid) else AceOO:error("%s is not an appropriate mixin", ts(m8)) end + if m9 then if m9.uid then table.insert(t, m9.uid) else AceOO:error("%s is not an appropriate mixin", ts(m9)) end + if m10 then if m10.uid then table.insert(t, m10.uid) else AceOO:error("%s is not an appropriate mixin", ts(m10)) end + if m11 then if m11.uid then table.insert(t, m11.uid) else AceOO:error("%s is not an appropriate mixin", ts(m11)) end + if m12 then if m12.uid then table.insert(t, m12.uid) else AceOO:error("%s is not an appropriate mixin", ts(m12)) end + if m13 then if m13.uid then table.insert(t, m13.uid) else AceOO:error("%s is not an appropriate mixin", ts(m13)) end + if m14 then if m14.uid then table.insert(t, m14.uid) else AceOO:error("%s is not an appropriate mixin", ts(m14)) end + if m15 then if m15.uid then table.insert(t, m15.uid) else AceOO:error("%s is not an appropriate mixin", ts(m15)) end + if m16 then if m16.uid then table.insert(t, m16.uid) else AceOO:error("%s is not an appropriate mixin", ts(m16)) end + if m17 then if m17.uid then table.insert(t, m17.uid) else AceOO:error("%s is not an appropriate mixin", ts(m17)) end + if m18 then if m18.uid then table.insert(t, m18.uid) else AceOO:error("%s is not an appropriate mixin", ts(m18)) end + if m19 then if m19.uid then table.insert(t, m19.uid) else AceOO:error("%s is not an appropriate mixin", ts(m19)) end + if m20 then if m20.uid then table.insert(t, m20.uid) else AceOO:error("%s is not an appropriate mixin", ts(m20)) end + end end end end end end end end end end end end end end end end end end end end end + table.sort(t) + local uid = table.concat(t, '') + for k in pairs(t) do t[k] = nil end + table_setn(t, 0) + return uid + end + local classmeta + function Classpool(sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, + m10, m11, m12, m13, m14, m15, m16, + m17, m18, m19, m20) + local l = getlibrary + sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20 = l(sc), l(m1), l(m2), l(m3), l(m4), l(m5), l(m6), l(m7), l(m8), l(m9), l(m10), l(m11), l(m12), l(m13), l(m14), l(m15), l(m16), l(m17), l(m18), l(m19), l(m20) + if sc and sc.class then + sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20 = Class, sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19 + end + sc = sc or Class + local key = getcomplexuid(sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20) + if not pool[key] then + local class = Class(sc, m1, m2, m3, m4, m5, m6, m7, m8, m9, + m10, m11, m12, m13, m14, m15, m16, m17, + m18, m19, m20) + if not classmeta then + classmeta = {} + local mt = getmetatable(class) + for k,v in pairs(mt) do + classmeta[k] = v + end + classmeta.__newindex = newindex + end + -- Prevent the user from adding methods to this class. + -- NOTE: I'm not preventing modifications of existing class members, + -- but it's likely that only a truly malicious user will be doing so. + class.sealed = true + setmetatable(class, classmeta) + getmetatable(class.prototype).__newindex = protonewindex + pool[key] = class + end + return pool[key] + end +end + +AceOO.Factory = Factory +AceOO.Object = Object +AceOO.Class = Class +AceOO.Mixin = Mixin +AceOO.Interface = Interface +AceOO.Classpool = Classpool +AceOO.inherits = inherits + +-- Library handling bits + +local function activate(self, oldLib, oldDeactivate) + AceOO = self + Factory = self.Factory + Object = self.Object + Class = self.Class + ClassFactory.prototype = Class + Mixin = self.Mixin + Interface = self.Interface + Classpool = self.Classpool + + if oldLib then + self.classes = oldLib.classes + end + if not self.classes then + self.classes = setmetatable({}, {__mode="k"}) + else + for class in pairs(self.classes) do + class.new = class_new + end + end + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) +AceOO = AceLibrary(MAJOR_VERSION) diff --git a/Outfitter.lua b/Outfitter.lua new file mode 100644 index 0000000..2c3210e --- /dev/null +++ b/Outfitter.lua @@ -0,0 +1,7387 @@ +gOutfitter_Settings = nil; + +Outfitter_cTitleVersion = GetAddOnMetadata( "Outfitter", "Title" ) .. " " .. GetAddOnMetadata( "Outfitter", "Version" ) + +local AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") + +local Outfitter_cInitializationEvent = "PLAYER_ENTERING_WORLD"; + +local BANKED_FONT_COLOR = { r = 0.25, g = 0.2, b = 1.0 }; +local BANKED_FONT_COLOR_CODE = "|cff4033ff"; +local OUTFIT_MESSAGE_COLOR = { r = 0.2, g = 0.75, b = 0.3 }; + +local Outfitter_cSlotNames = { + -- First priority goes to armor + + "HeadSlot", + "ShoulderSlot", + "ChestSlot", + "WristSlot", + "HandsSlot", + "WaistSlot", + "LegsSlot", + "FeetSlot", + + -- Second priority goes to weapons + + "MainHandSlot", + "SecondaryHandSlot", + "RangedSlot", + "AmmoSlot", + + -- Last priority goes to items with no durability + + "BackSlot", + "NeckSlot", + "ShirtSlot", + "TabardSlot", + "Finger0Slot", + "Finger1Slot", + "Trinket0Slot", + "Trinket1Slot", +}; + +local Outfitter_cSlotDisplayNames = { + HeadSlot = HEADSLOT, + NeckSlot = NECKSLOT, + ShoulderSlot = SHOULDERSLOT, + BackSlot = BACKSLOT, + ChestSlot = CHESTSLOT, + ShirtSlot = SHIRTSLOT, + TabardSlot = TABARDSLOT, + WristSlot = WRISTSLOT, + HandsSlot = HANDSSLOT, + WaistSlot = WAISTSLOT, + LegsSlot = LEGSSLOT, + FeetSlot = FEETSLOT, + Finger0Slot = Outfitter_cFinger0SlotName, + Finger1Slot = Outfitter_cFinger1SlotName, + Trinket0Slot = Outfitter_cTrinket0SlotName, + Trinket1Slot = Outfitter_cTrinket1SlotName, + MainHandSlot = MAINHANDSLOT, + SecondaryHandSlot = SECONDARYHANDSLOT, + RangedSlot = RANGEDSLOT, + AmmoSlot = AMMOSLOT, +}; + +local Outfitter_cInvTypeToSlotName = { + INVTYPE_2HWEAPON = { SlotName = "MainHandSlot", MetaSlotName = "TwoHandSlot" }, + INVTYPE_BAG = { SlotName = "Bag" }, + INVTYPE_BODY = { SlotName = "ShirtSlot" }, + INVTYPE_CHEST = { SlotName = "ChestSlot" }, + INVTYPE_CLOAK = { SlotName = "BackSlot" }, + INVTYPE_FEET = { SlotName = "FeetSlot" }, + INVTYPE_FINGER = { SlotName = "Finger0Slot" }, + INVTYPE_HAND = { SlotName = "HandsSlot" }, + INVTYPE_HEAD = { SlotName = "HeadSlot" }, + INVTYPE_HOLDABLE = { SlotName = "SecondaryHandSlot" }, + INVTYPE_LEGS = { SlotName = "LegsSlot" }, + INVTYPE_NECK = { SlotName = "NeckSlot" }, + INVTYPE_RANGED = { SlotName = "RangedSlot" }, + INVTYPE_ROBE = { SlotName = "ChestSlot" }, + INVTYPE_SHIELD = { SlotName = "SecondaryHandSlot" }, + INVTYPE_SHOULDER = { SlotName = "ShoulderSlot" }, + INVTYPE_TABARD = { SlotName = "TabardSlot" }, + INVTYPE_TRINKET = { SlotName = "Trinket0Slot" }, + INVTYPE_WAIST = { SlotName = "WaistSlot" }, + INVTYPE_WEAPON = { SlotName = "MainHandSlot", MetaSlotName = "Weapon0Slot" }, + INVTYPE_WEAPONMAINHAND = { SlotName = "MainHandSlot" }, + INVTYPE_WEAPONOFFHAND = { SlotName = "SecondaryHandSlot" }, + INVTYPE_WRIST = { SlotName = "WristSlot" }, + INVTYPE_RANGEDRIGHT = { SlotName = "RangedSlot" }, + INVTYPE_AMMO = { SlotName = "AmmoSlot" }, + INVTYPE_THROWN = { SlotName = "RangedSlot" }, + INVTYPE_RELIC = { SlotName = "RangedSlot" }, +}; + +local Outfitter_cHalfAlternateStatSlot = { + Trinket0Slot = "Trinket1Slot", + Finger0Slot = "Finger1Slot", + Weapon0Slot = "Weapon1Slot", +}; + +local Outfitter_cFullAlternateStatSlot = { + Trinket0Slot = "Trinket1Slot", + Trinket1Slot = "Trinket0Slot", + Finger0Slot = "Finger1Slot", + Finger1Slot = "Finger0Slot", + Weapon0Slot = "Weapon1Slot", + Weapon1Slot = "Weapon0Slot", +}; + +local gOutfitter_cCategoryOrder = { + "Complete", + "Partial", + "Accessory", + "Special" +}; + +local gOutfitter_Collapsed = {}; +local gOutfitter_BankFrameOpened = false; + +local Outfitter_cItemAliases = { + [18608] = 18609, -- Benediction -> Anathema + [18609] = 18608, -- Anathema -> Benediction + [17223] = 17074, -- Thunderstrike -> Shadowstrike + [17074] = 17223, -- Shadowstrike -> Thunderstrike +}; + +local Outfitter_cSpecialtyBags = { + [21340] = { Name = "Soul Pouch", Type = "ShardBag" }, + [21341] = { Name = "Felcloth Bag", Type = "ShardBag" }, + [21342] = { Name = "Core Felcloth Bag", Type = "ShardBag" }, + [22243] = { Name = "Small Soul Pouch", Type = "ShardBag" }, + [22244] = { Name = "Box of Souls", Type = "ShardBag" }, + + [2102] = { Name = "Small Ammo Pouch", Type = "AmmoPouch" }, + [7279] = { Name = "Small Leather Ammo Pouch", Type = "AmmoPouch" }, + [8218] = { Name = "Thick Leather Ammo Pouch", Type = "AmmoPouch" }, + [7372] = { Name = "Heavy Leather Ammo Pouch", Type = "AmmoPouch" }, + [3574] = { Name = "Hunting Ammo Sack", Type = "AmmoPouch" }, + [3604] = { Name = "Bandolier of the Night Watch", Type = "AmmoPouch" }, + [5441] = { Name = "Small Shot Pouch", Type = "AmmoPouch" }, + [2663] = { Name = "Ribbly's Bandolier", Type = "AmmoPouch" }, + [19320] = { Name = "Gnoll Skin Bandolier", Type = "AmmoPouch" }, + + [19319] = { Name = "Harpy Hide Quiver", Type = "Quiver" }, + [7371] = { Name = "Heavy Quiver", Type = "Quiver" }, + [3573] = { Name = "Hunting Quiver", Type = "Quiver" }, + [7278] = { Name = "Light Leather Quiver", Type = "Quiver" }, + [2101] = { Name = "Light Quiver", Type = "Quiver" }, + [11362] = { Name = "Medium Quiver", Type = "Quiver" }, + [8217] = { Name = "Quickdraw Quiver", Type = "Quiver" }, + [3605] = { Name = "Quiver of the Night Watch", Type = "Quiver" }, + [2662] = { Name = "Ribbly's Quiver", Type = "Quiver" }, + [5439] = { Name = "Small Quiver", Type = "Quiver" }, + [18714] = { Name = "Ancient Sinew Wrapped Lamina", Type = "Quiver" }, + + [22246] = { Name = "Enchanted Mageweave Pouch", Type = "Enchant" }, + [22248] = { Name = "Enchanted Runecloth Bag", Type = "Enchant" }, + [22249] = { Name = "Big Bag of Enchantment", Type = "Enchant" }, + + [22250] = { Name = "Herb Pouch", Type = "Herb" }, + [22251] = { Name = "Cenarian Herb Bag", Type = "Herb" }, + [22252] = { Name = "Satchel of Cenarious", Type = "Herb" }, +}; + +local Outfitter_cFishingPoles = { + { Code = 84507, SubCode = 0 }, -- Outfitter_cBarkskinFisher + { Code = 19970, SubCode = 0 }, -- Outfitter_cArcaniteFishingPole + { Code = 19022, SubCode = 0 }, -- Outfitter_cNatPaglesFishingPole + { Code = 12225, SubCode = 0 }, -- Outfitter_cBlumpFishingPole + { Code = 6367, SubCode = 0 }, -- Outfitter_cBigIronFishingPole + { Code = 6366, SubCode = 0 }, -- Outfitter_cDarkwoodFishingPole + { Code = 6365, SubCode = 0 }, -- Outfitter_cStrongFishingPole + { Code = 6256, SubCode = 0 }, -- Outfitter_cFishingPole +}; + +local Outfitter_cRidingItems = { + { Code = 60501, SubCode = 0 }, -- Outfitter_cWhipOfEncouragement + { Code = 50525, SubCode = 0 }, -- Outfitter_cGoblinCarKey + { Code = 50524, SubCode = 0 }, -- Outfitter_cGnomeCarKey + { Code = 11122, SubCode = 0 }, -- Outfitter_cCarrotOnAStick +}; + +local Outfitter_cArgentDawnTrinkets = { + { Code = 13209, SubCode = 0 }, -- Outfitter_cSealOfTheDawn + { Code = 19812, SubCode = 0 }, -- Outfitter_cRuneOfTheDawn + { Code = 12846, SubCode = 0 }, -- Outfitter_cArgentDawnCommission +}; + +local Outfitter_cStatIDItems = { + Fishing = Outfitter_cFishingPoles, + Riding = Outfitter_cRidingItems, + ArgentDawn = Outfitter_cArgentDawnTrinkets, +}; + +local Outfitter_cIgnoredUnusedItems = { + [2901] = "Mining Pick", + [5956] = "Blacksmith hammer", + [6219] = "Arclight Spanner", + [7005] = "Skinning Knife", + [7297] = "Morbent's Bane", + [10696] = "Enchanted Azsharite Felbane Sword", + [10697] = "Enchanted Azsharite Felbane Dagger", + [10698] = "Enchanted Azsharite Felbane Staff", + [20406] = "Twilight Cultist Mantle", + [20407] = "Twilight Cultist Robe", + [20408] = "Twilight Cultist Cowl", +}; + +local Outfitter_cSmartOutfits = { + { Name = Outfitter_cFishingOutfit, StatID = "Fishing", IsAccessory = true }, + { Name = Outfitter_cHerbalismOutfit, StatID = "Herbalism", IsAccessory = true }, + { Name = Outfitter_cMiningOutfit, StatID = "Mining", IsAccessory = true }, + { Name = Outfitter_cSkinningOutfit, StatID = "Skinning", IsAccessory = true }, + { Name = Outfitter_cFireResistOutfit, StatID = "FireResist" }, + { Name = Outfitter_cNatureResistOutfit, StatID = "NatureResist" }, + { Name = Outfitter_cShadowResistOutfit, StatID = "ShadowResist" }, + { Name = Outfitter_cArcaneResistOutfit, StatID = "ArcaneResist" }, + { Name = Outfitter_cFrostResistOutfit, StatID = "FrostResist" }, +}; + +local Outfitter_cStatCategoryInfo = { + { Category = "Stat", Name = Outfitter_cStatsCategory }, + { Category = "Melee", Name = Outfitter_cMeleeCategory }, + { Category = "Spell", Name = Outfitter_cSpellsCategory }, + { Category = "Regen", Name = Outfitter_cRegenCategory }, + { Category = "Resist", Name = Outfitter_cResistCategory }, + { Category = "Trade", Name = Outfitter_cTradeCategory }, +}; + +local Outfitter_cItemStatInfo = { + { ID = "Agility", Name = Outfitter_cAgilityStatName, Category = "Stat" }, + { ID = "Armor", Name = Outfitter_cArmorStatName, Category = "Stat" }, + { ID = "Defense", Name = Outfitter_cDefenseStatName, Category = "Stat" }, + { ID = "Intellect", Name = Outfitter_cIntellectStatName, Category = "Stat" }, + { ID = "Spirit", Name = Outfitter_cSpiritStatName, Category = "Stat" }, + { ID = "Stamina", Name = Outfitter_cStaminaStatName, Category = "Stat" }, + { ID = "Strength", Name = Outfitter_cStrengthStatName, Category = "Stat" }, + + { ID = "ManaRegen", Name = Outfitter_cManaRegenStatName, Category = "Regen" }, + { ID = "HealthRegen", Name = Outfitter_cHealthRegenStatName, Category = "Regen" }, + + { ID = "SpellCrit", Name = Outfitter_cSpellCritStatName, Category = "Spell" }, + { ID = "SpellHit", Name = Outfitter_cSpellHitStatName, Category = "Spell" }, + { ID = "SpellDmg", Name = Outfitter_cSpellDmgStatName, Category = "Spell" }, + { ID = "FrostDmg", Name = Outfitter_cFrostDmgStatName, Category = "Spell" }, + { ID = "FireDmg", Name = Outfitter_cFireDmgStatName, Category = "Spell" }, + { ID = "ArcaneDmg", Name = Outfitter_cArcaneDmgStatName, Category = "Spell" }, + { ID = "ShadowDmg", Name = Outfitter_cShadowDmgStatName, Category = "Spell" }, + { ID = "NatureDmg", Name = Outfitter_cNatureDmgStatName, Category = "Spell" }, + { ID = "Healing", Name = Outfitter_cHealingStatName, Category = "Spell" }, + + { ID = "MeleeCrit", Name = Outfitter_cMeleeCritStatName, Category = "Melee" }, + { ID = "MeleeHit", Name = Outfitter_cMeleeHitStatName, Category = "Melee" }, + { ID = "MeleeDmg", Name = Outfitter_cMeleeDmgStatName, Category = "Melee" }, + { ID = "Dodge", Name = Outfitter_cDodgeStatName, Category = "Melee" }, + { ID = "Attack", Name = Outfitter_cAttackStatName, Category = "Melee" }, + + { ID = "ArcaneResist", Name = Outfitter_cArcaneResistStatName, Category = "Resist" }, + { ID = "FireResist", Name = Outfitter_cFireResistStatName, Category = "Resist" }, + { ID = "FrostResist", Name = Outfitter_cFrostResistStatName, Category = "Resist" }, + { ID = "NatureResist", Name = Outfitter_cNatureResistStatName, Category = "Resist" }, + { ID = "ShadowResist", Name = Outfitter_cShadowResistStatName, Category = "Resist" }, + + { ID = "Fishing", Name = Outfitter_cFishingStatName, Category = "Trade" }, + { ID = "Herbalism", Name = Outfitter_cHerbalismStatName, Category = "Trade" }, + { ID = "Mining", Name = Outfitter_cMiningStatName, Category = "Trade" }, + { ID = "Skinning", Name = Outfitter_cSkinningStatName, Category = "Trade" }, +}; + +local Outfitter_cNormalizedClassName = { + [Outfitter_cDruidClassName] = "Druid", + [Outfitter_cHunterClassName] = "Hunter", + [Outfitter_cMageClassName] = "Mage", + [Outfitter_cPaladinClassName] = "Paladin", + [Outfitter_cPriestClassName] = "Priest", + [Outfitter_cRogueClassName] = "Rogue", + [Outfitter_cShamanClassName] = "Shaman", + [Outfitter_cWarlockClassName] = "Warlock", + [Outfitter_cWarriorClassName] = "Warrior", +}; + +local Outfitter_cClassSpecialOutfits = { + Warrior = { + { Name = Outfitter_cWarriorBattleStance, SpecialID = "Battle" }, + { Name = Outfitter_cWarriorDefensiveStance, SpecialID = "Defensive" }, + { Name = Outfitter_cWarriorBerserkerStance, SpecialID = "Berserker" }, + }, + + Druid = { + { Name = Outfitter_cDruidBearForm, SpecialID = "Bear" }, + { Name = Outfitter_cDruidCatForm, SpecialID = "Cat" }, + { Name = Outfitter_cDruidAquaticForm, SpecialID = "Aquatic" }, + { Name = Outfitter_cDruidTravelForm, SpecialID = "Travel" }, + { Name = Outfitter_cDruidMoonkinForm, SpecialID = "Moonkin" }, + }, + + Priest = { + { Name = Outfitter_cPriestShadowform, SpecialID = "Shadowform" }, + }, + + Rogue = { + { Name = Outfitter_cRogueStealth, SpecialID = "Stealth" }, + }, + + Shaman = { + { Name = Outfitter_cShamanGhostWolf, SpecialID = "GhostWolf" }, + }, + + Hunter = { + { Name = Outfitter_cHunterMonkey, SpecialID = "Monkey" }, + { Name = Outfitter_cHunterHawk, SpecialID = "Hawk" }, + { Name = Outfitter_cHunterCheetah, SpecialID = "Cheetah" }, + { Name = Outfitter_cHunterPack, SpecialID = "Pack" }, + { Name = Outfitter_cHunterBeast, SpecialID = "Beast" }, + { Name = Outfitter_cHunterWild, SpecialID = "Wild" }, + }, + + Mage = { + { Name = Outfitter_cMageEvocate, SpecialID = "Evocate" }, + }, +}; + +local gOutfitter_SpellNameSpecialID = { + [Outfitter_cAspectOfTheCheetah] = "Cheetah", + [Outfitter_cAspectOfThePack] = "Pack", + [Outfitter_cAspectOfTheBeast] = "Beast", + [Outfitter_cAspectOfTheWild] = "Wild", + [Outfitter_cAspectOfTheBeast] = "Beast", + [Outfitter_cEvocate] = "Evocate", +}; + +local gOutfitter_AuraIconSpecialID = { + ["INV_Misc_Fork&Knife"] = "Dining", + ["INV_Misc_Food_28"] = "Dining", + ["Spell_Shadow_Shadowform"] = "Shadowform", + ["Spell_Nature_SpiritWolf"] = "GhostWolf", + ["Ability_Rogue_FeignDeath"] = "Feigning", + ["Ability_Hunter_AspectOfTheMonkey"] = "Monkey", + ["Spell_Nature_RavenForm"] = "Hawk", + ["Ability_Mount_Pinktiger"] = "Beast", +}; + +local Outfitter_cSpecialOutfitDescriptions = { + ArgentDawn = Outfitter_cArgentDawnOutfitDescription, + Riding = Outfitter_cRidingOutfitDescription, + Dining = Outfitter_cDiningOutfitDescription, + Battleground = Outfitter_cBattlegroundOutfitDescription, + AB = Outfitter_cArathiBasinOutfitDescription, + AV = Outfitter_cAlteracValleyOutfitDescription, + WSG = Outfitter_cWarsongGulchOutfitDescription, + BR = Outfitter_cBloodRingOutfitDescription, + SGV = Outfitter_cSunnygladeValleyOutfitDescription, + City = Outfitter_cCityOutfitDescription, + Boss = Outfitter_cBossOutfitDescription, + Lvl63 = Outfitter_cLvl63OutfitDescription, + Trash = Outfitter_cTrashOutfitDescription, + Critter = Outfitter_cCritterOutfitDescription, + BeastTrash = Outfitter_cBeastTrashOutfitDescription, + UndeadTrash = Outfitter_cUndeadTrashOutfitDescription, + DemonTrash = Outfitter_cDemonTrashOutfitDescription, + Swimming = Outfitter_cSwimmingOutfitDescription, +}; + +-- Note that zone special outfits will be worn in the order +-- the are listed here, with later outfits being worn over +-- earlier outfits (when they're being applied at the same time) +-- This allows BG-specific outfits to take priority of the generic +-- BG outfit + +local Outfitter_cZoneSpecialIDs = { + "ArgentDawn", + "City", + "Battleground", + "AV", + "AB", + "WSG", + "BR", + "SGV", + "Instance", +}; + +local Outfitter_cZoneSpecialIDMap = { + [Outfitter_cWesternPlaguelands] = { "ArgentDawn" }, + [Outfitter_cEasternPlaguelands] = { "ArgentDawn" }, + [Outfitter_cStratholme] = { "ArgentDawn" }, + [Outfitter_cScholomance] = { "ArgentDawn" }, + [Outfitter_cNaxxramas] = { "ArgentDawn" }, + [Outfitter_cAlteracValley] = { "Battleground", "AV" }, + [Outfitter_cArathiBasin] = { "Battleground", "AB" }, + [Outfitter_cWarsongGulch] = { "Battleground", "WSG" }, + [Outfitter_cBloodRing] = { "Battleground", "BR" }, + [Outfitter_cSunnygladeValley] = { "Battleground", "SGV" }, + [Outfitter_cIronforge] = { "City" }, + [Outfitter_cCityOfIronforge] = { "City" }, + [Outfitter_cDarnassus] = { "City" }, + [Outfitter_cStormwind] = { "City" }, + [Outfitter_cOrgrimmar] = { "City" }, + [Outfitter_cThunderBluff] = { "City" }, + [Outfitter_cUndercity] = { "City" }, + [Outfitter_cAQ20] = { "Instance" }, + [Outfitter_cAQ40] = { "Instance" }, + [Outfitter_cZG] = { "Instance" }, + [Outfitter_cES] = { "Instance" }, + [Outfitter_cBM] = { "Instance" }, + [Outfitter_cK40] = { "Instance" }, +}; + +local gOutfitter_StatDistribution = { + DRUID = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1 / 30 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + HUNTER = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 26.5 }, MeleeCrit = { Coeff = 1 / 53 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + MAGE = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1.0 / 59.5 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + PALADIN = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1.0 / 20 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + PRIEST = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1.0 / 30 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + ROGUE = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 14.5 }, MeleeCrit = { Coeff = 1 / 29 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + SHAMAN = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1.0 / 20 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + WARLOCK = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 }, SpellCrit = { Coeff = 1.0 / 30 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, + + WARRIOR = { + Agility = { Armor = { Coeff = 2 }, Dodge = { Coeff = 1 / 20 }, MeleeCrit = { Coeff = 1 / 20 } }, + Stamina = { Health = { Coeff = 10 } }, + Intellect = { Mana = { Coeff = 15 } }, + Spirit = { ManaRegen = { Coeff = 0.25 * 2.5 } }, -- * 2.5 to convert from ticks to per-five-seconds + Strength = { BlockAmount = { Coeff = 1 / 22 } }, + }, +}; + +local Outfitter_cCombatEquipmentSlots = { + MainHandSlot = true, + SecondaryHandSlot = true, + RangedSlot = true, + AmmoSlot = true, +}; + +local gOutfitter_OutfitStack = {}; + +local gOutfitter_SelectedOutfit = nil; +local gOutfitter_DisplayIsDirty = true; + +local gOutfitter_CurrentZone = nil; +local gOutfitter_InCombat = false; +local gOutfitter_IsDead = false; +local gOutfitter_IsFeigning = false; + +local gOutfitter_EquippedNeedsUpdate = false; +local gOutfitter_WeaponsNeedUpdate = false; +local gOutfitter_LastEquipmentUpdateTime = 0; +local Outfitter_cMinEquipmentUpdateInterval = 1.5; + +local gOutfitter_CurrentOutfit = nil; +local gOutfitter_ExpectedOutfit = nil; +local gOutfitter_CurrentInventoryOutfit = nil; +local gOutfitter_CurrentProfessionOutfit = nil; +local gOutfitter_EquippableItems = nil; + +local gOutfitter_Initialized = false; +local gOutfitter_Suspended = false; + +-- False until the equipped items have been read back reliably after login or +-- zoning. While false, Outfitter neither records inventory differences nor +-- equips anything. See Outfitter_BeginInventoryVerification. +local gOutfitter_InventoryVerified = false; + +local gOutfitter_CurrentTarget = UnitName("target"); + +local Outfitter_cMaxDisplayedItems = 14; + +local gOutfitter_PanelFrames = { + "OutfitterMainFrame", + "OutfitterOptionsFrame", + "OutfitterAboutFrame", +}; + +local gOutfitter_CurrentPanel = 0; + +local Outfitter_cShapeshiftSpecialIDs = { + -- Warriors + + [Outfitter_cBattleStance] = { ID = "Battle" }, + [Outfitter_cDefensiveStance] = { ID = "Defensive" }, + [Outfitter_cBerserkerStance] = { ID = "Berserker" }, + + -- Druids + + [Outfitter_cBearForm] = { ID = "Bear" }, + [Outfitter_cCatForm] = { ID = "Cat" }, + [Outfitter_cAquaticForm] = { ID = "Aquatic" }, + [Outfitter_cTravelForm] = { ID = "Travel" }, + [Outfitter_cDireBearForm] = { ID = "Bear" }, + [Outfitter_cMoonkinForm] = { ID = "Moonkin" }, + + -- Rogues + + [Outfitter_cStealth] = { ID = "Stealth" }, +}; + +local gOutfitter_SpecialState = {}; + +StaticPopupDialogs["OUTFITTER_CONFIRM_DELETE"] = { + text = TEXT(Outfitter_cConfirmDeleteMsg), + button1 = TEXT(DELETE), + button2 = TEXT(CANCEL), + OnAccept = function() + Outfitter_DeleteSelectedOutfit(); + end, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 +}; + +StaticPopupDialogs["OUTFITTER_CONFIRM_UPDATE"] = +{ + text = TEXT(Outfitter_cConfirmUpdateMsg), + button1 = TEXT(Outfitter_cUpdate), + button2 = TEXT(CANCEL), + OnAccept = function() Outfitter_UpdateSelectedOutfit(); end, + timeout = 0, + whileDead = 1, + hideOnEscape = 1 +}; + +StaticPopupDialogs["OUTFITTER_CONFIRM_REBUILD"] = +{ + text = TEXT(Outfitter_cConfirmRebuildMsg), + button1 = TEXT(Outfitter_cRebuild), + button2 = TEXT(CANCEL), + OnAccept = function() + Outfitter_RebuildSelectedOutfit(); + end, + timeout = 0, + whileDead = 1, + hideOnEscape = 1, +}; + +local function Outfitter_CreateCurrentOutfitFrame() + local frame = CreateFrame("Frame", "OutfitterCurrentOutfit", UIParent) + frame:SetWidth(150) -- Adjust size as needed + frame:SetHeight(25) + frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0) -- Position at center of the parent frame + frame:SetBackdrop({ + bgFile = "Interface/Tooltips/UI-Tooltip-Background", + edgeFile = "Interface/Tooltips/UI-Tooltip-Border", + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 4, right = 4, top = 4, bottom = 4 } + }) + frame:SetBackdropColor(0, 0, 0, 1) -- Black background with full opacity + frame:SetMovable(true) + frame:EnableMouse(true) + + frame:SetFrameStrata("HIGH") + + -- Create a FontString for currently equipped outfits + frame.equippedOutfits = frame:CreateFontString(nil, "DIALOG", "GameFontNormal") + frame.equippedOutfits:SetWidth(140) + frame.equippedOutfits:SetHeight(15) + frame.equippedOutfits:SetJustifyH("CENTER") + frame.equippedOutfits:SetNonSpaceWrap(false) + frame.equippedOutfits:SetPoint("LEFT", frame, "LEFT", 5, 0) -- Position at left center + + frame:RegisterForDrag("LeftButton") -- Only start dragging with the left mouse button + frame:SetScript("OnDragStart", function() + frame:StartMoving() + end) + frame:SetScript("OnDragStop", function() + frame:StopMovingOrSizing() + end) + frame:SetScript("OnMouseUp", function() + if arg1 == "RightButton" then + if not this.dropdown then + this.dropdown = CreateFrame("Frame", "OutfitterCurrentOutfitDropDown"); + OutfitterMinimapDropDown_OnLoad( this.dropdown ); + this.dropdown.ChangedValueFunc = OutfitterMinimapButton_ItemSelected; + end + ToggleDropDownMenu(nil, nil, this.dropdown, this:GetName(), 2, 2); + end + end) + frame:Hide() + + return frame +end + +local currentOutfitFrame = Outfitter_CreateCurrentOutfitFrame(); + +local function Outfitter_UpdateCurrentOutfit() + if gOutfitter_Settings.Options.ShowCurrentOutfit then + local equippedNames = ""; + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vIndex, vOutfit in vOutfits do + if Outfitter_WearingOutfit(vOutfit) then + if equippedNames ~= "" then + equippedNames = vOutfit.Name .. ", " .. equippedNames; + else + equippedNames = vOutfit.Name; + end + end + end + end + currentOutfitFrame.equippedOutfits:SetText(equippedNames) + end +end + +function Outfitter_ToggleOutfitterFrame() + if Outfitter_IsOpen() then + OutfitterFrame:Hide(); + else + OutfitterFrame:Show(); + end +end + +function Outfitter_IsOpen() + return OutfitterFrame:IsVisible(); +end + +function Outfitter_OnLoad() + Outfitter_DetectClientMods(); + + Outfitter_RegisterEvent(this, "PLAYER_ENTERING_WORLD", Outfitter_PlayerEnteringWorld); + Outfitter_RegisterEvent(this, "PLAYER_LEAVING_WORLD", Outfitter_PlayerLeavingWorld); + Outfitter_RegisterEvent(this, "VARIABLES_LOADED", Outfitter_VariablesLoaded); + + -- For monitoring mounted, dining and shadowform states + + Outfitter_RegisterEvent(this, "PLAYER_AURAS_CHANGED", Outfitter_UpdateAuraStates); + + -- For monitoring plaguelands and battlegrounds + + Outfitter_RegisterEvent(this, "ZONE_CHANGED_NEW_AREA", Outfitter_UpdateZone); + + -- For monitoring player combat state + + Outfitter_RegisterEvent(this, "PLAYER_REGEN_ENABLED", Outfitter_RegenEnabled); + Outfitter_RegisterEvent(this, "PLAYER_REGEN_DISABLED", Outfitter_RegenDisabled); + + -- For monitoring player dead/alive stat + + Outfitter_RegisterEvent(this, "PLAYER_DEAD", Outfitter_PlayerDead); + Outfitter_RegisterEvent(this, "PLAYER_ALIVE", Outfitter_PlayerAlive); + Outfitter_RegisterEvent(this, "PLAYER_UNGHOST", Outfitter_PlayerAlive); + + Outfitter_RegisterEvent(this, "UNIT_INVENTORY_CHANGED", Outfitter_InventoryChanged); + + -- For indicating which outfits are missing items + + Outfitter_RegisterEvent(this, "BAG_UPDATE", Outfitter_BagUpdate); + Outfitter_RegisterEvent(this, "PLAYERBANKSLOTS_CHANGED", Outfitter_BankSlotsChanged); + + -- For monitoring bank bags + + Outfitter_RegisterEvent(this, "BANKFRAME_OPENED", Outfitter_BankFrameOpened); + Outfitter_RegisterEvent(this, "BANKFRAME_CLOSED", Outfitter_BankFrameClosed); + + -- For unequipping the dining outfit + + Outfitter_RegisterEvent(this, "UNIT_HEALTH", Outfitter_UnitHealthOrManaChanged); + Outfitter_RegisterEvent(this, "UNIT_MANA", Outfitter_UnitHealthOrManaChanged); + + Outfitter_SuspendEvent(this, "UNIT_HEALTH"); -- Don't actually care until the dining outfit equips + Outfitter_SuspendEvent(this, "UNIT_MANA"); + + -- For boss/trash outfit + Outfitter_RegisterEvent(this, "PLAYER_TARGET_CHANGED", Outfitter_TargetChanged); + + -- For the swimming outfit. With SuperWoW/ClassicAPI the client swim flag + -- is polled (catches surface swimming); otherwise fall back to the + -- breath timer, which only shows while submerged + + if not Outfitter_ClientMods.HasIsSwimming then + Outfitter_RegisterEvent(this, "MIRROR_TIMER_START", Outfitter_MirrorTimerChanged); + Outfitter_RegisterEvent(this, "MIRROR_TIMER_STOP", Outfitter_MirrorTimerChanged); + end + + -- For auto-equip/unequip of profession outfits + Outfitter_RegisterEvent(this, "UI_ERROR_MESSAGE", Outfitter_ProfessionCheck); + Outfitter_RegisterEvent(this, "LOOT_CLOSED", Outfitter_ProfessionUnequip); + + -- Tabs + + PanelTemplates_SetNumTabs(this, table.getn(gOutfitter_PanelFrames)); + OutfitterFrame.selectedTab = gOutfitter_CurrentPanel; + PanelTemplates_UpdateTabs(this); + + -- Install the /outfit command handler + + SlashCmdList["OUTFITTER"] = Outfitter_ExecuteCommand; + + SLASH_OUTFITTER1 = "/outfitter"; + + -- Fake a leaving world event to suspend inventory/bag + -- updating until loading is completed + + Outfitter_PlayerLeavingWorld(); +end + +function Outfitter_OnShow() + Outfitter_ShowPanel(1); -- Always switch to the main view when showing the window +end + +function Outfitter_OnHide() + Outfitter_ClearSelection(); + OutfitterQuickSlots_Close(); + OutfitterFrame:Hide(); -- This seems redundant, but the OnHide handler gets called + -- in response to the parent being hidden (the character window) + -- so calling Hide() on the frame here ensures that when the + -- character window is hidden then Outfitter won't be displayed + -- next time it's opened +end + +function Outfitter_OnEvent(pEvent) + -- Ignore all events except for entering world until initialization is + -- completed + + if not gOutfitter_Initialized + and pEvent ~= "VARIABLES_LOADED" then + if pEvent ~= Outfitter_cInitializationEvent then + return ; + end + + Outfitter_Initialize(); + end + + -- + + Outfitter_DispatchEvent(this, pEvent); + Outfitter_Update(false); +end + +function Outfitter_PlayerLeavingWorld() + -- To improve load screen performance, suspend events which are + -- fired repeatedly and rapidly during zoning + + gOutfitter_Suspended = true; + gOutfitter_InventoryVerified = false; + + Outfitter_SuspendEvent(OutfitterFrame, "BAG_UPDATE"); + Outfitter_SuspendEvent(OutfitterFrame, "UNIT_INVENTORY_CHANGED"); + Outfitter_SuspendEvent(OutfitterFrame, "UPDATE_INVENTORY_ALERTS"); + Outfitter_SuspendEvent(OutfitterFrame, "SPELLS_CHANGED"); + Outfitter_SuspendEvent(OutfitterFrame, "PLAYER_AURAS_CHANGED"); + Outfitter_SuspendEvent(OutfitterFrame, "PLAYERBANKSLOTS_CHANGED"); +end + +function Outfitter_PlayerEnteringWorld() + OutfitterItemList_FlushEquippableItems(); + + Outfitter_RegenEnabled(); + Outfitter_UpdateAuraStates(); + Outfitter_SetSpecialOutfitEnabled("Riding", false); + Outfitter_pfUISkin() + + Outfitter_ResumeLoadScreenEvents(); +end + +function Outfitter_ResumeLoadScreenEvents() + if gOutfitter_Suspended then + -- To improve load screen performance, suspend events which are + -- fired repeatedly and rapidly during zoning + + gOutfitter_Suspended = false; + + Outfitter_ResumeEvent(OutfitterFrame, "BAG_UPDATE"); + Outfitter_ResumeEvent(OutfitterFrame, "UNIT_INVENTORY_CHANGED"); + Outfitter_ResumeEvent(OutfitterFrame, "UPDATE_INVENTORY_ALERTS"); + Outfitter_ResumeEvent(OutfitterFrame, "SPELLS_CHANGED"); + Outfitter_ResumeEvent(OutfitterFrame, "PLAYER_AURAS_CHANGED"); + Outfitter_ResumeEvent(OutfitterFrame, "PLAYERBANKSLOTS_CHANGED"); + + Outfitter_BeginInventoryVerification(); + end +end + +function Outfitter_VariablesLoaded() + -- Change the initialization event to PLAYER_ALIVE if this is the first use + -- This will ensure that the bags and inventory info has been loaded before + -- trying to generate the automatic outfits + + if not gOutfitter_Settings + or not gOutfitter_Settings.Outfits then + Outfitter_cInitializationEvent = "PLAYER_ALIVE"; + end +end + +function Outfitter_BankSlotsChanged() + OutfitterItemList_FlushBagFromEquippableItems(-1); + + for vBagIndex = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do + OutfitterItemList_FlushBagFromEquippableItems(vBagIndex); + end + + -- Force the bank bags to update since they now exist + + if gOutfitter_EquippableItems then + gOutfitter_EquippableItems.NeedsUpdate = true; + end + + gOutfitter_DisplayIsDirty = true; + Outfitter_Update(false); +end + +function Outfitter_BagUpdate() + local vBagIndex = arg1; + + OutfitterItemList_FlushBagFromEquippableItems(vBagIndex); + + -- This is a messy hack to ensure the database gets updated properly + -- after an upgrade. WoW doesn't always have the players items + -- loaded on PLAYER_ENTERING_WORLD so once the bag update fires + -- we check the databases again if necessary + + if gOutfitter_NeedItemCodesUpdated then + gOutfitter_NeedItemCodesUpdated = gOutfitter_NeedItemCodesUpdated - 1; + + if gOutfitter_NeedItemCodesUpdated == 0 then + gOutfitter_NeedItemCodesUpdated = nil; + end + + if Outfitter_UpdateDatabaseItemCodes() then + gOutfitter_NeedItemCodesUpdated = nil; + end + end + + -- + + gOutfitter_DisplayIsDirty = true; + Outfitter_Update(false); +end + +local gOutfitter_OutfitEvents = {}; + +function Outfitter_RegisterOutfitEvent(pEvent, pFunction) + local vHandlers = gOutfitter_OutfitEvents[pEvent]; + + if not vHandlers then + vHandlers = {}; + gOutfitter_OutfitEvents[pEvent] = vHandlers; + end + + table.insert(vHandlers, pFunction); +end + +function Outfitter_UnregisterOutfitEvent(pEvent, pFunction) + local vHandlers = gOutfitter_OutfitEvents[pEvent]; + + if not vHandlers then + return ; + end + + for vIndex, vFunction in vHandlers do + if vFunction == pFunction then + table.remove(vHandlers, vIndex); + return ; + end + end +end + +function Outfitter_DispatchOutfitEvent(pEvent, pParameter1, pParameter2) + -- Don't send out events until we're initialized + + if not gOutfitter_Initialized then + return ; + end + + -- + + OutfitterMinimapDropDown_OutfitEvent(pEvent, pParameter1, pParameter2); + + local vHandlers = gOutfitter_OutfitEvents[pEvent]; + + if not vHandlers then + return ; + end + + for _, vFunction in vHandlers do + -- Call in protected mode so that if they fail it doesn't + -- screw up Outfitter or other addons wishing to be notified + + pcall(vFunction, pEvent, pParameter1, pParameter2); + end +end + +function Outfitter_BankFrameOpened() + gOutfitter_BankFrameOpened = true; + gOutfitter_DisplayIsDirty = true; + + Outfitter_BankSlotsChanged(); + + Outfitter_Update(false); +end + +function Outfitter_BankFrameClosed() + gOutfitter_BankFrameOpened = false; + + Outfitter_BankSlotsChanged(); + + gOutfitter_DisplayIsDirty = true; + Outfitter_Update(false); +end + +function Outfitter_RegenEnabled(pEvent) + gOutfitter_InCombat = false; +end + +function Outfitter_RegenDisabled(pEvent) + gOutfitter_InCombat = true; +end + +function Outfitter_PlayerDead(pEvent) + gOutfitter_IsDead = true; +end + +function Outfitter_PlayerAlive(pEvent) + if not UnitIsDeadOrGhost("player") then + gOutfitter_IsDead = false; + end +end + +function Outfitter_ProfessionCheck(pEvent) + local profession + if string.find(arg1, Outfitter_cRequiresSkinning) then + profession = "Skinning"; + elseif string.find(arg1, Outfitter_cRequiresMining) then + profession = "Mining"; + elseif string.find(arg1, Outfitter_cRequiresHerbalism) then + profession = "Herbalism"; + end + + if profession then + local vOutfit = Outfitter_FindOutfitByStatID(profession) + if vOutfit and vOutfit.AutoEquip then + gOutfitter_CurrentProfessionOutfit = vOutfit; + Outfitter_WearOutfit(gOutfitter_CurrentProfessionOutfit); + end + end +end + +function Outfitter_ProfessionUnequip(pEvent) + if gOutfitter_CurrentProfessionOutfit then + if gOutfitter_CurrentProfessionOutfit.AutoUnEquip and Outfitter_WearingOutfit(gOutfitter_CurrentProfessionOutfit) then + Outfitter_RemoveOutfit(gOutfitter_CurrentProfessionOutfit); + end + gOutfitter_CurrentProfessionOutfit = nil; + end +end + +function Outfitter_UnitHealthOrManaChanged() + if arg1 ~= "player" then + return ; + end + + local vHealth = UnitHealth("player"); + local vMaxHealth = UnitHealthMax("player"); + local vFullHealth = false; + local vFullMana = false; + + if vHealth > (vMaxHealth * 0.99) then + vFullHealth = true; + end + + if UnitPowerType("player") == 0 then + local vMana = UnitMana("player"); + local vMaxMana = UnitManaMax("player"); + + if vMana > (vMaxMana * 0.99) then + vFullMana = true; + end + else + vFullMana = true; + end + + if vFullHealth and vFullMana then + Outfitter_SetSpecialOutfitEnabled("Dining", false); + end +end + +function Outfitter_TargetChanged() + -- Delay the event to avoid triggering when addons briefly change targets + AceEvent:ScheduleEvent("OutfitterDelayedTargetChange", Outfitter_TargetChangedDelayedEvent, 0.1); +end + +function Outfitter_TargetChangedDelayedEvent() + -- GUID with SuperWoW/ClassicAPI, otherwise name + level. The old + -- name-only check skipped re-evaluation when a different mob shared the + -- previous target's name. + local newTarget = Outfitter_GetUnitIdentity("target"); + -- check if target actually changed + if newTarget == gOutfitter_CurrentTarget or UnitIsDead("target") then + return ; + end + + gOutfitter_CurrentTarget = newTarget; + + -- check level of target + -- -1 indicates ? (lvl 63+) unit. Also honour the worldboss + -- classification, which covers bosses whose level is shown. + local level = UnitLevel("target"); + if level == -1 or (level ~= 0 and UnitClassification("target") == "worldboss") then + Outfitter_SetSpecialOutfitEnabled("Boss", true); + Outfitter_SetSpecialOutfitEnabled("Lvl63", true); + Outfitter_SetSpecialOutfitEnabled("Trash", false); + Outfitter_SetSpecialOutfitEnabled("Critter", false); + elseif level >= 63 then + Outfitter_SetSpecialOutfitEnabled("Boss", false); + Outfitter_SetSpecialOutfitEnabled("Lvl63", true); + Outfitter_SetSpecialOutfitEnabled("Trash", false); + Outfitter_SetSpecialOutfitEnabled("Critter", false); + elseif UnitCreatureType("target") == Outfitter_cCritter then + Outfitter_SetSpecialOutfitEnabled("Critter", true); + Outfitter_SetSpecialOutfitEnabled("Lvl63", false); + Outfitter_SetSpecialOutfitEnabled("Boss", false); + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + elseif level > 0 then + -- check if boss trash + Outfitter_SetSpecialOutfitEnabled("Critter", false); + if gBossTrashNames[UnitName("target")] then + Outfitter_SetSpecialOutfitEnabled("Boss", true); + Outfitter_SetSpecialOutfitEnabled("Lvl63", true); + Outfitter_SetSpecialOutfitEnabled("Trash", false); + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + else + Outfitter_SetSpecialOutfitEnabled("Boss", false); + Outfitter_SetSpecialOutfitEnabled("Lvl63", false); + Outfitter_SetSpecialOutfitEnabled("Trash", true); + + local creatureType = UnitCreatureType("target"); + -- check if undead trash + if creatureType == Outfitter_cCreatureBeast then + Outfitter_SetSpecialOutfitEnabled("BeastTrash", true); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + elseif creatureType == Outfitter_cCreatureUndead then + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", true); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + elseif creatureType == Outfitter_cCreatureDemon then + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", true); + else + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + end + end + else + Outfitter_SetSpecialOutfitEnabled("Boss", false); + Outfitter_SetSpecialOutfitEnabled("Lvl63", false); + Outfitter_SetSpecialOutfitEnabled("Trash", false); + Outfitter_SetSpecialOutfitEnabled("BeastTrash", false); + Outfitter_SetSpecialOutfitEnabled("UndeadTrash", false); + Outfitter_SetSpecialOutfitEnabled("DemonTrash", false); + Outfitter_SetSpecialOutfitEnabled("Critter", false); + end +end + +function Outfitter_InventoryChanged(pEvent) + if arg1 ~= "player" then + return ; + end + + -- debounce the event to avoid doing the same logic many times when swapping sets + AceEvent:ScheduleEvent("OutfitterUnitInventoryChanged", Outfitter_InventoryChanged2, 0.5) +end + +function Outfitter_InventoryChanged2() + OutfitterItemList_FlushEquippableItems(); -- Flush everything because the game sends bag update + -- events for an item after it's already appeared in the inventory. This + -- creates a brief situation in which the item appears to be both in the + -- bank and in the inventory which causes various problems for Outfitter + -- when checking for items. + + gOutfitter_DisplayIsDirty = true; -- Update the list so the checkboxes reflect the current state + + -- Until the equipped items can be read reliably, any difference may just + -- be item data that hasn't loaded; verification does this pass later + + if not gOutfitter_InventoryVerified then + return ; + end + + local vNewItemsOutfit, vCurrentOutfit = Outfitter_GetNewItemsOutfit(gOutfitter_CurrentOutfit); + + -- Several slots emptying in one update means the read failed (e.g. a + -- disconnect is in progress). Re-verify instead of recording it. + + if vNewItemsOutfit + and Outfitter_IsSuspiciousStripOutfit(vNewItemsOutfit) then + local vUnexpected = Outfitter_NewEmptyOutfit(); + + for vInventorySlot, vItem in vNewItemsOutfit.Items do + vUnexpected.Items[vInventorySlot] = vItem; + end + + Outfitter_SubtractOutfit(vUnexpected, gOutfitter_ExpectedOutfit); + + if Outfitter_IsSuspiciousStripOutfit(vUnexpected) then + Outfitter_BeginInventoryVerification(); + return ; + end + end + + if vNewItemsOutfit then + if not gOutfitter_Settings.Options.DisableAutoVisibility then + -- If the cloak is changing, remember the visibility for the old one and set + -- it for the new one + + if vNewItemsOutfit.Items.BackSlot then + if gOutfitter_CurrentOutfit.Items.BackSlot.Code then + if ShowingCloak() then + gOutfitter_Settings.HideCloak[gOutfitter_CurrentOutfit.Items.BackSlot.Code] = false; + else + gOutfitter_Settings.HideCloak[gOutfitter_CurrentOutfit.Items.BackSlot.Code] = true; + end + end + + if gOutfitter_Settings.HideCloak[vNewItemsOutfit.Items.BackSlot.Code] ~= nil then + if gOutfitter_Settings.HideCloak[vNewItemsOutfit.Items.BackSlot.Code] then + ShowCloak(0); + else + ShowCloak(1); + end + end + end + + -- If the helm is changing, remember the visibility for the old one and set + -- it for the new one + + if vNewItemsOutfit.Items.HeadSlot then + if gOutfitter_CurrentOutfit.Items.HeadSlot.Code then + if ShowingHelm() then + gOutfitter_Settings.HideHelm[gOutfitter_CurrentOutfit.Items.HeadSlot.Code] = false; + else + gOutfitter_Settings.HideHelm[gOutfitter_CurrentOutfit.Items.HeadSlot.Code] = true; + end + end + + if gOutfitter_Settings.HideHelm[vNewItemsOutfit.Items.HeadSlot.Code] ~= nil then + if gOutfitter_Settings.HideHelm[vNewItemsOutfit.Items.HeadSlot.Code] then + ShowHelm(0); + else + ShowHelm(1); + end + end + end + end + + -- Save the new outfit + + gOutfitter_CurrentOutfit = vCurrentOutfit; + + -- Close QuickSlots if there's an inventory change (except if the only + -- change is with the ammo slots) + + if OutfitterQuickSlots.SlotName ~= "AmmoSlot" + or not Outfitter_OutfitIsAmmoOnly(vNewItemsOutfit) then + OutfitterQuickSlots_Close(); + end + + -- Update the selected outfit or temporary outfit + + Outfitter_SubtractOutfit(vNewItemsOutfit, gOutfitter_ExpectedOutfit); + + if gOutfitter_SelectedOutfit then + Outfitter_UpdateOutfitFromInventory(gOutfitter_SelectedOutfit, vNewItemsOutfit); + else + Outfitter_UpdateTemporaryOutfit(vNewItemsOutfit); + end + end + + Outfitter_Update(true); +end + +function Outfitter_OutfitIsAmmoOnly(pOutfit) + local vHasAmmoItem = false; + + for vInventorySlot, vItem in pOutfit.Items do + if vInventorySlot ~= "AmmoSlot" then + return false; + else + vHasAmmoItem = true; + end + end + + return vHasAmmoItem; +end + +function Outfitter_ExecuteCommand(pCommand) + local vCommands = { + wear = { useOutfit = true, func = Outfitter_WearOutfit }, + unwear = { useOutfit = true, func = Outfitter_RemoveOutfit }, + toggle = { useOutfit = true, func = Outfitter_ToggleOutfit }, + summary = { useOutfit = false, func = Outfitter_OutfitSummary }, + mods = { useOutfit = false, func = Outfitter_ClientModsSummary }, + } + + local vStartIndex, vEndIndex, vCommand, vParameter = string.find(pCommand, "(%w+) ?(.*)"); + + if not vCommand then + Outfitter_NoteMessage(HIGHLIGHT_FONT_COLOR_CODE .. "/outfitter wear " .. NORMAL_FONT_COLOR_CODE .. ": Wear an outfit"); + Outfitter_NoteMessage(HIGHLIGHT_FONT_COLOR_CODE .. "/outfitter unwear " .. NORMAL_FONT_COLOR_CODE .. ": Remove an outfit"); + Outfitter_NoteMessage(HIGHLIGHT_FONT_COLOR_CODE .. "/outfitter toggle " .. NORMAL_FONT_COLOR_CODE .. ": Wears or removes an outfit"); + Outfitter_NoteMessage(HIGHLIGHT_FONT_COLOR_CODE .. "/outfitter mods" .. NORMAL_FONT_COLOR_CODE .. ": Show which client mods Outfitter is using"); + return ; + end + + vCommand = strlower(vCommand); + + local vCommandInfo = vCommands[vCommand]; + + if not vCommandInfo then + Outfitter_ErrorMessage("Outfitter: Expected command"); + return ; + end + + local vOutfit = nil; + local vCategoryID = nil; + + if vCommandInfo.useOutfit then + if not vParameter then + Outfitter_ErrorMessage("Outfitter: Expected outfit name for " .. vCommand .. " command"); + return ; + end + + vOutfit, vCategoryID = Outfitter_FindOutfitByName(vParameter); + + if not vOutfit then + Outfitter_ErrorMessage("Outfitter: Couldn't find outfit named " .. vParameter); + return ; + end + + vCommandInfo.func(vOutfit, vCategoryID); + else + vCommandInfo.func(); + end +end + +function Outfitter_AskRebuildOutfit(pOutfit, pCategoryID) + gOutfitter_OutfitToRebuild = pOutfit; + gOutfitter_OutfitCategoryToRebuild = pCategoryID; + + StaticPopup_Show("OUTFITTER_CONFIRM_REBUILD", gOutfitter_OutfitToRebuild.Name); +end + +function Outfitter_RebuildSelectedOutfit() + if not gOutfitter_OutfitToRebuild then + return ; + end + + local vOutfit = Outfitter_GenerateSmartOutfit("temp", gOutfitter_OutfitToRebuild.StatID, OutfitterItemList_GetEquippableItems(true)); + + if vOutfit then + gOutfitter_OutfitToRebuild.Items = vOutfit.Items; + Outfitter_UpdateOutfitCategory(gOutfitter_OutfitToRebuild); + Outfitter_WearOutfit(gOutfitter_OutfitToRebuild, gOutfitter_OutfitCategoryToRebuild); + Outfitter_Update(true); + end + + gOutfitter_OutfitToRebuild = nil; + gOutfitter_OutfitCategoryToRebuild = nil; +end + +function Outfitter_AskDeleteOutfit(pOutfit) + gOutfitter_OutfitToDelete = pOutfit; + StaticPopup_Show("OUTFITTER_CONFIRM_DELETE", gOutfitter_OutfitToDelete.Name); +end + +function Outfitter_DeleteSelectedOutfit() + if not gOutfitter_OutfitToDelete then + return ; + end + + Outfitter_DeleteOutfit(gOutfitter_OutfitToDelete); + + Outfitter_Update(true); +end + +function Outfitter_AskUpdateOutfit(pOutfit) + gOutfitter_OutfitToUpdate = pOutfit; + StaticPopup_Show("OUTFITTER_CONFIRM_UPDATE", gOutfitter_OutfitToUpdate.Name); +end + +function Outfitter_UpdateSelectedOutfit() + if not gOutfitter_OutfitToUpdate then + return; + end + + Outfitter_UpdateOutfit(gOutfitter_OutfitToUpdate); + + Outfitter_Update(true); +end + +function Outfitter_ShowPanel(pPanelIndex) + Outfitter_CancelDialogs(); -- Force any dialogs to close if they're open + + if gOutfitter_CurrentPanel > 0 + and gOutfitter_CurrentPanel ~= pPanelIndex then + Outfitter_HidePanel(gOutfitter_CurrentPanel); + end + + -- NOTE: Don't check for redundant calls since this function + -- will be called to reset the field values as well as to + -- actually show the panel when it's hidden + + gOutfitter_CurrentPanel = pPanelIndex; + + getglobal(gOutfitter_PanelFrames[pPanelIndex]):Show(); + + PanelTemplates_SetTab(OutfitterFrame, pPanelIndex); + + -- Update the control values + + if pPanelIndex == 1 then + -- Main panel + + elseif pPanelIndex == 2 then + -- Options panel + + elseif pPanelIndex == 3 then + -- About panel + + else + Outfitter_ErrorMessage("Outfitter: Unknown index (" .. pPanelIndex .. ") in ShowPanel()"); + end + + Outfitter_Update(false); +end + +function Outfitter_HidePanel(pPanelIndex) + if gOutfitter_CurrentPanel ~= pPanelIndex then + return ; + end + + getglobal(gOutfitter_PanelFrames[pPanelIndex]):Hide(); + gOutfitter_CurrentPanel = 0; +end + +function Outfitter_CancelDialogs() +end + +function OutfitterItemDropDown_OnLoad() + UIDropDownMenu_SetAnchor(0, 0, this, "TOPLEFT", this:GetName(), "CENTER"); + UIDropDownMenu_Initialize(this, OutfitterItemDropDown_Initialize); + --UIDropDownMenu_Refresh(this); -- Don't refresh on menus which don't have a text portion + + this:SetHeight(this.SavedHeight); +end + +function Outfitter_AddDividerMenuItem() + UIDropDownMenu_AddButton({ text = " ", notCheckable = true, notClickable = true }); +end + +function Outfitter_AddCategoryMenuItem(pName) + UIDropDownMenu_AddButton({ text = pName, notCheckable = true, notClickable = true }); +end + +function Outfitter_AddMenuItem(pFrame, pName, pValue, pChecked, pLevel, pColor, pDisabled) + if not pColor then + pColor = NORMAL_FONT_COLOR; + end + + UIDropDownMenu_AddButton({ text = pName, value = pValue, owner = pFrame, checked = pChecked, func = OutfitterDropDown_OnClick2, textR = pColor.r, textG = pColor.g, textB = pColor.b, disabled = pDisabled }, pLevel); +end + +function Outfitter_AddSubmenuItem(pFrame, pName, pValue) + UIDropDownMenu_AddButton({ text = pName, owner = pFrame, hasArrow = 1, value = pValue, textR = NORMAL_FONT_COLOR.r, textG = NORMAL_FONT_COLOR.g, textB = NORMAL_FONT_COLOR.b }); +end + +function OutfitterItemDropDown_Initialize() + local vFrame = getglobal(UIDROPDOWNMENU_INIT_MENU); + local vItem = vFrame:GetParent():GetParent(); + local vOutfit, vCategoryID = Outfitter_GetOutfitFromListItem(vItem); + + if not vOutfit then + return ; + end + + if UIDROPDOWNMENU_MENU_LEVEL == 1 then + local vIsSpecialOutfit = vCategoryID == "Special"; + + Outfitter_AddCategoryMenuItem(vOutfit.Name); + + if vIsSpecialOutfit then + Outfitter_AddMenuItem(vFrame, Outfitter_cDisableOutfit, "DISABLE", vOutfit.Disabled); + Outfitter_AddMenuItem(vFrame, Outfitter_cDisableOutfitInBG, "BGDISABLE", vOutfit.BGDisabled); + --hax + Outfitter_AddMenuItem(vFrame, Outfitter_cDisableOutfitInInstance, "INSTDISABLE", vOutfit.InstDisabled); + else + Outfitter_AddMenuItem(vFrame, PET_RENAME, "RENAME"); + end + + if not vIsSpecialOutfit + and vOutfit.StatID then + local vStatName = Outfitter_GetStatIDName(vOutfit.StatID); + + if vStatName then + Outfitter_AddMenuItem(vFrame, format(Outfitter_cRebuildOutfitFormat, vStatName), "REBUILD"); + end + end + + Outfitter_AddSubmenuItem(vFrame, Outfitter_cKeyBinding, "BINDING"); + + if not vIsSpecialOutfit then + Outfitter_AddMenuItem(vFrame, DELETE, "DELETE"); + end + + Outfitter_AddMenuItem(vFrame, Outfitter_cUpdateToCurrent, "UPDATE"); + + if vOutfit.StatID == "Mining" or vOutfit.StatID == "Skinning" or vOutfit.StatID == "Herbalism" then + Outfitter_AddMenuItem(vFrame, Outfitter_cAutoEquip, "AUTOEQUIP", vOutfit.AutoEquip); + Outfitter_AddMenuItem(vFrame, Outfitter_cAutoUnEquip, "AUTOUNEQUIP", vOutfit.AutoUnEquip); + end + + Outfitter_AddCategoryMenuItem(Outfitter_cBankCategoryTitle); + Outfitter_AddMenuItem(vFrame, Outfitter_cDepositToBank, "DEPOSIT", nil, nil, nil, not gOutfitter_BankFrameOpened); + Outfitter_AddMenuItem(vFrame, Outfitter_cDepositUniqueToBank, "DEPOSITUNIQUE", nil, nil, nil, not gOutfitter_BankFrameOpened); + Outfitter_AddMenuItem(vFrame, Outfitter_cWithdrawFromBank, "WITHDRAW", nil, nil, nil, not gOutfitter_BankFrameOpened); + + if not vIsSpecialOutfit + and vCategoryID ~= "Complete" then + Outfitter_AddCategoryMenuItem(Outfitter_cOutfitCategoryTitle); + Outfitter_AddMenuItem(vFrame, Outfitter_cPartialOutfits, "PARTIAL", vCategoryID == "Partial"); + Outfitter_AddMenuItem(vFrame, Outfitter_cAccessoryOutfits, "ACCESSORY", vCategoryID == "Accessory"); + end + + elseif UIDROPDOWNMENU_MENU_LEVEL == 2 then + if UIDROPDOWNMENU_MENU_VALUE == "BINDING" then + for vIndex = 1, 10 do + Outfitter_AddMenuItem(vFrame, getglobal("BINDING_NAME_OUTFITTER_OUTFIT" .. vIndex), "BINDING" .. vIndex, vOutfit.BindingIndex == vIndex, UIDROPDOWNMENU_MENU_LEVEL); + end + end + end + + vFrame:SetHeight(vFrame.SavedHeight); +end + +function Outfitter_SetShowMinimapButton(pShowButton) + gOutfitter_Settings.Options.HideMinimapButton = not pShowButton; + + if gOutfitter_Settings.Options.HideMinimapButton then + OutfitterMinimapButton:Hide(); + else + OutfitterMinimapButton:Show(); + end + + Outfitter_Update(false); +end + +function Outfitter_SetRememberVisibility(pRememberVisibility) + gOutfitter_Settings.Options.DisableAutoVisibility = not pRememberVisibility; + + Outfitter_Update(false); +end + +function Outfitter_SetShowHotkeyMessages(pShowHotkeyMessages) + gOutfitter_Settings.Options.DisableHotkeyMessages = not pShowHotkeyMessages; + + Outfitter_Update(false); +end + +function Outfitter_SetShowCurrentOutfit(pShowCurrentOutfit) + gOutfitter_Settings.Options.ShowCurrentOutfit = pShowCurrentOutfit; + + if gOutfitter_Settings.Options.ShowCurrentOutfit then + currentOutfitFrame:Show(); + Outfitter_UpdateCurrentOutfit(); + else + currentOutfitFrame:Hide(); + end +end + +function Outfitter_SetHideDisabledOutfits(pHideDisabledOutfits) + gOutfitter_Settings.Options.HideDisabledOutfits = pHideDisabledOutfits; + + Outfitter_Update(false); +end + +function OutfitterMinimapDropDown_OnLoad(dropdown) + if ( not dropdown ) then + dropdown = this; + end + UIDropDownMenu_SetAnchor(3, -7, dropdown, "TOPRIGHT", this:GetName(), "TOPLEFT"); + UIDropDownMenu_Initialize(dropdown, OutfitterMinimapDropDown_Initialize); + --UIDropDownMenu_Refresh(this); -- Don't refresh on menus which don't have a text portion + + Outfitter_RegisterOutfitEvent("WEAR_OUTFIT", OutfitterMinimapDropDown_OutfitEvent); + Outfitter_RegisterOutfitEvent("UNWEAR_OUTFIT", OutfitterMinimapDropDown_OutfitEvent); +end + +function OutfitterMinimapDropDown_OutfitEvent(pEvent, pParameter1, pParameter2) + if UIDROPDOWNMENU_OPEN_MENU ~= "OutfitterMinimapButton" then + return ; + end + + UIDropDownMenu_Initialize(OutfitterMinimapButton, OutfitterMinimapDropDown_Initialize); +end + +function OutfitterMinimapDropDown_AdjustScreenPosition(pMenu) + local vListFrame = getglobal("DropDownList1"); + + if not vListFrame:IsVisible() then + return ; + end + + local vCenterX, vCenterY = pMenu:GetCenter(); + local vScreenWidth, vScreenHeight = GetScreenWidth(), GetScreenHeight(); + + local vAnchor; + local vOffsetX, vOffsetY; + + if vCenterY < vScreenHeight / 2 then + vAnchor = "BOTTOM"; + vOffsetY = -8; + else + vAnchor = "TOP"; + vOffsetY = -17; + end + + if vCenterX < vScreenWidth / 2 then + vAnchor = vAnchor .. "LEFT"; + vOffsetX = 21; + else + vAnchor = vAnchor .. "RIGHT"; + vOffsetX = 3; + end + + vListFrame:ClearAllPoints(); + vListFrame:SetPoint(vAnchor, pMenu.relativeTo, pMenu.relativePoint, vOffsetX, vOffsetY); +end + +function Outfitter_OutfitIsVisible(pOutfit) + return not pOutfit.Disabled + and not Outfitter_IsEmptyOutfit(pOutfit); +end + +function Outfitter_HasVisibleOutfits(pOutfits) + if not pOutfits then + return false; + end + + for vIndex, vOutfit in pOutfits do + if Outfitter_OutfitIsVisible(vOutfit) then + return true; + end + end + + return false; +end + +function OutfitterMinimapDropDown_Initialize() + -- Just return if not initialized yet + + if not gOutfitter_Initialized then + return ; + end + + -- + + local vFrame = getglobal(UIDROPDOWNMENU_INIT_MENU); + + Outfitter_AddCategoryMenuItem(Outfitter_cTitleVersion); + Outfitter_AddMenuItem(vFrame, Outfitter_cOpenOutfitter, 0); + + OutfitterMinimapDropDown_InitializeOutfitList(); +end + +function Outfitter_GetCategoryOrder() + return gOutfitter_cCategoryOrder; +end + +function Outfitter_GetOutfitsByCategoryID(pCategoryID) + return gOutfitter_Settings.Outfits[pCategoryID]; +end + +function OutfitterMinimapDropDown_InitializeOutfitList() + -- Just return if not initialized yet + + if not gOutfitter_Initialized then + return ; + end + + -- + + local vFrame = getglobal(UIDROPDOWNMENU_INIT_MENU); + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + local vCategoryOrder = Outfitter_GetCategoryOrder(); + + for vCategoryIndex, vCategoryID in vCategoryOrder do + local vCategoryName = getglobal("Outfitter_c" .. vCategoryID .. "Outfits"); + local vOutfits = Outfitter_GetOutfitsByCategoryID(vCategoryID); + + if Outfitter_HasVisibleOutfits(vOutfits) then + Outfitter_AddCategoryMenuItem(vCategoryName); + + for vIndex, vOutfit in vOutfits do + if Outfitter_OutfitIsVisible(vOutfit) then + local vWearingOutfit = Outfitter_WearingOutfit(vOutfit); + local vMissingItems, vBankedItems = OutfitterItemList_GetMissingItems(vEquippableItems, vOutfit); + local vItemColor = NORMAL_FONT_COLOR; + + if vMissingItems then + vItemColor = RED_FONT_COLOR; + elseif vBankedItems then + vItemColor = BANKED_FONT_COLOR; + end + + Outfitter_AddMenuItem(vFrame, vOutfit.Name, { CategoryID = vCategoryID, Index = vIndex }, vWearingOutfit, nil, vItemColor); + end + end + end + end +end + +function OutfitterDropDown_OnClick() + UIDropDownMenu_SetSelectedValue(this.owner, this.value); + OutfitterDropDown_OnClick2(); +end + +function OutfitterDropDown_OnClick2() + if this.owner.ChangedValueFunc then + this.owner.ChangedValueFunc(this.owner, this.value); + end + + CloseDropDownMenus(); +end + +function OutfitterItem_SetTextColor(pItem, pRed, pGreen, pBlue) + local vItemNameField; + + if pItem.isCategory then + vItemNameField = getglobal(pItem:GetName() .. "CategoryName"); + else + vItemNameField = getglobal(pItem:GetName() .. "OutfitName"); + end + + vItemNameField:SetTextColor(pRed, pGreen, pBlue); +end + +Outfitter_cCategoryDescriptions = { + Complete = Outfitter_cCompleteCategoryDescripton, + Partial = Outfitter_cPartialCategoryDescription, + Accessory = Outfitter_cAccessoryCategoryDescription, + Special = Outfitter_cSpecialCategoryDescription, + OddsNEnds = Outfitter_cOddsNEndsCategoryDescription, +}; + +Outfitter_cMissingItemsSeparator = ", "; + +function Outfitter_GenerateItemListString(pLabel, pListColorCode, pItems) + local vItemList = nil; + + for vIndex, vOutfitItem in pItems do + if not vItemList then + vItemList = HIGHLIGHT_FONT_COLOR_CODE .. pLabel .. pListColorCode .. vOutfitItem.Name; + else + vItemList = vItemList .. Outfitter_cMissingItemsSeparator .. vOutfitItem.Name; + end + end + + return vItemList; +end + +function OutfitterItem_OnEnter(pItem) + OutfitterItem_SetTextColor(pItem, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); + + if pItem.isCategory then + local vDescription = Outfitter_cCategoryDescriptions[pItem.categoryID]; + + if vDescription then + local vCategoryName = getglobal("Outfitter_c" .. pItem.categoryID .. "Outfits"); + + GameTooltip_AddNewbieTip(vCategoryName, 1.0, 1.0, 1.0, vDescription, 1); + end + + ResetCursor(); + elseif pItem.isOutfitItem then + local vHasCooldown, vRepairCost; + + GameTooltip:SetOwner(pItem, "ANCHOR_TOP"); + + if pItem.outfitItem.Location.SlotName then + if not pItem.outfitItem.Location.SlotID then + local vSlotID, vEmptySlotTexture = GetInventorySlotInfo(pItem.outfitItem.Location.SlotName); + + pItem.outfitItem.Location.SlotID = vSlotID; + end + + GameTooltip:SetInventoryItem("player", pItem.outfitItem.Location.SlotID); + else + vHasCooldown, vRepairCost = GameTooltip:SetBagItem(pItem.outfitItem.Location.BagIndex, pItem.outfitItem.Location.BagSlotIndex); + end + + GameTooltip:Show(); + + if InRepairMode() and (vRepairCost and vRepairCost > 0) then + GameTooltip:AddLine(TEXT(REPAIR_COST), "", 1, 1, 1); + SetTooltipMoney(GameTooltip, vRepairCost); + GameTooltip:Show(); + elseif MerchantFrame:IsShown() and MerchantFrame.selectedTab == 1 then + if pItem.outfitItem.Location.BagIndex then + ShowContainerSellCursor(pItem.outfitItem.Location.BagIndex, pItem.outfitItem.Location.BagSlotIndex); + end + else + ResetCursor(); + end + else + local vOutfit = Outfitter_GetOutfitFromListItem(pItem); + + if pItem.MissingItems + or pItem.BankedItems then + GameTooltip:SetOwner(pItem, "ANCHOR_LEFT"); + + GameTooltip:AddLine(vOutfit.Name); + + if pItem.MissingItems then + local vItemList = Outfitter_GenerateItemListString(Outfitter_cMissingItemsLabel, RED_FONT_COLOR_CODE, pItem.MissingItems); + GameTooltip:AddLine(vItemList, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true); + end + + if pItem.BankedItems then + local vItemList = Outfitter_GenerateItemListString(Outfitter_cBankedItemsLabel, BANKED_FONT_COLOR_CODE, pItem.BankedItems); + GameTooltip:AddLine(vItemList, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true); + end + + GameTooltip:Show(); + elseif vOutfit.SpecialID then + local vDescription = Outfitter_cSpecialOutfitDescriptions[vOutfit.SpecialID]; + + if vDescription then + GameTooltip_AddNewbieTip(vOutfit.Name, 1.0, 1.0, 1.0, vDescription, 1); + end + end + + ResetCursor(); + end +end + +function OutfitterItem_OnLeave(pItem) + if pItem.isCategory then + OutfitterItem_SetTextColor(pItem, 1, 1, 1); + else + OutfitterItem_SetTextColor(pItem, pItem.DefaultColor.r, pItem.DefaultColor.g, pItem.DefaultColor.b); + end + + GameTooltip:Hide(); +end + +function OutfitterItem_OnClick(pItem, pButton, pIgnoreModifiers) + if pItem.isCategory then + local vCategoryOutfits = gOutfitter_Settings.Outfits[pItem.categoryID]; + + gOutfitter_Collapsed[pItem.categoryID] = not gOutfitter_Collapsed[pItem.categoryID]; + gOutfitter_DisplayIsDirty = true; + elseif pItem.isOutfitItem then + if pButton == "LeftButton" then + Outfitter_PickupItemLocation(pItem.outfitItem.Location); + StackSplitFrame:Hide(); + else + if MerchantFrame:IsShown() and MerchantFrame.selectedTab == 2 then + -- Don't sell the item if the buyback tab is selected + return ; + else + if pItem.outfitItem.Location.BagIndex then + UseContainerItem(pItem.outfitItem.Location.BagIndex, pItem.outfitItem.Location.BagSlotIndex); + StackSplitFrame:Hide(); + end + end + end + else + local vOutfit = Outfitter_GetOutfitFromListItem(pItem); + + if not vOutfit then + -- Error: outfit not found + return ; + end + + vOutfit.Disabled = nil; + Outfitter_WearOutfit(vOutfit, pItem.categoryID); + end + + Outfitter_Update(true); +end + +function OutfitterItem_CheckboxClicked(pItem) + if pItem.isCategory then + return ; + end + + local vOutfits = gOutfitter_Settings.Outfits[pItem.categoryID]; + + if not vOutfits then + -- Error: outfit category not found + return ; + end + + local vOutfit = vOutfits[pItem.outfitIndex]; + + if not vOutfit then + -- Error: outfit not found + return ; + end + + local vCheckbox = getglobal(pItem:GetName() .. "OutfitSelected"); + + if vCheckbox:GetChecked() then + vOutfit.Disabled = nil; + Outfitter_WearOutfit(vOutfit, pItem.categoryID); + else + Outfitter_RemoveOutfit(vOutfit); + end + + Outfitter_Update(true); +end + +function OutfitterItem_SetToOutfit(pItemIndex, pOutfit, pCategoryID, pOutfitIndex, pEquippableItems) + local vItemName = "OutfitterItem" .. pItemIndex; + local vItem = getglobal(vItemName); + local vOutfitFrameName = vItemName .. "Outfit"; + local vOutfitFrame = getglobal(vOutfitFrameName); + local vItemFrame = getglobal(vItemName .. "Item"); + local vCategoryFrame = getglobal(vItemName .. "Category"); + local vMissingItems, vBankedItems = OutfitterItemList_GetMissingItems(pEquippableItems, pOutfit); + + vOutfitFrame:Show(); + vCategoryFrame:Hide(); + vItemFrame:Hide(); + + local vItemSelectedCheckmark = getglobal(vOutfitFrameName .. "Selected"); + local vItemNameField = getglobal(vOutfitFrameName .. "Name"); + local vItemMenu = getglobal(vOutfitFrameName .. "Menu"); + + vItemSelectedCheckmark:Show(); + + if Outfitter_WearingOutfit(pOutfit) then + vItemSelectedCheckmark:SetChecked(true); + else + vItemSelectedCheckmark:SetChecked(nil); + end + + vItem.MissingItems = vMissingItems; + vItem.BankedItems = vBankedItems; + + if pOutfit.Disabled then + vItemNameField:SetText(format(Outfitter_cDisabledOutfitName, pOutfit.Name)); + vItem.DefaultColor = GRAY_FONT_COLOR; + else + vItemNameField:SetText(pOutfit.Name); + if vMissingItems then + vItem.DefaultColor = RED_FONT_COLOR; + elseif vBankedItems then + vItem.DefaultColor = BANKED_FONT_COLOR; + else + vItem.DefaultColor = NORMAL_FONT_COLOR; + end + end + + vItemNameField:SetTextColor(vItem.DefaultColor.r, vItem.DefaultColor.g, vItem.DefaultColor.b); + + vItemMenu:Show(); + + vItem.isCategory = false; + vItem.isOutfitItem = false; + vItem.outfitItem = nil; + vItem.categoryID = pCategoryID; + vItem.outfitIndex = pOutfitIndex; + + vItem:Show(); + + -- Update the highlighting + + if gOutfitter_SelectedOutfit == pOutfit then + OutfitterMainFrameHighlight:SetPoint("TOPLEFT", vItem, "TOPLEFT", 0, 0); + OutfitterMainFrameHighlight:Show(); + end +end + +function OutfitterItem_SetToItem(pItemIndex, pOutfitItem) + local vItemName = "OutfitterItem" .. pItemIndex; + local vItem = getglobal(vItemName); + local vCategoryFrameName = vItemName .. "Category"; + local vItemFrameName = vItemName .. "Item"; + local vItemFrame = getglobal(vItemFrameName); + local vOutfitFrame = getglobal(vItemName .. "Outfit"); + local vCategoryFrame = getglobal(vCategoryFrameName); + + vItem.isOutfitItem = true; + vItem.isCategory = false; + vItem.outfitItem = pOutfitItem; + + vItemFrame:Show(); + vOutfitFrame:Hide(); + vCategoryFrame:Hide(); + + local vItemNameField = getglobal(vItemFrameName .. "Name"); + local vItemIcon = getglobal(vItemFrameName .. "Icon"); + + vItemNameField:SetText(pOutfitItem.Name); + + if pOutfitItem.Quality then + vItem.DefaultColor = ITEM_QUALITY_COLORS[pOutfitItem.Quality]; + else + vItem.DefaultColor = GRAY_FONT_COLOR; + end + + if pOutfitItem.Texture then + vItemIcon:SetTexture(pOutfitItem.Texture); + vItemIcon:Show(); + else + vItemIcon:Hide(); + end + + vItemNameField:SetTextColor(vItem.DefaultColor.r, vItem.DefaultColor.g, vItem.DefaultColor.b); + + vItem:Show(); +end + +function OutfitterItem_SetToCategory(pItemIndex, pCategoryID) + local vCategoryName = getglobal("Outfitter_c" .. pCategoryID .. "Outfits"); + local vItemName = "OutfitterItem" .. pItemIndex; + local vItem = getglobal(vItemName); + local vCategoryFrameName = vItemName .. "Category"; + local vOutfitFrame = getglobal(vItemName .. "Outfit"); + local vItemFrame = getglobal(vItemName .. "Item"); + local vCategoryFrame = getglobal(vCategoryFrameName); + + vOutfitFrame:Hide(); + vCategoryFrame:Show(); + vItemFrame:Hide(); + + local vItemNameField = getglobal(vCategoryFrameName .. "Name"); + local vExpandButton = getglobal(vCategoryFrameName .. "Expand"); + + vItem.MissingItems = nil; + vItem.BankedItems = nil; + + if gOutfitter_Collapsed[pCategoryID] then + vExpandButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + else + vExpandButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + end + + vItemNameField:SetText(vCategoryName); + + vItem.isCategory = true; + vItem.isOutfitItem = false; + vItem.outfitItem = nil; + vItem.categoryID = pCategoryID; + + vItem:Show(); +end + +function Outfitter_AddOutfitsToList(pOutfits, pCategoryID, pItemIndex, pFirstItemIndex, pEquippableItems) + local vOutfits = pOutfits[pCategoryID]; + local vItemIndex = pItemIndex; + local vFirstItemIndex = pFirstItemIndex; + + if vFirstItemIndex == 0 then + OutfitterItem_SetToCategory(vItemIndex, pCategoryID, false); + vItemIndex = vItemIndex + 1; + else + vFirstItemIndex = vFirstItemIndex - 1; + end + + if vItemIndex >= Outfitter_cMaxDisplayedItems then + return vItemIndex, vFirstItemIndex; + end + + if not gOutfitter_Collapsed[pCategoryID] + and vOutfits then + for vIndex, vOutfit in vOutfits do + -- skip disabled outfits if the option is set + if not vOutfit.Disabled or not gOutfitter_Settings.Options.HideDisabledOutfits then + if vFirstItemIndex == 0 then + OutfitterItem_SetToOutfit(vItemIndex, vOutfit, pCategoryID, vIndex, pEquippableItems); + vItemIndex = vItemIndex + 1; + + if vItemIndex >= Outfitter_cMaxDisplayedItems then + return vItemIndex, vFirstItemIndex; + end + else + vFirstItemIndex = vFirstItemIndex - 1; + end + end + end + end + + return vItemIndex, vFirstItemIndex; +end + +function Outfitter_AddOutfitItemsToList(pOutfitItems, pCategoryID, pItemIndex, pFirstItemIndex) + local vItemIndex = pItemIndex; + local vFirstItemIndex = pFirstItemIndex; + + if vFirstItemIndex == 0 then + OutfitterItem_SetToCategory(vItemIndex, pCategoryID, false); + vItemIndex = vItemIndex + 1; + else + vFirstItemIndex = vFirstItemIndex - 1; + end + + if vItemIndex >= Outfitter_cMaxDisplayedItems then + return vItemIndex, vFirstItemIndex; + end + + if not gOutfitter_Collapsed[pCategoryID] then + for vIndex, vOutfitItem in pOutfitItems do + if vFirstItemIndex == 0 then + OutfitterItem_SetToItem(vItemIndex, vOutfitItem); + vItemIndex = vItemIndex + 1; + + if vItemIndex >= Outfitter_cMaxDisplayedItems then + return vItemIndex, vFirstItemIndex; + end + else + vFirstItemIndex = vFirstItemIndex - 1; + end + end + end + + return vItemIndex, vFirstItemIndex; +end + +function Outfitter_SortOutfits() + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + table.sort(vOutfits, Outfiter_CompareOutfitNames); + end +end + +function Outfiter_CompareOutfitNames(pOutfit1, pOutfit2) + return pOutfit1.Name < pOutfit2.Name; +end + +function Outfitter_Update(pUpdateSlotEnables) + if not OutfitterFrame:IsVisible() then + return ; + end + + if gOutfitter_CurrentPanel == 1 then + -- Main panel + + if not gOutfitter_DisplayIsDirty then + return ; + end + + gOutfitter_DisplayIsDirty = false; + + -- Sort the outfits + + Outfitter_SortOutfits(); + + -- Get the equippable items so outfits can be marked if they're missing anything + + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + -- Update the slot enables if they're shown + + if pUpdateSlotEnables + and OutfitterSlotEnables:IsVisible() then + Outfitter_UpdateSlotEnables(gOutfitter_SelectedOutfit, vEquippableItems); + end + + OutfitterItemList_CompiledUnusedItemsList(vEquippableItems); + + -- Update the list + + OutfitterMainFrameHighlight:Hide(); + + local vFirstItemIndex = FauxScrollFrame_GetOffset(OutfitterMainFrameScrollFrame); + local vItemIndex = 0; + + OutfitterItemList_ResetIgnoreItemFlags(vEquippableItems); + + for vCategoryIndex, vCategoryID in gOutfitter_cCategoryOrder do + vItemIndex, vFirstItemIndex = Outfitter_AddOutfitsToList(gOutfitter_Settings.Outfits, vCategoryID, vItemIndex, vFirstItemIndex, vEquippableItems); + + if vItemIndex >= Outfitter_cMaxDisplayedItems then + break ; + end + end + + if vItemIndex < Outfitter_cMaxDisplayedItems + and vEquippableItems.UnusedItems then + vItemIndex, vFirstItemIndex = Outfitter_AddOutfitItemsToList(vEquippableItems.UnusedItems, "OddsNEnds", vItemIndex, vFirstItemIndex); + end + + -- Hide any unused items + + for vItemIndex2 = vItemIndex, (Outfitter_cMaxDisplayedItems - 1) do + local vItemName = "OutfitterItem" .. vItemIndex2; + local vItem = getglobal(vItemName); + + vItem:Hide(); + end + + local vTotalNumItems = 0; + + for vCategoryIndex, vCategoryID in gOutfitter_cCategoryOrder do + vTotalNumItems = vTotalNumItems + 1; + + local vOutfits = gOutfitter_Settings.Outfits[vCategoryID]; + + if not gOutfitter_Collapsed[vCategoryID] + and vOutfits then + vTotalNumItems = vTotalNumItems + table.getn(vOutfits); + end + end + + if vEquippableItems.UnusedItems then + vTotalNumItems = vTotalNumItems + 1; + + if not gOutfitter_Collapsed["OddsNEnds"] then + vTotalNumItems = vTotalNumItems + table.getn(vEquippableItems.UnusedItems); + end + end + + FauxScrollFrame_Update( + OutfitterMainFrameScrollFrame, + vTotalNumItems, -- numItems + Outfitter_cMaxDisplayedItems, -- numToDisplay + 18, -- valueStep + nil, nil, nil, -- button, smallWidth, bigWidth + nil, -- highlightFrame + 0, 0); -- smallHighlightWidth, bigHighlightWidth + elseif gOutfitter_CurrentPanel == 2 then + -- Options panel + OutfitterShowMinimapButton:SetChecked(not gOutfitter_Settings.Options.HideMinimapButton); + OutfitterRememberVisibility:SetChecked(not gOutfitter_Settings.Options.DisableAutoVisibility); + OutfitterShowHotkeyMessages:SetChecked(not gOutfitter_Settings.Options.DisableHotkeyMessages); + OutfitterShowCurrentOutfit:SetChecked(gOutfitter_Settings.Options.ShowCurrentOutfit); + end +end + +function Outfitter_OnVerticalScroll() + gOutfitter_DisplayIsDirty = true; + Outfitter_Update(false); +end + +function Outfitter_SelectOutfit(pOutfit, pCategoryID) + if not Outfitter_IsOpen() then + return ; + end + + gOutfitter_SelectedOutfit = pOutfit; + + -- Get the equippable items so outfits can be marked if they're missing anything + + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + -- Update the slot enables + + Outfitter_UpdateSlotEnables(pOutfit, vEquippableItems); + OutfitterSlotEnables:Show(); + + -- Done, rebuild the list + + gOutfitter_DisplayIsDirty = true; +end + +function Outfitter_UpdateSlotEnables(pOutfit, pEquippableItems) + if UnitHasRelicSlot("player") then + OutfitterEnableAmmoSlot:Hide(); + else + OutfitterEnableAmmoSlot:Show(); + end + + for _, vInventorySlot in Outfitter_cSlotNames do + local vOutfitItem = pOutfit.Items[vInventorySlot]; + local vCheckbox = getglobal("OutfitterEnable" .. vInventorySlot); + + if not vOutfitItem then + vCheckbox:SetChecked(false); + else + if OutfitterItemList_InventorySlotContainsItem(pEquippableItems, vInventorySlot, vOutfitItem) then + vCheckbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check"); + vCheckbox.IsUnknown = false; + else + vCheckbox:SetCheckedTexture("Interface\\Addons\\Outfitter\\Textures\\CheckboxUnknown"); + vCheckbox.IsUnknown = true; + end + + vCheckbox:SetChecked(true); + end + end +end + +function Outfitter_ClearSelection() + gOutfitter_SelectedOutfit = nil; + gOutfitter_DisplayIsDirty = true; + OutfitterSlotEnables:Hide(); +end + +function Outfitter_FindOutfitItemIndex(pOutfit) + local vOutfitCategoryID, vOutfitIndex = Outfitter_FindOutfit(pOutfit); + + if not vOutfitCategoryID then + return nil; + end + + local vItemIndex = 0; + + for vCategoryIndex, vCategoryID in gOutfitter_cCategoryOrder do + vItemIndex = vItemIndex + 1; + + if not gOutfitter_Collapsed[vCategoryID] then + if vOutfitCategoryID == vCategoryID then + return vItemIndex + vOutfitIndex - 1; + else + vItemIndex = vItemIndex + table.getn(gOutfitter_Settings.Outfits[vCategoryID]); + end + end + end + + return nil; +end + +function OutfitterStack_FindOutfit(pOutfit) + for vIndex, vOutfit in gOutfitter_OutfitStack do + if vOutfit == pOutfit then + return true, vIndex; + end + end + + return false, nil; +end + +function OutfitterStack_FindOutfitByCategory(pCategoryID) + for vIndex, vOutfit in gOutfitter_OutfitStack do + if vOutfit.CategoryID == pCategoryID then + return true, vIndex; + end + end + + return false, nil; +end + +function OutfitterStack_Clear() + for vIndex, vOutfit in gOutfitter_OutfitStack do + Outfitter_DispatchOutfitEvent("UNWEAR_OUTFIT", vOutfit.Name, vOutfit) + end + + gOutfitter_OutfitStack = {}; + gOutfitter_Settings.LastOutfitStack = {}; + gOutfitter_DisplayIsDirty = true; + + if gOutfitter_Settings.Options.ShowStackContents then + Outfitter_DebugMessage("Outfitter stack cleared"); + end +end + +function OutfitterStack_ClearCategory(pCategoryID) + local vIndex = 1; + local vStackLength = table.getn(gOutfitter_OutfitStack); + local vChanged = false; + + while vIndex <= vStackLength do + local vOutfit = gOutfitter_OutfitStack[vIndex]; + + if vOutfit + and vOutfit.CategoryID == pCategoryID then + Outfitter_DispatchOutfitEvent("UNWEAR_OUTFIT", vOutfit.Name, vOutfit) + + table.remove(gOutfitter_OutfitStack, vIndex); + table.remove(gOutfitter_Settings.LastOutfitStack, vIndex); + + vStackLength = vStackLength - 1; + vChanged = true; + else + vIndex = vIndex + 1; + end + end + + OutfitterStack_CollapseTemporaryOutfits(); + + if vChanged then + if gOutfitter_Settings.Options.ShowStackContents then + OutfitterStack_DumpStackContents("Clear category " .. pCategoryID); + end + + gOutfitter_DisplayIsDirty = true; + end +end + +function OutfitterStack_GetTemporaryOutfit() + local vStackSize = table.getn(gOutfitter_OutfitStack); + + if vStackSize == 0 then + return nil; + end + + local vOutfit = gOutfitter_OutfitStack[vStackSize]; + + if vOutfit.Name then + return nil; + end + + return vOutfit; +end + +function OutfitterStack_CollapseTemporaryOutfits() + local vIndex = 1; + local vStackLength = table.getn(gOutfitter_OutfitStack); + local vTemporaryOutfit1 = nil; + + while vIndex <= vStackLength do + local vOutfit = gOutfitter_OutfitStack[vIndex]; + + if vOutfit + and vOutfit.Name == nil then + if vTemporaryOutfit1 then + -- Copy the items up + + for vInventorySlot, vItem in vTemporaryOutfit1.Items do + if not vOutfit.Items[vInventorySlot] then + vOutfit.Items[vInventorySlot] = vItem; + end + end + + -- Remove the lower temp outfit + + table.remove(gOutfitter_OutfitStack, vIndex - 1); + vStackLength = vStackLength - 1; + else + vIndex = vIndex + 1; + end + + vTemporaryOutfit1 = vOutfit; + else + vTemporaryOutfit1 = nil; + vIndex = vIndex + 1; + end + end +end + +function OutfitterStack_IsTopmostOutfit(pOutfit) + local vStackLength = table.getn(gOutfitter_OutfitStack); + + if vStackLength == 0 then + return false; + end + + return gOutfitter_OutfitStack[vStackLength] == pOutfit; +end + +function OutfitterStack_AddOutfit(pOutfit, pBelowOutfit) + local vFound, vIndex = OutfitterStack_FindOutfit(pOutfit); + + -- If it's already on then remove it from the stack + -- so it can be added to the end + + if vFound then + table.remove(gOutfitter_OutfitStack, vIndex); + table.remove(gOutfitter_Settings.LastOutfitStack, vIndex); + Outfitter_DispatchOutfitEvent("UNWEAR_OUTFIT", pOutfit.Name, pOutfit); + end + + -- Figure out the position to insert at + + local vStackLength = table.getn(gOutfitter_OutfitStack); + local vInsertIndex = vStackLength + 1; + + if pBelowOutfit then + local vFound2, vIndex = OutfitterStack_FindOutfit(pBelowOutfit); + + if vFound2 then + vInsertIndex = vIndex; + end + end + + --[[ Always insert below the temporary outfit + + local vTemporaryOutfit; + + if vStackLength > 0 then + vTemporaryOutfit = gOutfitter_OutfitStack[vStackLength]; + end + + if vTemporaryOutfit and vTemporaryOutfit.Name == nil then + -- Knock out any slots used by the new outfit if it's being inserted at the top + + if vInsertIndex >= vStackLength then + for vInventorySlot, vItem in pOutfit.Items do + vTemporaryOutfit.Items[vInventorySlot] = nil; + end + + -- Remove the temporary outfit if it's empty now + + if Outfitter_IsEmptyOutfit(vTemporaryOutfit) then + table.remove(gOutfitter_OutfitStack, vStackLength); + table.remove(gOutfitter_Settings.LastOutfitStack, vStackLength); + + vInsertIndex = vStackLength; + vStackLength = vStackLength - 1; + else + vInsertIndex = vStackLength; + end + end + end + + ]]-- + + -- Add the outfit + + table.insert(gOutfitter_OutfitStack, vInsertIndex, pOutfit); + + if pOutfit.Name then + table.insert(gOutfitter_Settings.LastOutfitStack, vInsertIndex, { Name = pOutfit.Name }); + else + table.insert(gOutfitter_Settings.LastOutfitStack, vInsertIndex, pOutfit); + end + + gOutfitter_DisplayIsDirty = true; + + if gOutfitter_Settings.Options.ShowStackContents then + OutfitterStack_DumpStackContents("Add outfit"); + end + + if vFound then + OutfitterStack_CollapseTemporaryOutfits(); + end + + Outfitter_DispatchOutfitEvent("WEAR_OUTFIT", pOutfit.Name, pOutfit); +end + +function OutfitterStack_RemoveOutfit(pOutfit) + local vFound, vIndex = OutfitterStack_FindOutfit(pOutfit); + + if not vFound then + return false; + end + + -- Remove the outfit + + table.remove(gOutfitter_OutfitStack, vIndex); + table.remove(gOutfitter_Settings.LastOutfitStack, vIndex); + + OutfitterStack_CollapseTemporaryOutfits(); + + gOutfitter_DisplayIsDirty = true; + + if gOutfitter_Settings.Options.ShowStackContents then + OutfitterStack_DumpStackContents("Remove outfit"); + end + + return true; +end + +function OutfitterStack_RestoreSavedStack() + if not gOutfitter_Settings.LastOutfitStack then + gOutfitter_Settings.LastOutfitStack = {}; + end + + for vIndex, vOutfit in gOutfitter_Settings.LastOutfitStack do + if vOutfit.Name then + vOutfit = Outfitter_FindOutfitByName(vOutfit.Name); + end + + if vOutfit then + table.insert(gOutfitter_OutfitStack, vOutfit); + end + end + + -- A temporary outfit that only empties several slots is the footprint of + -- an earlier login where the gear hadn't loaded yet. Wearing it would strip + -- the character, so drop it. + + local vTemporaryOutfit = OutfitterStack_GetTemporaryOutfit(); + + if vTemporaryOutfit and Outfitter_IsSuspiciousStripOutfit(vTemporaryOutfit) then + local vStackSize = table.getn(gOutfitter_OutfitStack); + + table.remove(gOutfitter_OutfitStack, vStackSize); + gOutfitter_Settings.LastOutfitStack = {}; + + for _, vOutfit in gOutfitter_OutfitStack do + if vOutfit.Name then + table.insert(gOutfitter_Settings.LastOutfitStack, { Name = vOutfit.Name }); + else + table.insert(gOutfitter_Settings.LastOutfitStack, vOutfit); + end + end + + Outfitter_NoteMessage(Outfitter_cDiscardedStripOutfit); + end + + gOutfitter_ExpectedOutfit = Outfitter_GetCompiledOutfit(); + + -- Comparing the saved outfit with what's equipped is deferred until the + -- equipped items can be read (Outfitter_InventoryVerified) + + if gOutfitter_Settings.Options.ShowStackContents then + OutfitterStack_DumpStackContents("Restore saved stack"); + end +end + +-- An outfit counts as a suspicious strip when it has no items at all, only +-- emptied slots, and empties at least three of them. Players don't take off +-- three pieces within one inventory update by hand; a failed read does. + +function Outfitter_IsSuspiciousStripOutfit(pOutfit) + local vEmptySlots = 0; + + for vInventorySlot, vItem in pOutfit.Items do + if vInventorySlot ~= "AmmoSlot" then + if vItem.Code and vItem.Code ~= 0 then + return false; + end + + vEmptySlots = vEmptySlots + 1; + end + end + + return vEmptySlots >= 3; +end + +-- Inventory verification +-- +-- After a crash the client's item cache (WDB) is usually discarded, so for a +-- while after login GetInventoryItemLink() returns nil for equipped items. +-- Outfitter used to read that as "every slot is empty", record it as a +-- temporary outfit on top of the stack and, on the next equipment update, +-- move all the gear into the bags. Now nothing is compared or equipped until +-- two consecutive reads agree and the item data is available. + +local cOutfitter_VerifyInterval = 0.5; +local cOutfitter_VerifyMaxAttempts = 60; -- 30 seconds + +local gOutfitter_VerifyAttempts = 0; +local gOutfitter_VerifyLastSignature = nil; + +function Outfitter_ReadInventorySignature() + local vSignature = ""; + local vNumItems = 0; + local vNumUnreadable = 0; + + for _, vInventorySlot in Outfitter_cSlotNames do + if vInventorySlot ~= "AmmoSlot" then + local vSlotID = GetInventorySlotInfo(vInventorySlot); + local vItemInfo = Outfitter_GetItemInfoFromLink(GetInventoryItemLink("player", vSlotID)); + + if vItemInfo then + vNumItems = vNumItems + 1; + vSignature = vSignature .. vItemInfo.Code .. ","; + else + -- An icon with no readable link means the slot is occupied + -- but the item data hasn't arrived yet + + if GetInventoryItemTexture("player", vSlotID) then + vNumUnreadable = vNumUnreadable + 1; + end + + vSignature = vSignature .. "0,"; + end + end + end + + return vSignature, vNumItems, vNumUnreadable; +end + +-- True when the client has item data for everything the saved outfit +-- expects to be worn. GetItemInfo() returns nil for uncached items. + +function Outfitter_ExpectedItemsAreCached() + if not gOutfitter_ExpectedOutfit then + return true; + end + + for vInventorySlot, vItem in gOutfitter_ExpectedOutfit.Items do + if vItem.Code and vItem.Code ~= 0 and not GetItemInfo(vItem.Code) then + return false; + end + end + + return true; +end + +function Outfitter_ExpectedOutfitIsEmpty() + if not gOutfitter_ExpectedOutfit then + return true; + end + + for vInventorySlot, vItem in gOutfitter_ExpectedOutfit.Items do + if vInventorySlot ~= "AmmoSlot" and vItem.Code and vItem.Code ~= 0 then + return false; + end + end + + return true; +end + +function Outfitter_IsInventoryVerified() + return gOutfitter_InventoryVerified; +end + +function Outfitter_BeginInventoryVerification() + gOutfitter_InventoryVerified = false; + gOutfitter_VerifyAttempts = 0; + gOutfitter_VerifyLastSignature = nil; + + if AceEvent then + AceEvent:ScheduleEvent("OutfitterVerifyInventory", Outfitter_VerifyInventoryTick, cOutfitter_VerifyInterval); + else + Outfitter_InventoryVerifiedNow(); + end +end + +function Outfitter_VerifyInventoryTick() + if gOutfitter_InventoryVerified then + return ; + end + + gOutfitter_VerifyAttempts = gOutfitter_VerifyAttempts + 1; + + local vSignature, vNumItems, vNumUnreadable = Outfitter_ReadInventorySignature(); + local vStable = vSignature == gOutfitter_VerifyLastSignature; + local vTimedOut = gOutfitter_VerifyAttempts >= cOutfitter_VerifyMaxAttempts; + + gOutfitter_VerifyLastSignature = vSignature; + + local vReady = vStable + and vNumUnreadable == 0 + and Outfitter_ExpectedItemsAreCached() + and (vNumItems > 0 or Outfitter_ExpectedOutfitIsEmpty()); + + if vReady or vTimedOut then + Outfitter_InventoryVerifiedNow(); + else + AceEvent:ScheduleEvent("OutfitterVerifyInventory", Outfitter_VerifyInventoryTick, cOutfitter_VerifyInterval); + end +end + +function Outfitter_InventoryVerifiedNow() + gOutfitter_InventoryVerified = true; + + Outfitter_BeginEquipmentUpdate(); + + -- Re-read everything now that the item data is trustworthy + + OutfitterItemList_FlushEquippableItems(); + gOutfitter_CurrentOutfit = Outfitter_GetInventoryOutfit(); + + if gOutfitter_ExpectedOutfit then + local vNewItemsOutfit = Outfitter_GetNewItemsOutfit(gOutfitter_ExpectedOutfit); + + -- Even after waiting, never turn a mass disappearance of gear into a + -- temporary outfit; let the saved outfit re-equip instead + + if vNewItemsOutfit + and not Outfitter_IsSuspiciousStripOutfit(vNewItemsOutfit) then + Outfitter_UpdateTemporaryOutfit(vNewItemsOutfit); + end + end + + gOutfitter_DisplayIsDirty = true; + + Outfitter_EndEquipmentUpdate("Outfitter_InventoryVerifiedNow"); +end + +function OutfitterStack_DumpStackContents(pOperation) + Outfitter_DebugMessage("Outfitter Stack Contents: " .. pOperation); + + for vIndex, vOutfit in gOutfitter_OutfitStack do + if vOutfit.Name then + Outfitter_DebugMessage("Slot " .. vIndex .. ": " .. vOutfit.Name); + else + Outfitter_DebugMessage("Slot " .. vIndex .. ": Temporaray outfit"); + end + end +end + +function Outfitter_WearOutfit(pOutfit, pCategoryID, pWearBelowOutfit) + if pOutfit.Disabled then + return ; + end + + -- + + Outfitter_BeginEquipmentUpdate(); + + if pCategoryID == "Complete" then + OutfitterStack_Clear(); + elseif pCategoryID == "Partial" then + OutfitterStack_ClearCategory(pCategoryID); + OutfitterStack_ClearCategory("Accessory"); + end + + OutfitterStack_AddOutfit(pOutfit, pWearBelowOutfit); + + -- If outfitter is open then also select the outfit + + if Outfitter_IsOpen() then + if OutfitterStack_IsTopmostOutfit(pOutfit) then + Outfitter_SelectOutfit(pOutfit, pCategoryID); + else + Outfitter_ClearSelection(); + end + end + + -- Update the equipment + + gOutfitter_EquippedNeedsUpdate = true; + gOutfitter_WeaponsNeedUpdate = true; + + Outfitter_EndEquipmentUpdate("Outfitter_WearOutfit"); + + Outfitter_UpdateCurrentOutfit(); +end + +function Outfitter_SetOutfitBindingIndex(pOutfit, pBindingIndex) + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if vOutfit.BindingIndex == pBindingIndex then + vOutfit.BindingIndex = nil; + end + end + end + + pOutfit.BindingIndex = pBindingIndex; +end + +local gOutfitter_LastBindingIndex = nil; +local gOutfitter_LastBindingTime = nil; +local Outfitter_cMinBindingTime = 0.75; + +function Outfitter_WearBoundOutfit(pBindingIndex) + -- Check for the user spamming the button so prevent the outfit from + -- toggling if they're panicking + + local vTime = GetTime(); + + if gOutfitter_LastBindingIndex == pBindingIndex then + local vElapsed = vTime - gOutfitter_LastBindingTime; + + if vElapsed < Outfitter_cMinBindingTime then + gOutfitter_LastBindingTime = vTime; + return ; + end + end + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if vOutfit.BindingIndex == pBindingIndex then + vOutfit.Disabled = nil; + if vCategoryID == "Complete" then + Outfitter_WearOutfit(vOutfit, vCategoryID); + if not gOutfitter_Settings.Options.DisableHotkeyMessages then + UIErrorsFrame:AddMessage(format(Outfitter_cEquipOutfitMessageFormat, vOutfit.Name), OUTFIT_MESSAGE_COLOR.r, OUTFIT_MESSAGE_COLOR.g, OUTFIT_MESSAGE_COLOR.b); + end + else + local vEquipped = Outfitter_ToggleOutfit(vOutfit, vCategoryID); + + if not gOutfitter_Settings.Options.DisableHotkeyMessages then + if vEquipped then + UIErrorsFrame:AddMessage(format(Outfitter_cEquipOutfitMessageFormat, vOutfit.Name), OUTFIT_MESSAGE_COLOR.r, OUTFIT_MESSAGE_COLOR.g, OUTFIT_MESSAGE_COLOR.b); + else + UIErrorsFrame:AddMessage(format(Outfitter_cUnequipOutfitMessageFormat, vOutfit.Name), OUTFIT_MESSAGE_COLOR.r, OUTFIT_MESSAGE_COLOR.g, OUTFIT_MESSAGE_COLOR.b); + end + end + + end + + -- Remember the binding used to filter for button spam + + gOutfitter_LastBindingIndex = pBindingIndex; + gOutfitter_LastBindingTime = vTime; + + return ; + end + end + end +end + +function Outfitter_FindOutfit(pOutfit) + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if vOutfit == pOutfit then + return vCategoryID, vOutfitIndex; + end + end + end + + return nil, nil; +end + +function Outfitter_FindOutfitByName(pName) + if not pName + or pName == "" then + return nil; + end + + local vLowerName = strlower(pName); + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if strlower(vOutfit.Name) == vLowerName then + return vOutfit, vCategoryID, vOutfitIndex; + end + end + end + + return nil, nil; +end + +-- Outfitter doesn't use this function, but other addons such as +-- Fishing Buddy might use it to locate specific generated outfits + +function Outfitter_FindOutfitByStatID(pStatID) + if not pStatID or pStatID == "" then + return nil; + end + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if vOutfit.StatID and vOutfit.StatID == pStatID then + return vOutfit, vCategoryID, vOutfitIndex; + end + end + end + + return nil; +end + +function Outfitter_RemoveOutfit(pOutfit) + if not OutfitterStack_RemoveOutfit(pOutfit) then + return ; + end + + -- Stop monitoring health and mana if it's the dining outfit + + if pOutfit.SpecialID == "Dining" then + Outfitter_SuspendEvent(OutfitterFrame, "UNIT_HEALTH"); + Outfitter_SuspendEvent(OutfitterFrame, "UNIT_MANA"); + end + + -- + + Outfitter_BeginEquipmentUpdate(); + + -- Clear the selection if the outfit being removed + -- is selected too + + if gOutfitter_SelectedOutfit == pOutfit then + Outfitter_ClearSelection(); + end + + -- Update the list + + gOutfitter_EquippedNeedsUpdate = true; + gOutfitter_WeaponsNeedUpdate = true; + + Outfitter_EndEquipmentUpdate("Outfitter_RemoveOutfit"); + + Outfitter_DispatchOutfitEvent("UNWEAR_OUTFIT", pOutfit.Name, pOutfit); + + Outfitter_UpdateCurrentOutfit(); +end + +function Outfitter_ToggleOutfit(pOutfit, pCategoryID) + if Outfitter_WearingOutfit(pOutfit) then + Outfitter_RemoveOutfit(pOutfit); + return false; + else + Outfitter_WearOutfit(pOutfit, pCategoryID); + return true; + end +end + +function Outfitter_OutfitSummary() + local _, vPlayerClass = UnitClass("player"); + local vStatDistribution = gOutfitter_StatDistribution[vPlayerClass]; + local vCurrentOutfitStats = OutfitterTankPoints_GetCurrentOutfitStats(vStatDistribution); + + Outfitter_DumpArray("Current Stats", vCurrentOutfitStats); +end + +function Outfitter_GetCompiledOutfit() + local vCompiledOutfit = Outfitter_NewEmptyOutfit(); + + vCompiledOutfit.SourceOutfit = {}; + + for vStackIndex, vOutfit in gOutfitter_OutfitStack do + for vInventorySlot, vOutfitItem in vOutfit.Items do + vCompiledOutfit.Items[vInventorySlot] = vOutfitItem; + vCompiledOutfit.SourceOutfit[vInventorySlot] = vOutfit.Name; + end + end + + return vCompiledOutfit; +end + +function Outfitter_GetExpectedOutfit(pExcludeOutfit) + local vCompiledOutfit = Outfitter_NewEmptyOutfit(); + + vCompiledOutfit.SourceOutfit = {}; + + for vStackIndex, vOutfit in gOutfitter_OutfitStack do + if vOutfit ~= pExcludeOutfit then + for vInventorySlot, vOutfitItem in vOutfit.Items do + vCompiledOutfit.Items[vInventorySlot] = vOutfitItem; + vCompiledOutfit.SourceOutfit[vInventorySlot] = vOutfit.Name; + end + end + end + + return vCompiledOutfit; +end + +function Outfitter_GetEmptyBagSlot(pStartBagIndex, pStartBagSlotIndex, pIncludeBank) + local vStartBagIndex = pStartBagIndex; + local vStartBagSlotIndex = pStartBagSlotIndex; + + if not vStartBagIndex then + vStartBagIndex = NUM_BAG_SLOTS; + end + + if not vStartBagSlotIndex then + vStartBagSlotIndex = 1; + end + + local vEndBagIndex = 0; + + if pIncludeBank then + vEndBagIndex = -1; + end + + for vBagIndex = vStartBagIndex, vEndBagIndex, -1 do + -- Skip the bag if it's a specialty bag (ammo pouch, quiver, shard bag) + + local vSkipBag = false; + + if vBagIndex > 0 then + -- Don't worry about the backpack + local vItemLink = GetInventoryItemLink("player", ContainerIDToInventoryID(vBagIndex)); + local vItemInfo = Outfitter_GetItemInfoFromLink(vItemLink); + + if vItemInfo + and Outfitter_cSpecialtyBags[vItemInfo.Code] ~= nil then + vSkipBag = true; + end + end + + -- Search the bag for empty slots + + if not vSkipBag then + local vNumBagSlots = GetContainerNumSlots(vBagIndex); + + if vNumBagSlots > 0 then + for vSlotIndex = vStartBagSlotIndex, vNumBagSlots do + local vItemInfo = Outfitter_GetBagItemInfo(vBagIndex, vSlotIndex); + + if not vItemInfo then + return { BagIndex = vBagIndex, BagSlotIndex = vSlotIndex }; + end + end + end + end + + vStartBagSlotIndex = 1; + end + + return nil; +end + +function Outfitter_GetEmptyBagSlotList() + local vEmptyBagSlots = {}; + + local vBagIndex = NUM_BAG_SLOTS; + local vBagSlotIndex = 1; + + while true do + local vBagSlotInfo = Outfitter_GetEmptyBagSlot(vBagIndex, vBagSlotIndex); + + if not vBagSlotInfo then + return vEmptyBagSlots; + end + + table.insert(vEmptyBagSlots, vBagSlotInfo); + + vBagIndex = vBagSlotInfo.BagIndex; + vBagSlotIndex = vBagSlotInfo.BagSlotIndex + 1; + end +end + +function Outfitter_GetEmptyBankSlotList() + local vEmptyBagSlots = {}; + + local vBagIndex = NUM_BAG_SLOTS + NUM_BANKBAGSLOTS; + local vBagSlotIndex = 1; + + while true do + local vBagSlotInfo = Outfitter_GetEmptyBagSlot(vBagIndex, vBagSlotIndex, true); + + if not vBagSlotInfo then + return vEmptyBagSlots; + + elseif vBagSlotInfo.BagIndex > NUM_BAG_SLOTS + or vBagSlotInfo.BagIndex < 0 then + table.insert(vEmptyBagSlots, vBagSlotInfo); + end + + vBagIndex = vBagSlotInfo.BagIndex; + vBagSlotIndex = vBagSlotInfo.BagSlotIndex + 1; + end +end + +function Outfitter_FindItemsInBagsForSlot(pSlotName) + local vInventorySlot = pSlotName; + + -- Alias the slot names down for finger and trinket + + if vInventorySlot == "Finger1Slot" then + vInventorySlot = "Finger0Slot"; + elseif vInventorySlot == "Trinket1Slot" then + vInventorySlot = "Trinket0Slot"; + end + + -- + + local vItems = {}; + local vNumBags, vFirstBagIndex = Outfitter_GetNumBags(); + + for vBagIndex = vFirstBagIndex, vNumBags do + local vNumBagSlots = GetContainerNumSlots(vBagIndex); + + if vNumBagSlots > 0 then + for vSlotIndex = 1, vNumBagSlots do + local vItemInfo = Outfitter_GetBagItemInfo(vBagIndex, vSlotIndex); + + if vItemInfo then + local vItemSlotName = vItemInfo.ItemSlotName; + + if vItemInfo.MetaSlotName then + vItemSlotName = vItemInfo.MetaSlotName; + end + + if vItemSlotName == "TwoHandSlot" then + vItemSlotName = "MainHandSlot"; + elseif vItemSlotName == "Weapon0Slot" then + if vInventorySlot == "MainHandSlot" + or vInventorySlot == "SecondaryHandSlot" then + vItemSlotName = vInventorySlot; + end + end + + if vItemSlotName == vInventorySlot then + table.insert(vItems, { BagIndex = vBagIndex, BagSlotIndex = vSlotIndex, Code = vItemInfo.Code, Name = vItemInfo.Name }); + end + end + end + end + end + + if table.getn(vItems) == 0 then + return nil; + end + + return vItems; +end + +function Outfitter_PickupItemLocation(pItemLocation) + if pItemLocation == nil then + Outfitter_ErrorMessage("Outfitter: nil location in PickupItemLocation"); + return ; + end + + if pItemLocation.BagIndex then + PickupContainerItem(pItemLocation.BagIndex, pItemLocation.BagSlotIndex); + elseif pItemLocation.SlotName then + local vSlotID, vEmptySlotTexture = GetInventorySlotInfo(pItemLocation.SlotName); + + PickupInventoryItem(vSlotID); + else + Outfitter_ErrorMessage("Outfitter: Unknown location in PickupItemLocation"); + return ; + end +end + +function Outfitter_BuildUnequipChangeList(pOutfit, pEquippableItems) + local vEquipmentChangeList = {}; + + for vInventorySlot, vOutfitItem in pOutfit.Items do + local vItem, vIgnoredItem = OutfitterItemList_FindItemOrAlt(pEquippableItems, vOutfitItem, true); + + if vItem then + table.insert(vEquipmentChangeList, { FromLocation = vItem.Location, Item = vItem, ToLocation = nil }); + end + end -- for + + return vEquipmentChangeList; +end + +function Outfitter_BuildEquipmentChangeList(pOutfit, pEquippableItems) + local vEquipmentChangeList = {}; + + OutfitterItemList_ResetIgnoreItemFlags(pEquippableItems); + + -- Remove items which are already in the correct slot from the outfit and from the + -- equippable items list + + for vInventorySlot, vOutfitItem in pOutfit.Items do + local vContainsItem, vItem = OutfitterItemList_InventorySlotContainsItem(pEquippableItems, vInventorySlot, vOutfitItem); + + if vContainsItem then + pOutfit.Items[vInventorySlot] = nil; + + if vItem then + vItem.IgnoreItem = true; + end + end + end + + -- Scan the outfit using the Outfitter_cSlotNames array as an index so that changes + -- are executed in the specified order + + for _, vInventorySlot in Outfitter_cSlotNames do + local vOutfitItem = pOutfit.Items[vInventorySlot]; + + if vOutfitItem then + local vSlotID, vEmptySlotTexture = GetInventorySlotInfo(vInventorySlot); + local vCurrentItemInfo = Outfitter_GetInventoryItemInfo(vInventorySlot); + + -- Empty the slot if it's supposed to be blank + + if vOutfitItem.Code == 0 then + if vCurrentItemInfo then + table.insert(vEquipmentChangeList, { SlotName = vInventorySlot, SlotID = vSlotID, ItemName = vOutfitItem.Name, ItemLocation = nil }); + end + + else + -- Find the item + + local vItem, vIgnoredItem = OutfitterItemList_FindItemOrAlt(pEquippableItems, vOutfitItem, true); + + -- If the item wasn't found then show an appropriate error message + + if not vItem then + if vOutfitItem.Name then + if vIgnoredItem then + local vSlotDisplayName = Outfitter_cSlotDisplayNames[vInventorySlot]; + + if not vSlotDisplayName then + vSlotDisplayName = vInventorySlot; + end + + Outfitter_ErrorMessage(format(Outfitter_cItemAlreadyUsedError, vOutfitItem.Name, vSlotDisplayName)); + else + Outfitter_ErrorMessage(format(Outfitter_cItemNotFoundError, vOutfitItem.Name)); + end + else + Outfitter_ErrorMessage(format(Outfitter_cItemNotFoundError, "unknown")); + end + + -- Generate a change to move the item from its present location to the correct slot + + else + pOutfit.Items[vInventorySlot].MetaSlotName = vItem.MetaSlotName; + table.insert(vEquipmentChangeList, { SlotName = vInventorySlot, SlotID = vSlotID, ItemName = vOutfitItem.Name, ItemMetaSlotName = vItem.MetaSlotName, ItemLocation = vItem }); + end + end + end -- if + end -- for + + if table.getn(vEquipmentChangeList) == 0 then + return nil; + end + + Outfitter_OptimizeEquipmentChangeList(vEquipmentChangeList); + + return vEquipmentChangeList; +end + +function Outfitter_FindEquipmentChangeForSlot(pEquipmentChangeList, pSlotName) + for vChangeIndex, vEquipmentChange in pEquipmentChangeList do + if vEquipmentChange.SlotName == pSlotName then + return vChangeIndex, vEquipmentChange; + end + end + + return nil, nil; +end + +function Outfitter_FixSlotSwapChange(pEquipmentList, pChangeIndex1, pEquipmentChange1, pSlotName1, pChangeIndex2, pEquipmentChange2, pSlotName2) + -- No problem if both slots will be emptied + + if not pEquipmentChange1.ItemLocation + and not pEquipmentChange2.ItemLocation then + return ; + end + + -- No problem if neither slot is being moved to the other one + + local vSlot2ToSlot1 = pEquipmentChange1.ItemLocation ~= nil + and pEquipmentChange1.ItemLocation.SlotName == pSlotName2; + + local vSlot1ToSlot2 = pEquipmentChange2.ItemLocation ~= nil + and pEquipmentChange2.ItemLocation.SlotName == pSlotName1; + + -- No problem if the slots are swapping with each other + -- or not moving between each other at all + + if vSlot2ToSlot1 == vSlot1ToSlot2 then + return ; + end + + -- Slot 1 is moving to slot 2 + + if vSlot1ToSlot2 then + + if pEquipmentChange1.ItemLocation then + -- Swap change 1 and change 2 around + + pEquipmentList[pChangeIndex1] = pEquipmentChange2; + pEquipmentList[pChangeIndex2] = pEquipmentChange1; + + -- Insert a change to empty slot 2 + + table.insert(pEquipmentList, pChangeIndex1, { SlotName = pEquipmentChange2.SlotName, SlotID = pEquipmentChange2.SlotID, ItemLocation = nil }); + else + -- Slot 1 is going to be empty, so empty slot 2 instead + -- and then when slot 1 is moved it'll swap the empty space + + pEquipmentChange1.SlotName = pSlotName2; + pEquipmentChange1.SlotID = pEquipmentChange2.SlotID; + pEquipmentChange1.ItemLocation = nil; + end + + -- Slot 2 is moving to slot 1 + + else + if pEquipmentChange2.ItemLocation then + -- Insert a change to empty slot 1 first + + table.insert(pEquipmentList, pChangeIndex1, { SlotName = pEquipmentChange1.SlotName, SlotID = pEquipmentChange1.SlotID, ItemLocation = nil }); + else + -- Slot 2 is going to be empty, so empty slot 1 instead + -- and then when slot 2 is moved it'll swap the empty space + + pEquipmentChange2.SlotName = pSlotName1; + pEquipmentChange2.SlotID = pEquipmentChange1.SlotID; + pEquipmentChange2.ItemLocation = nil; + + -- Change the order so that slot 1 gets emptied before the move + + pEquipmentList[pChangeIndex1] = pEquipmentChange2; + pEquipmentList[pChangeIndex2] = pEquipmentChange1; + end + end +end + +function Outfitter_OptimizeEquipmentChangeList(pEquipmentChangeList) + local vSwapList = { + { Slot1 = "Finger0Slot", Slot2 = "Finger1Slot" }, + { Slot1 = "Trinket0Slot", Slot2 = "Trinket1Slot" }, + { Slot1 = "MainHandSlot", Slot2 = "SecondaryHandSlot" }, + }; + + local vDidSlot = {}; + + local vChangeIndex = 1; + local vNumChanges = table.getn(pEquipmentChangeList); + + while vChangeIndex <= vNumChanges do + local vEquipmentChange = pEquipmentChangeList[vChangeIndex]; + + -- If a two-hand weapon is being equipped, remove the change event + -- for removing the offhand slot + + if vEquipmentChange.ItemMetaSlotName == "TwoHandSlot" then + local vChangeIndex2, vEquipmentChange2 = Outfitter_FindEquipmentChangeForSlot(pEquipmentChangeList, "SecondaryHandSlot"); + + -- If there's a change for the offhand slot, remove it + + if vChangeIndex2 then + table.remove(pEquipmentChangeList, vChangeIndex2); + + if vChangeIndex2 < vChangeIndex then + vChangeIndex = vChangeIndex - 1; + end + + vNumChanges = vNumChanges - 1; + end + + -- Insert a new change for the offhand slot to empty it ahead + -- of equipping the two-hand item + + local vSlotID, vEmptySlotTexture = GetInventorySlotInfo("SecondaryHandSlot"); + + table.insert(pEquipmentChangeList, vChangeIndex, { SlotName = "SecondaryHandSlot", SlotID = vSlotID, ItemLocation = nil }); + + -- Otherwise see if the change needs to be re-arranged so that slot + -- swapping works correctly + + else + for vSwapListIndex, vSwapSlotInfo in vSwapList do + if vEquipmentChange.SlotName == vSwapSlotInfo.Slot1 + and not vDidSlot[vEquipmentChange.SlotName] then + local vChangeIndex2, vEquipmentChange2 = Outfitter_FindEquipmentChangeForSlot(pEquipmentChangeList, vSwapSlotInfo.Slot2); + + if vChangeIndex2 then + Outfitter_FixSlotSwapChange(pEquipmentChangeList, vChangeIndex, vEquipmentChange, vSwapSlotInfo.Slot1, vChangeIndex2, vEquipmentChange2, vSwapSlotInfo.Slot2); + end + + vDidSlot[vEquipmentChange.SlotName] = true; + + vNumChanges = table.getn(pEquipmentChangeList); + end + end + end + + vChangeIndex = vChangeIndex + 1; + end +end + +function Outfitter_ExecuteEquipmentChangeList(pEquipmentChangeList, pEmptyBagSlots, pExpectedEquippableItems) + for vChangeIndex, vEquipmentChange in pEquipmentChangeList do + if vEquipmentChange.ItemLocation then + Outfitter_PickupItemLocation(vEquipmentChange.ItemLocation); + EquipCursorItem(vEquipmentChange.SlotID); + + if pExpectedEquippableItems then + OutfitterItemList_SwapLocationWithInventorySlot(pExpectedEquippableItems, vEquipmentChange.ItemLocation, vEquipmentChange.SlotName); + end + else + -- Remove the item + + if not pEmptyBagSlots + or table.getn(pEmptyBagSlots) == 0 then + local vItemInfo = Outfitter_GetInventoryItemInfo(vEquipmentChange.SlotName); + + if not vItemInfo then + Outfitter_ErrorMessage("Outfitter internal error: Can't empty slot " .. vEquipmentChange.SlotName .. " because bags are full but slot is empty"); + else + Outfitter_ErrorMessage(format(Outfitter_cBagsFullError, vItemInfo.Name)); + end + else + local vBagIndex = pEmptyBagSlots[1].BagIndex; + local vBagSlotIndex = pEmptyBagSlots[1].BagSlotIndex; + + table.remove(pEmptyBagSlots, 1); + + PickupInventoryItem(vEquipmentChange.SlotID); + PickupContainerItem(vBagIndex, vBagSlotIndex); + + if pExpectedEquippableItems then + OutfitterItemList_SwapBagSlotWithInventorySlot(pExpectedEquippableItems, vBagIndex, vBagSlotIndex, vEquipmentChange.SlotName); + end + end + end + end +end + +function Outfitter_ExecuteEquipmentChangeList2(pEquipmentChangeList, pEmptySlots, pBagsFullErrorFormat, pExpectedEquippableItems) + for vChangeIndex, vEquipmentChange in pEquipmentChangeList do + if vEquipmentChange.ToLocation then + Outfitter_PickupItemLocation(vEquipmentChange.FromLocation); + EquipCursorItem(vEquipmentChange.SlotID); + + if pExpectedEquippableItems then + OutfitterItemList_SwapLocationWithInventorySlot(pExpectedEquippableItems, vEquipmentChange.ToLocation, vEquipmentChange.SlotName); + end + else + -- Remove the item + + if not pEmptySlots + or table.getn(pEmptySlots) == 0 then + Outfitter_ErrorMessage(format(pBagsFullErrorFormat, vEquipmentChange.Item.Name)); + else + local vToLocation = { BagIndex = pEmptySlots[1].BagIndex, BagSlotIndex = pEmptySlots[1].BagSlotIndex }; + + table.remove(pEmptySlots, 1); + + Outfitter_PickupItemLocation(vEquipmentChange.FromLocation); + Outfitter_PickupItemLocation(vToLocation); + + if pExpectedEquippableItems then + OutfitterItemList_SwapLocations(pExpectedEquippableItems, vEquipmentChange.FromLocation, vToLocation); + end + end + end + end +end + +function Outfitter_OutfitHasCombatEquipmentSlots(pOutfit) + for vEquipmentSlot, _ in Outfitter_cCombatEquipmentSlots do + if pOutfit.Items[vEquipmentSlot] then + return true; + end + end + + return false; +end + +function Outfitter_OutfitOnlyHasCombatEquipmentSlots(pOutfit) + for vEquipmentSlot, _ in pOutfit.Items do + if not Outfitter_cCombatEquipmentSlots[vEquipmentSlot] then + return false; + end + end + + return true; +end + +local gOutfitter_EquipmentUpdateCount = 0; + +function Outfitter_BeginEquipmentUpdate() + gOutfitter_EquipmentUpdateCount = gOutfitter_EquipmentUpdateCount + 1; +end + +function Outfitter_EndEquipmentUpdate(pCallerName) + gOutfitter_EquipmentUpdateCount = gOutfitter_EquipmentUpdateCount - 1; + + if gOutfitter_EquipmentUpdateCount == 0 then + Outfitter_UpdateEquippedItems(); + Outfitter_Update(false); + end +end + +function Outfitter_UpdateEquippedItems() + if not gOutfitter_EquippedNeedsUpdate + and not gOutfitter_WeaponsNeedUpdate then + return ; + end + + -- Don't equip anything until the current gear has been read reliably; + -- the pending flags stay set and verification runs this again + + if not gOutfitter_InventoryVerified then + return ; + end + + -- Delay all changes until they're alive + + if gOutfitter_IsDead then + -- or gOutfitter_IsFeigning then -- no longer disabling outfit changes during FD + return ; + end + + local vCurrentTime = GetTime(); + + if vCurrentTime - gOutfitter_LastEquipmentUpdateTime < Outfitter_cMinEquipmentUpdateInterval then + OutfitterTimer_AdjustTimer(); + return ; + end + + gOutfitter_LastEquipmentUpdateTime = vCurrentTime; + + local vWeaponsNeedUpdate = gOutfitter_WeaponsNeedUpdate; + + gOutfitter_EquippedNeedsUpdate = false; + gOutfitter_WeaponsNeedUpdate = false; + + -- Compile the outfit + + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + local vCompiledOutfit = Outfitter_GetCompiledOutfit(); + + -- If the outfit contains non-weapon changes then + -- delay the change until they're out of combat but go + -- ahead and swap the weapon slots if there are any + + if gOutfitter_InCombat then + if vWeaponsNeedUpdate + and Outfitter_OutfitHasCombatEquipmentSlots(vCompiledOutfit) then + + -- Allow the weapon change to proceed but defer the rest + -- until they're out of combat + + local vWeaponOutfit = Outfitter_NewEmptyOutfit(); + + for vEquipmentSlot, _ in Outfitter_cCombatEquipmentSlots do + vWeaponOutfit.Items[vEquipmentSlot] = vCompiledOutfit.Items[vEquipmentSlot]; + end + + -- Still need to update the rest once they exit combat + -- if there are non-equipment slot items + + if not Outfitter_OutfitOnlyHasCombatEquipmentSlots(vCompiledOutfit) then + gOutfitter_EquippedNeedsUpdate = true; + end + + -- Switch to the weapons-only part + + vCompiledOutfit = vWeaponOutfit; + else + -- No weapon changes, just defer the whole outfit change + + gOutfitter_EquippedNeedsUpdate = true; + return ; + end + end + + -- Equip it + + local vEquipmentChangeList = Outfitter_BuildEquipmentChangeList(vCompiledOutfit, vEquippableItems); + + if vEquipmentChangeList then + -- local vExpectedEquippableItems = OutfitterItemList_New(); + + Outfitter_ExecuteEquipmentChangeList(vEquipmentChangeList, Outfitter_GetEmptyBagSlotList(), vExpectedEquippableItems); + + -- Outfitter_DumpArray("ExpectedEquippableItems", vExpectedEquippableItems); + end + + -- Update the outfit we're expecting to see on the player + + for vInventorySlot, vItem in vCompiledOutfit.Items do + gOutfitter_ExpectedOutfit.Items[vInventorySlot] = vCompiledOutfit.Items[vInventorySlot]; + end +end + +function Outfitter_InitDebugging() + if gOutfitter_InitializedDebug then + return ; + end + + gOutfitter_InitializedDebug = true; + + -- Find the debug frame if there is one + + for vChatIndex = 1, NUM_CHAT_WINDOWS do + local vChatFrame = getglobal("ChatFrame" .. vChatIndex); + + if vChatFrame + and (vChatFrame:IsVisible() or vChatFrame.isDocked) then + local vTab = getglobal("ChatFrame" .. vChatIndex .. "Tab"); + local vName = vTab:GetText(); + + if vName == "Debug" then + gOutfitter_DebugFrame = vChatFrame; + if gOutfitter_DebugFrame:GetMaxLines() < 1000 then + gOutfitter_DebugFrame:SetMaxLines(1000); + end + _ERRORMESSAGE = function(message) + Outfitter_DebugMessage(message); + end; + end + end + end + + if gOutfitter_DebugFrame then + Outfitter_DebugMessage("Found debugging chat frame"); + end +end + +function Outfitter_DebugMessage(pMessage) + if gOutfitter_DebugFrame then + gOutfitter_DebugFrame:AddMessage("DEBUG: " .. pMessage, 0.7, 0.3, 1.0); + + local vTabFlash = getglobal(gOutfitter_DebugFrame:GetName() .. "TabFlash"); + + vTabFlash:Show(); + UIFrameFlash(vTabFlash, 0.25, 0.25, 60, nil, 0.5, 0.5); + else + DEFAULT_CHAT_FRAME:AddMessage("DEBUG: " .. pMessage, 0.7, 0.3, 1.0); + end +end + +function Outfitter_ErrorMessage(pMessage) + DEFAULT_CHAT_FRAME:AddMessage(pMessage, 0.8, 0.3, 0.5); +end + +function Outfitter_TestMessage(pMessage) + if gOutfitter_DebugFrame then + gOutfitter_DebugFrame:AddMessage("TEST: " .. pMessage, 0.7, 0.3, 1.0); + else + DEFAULT_CHAT_FRAME:AddMessage("TEST: " .. pMessage, 0.7, 0.3, 1.0); + end +end + +function Outfitter_NoteMessage(pMessage) + DEFAULT_CHAT_FRAME:AddMessage(pMessage, 0.6, 1.0, 0.3); +end + +function Outfitter_RenameLink(pLink, pName) + local vMessage = string.gsub(pLink, "%[.*%]", "[" .. pName .. "]"); + -- local vMessage = string.gsub(pMessage, "||", "|"); + + DEFAULT_CHAT_FRAME:AddMessage(vMessage); +end + +function Outfitter_DumpArray(pPrefixString, pArray) + if not pArray then + Outfitter_DebugMessage(pPrefixString .. " is nil"); + return ; + end + + local vFoundElement = false; + + for vIndex, vElement in pArray do + vFoundElement = true; + + local vType = type(vElement); + local vPrefix; + + if type(vIndex) == "number" then + vPrefix = pPrefixString .. "[" .. vIndex .. "]"; + else + vPrefix = pPrefixString .. "." .. vIndex; + end + + if vType == "number" then + Outfitter_DebugMessage(vPrefix .. " = " .. vElement); + elseif vType == "string" then + Outfitter_DebugMessage(vPrefix .. " = \"" .. vElement .. "\""); + elseif vType == "boolean" then + if vElement then + Outfitter_DebugMessage(vPrefix .. " = true"); + else + Outfitter_DebugMessage(vPrefix .. " = false"); + end + elseif vType == "table" then + Outfitter_DumpArray(vPrefix, vElement); + else + Outfitter_DebugMessage(vPrefix .. " " .. vType); + end + end + + if not vFoundElement then + Outfitter_DebugMessage(pPrefixString .. " is empty"); + end +end + +function Outfitter_InventorySlotIsEmpty(pInventorySlot) + return Outfitter_GetInventoryItemInfo(pInventorySlot) == nil; +end + +function Outfitter_GetBagItemInfo(pBagIndex, pSlotIndex) + local vItemLink = GetContainerItemLink(pBagIndex, pSlotIndex); + local vItemInfo = Outfitter_GetItemInfoFromLink(vItemLink); + + if not vItemInfo then + return nil; + end + + vItemInfo.Texture, _, _, vItemInfo.Quality, _ = GetContainerItemInfo(pBagIndex, pSlotIndex); + + return vItemInfo; +end + +local gOutfitter_AmmoSlotInfoCache = nil; + +function Outfitter_FindAmmoSlotItem(pName, pTexture) + if gOutfitter_AmmoSlotInfoCache + and gOutfitter_AmmoSlotInfoCache.Name == pName + and gOutfitter_AmmoSlotInfoCache.Texture == pTexture then + return gOutfitter_AmmoSlotInfoCache.ItemInfo; + end + + for vBagIndex = 0, NUM_BAG_SLOTS do + local vNumBagSlots = GetContainerNumSlots(vBagIndex); + + if vNumBagSlots > 0 then + for vBagSlotIndex = 1, vNumBagSlots do + local vTexture = GetContainerItemInfo(vBagIndex, vBagSlotIndex); + + if vTexture == pTexture then + local vItemInfo = Outfitter_GetBagItemInfo(vBagIndex, vBagSlotIndex); + + if vItemInfo.Name == pName then + if not gOutfitter_AmmoSlotInfoCache then + gOutfitter_AmmoSlotInfoCache = {}; + end + + gOutfitter_AmmoSlotInfoCache.Name = pName; + gOutfitter_AmmoSlotInfoCache.Texture = pTexture; + gOutfitter_AmmoSlotInfoCache.ItemInfo = vItemInfo; + + return vItemInfo; + end + end + end -- for vBagSlotIndex + end -- if vNumBagSlots + end -- for vBagIndex + + return nil; +end + +function Outfitter_GetInventoryItemInfo(pInventorySlot) + local vSlotID = GetInventorySlotInfo(pInventorySlot); + local vItemLink = GetInventoryItemLink("player", vSlotID); + + -- GetInventoryItemLink doesn't work for the ammo slot, so instead get the icon + -- for the slot and then search for a matching icon in the bags + + if vItemLink == nil + and pInventorySlot == "AmmoSlot" then + OutfitterTooltip:SetOwner(OutfitterFrame, "ANCHOR_BOTTOMRIGHT", 0, 0); + OutfitterTooltip:SetInventoryItem("player", vSlotID); + + if not OutfitterTooltipTextLeft1:IsShown() then + OutfitterTooltip:Hide(); + return nil; + end + + local vAmmoItemName = OutfitterTooltipTextLeft1:GetText(); + + OutfitterTooltip:Hide(); + + local vAmmoItemTexture = GetInventoryItemTexture("player", vSlotID); + + return Outfitter_FindAmmoSlotItem(vAmmoItemName, vAmmoItemTexture); + end + + local vItemInfo = Outfitter_GetItemInfoFromLink(vItemLink); + + if not vItemInfo then + return nil; + end + + vItemInfo.Quality = GetInventoryItemQuality("player", vSlotID); + vItemInfo.Texture = GetInventoryItemTexture("player", vSlotID); + + return vItemInfo; +end + +function Outfitter_GetItemInfoFromLink(pItemLink) + if not pItemLink then + return nil; + end + -- |cff1eff00|Hitem:1465:803:0:0|h[Tigerbane]|h|r + -- |cff1eff00|Hitem:1465:803:0:0|h[Tigerbane]|h|r + -- |(hex code for item color)|Hitem:(item ID code):(enchant code):(added stats code):0|h[(item name)]|h|r + + local vStartIndex, vEndIndex, vLinkColor, vItemCode, vItemEnchantCode, vItemSubCode, vUnknownCode, vItemName = strfind(pItemLink, "|(%x+)|Hitem:(%d+):(%d+):(%d+):(%d+)|h%[([^%]]+)%]|h|r"); + + if not vStartIndex then + return nil; + end + + vItemCode = tonumber(vItemCode); + vItemSubCode = tonumber(vItemSubCode); + vItemEnchantCode = tonumber(vItemEnchantCode); + + local vItemFamilyName, + vItemLink, + vItemQuality, + vItemLevel, + vItemType, + vItemSubType, + vItemCount, + vItemInvType = GetItemInfo(vItemCode); + + local vItemInfo = { + Code = vItemCode, + SubCode = vItemSubCode, + Name = vItemName, + EnchantCode = vItemEnchantCode, + Level = vItemLevel, + }; + + -- Just return if there's no inventory type + + if not vItemInvType + or vItemInvType == "" then + return vItemInfo; + end + + -- Just return if we don't know anything about the inventory type + + local vInvTypeInfo = Outfitter_cInvTypeToSlotName[vItemInvType]; + + if not vInvTypeInfo then + Outfitter_ErrorMessage("Outfitter error: Unknown slot type " .. vItemInvType .. " for item " .. vItemName); + return vItemInfo; + end + + -- Get the slot name + + if not vInvTypeInfo.SlotName then + Outfitter_ErrorMessage("Unknown slot name for inventory type " .. vItemInvType); + return vItemInfo; + end + + vItemInfo.ItemSlotName = vInvTypeInfo.SlotName; + vItemInfo.MetaSlotName = vInvTypeInfo.MetaSlotName; + + -- Return the info + + return vItemInfo; +end + +function Outfitter_CreateNewOutfit() + OutfitterNameOutfit_Open(nil); +end + +function Outfitter_NewEmptyOutfit(pName) + return { Name = pName, Items = {} }; +end + +function Outfitter_IsEmptyOutfit(pOutfit) + return Outfitter_ArrayIsEmpty(pOutfit.Items); +end + +function Outfitter_NewNakedOutfit(pName) + local vOutfit = Outfitter_NewEmptyOutfit(pName); + + for _, vInventorySlot in Outfitter_cSlotNames do + Outfitter_AddOutfitItem(vOutfit, vInventorySlot, 0, 0, "", 0); + end + + return vOutfit; +end + +function Outfitter_AddOutfitItem(pOutfit, pSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode) + pOutfit.Items[pSlotName] = { Code = pItemCode, SubCode = pItemSubCode, Name = pItemName, EnchantCode = pItemEnchantCode }; +end + +function Outfitter_AddOutfitStatItem(pOutfit, pSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode, pStatID, pStatValue) + if not pSlotName then + Outfitter_ErrorMessage("AddOutfitStatItem: SlotName is nil for " .. pItemName); + return ; + end + + if not pStatID then + Outfitter_ErrorMessage("AddOutfitStatItem: StatID is nil for " .. pItemName); + return ; + end + + Outfitter_AddOutfitItem(pOutfit, pSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode); + pOutfit.Items[pSlotName][pStatID] = pStatValue; +end + +function Outfitter_AddOutfitStatItemIfBetter(pOutfit, pSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode, pStatID, pStatValue) + local vCurrentItem = pOutfit.Items[pSlotName]; + local vAlternateSlotName = Outfitter_cHalfAlternateStatSlot[pSlotName]; + + if not vCurrentItem + or not vCurrentItem[pStatID] + or vCurrentItem[pStatID] < pStatValue then + -- If we're bumping the current item, see if it should be moved to the alternate slot + + if vCurrentItem + and vCurrentItem[pStatID] + and vAlternateSlotName then + Outfitter_AddOutfitStatItemIfBetter(pOutfit, vAlternateSlotName, vCurrentItem.Code, vCurrentItem.SubCode, vCurrentItem.Name, vCurrentItem.EnchantCode, pStatID, vCurrentItem[pStatID]) + end + + Outfitter_AddOutfitStatItem(pOutfit, pSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode, pStatID, pStatValue); + else + if not vAlternateSlotName then + return ; + end + + return Outfitter_AddOutfitStatItemIfBetter(pOutfit, vAlternateSlotName, pItemCode, pItemSubCode, pItemName, pItemEnchantCode, pStatID, pStatValue); + end +end + +function Outfitter_AddStats(pItem1, pItem2, pStatID) + local vStat = 0; + + if pItem1 + and pItem1[pStatID] then + vStat = pItem1[pStatID]; + end + + if pItem2 + and pItem2[pStatID] then + vStat = vStat + pItem2[pStatID]; + end + + return vStat; +end + +function Outfitter_CollapseMetaSlotsIfBetter(pOutfit, pStatID) + -- Compare the weapon slot with the 1H/OH slots + + local vWeapon0Item = pOutfit.Items.Weapon0Slot; + local vWeapon1Item = pOutfit.Items.Weapon1Slot; + + if vWeapon0Item or vWeapon1Item then + -- Try the various combinations of MH/OH/W0/W1 + + local v1HItem = pOutfit.Items.MainHandSlot; + local vOHItem = pOutfit.Items.SecondaryHandSlot; + + local vCombinations = { + { MainHand = v1HItem, SecondaryHand = vOHItem, AllowEmptyMainHand = true }, + { MainHand = v1HItem, SecondaryHand = vWeapon0Item, AllowEmptyMainHand = false }, + { MainHand = v1HItem, SecondaryHand = vWeapon1Item, AllowEmptyMainHand = false }, + { MainHand = vWeapon0Item, SecondaryHand = vOHItem, AllowEmptyMainHand = true }, + { MainHand = vWeapon1Item, SecondaryHand = vOHItem, AllowEmptyMainHand = true }, + { MainHand = vWeapon0Item, SecondaryHand = vWeapon1Item, AllowEmptyMainHand = false }, + }; + + local vBestCombinationIndex = nil; + local vBestCombinationValue = nil; + + for vIndex = 1, 6 do + local vCombination = vCombinations[vIndex]; + + -- Ignore combinations where the main hand is empty if + -- that's not allowed in this combinations + + if vCombination.AllowEmptyMainHand + or vCombination.MainHand then + local vCombinationValue = Outfitter_AddStats(vCombination.MainHand, vCombination.SecondaryHand, pStatID); + + if not vBestCombinationIndex + or vCombinationValue > vBestCombinationValue then + vBestCombinationIndex = vIndex; + vBestCombinationValue = vCombinationValue; + end + end + end + + if vBestCombinationIndex then + local vCombination = vCombinations[vBestCombinationIndex]; + + pOutfit.Items.MainHandSlot = vCombination.MainHand; + pOutfit.Items.SecondaryHandSlot = vCombination.SecondaryHand; + end + + pOutfit.Items.Weapon0Slot = nil; + pOutfit.Items.Weapon1Slot = nil; + end + + -- Compare the 2H slot with the 1H/OH slots + + local v2HItem = pOutfit.Items.TwoHandSlot; + + if v2HItem then + local v1HItem = pOutfit.Items.MainHandSlot; + local vOHItem = pOutfit.Items.SecondaryHandSlot; + local v1HOHTotalStat = Outfitter_AddStats(v1HItem, vOHItem, pStatID); + + if v2HItem[pStatID] + and v2HItem[pStatID] > v1HOHTotalStat then + pOutfit.Items.MainHandSlot = v2HItem; + pOutfit.Items.SecondaryHandSlot = nil; + end + + pOutfit.Items.TwoHandSlot = nil; + end +end + +function Outfitter_RemoveOutfitItem(pOutfit, pSlotName) + pOutfit.Items[pSlotName] = nil; +end + +function Outfitter_GetInventoryOutfit(pName, pOutfit) + local vOutfit; + + if pOutfit then + vOutfit = pOutfit; + else + vOutfit = Outfitter_NewEmptyOutfit(pName); + end + + for _, vInventorySlot in Outfitter_cSlotNames do + local vItemInfo = Outfitter_GetInventoryItemInfo(vInventorySlot); + + -- To avoid extra memory operations, only update the item if it's different + + local vExistingItem = vOutfit.Items[vInventorySlot]; + + if not vItemInfo then + if not vExistingItem + or vExistingItem.Code ~= 0 then + Outfitter_AddOutfitItem(vOutfit, vInventorySlot, 0, 0, "", 0); + end + else + if not vExistingItem + or vExistingItem.Code ~= vItemInfo.Code + or vExistingItem.SubCode ~= vItemInfo.SubCode + or vExistingItem.EnchantCode ~= vItemInfo.EnchantCode then + Outfitter_AddOutfitItem(vOutfit, vInventorySlot, vItemInfo.Code, vItemInfo.SubCode, vItemInfo.Name, vItemInfo.EnchantCode); + end + end + end + + return vOutfit; +end + +function Outfitter_UpdateOutfitFromInventory(pOutfit, pNewItemsOutfit) + if not pNewItemsOutfit then + return ; + end + + for vInventorySlot, vItem in pNewItemsOutfit.Items do + -- Only update slots which aren't in an unknown state + + local vCheckbox = getglobal("OutfitterEnable" .. vInventorySlot); + + if not vCheckbox:GetChecked() + or not vCheckbox.IsUnknown then + pOutfit.Items[vInventorySlot] = vItem; + Outfitter_NoteMessage(format(Outfitter_cAddingItem, vItem.Name, pOutfit.Name)); + Outfitter_UpdateOutfitCategory(pOutfit); + end + end + + -- Add the new items to the current compiled outfit + + for vInventorySlot, vItem in pNewItemsOutfit.Items do + gOutfitter_ExpectedOutfit.Items[vInventorySlot] = pNewItemsOutfit.Items[vInventorySlot]; + end + + gOutfitter_DisplayIsDirty = true; +end + +function Outfitter_SubtractOutfit(pOutfit1, pOutfit2, pCheckAlternateSlots) + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + -- Remove items from pOutfit1 if they match the item in pOutfit2 + + for _, vInventorySlot in Outfitter_cSlotNames do + local vItem1 = pOutfit1.Items[vInventorySlot]; + local vItem2 = pOutfit2.Items[vInventorySlot]; + + if OutfitterItemList_ItemsAreSame(vEquippableItems, vItem1, vItem2) then + pOutfit1.Items[vInventorySlot] = nil; + elseif pCheckAlternateSlots then + local vAlternateSlotName = Outfitter_cFullAlternateStatSlot[vInventorySlot]; + + vItem2 = pOutfit2.Items[vAlternateSlotName]; + + if OutfitterItemList_ItemsAreSame(vEquippableItems, vItem1, vItem2) then + pOutfit1.Items[vInventorySlot] = nil; + end + end + end +end + +function Outfitter_GetNewItemsOutfit(pPreviousOutfit) + -- Get the current outfit and the list + -- of equippable items + + gOutfitter_CurrentInventoryOutfit = Outfitter_GetInventoryOutfit(gOutfitter_CurrentInventoryOutfit); + + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + -- Create a temporary outfit from the differences + + local vNewItemsOutfit = Outfitter_NewEmptyOutfit(); + local vOutfitHasItems = false; + + for _, vInventorySlot in Outfitter_cSlotNames do + local vCurrentItem = gOutfitter_CurrentInventoryOutfit.Items[vInventorySlot]; + local vPreviousItem = pPreviousOutfit.Items[vInventorySlot]; + local vSkipSlot = false; + + if vInventorySlot == "SecondaryHandSlot" then + local vMainHandItem = pPreviousOutfit.Items["MainHandSlot"]; + + if vMainHandItem + and vMainHandItem.MetaSlotName == "TwoHandSlot" then + vSkipSlot = true; + end + elseif vInventorySlot == "AmmoSlot" + and (not vCurrentItem or vCurrentItem.Code == 0) then + vSkipSlot = true; + end + + if not vSkipSlot + and not OutfitterItemList_InventorySlotContainsItem(vEquippableItems, vInventorySlot, vPreviousItem) then + vNewItemsOutfit.Items[vInventorySlot] = vCurrentItem; + vOutfitHasItems = true; + end + end + + if not vOutfitHasItems then + return nil; + end + + return vNewItemsOutfit, gOutfitter_CurrentInventoryOutfit; +end + +function Outfitter_UpdateTemporaryOutfit(pNewItemsOutfit) + -- Just return if nothing has changed + + if not pNewItemsOutfit then + return ; + end + + -- Merge the new items with an existing temporary outfit + + local vTemporaryOutfit = OutfitterStack_GetTemporaryOutfit(); + local vUsingExistingTempOutfit = false; + + if vTemporaryOutfit then + + for vInventorySlot, vItem in pNewItemsOutfit.Items do + vTemporaryOutfit.Items[vInventorySlot] = vItem; + end + + vUsingExistingTempOutfit = true; + + -- Otherwise add the new items as the temporary outfit + + else + vTemporaryOutfit = pNewItemsOutfit; + end + + -- Subtract out items which are expected to be in the outfit + + local vExpectedOutfit = Outfitter_GetExpectedOutfit(vTemporaryOutfit); + + Outfitter_SubtractOutfit(vTemporaryOutfit, vExpectedOutfit); + + if Outfitter_IsEmptyOutfit(vTemporaryOutfit) then + if vUsingExistingTempOutfit then + Outfitter_RemoveOutfit(vTemporaryOutfit); + end + else + if not vUsingExistingTempOutfit then + OutfitterStack_AddOutfit(vTemporaryOutfit); + end + end + + -- Add the new items to the current compiled outfit + + for vInventorySlot, vItem in pNewItemsOutfit.Items do + gOutfitter_ExpectedOutfit.Items[vInventorySlot] = vItem; + end +end + +function Outfitter_SetSlotEnable(pSlotName, pEnable) + if not gOutfitter_SelectedOutfit then + return ; + end + + if pEnable then + local vItemInfo = Outfitter_GetInventoryItemInfo(pSlotName); + + if vItemInfo then + gOutfitter_SelectedOutfit.Items[pSlotName] = { Code = vItemInfo.Code, SubCode = vItemInfo.SubCode, Name = vItemInfo.Name, EnchantCode = vItemInfo.EnchantCode }; + else + gOutfitter_SelectedOutfit.Items[pSlotName] = { Code = 0, SubCode = 0, Name = "", EnchantCode = 0 }; + end + else + gOutfitter_SelectedOutfit.Items[pSlotName] = nil; + end + + gOutfitter_DisplayIsDirty = true; +end + +function Outfitter_GetSpecialOutfit(pSpecialID) + for vOutfitIndex, vOutfit in gOutfitter_Settings.Outfits.Special do + if vOutfit.SpecialID == pSpecialID then + return vOutfit; + end + end + + return nil; +end + +-- Tooltip results keyed by aura spell ID. Only filled when a client mod +-- (SuperWoW / ClassicAPI) supplies spell IDs; each distinct aura is then +-- scanned once per session instead of on every PLAYER_AURAS_CHANGED. + +local gOutfitter_AuraTooltipCache = {}; + +local function Outfitter_GetBuffTooltipTextCached(pBuffIndex, pSpellID, pAuraName) + if not pSpellID then + return Outfitter_GetBuffTooltipText(pBuffIndex); + end + + local vCached = gOutfitter_AuraTooltipCache[pSpellID]; + + if not vCached then + local vText1, vText2 = Outfitter_GetBuffTooltipText(pBuffIndex); + + -- Don't cache an empty scan; the tooltip may not have been ready + + if not vText1 then + return nil; + end + + -- If the mod's aura name disagrees with the tooltip, the two APIs + -- indexed different auras; use the scan but don't cache it + + if pAuraName and pAuraName ~= vText1 then + return vText1, vText2; + end + + vCached = { Text1 = vText1, Text2 = vText2 }; + gOutfitter_AuraTooltipCache[pSpellID] = vCached; + end + + return vCached.Text1, vCached.Text2; +end + +function Outfitter_GetPlayerAuraStates() + local vAuraStates = { + Dining = false, + Shadowform = false, + Riding = false, + GhostWolf = false, + Feigning = false, + Evocate = false, + Monkey = false, + Hawk = false, + Cheetah = false, + Pack = false, + Beast = false, + Wild = false + }; + + -- A client mount flag is locale-independent and recognises every mount, + -- so when it's available the buff tooltip heuristic is skipped entirely + + local vClientMounted = Outfitter_ClientIsMounted(); + + if vClientMounted ~= nil then + vAuraStates.Riding = vClientMounted; + end + + local vBuffIndex = 1; + + while true do + local vTexture, vSpellID, vAuraName = Outfitter_GetPlayerBuffInfo(vBuffIndex); + + if not vTexture then + return vAuraStates; + end + + local vStartIndex, vEndIndex, vTextureName = string.find(vTexture, "([^%\\]*)$"); + + -- + + local vSpecialID = gOutfitter_AuraIconSpecialID[vTextureName]; + + if vSpecialID then + vAuraStates[vSpecialID] = true; + + -- + + elseif not vAuraStates.Dining + and string.find(vTextureName, "INV_Drink") then + vAuraStates.Dining = true; + + -- + + else + local vTextLine1, vTextLine2 = Outfitter_GetBuffTooltipTextCached(vBuffIndex, vSpellID, vAuraName); + + if vTextLine1 then + local vSpecialID = gOutfitter_SpellNameSpecialID[vTextLine1]; + + if vSpecialID then + vAuraStates[vSpecialID] = true; + + elseif vClientMounted == nil + and vTextLine2 + and ( + string.find(vTextLine2, Outfitter_cMountSpeedFormat) or --Mount fix by Red Mage Joe + string.find(vTextLine2, "Riding") or + string.find(vTextLine2, "Slow and steady...") + ) then + vAuraStates.Riding = true; + end + end + end + + vBuffIndex = vBuffIndex + 1; + end +end + +function Outfitter_GetBuffTooltipText(pBuffIndex) + OutfitterTooltip:SetOwner(OutfitterFrame, "ANCHOR_BOTTOMRIGHT", 0, 0); + OutfitterTooltip:SetUnitBuff("player", pBuffIndex); + + local vText1, vText2; + + if OutfitterTooltipTextLeft1:IsShown() then + vText1 = OutfitterTooltipTextLeft1:GetText(); + end -- if IsShown + + if OutfitterTooltipTextLeft2:IsShown() then + vText2 = OutfitterTooltipTextLeft2:GetText(); + end -- if IsShown + + OutfitterTooltip:Hide(); + + return vText1, vText2; +end + +function Outfitter_UpdateAuraStates() + Outfitter_ApplyAuraStates(); + + -- The client mount flag can lag the aura event by a server update, so + -- check once more shortly afterwards (debounced; only with a mount flag) + + if Outfitter_ClientMods.HasIsMounted and AceEvent then + AceEvent:ScheduleEvent("OutfitterAuraRecheck", Outfitter_ApplyAuraStates, 0.3); + end +end + +function Outfitter_ApplyAuraStates() + -- Check for special aura outfits + + local vAuraStates = Outfitter_GetPlayerAuraStates(); + + for vSpecialID, vIsActive in vAuraStates do + if vSpecialID == "Feigning" then + gOutfitter_IsFeigning = vIsActive; + else + if not gOutfitter_SpecialState[vSpecialID] then + gOutfitter_SpecialState[vSpecialID] = false; + end + + if gOutfitter_SpecialState[vSpecialID] ~= vIsActive then + gOutfitter_SpecialState[vSpecialID] = vIsActive; + Outfitter_SetSpecialOutfitEnabled(vSpecialID, vIsActive); + end + end + end + + -- As of 1.12 aura changes are the only way to detect shapeshifts, so update those too + + Outfitter_UpdateShapeshiftState(); +end + +function Outfitter_UpdateShapeshiftState() + local vNumForms = GetNumShapeshiftForms(); + + for vIndex = 1, vNumForms do + local vTexture, vName, vIsActive, vIsCastable = GetShapeshiftFormInfo(vIndex); + local vSpecialID = Outfitter_cShapeshiftSpecialIDs[vName]; + + if vSpecialID then + if not vIsActive then + vIsActive = false; + end + + if gOutfitter_SpecialState[vSpecialID.ID] == nil then + gOutfitter_SpecialState[vSpecialID.ID] = Outfitter_WearingSpecialOutfit(vSpecialID.ID); + end + + if gOutfitter_SpecialState[vSpecialID.ID] ~= vIsActive then + gOutfitter_SpecialState[vSpecialID.ID] = vIsActive; + Outfitter_SetSpecialOutfitEnabled(vSpecialID.ID, vIsActive); + end + end + end +end + +-- Swimming outfit + +function Outfitter_SetSwimmingState(pIsSwimming) + if not gOutfitter_Initialized then + return ; + end + + pIsSwimming = pIsSwimming and true or false; + + if gOutfitter_SpecialState.Swimming == nil then + gOutfitter_SpecialState.Swimming = Outfitter_WearingSpecialOutfit("Swimming") and true or false; + end + + if gOutfitter_SpecialState.Swimming ~= pIsSwimming then + gOutfitter_SpecialState.Swimming = pIsSwimming; + Outfitter_SetSpecialOutfitEnabled("Swimming", pIsSwimming); + end +end + +function Outfitter_MirrorTimerChanged(pEvent) + if arg1 ~= "BREATH" then + return ; + end + + Outfitter_SetSwimmingState(pEvent == "MIRROR_TIMER_START"); +end + +local gOutfitter_SwimPollElapsed = 0; +local gOutfitter_SwimDryTime = 0; + +function Outfitter_SwimPoll_OnUpdate() + gOutfitter_SwimPollElapsed = gOutfitter_SwimPollElapsed + arg1; + + if gOutfitter_SwimPollElapsed < 0.25 then + return ; + end + + gOutfitter_SwimPollElapsed = 0; + + if not gOutfitter_Initialized + or gOutfitter_Suspended + or gOutfitter_IsDead then + return ; + end + + -- Nothing to do unless there's a usable swimming outfit + + local vOutfit = Outfitter_GetSpecialOutfit("Swimming"); + + if not vOutfit + or vOutfit.Disabled + or Outfitter_IsEmptyOutfit(vOutfit) then + return ; + end + + local vIsSwimming = Outfitter_ClientIsSwimming(); + + if vIsSwimming == nil then + return ; + end + + -- Enter immediately, but only leave after being out of the water for a + -- second so bobbing at a shoreline doesn't thrash equipment + + if vIsSwimming then + gOutfitter_SwimDryTime = 0; + Outfitter_SetSwimmingState(true); + elseif gOutfitter_SpecialState.Swimming then + gOutfitter_SwimDryTime = gOutfitter_SwimDryTime + 0.25; + + if gOutfitter_SwimDryTime >= 1 then + gOutfitter_SwimDryTime = 0; + Outfitter_SetSwimmingState(false); + end + end +end + +function Outfitter_StartSwimPolling() + if not Outfitter_ClientMods.HasIsSwimming then + return ; + end + + if not gOutfitter_SwimPollFrame then + gOutfitter_SwimPollFrame = CreateFrame("Frame", "OutfitterSwimPollFrame"); + gOutfitter_SwimPollFrame:SetScript("OnUpdate", Outfitter_SwimPoll_OnUpdate); + end + + gOutfitter_SwimPollFrame:Show(); +end + +function Outfitter_SetSpecialOutfitEnabled(pSpecialID, pEnable) + local vOutfit = Outfitter_GetSpecialOutfit(pSpecialID); + + if not vOutfit + or vOutfit.Disabled + or (pEnable and vOutfit.BGDisabled and Outfitter_InBattlegroundZone()) + or (pEnable and vOutfit.InstDisabled and Outfitter_InInstanceZone()) then + return ; + end + + if pEnable then + -- Start monitoring health and mana if it's the dining outfit + + if pSpecialID == "Dining" then + Outfitter_ResumeEvent(OutfitterFrame, "UNIT_HEALTH"); + Outfitter_ResumeEvent(OutfitterFrame, "UNIT_MANA"); + end + + -- + + local vWearBelowOutfit = nil; + + -- If it's the ArgentDawn outfit, wear it below the + -- riding outfit. Once the player dismounts then + -- overlapping items from the ArgentDawn outfit will equip. + -- This will prevent the Argent Dawn trinket from interfering + -- with the carrot trinket when riding into the plaguelands + + if pSpecialID == "ArgentDawn" then + vWearBelowOutfit = Outfitter_GetSpecialOutfit("Riding"); + end + + -- + + Outfitter_WearOutfit(vOutfit, "Special", vWearBelowOutfit); + else + Outfitter_RemoveOutfit(vOutfit); + end +end + +function Outfitter_WearingSpecialOutfit(pSpecialID) + for vIndex, vOutfit in gOutfitter_OutfitStack do + if vOutfit.SpecialID == pSpecialID then + return true, vIndex; + end + end +end + +function Outfitter_UpdateZone() + local vCurrentZone = GetZoneText(); + local vPVPType, vFactionName, vIsArena = GetZonePVPInfo(); + + if vCurrentZone == gOutfitter_CurrentZone then + return ; + end + + gOutfitter_CurrentZone = vCurrentZone; + + local vZoneSpecialIDMap = Outfitter_cZoneSpecialIDMap[vCurrentZone]; + local vSpecialZoneStates = {}; + + if vZoneSpecialIDMap then + for _, vZoneSpecialID in vZoneSpecialIDMap do + if vZoneSpecialID ~= "City" or vPVPType ~= "hostile" then + vSpecialZoneStates[vZoneSpecialID] = true; + end + end + end + + for _, vSpecialID in Outfitter_cZoneSpecialIDs do + local vIsActive = vSpecialZoneStates[vSpecialID]; + + if vIsActive == nil then + vIsActive = false; + end + + local vCurrentIsActive = gOutfitter_SpecialState[vSpecialID]; + + if vCurrentIsActive == nil then + vCurrentIsActive = Outfitter_WearingSpecialOutfit(vSpecialID); + gOutfitter_SpecialState[vSpecialID] = vCurrentIsActive; + end + + if vCurrentIsActive ~= vIsActive then + gOutfitter_SpecialState[vSpecialID] = vIsActive; + Outfitter_SetSpecialOutfitEnabled(vSpecialID, vIsActive); + end + end +end + +function Outfitter_InBattlegroundZone() + local vZoneSpecialIDMap = Outfitter_cZoneSpecialIDMap[gOutfitter_CurrentZone]; + + return vZoneSpecialIDMap and vZoneSpecialIDMap[1] == "Battleground"; +end + +function Outfitter_InInstanceZone() + -- IsInInstance() covers every dungeon and raid; the zone list below only + -- knew a handful of raids (no MC, BWL, Onyxia, Naxxramas or 5-mans) + + if IsInInstance then + local vInInstance, vInstanceType = IsInInstance(); + + if vInInstance then + if vInstanceType then + return vInstanceType ~= "pvp"; + end + + return not Outfitter_InBattlegroundZone(); + end + end + + local vZoneSpecialIDMap = Outfitter_cZoneSpecialIDMap[gOutfitter_CurrentZone]; + + return vZoneSpecialIDMap and vZoneSpecialIDMap[1] == "Instance"; +end + +function Outfitter_SetAllSlotEnables(pEnable) + for _, vInventorySlot in Outfitter_cSlotNames do + Outfitter_SetSlotEnable(vInventorySlot, pEnable); + end + + Outfitter_UpdateOutfitCategory(gOutfitter_SelectedOutfit); + Outfitter_Update(true); +end + +function Outfitter_OutfitIsComplete(pOutfit, pIgnoreAmmoSlot) + for _, vInventorySlot in Outfitter_cSlotNames do + if not pOutfit.Items[vInventorySlot] + and (not pIgnoreAmmoSlot or vInventorySlot ~= "AmmoSlot") then + return false; + end + end + + return true; +end + +function Outfitter_CalculateOutfitCategory(pOutfit) + local vIgnoreAmmoSlot = UnitHasRelicSlot("player"); + + if Outfitter_OutfitIsComplete(pOutfit, vIgnoreAmmoSlot) then + return "Complete"; + elseif pOutfit.IsAccessory then + return "Accessory"; + else + return "Partial"; + end +end + +function Outfitter_UpdateOutfitCategory(pOutfit) + if not pOutfit then + return ; + end + + local vTargetCategoryID = Outfitter_CalculateOutfitCategory(pOutfit); + local vOutfitCategoryID, vOutfitIndex = Outfitter_FindOutfit(pOutfit); + + -- Don't move special outfits around + + if vOutfitCategoryID == "Special" then + return ; + end + + -- Move the outfit if necessary + + if vTargetCategoryID ~= vOutfitCategoryID then + table.remove(gOutfitter_Settings.Outfits[vOutfitCategoryID], vOutfitIndex); + Outfitter_AddOutfit(pOutfit); + end +end + +function Outfitter_DeleteOutfit(pOutfit) + local vWearingOutfit = Outfitter_WearingOutfit(pOutfit); + local vOutfitCategoryID, vOutfitIndex = Outfitter_FindOutfit(pOutfit); + + if not vOutfitCategoryID then + return ; + end + + -- Delete the outfit + + table.remove(gOutfitter_Settings.Outfits[vOutfitCategoryID], vOutfitIndex); + + -- Deselect the outfit + + if pOutfit == gOutfitter_SelectedOutfit then + Outfitter_ClearSelection(); + end + + -- Remove the outfit if it's being worn + + Outfitter_RemoveOutfit(pOutfit); + + -- + + gOutfitter_DisplayIsDirty = true; +end + +function Outfitter_UpdateOutfit(pOutfit) + + local vOutfitCategoryID, vOutfitIndex = Outfitter_FindOutfit(pOutfit); + local name = pOutfit.Name + + if not vOutfitCategoryID then + return; + end + + local UpdatedpOutfit = Outfitter_GetInventoryOutfit() + pOutfit.Items = UpdatedpOutfit.Items + + gOutfitter_Settings.Outfits[vOutfitCategoryID][vOutfitIndex] = pOutfit + + gOutfitter_DisplayIsDirty = true; +end + +function Outfitter_AddOutfit(pOutfit) + local vCategoryID; + + if pOutfit.SpecialID then + vCategoryID = "Special" + else + vCategoryID = Outfitter_CalculateOutfitCategory(pOutfit); + end + + if not gOutfitter_Settings.Outfits then + gOutfitter_Settings.Outfits = {}; + end + + if not gOutfitter_Settings.Outfits[vCategoryID] then + gOutfitter_Settings.Outfits[vCategoryID] = {}; + end + + table.insert(gOutfitter_Settings.Outfits[vCategoryID], pOutfit); + pOutfit.CategoryID = vCategoryID; + + gOutfitter_DisplayIsDirty = true; + + return vCategoryID; +end + +function Outfitter_SlotEnableClicked(pCheckbox, pButton) + -- If the user is attempting to drop an item put it in the slot for them + + if CursorHasItem() then + local vSlotID, vEmptySlotTexture = GetInventorySlotInfo(pCheckbox.SlotName); + PickupInventoryItem(vSlotID); + return ; + end + + -- + + local vChecked = pCheckbox:GetChecked(); + + if pCheckbox.IsUnknown then + pCheckbox.IsUnknown = false; + pCheckbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check"); + vChecked = true; + end + + Outfitter_SetSlotEnable(pCheckbox.SlotName, vChecked); + Outfitter_UpdateOutfitCategory(gOutfitter_SelectedOutfit); + Outfitter_Update(true); +end + +function Outfitter_FindMultipleItemLocation(pItems, pEquippableItems) + for vListIndex, vListItem in pItems do + local vItem = OutfitterItemList_FindItemOrAlt(pEquippableItems, vListItem); + + if vItem then + return vItem, vListItem; + end + end + + return nil, nil; +end + +function Outfitter_FindAndAddItemsToOutfit(pOutfit, pSlotName, pItems, pEquippableItems) + vItemLocation, vItem = Outfitter_FindMultipleItemLocation(pItems, pEquippableItems); + + if vItemLocation then + local vInventorySlot = pSlotName; + + if not vInventorySlot then + vInventorySlot = vItemLocation.ItemSlotName; + end + + Outfitter_AddOutfitItem(pOutfit, vInventorySlot, vItem.Code, vItem.SubCode, vItem.Name, vItem.EnchantCOde); + end +end + +function Outfitter_AddItemsWithStatToOutfit(pOutfit, pStatID, pEquippableItems) + local vItemStats; + + if not pEquippableItems then + return ; + end + + for vInventorySlot, vItems in pEquippableItems.ItemsBySlot do + for vIndex, vItem in vItems do + local vStatValue = vItem.Stats[pStatID]; + + if vStatValue then + local vSlotName = vItem.MetaSlotName; + + if not vSlotName then + vSlotName = vItem.ItemSlotName; + end + + Outfitter_AddOutfitStatItemIfBetter(pOutfit, vSlotName, vItem.Code, vItem.SubCode, vItem.Name, vItem.EnchantCode, pStatID, vStatValue); + end + end + end + + -- Collapse the meta slots (currently just 2H vs. 1H/OH) + + Outfitter_CollapseMetaSlotsIfBetter(pOutfit, pStatID); +end + +function Outfitter_IsInitialized() + return gOutfitter_Initialized; +end + +function Outfitter_Initialize() + if gOutfitter_Initialized then + return ; + end + + -- + if not gOutfitter_Settings then + gOutfitter_Settings = {}; + gOutfitter_Settings.Version = 7; + gOutfitter_Settings.Options = {}; + gOutfitter_Settings.LastOutfitStack = {}; + gOutfitter_Settings.HideHelm = {}; + gOutfitter_Settings.HideCloak = {}; + end + + if not gOutfitter_Settings.HideHelm then + gOutfitter_Settings.HideHelm = {}; + end + + if not gOutfitter_Settings.HideCloak then + gOutfitter_Settings.HideCloak = {}; + end + + -- + + Outfitter_InitDebugging(); + + -- Initialize the outfits and outfit stack + + gOutfitter_CurrentOutfit = Outfitter_GetInventoryOutfit(); + + if not gOutfitter_Settings.Outfits then + Outfitter_InitializeOutfits(); + end + + Outfitter_CheckDatabase(); + + Outfitter_InitializeSpecialOccassionOutfits(); -- Make sure the special occassion outfits are intact + -- since the user has no way of creating them himself + OutfitterStack_RestoreSavedStack(); + + -- Set the minimap button + + if gOutfitter_Settings.Options.HideMinimapButton then + OutfitterMinimapButton:Hide(); + else + OutfitterMinimapButton:Show(); + end + + if not gOutfitter_Settings.Options.MinimapButtonAngle then + gOutfitter_Settings.Options.MinimapButtonAngle = -1.5708; + end + + OutfitterMinimapButton_SetPositionAngle(gOutfitter_Settings.Options.MinimapButtonAngle); + + -- Hook QuickSlots into the paper doll frame + + Outfitter_HookPaperDollFrame(); + + -- Done initializing + + gOutfitter_Initialized = true; + + -- Make sure the outfit state is good + + Outfitter_SetSpecialOutfitEnabled("Riding", false); + Outfitter_SetSpecialOutfitEnabled("Spirit", false); + Outfitter_UpdateAuraStates(); + + Outfitter_ResumeLoadScreenEvents(); + + Outfitter_StartSwimPolling(); + + Outfitter_DispatchOutfitEvent("OUTFITTER_INIT") + + if gOutfitter_Settings.Options.ShowCurrentOutfit then + currentOutfitFrame:Show(); + Outfitter_UpdateCurrentOutfit(); + end +end + +function Outfitter_InitializeOutfits() + local vOutfit, vItemLocation, vItem; + local vEquippableItems = OutfitterItemList_GetEquippableItems(true); + + -- Create the outfit categories + + gOutfitter_Settings.Outfits = {}; + + for vCategoryIndex, vCategoryID in gOutfitter_cCategoryOrder do + gOutfitter_Settings.Outfits[vCategoryID] = {}; + end + + -- Create the normal outfit using the current + -- inventory and set it as the currently equipped outfit + + vOutfit = Outfitter_GetInventoryOutfit(Outfitter_cNormalOutfit); + Outfitter_AddOutfit(vOutfit); + gOutfitter_Settings.LastOutfitStack = { { Name = Outfitter_cNormalOutfit } }; + gOutfitter_OutfitStack = { vOutfit }; + + -- Create the naked outfit + + vOutfit = Outfitter_NewNakedOutfit(Outfitter_cNakedOutfit); + Outfitter_AddOutfit(vOutfit); + + -- Generate the smart outfits + + for vSmartIndex, vSmartOutfit in Outfitter_cSmartOutfits do + vOutfit = Outfitter_GenerateSmartOutfit(vSmartOutfit.Name, vSmartOutfit.StatID, vEquippableItems); + + if vOutfit then + vOutfit.IsAccessory = vSmartOutfit.IsAccessory; + Outfitter_AddOutfit(vOutfit); + end + end + + Outfitter_InitializeSpecialOccassionOutfits(); +end + +function Outfitter_CreateEmptySpecialOccassionOutfit(pSpecialID, pName) + local vOutfit = Outfitter_GetSpecialOutfit(pSpecialID); + + if not vOutfit then + vOutfit = Outfitter_NewEmptyOutfit(pName); + vOutfit.SpecialID = pSpecialID; + + Outfitter_AddOutfit(vOutfit); + end +end + +function Outfitter_InitializeSpecialOccassionOutfits() + local vEquippableItems = OutfitterItemList_GetEquippableItems(true); + local vOutfit; + + -- Find an argent dawn trinket and set the argent dawn outfit + + vOutfit = Outfitter_GetSpecialOutfit("ArgentDawn"); + + if not vOutfit then + vOutfit = Outfitter_GenerateSmartOutfit(Outfitter_cArgentDawnOutfit, "ArgentDawn", vEquippableItems, true); + vOutfit.SpecialID = "ArgentDawn"; + Outfitter_AddOutfit(vOutfit); + end + + -- Find riding items + + vOutfit = Outfitter_GetSpecialOutfit("Riding"); + + if not vOutfit then + vOutfit = Outfitter_GenerateSmartOutfit(Outfitter_cRidingOutfit, "Riding", vEquippableItems, true); + vOutfit.SpecialID = "Riding"; + vOutfit.BGDisabled = true; + Outfitter_AddOutfit(vOutfit); + end + + -- Create the dining outfit + + Outfitter_CreateEmptySpecialOccassionOutfit("Dining", Outfitter_cDiningOutfit); + + -- Create the Battlegrounds outfits + + Outfitter_CreateEmptySpecialOccassionOutfit("Battleground", Outfitter_cBattlegroundOutfit); + Outfitter_CreateEmptySpecialOccassionOutfit("AB", Outfitter_cABOutfit); + Outfitter_CreateEmptySpecialOccassionOutfit("AV", Outfitter_cAVOutfit); + Outfitter_CreateEmptySpecialOccassionOutfit("WSG", Outfitter_cWSGOutfit); + Outfitter_CreateEmptySpecialOccassionOutfit("BR", Outfitter_cBROutfit); + Outfitter_CreateEmptySpecialOccassionOutfit("SGV", Outfitter_cSGVOutfit); + + -- Create the swimming outfit + + Outfitter_CreateEmptySpecialOccassionOutfit("Swimming", Outfitter_cSwimmingOutfit); + + -- Create the city outfit + + Outfitter_CreateEmptySpecialOccassionOutfit("City", Outfitter_cCityOutfit); + + -- Create class-specific outfits + + Outfitter_InitializeClassOutfits(); + + -- Create boss outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("Boss"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("Boss", Outfitter_cBossOutfit); + vOutfit = Outfitter_GetSpecialOutfit("Boss"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create Lvl63+ outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("Lvl63"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("Lvl63", Outfitter_cLvl63Outfit); + vOutfit = Outfitter_GetSpecialOutfit("Lvl63"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create trash outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("Trash"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("Trash", Outfitter_cTrashOutfit); + vOutfit = Outfitter_GetSpecialOutfit("Trash"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create critter outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("Critter"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("Critter", Outfitter_cCritterOutfit); + vOutfit = Outfitter_GetSpecialOutfit("Critter"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create beast trash outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("BeastTrash"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("BeastTrash", Outfitter_cBeastTrashOutfit); + vOutfit = Outfitter_GetSpecialOutfit("BeastTrash"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create Undead trash outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("UndeadTrash"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("UndeadTrash", Outfitter_cUndeadTrashOutfit); + vOutfit = Outfitter_GetSpecialOutfit("UndeadTrash"); + vOutfit.Disabled = true; -- Disable it by default + end + + -- Create Demon trash outfit if needed + vOutfit = Outfitter_GetSpecialOutfit("DemonTrash"); + if not vOutfit then + Outfitter_CreateEmptySpecialOccassionOutfit("DemonTrash", Outfitter_cDemonTrashOutfit); + vOutfit = Outfitter_GetSpecialOutfit("DemonTrash"); + vOutfit.Disabled = true; -- Disable it by default + end +end + +function Outfitter_InitializeClassOutfits() + local vClassName = Outfitter_cNormalizedClassName[UnitClass("player")]; + local vOutfits = Outfitter_cClassSpecialOutfits[vClassName]; + + if not vOutfits then + return ; + end + + for vIndex, vOutfitInfo in vOutfits do + Outfitter_CreateEmptySpecialOccassionOutfit(vOutfitInfo.SpecialID, vOutfitInfo.Name); + end +end + +function Outfitter_IsStatText(pText) + for vStatIndex, vStatInfo in Outfitter_cItemStatFormats do + local vStartIndex, vEndIndex, vValue = string.find(pText, vStatInfo.Format); + + if vStartIndex then + vValue = tonumber(vValue); + + if not vValue then + vValue = vStatInfo.Value; + end + + if not vValue then + vValue = 0; + end + + return vStatInfo.Types, vValue; + end + end + + return nil, nil; +end + +function Outfitter_GetItemStatsFromTooltip(pTooltip, pDistribution) + local vStats = {}; + local vTooltipName = pTooltip:GetName(); + + for vLineIndex = 1, 30 do + local vLeftText = getglobal(vTooltipName .. "TextLeft" .. vLineIndex):GetText(); + -- local vRightText = getglobal(vTooltipName.."TextRight"..vLineIndex):GetText(); + + if vLeftText then + -- Check for the start of the set bonus section + + local vStartIndex, vEndIndex, vValue = string.find(vLeftText, "%(%d/%d%)"); + + if vStartIndex then + break ; + end + + -- + + for vStatString in string.gfind(vLeftText, "([^/]+)") do + local vStatIDs, vValue = Outfitter_IsStatText(vStatString); + + if vStatIDs then + for vStatIDIndex, vStatID in vStatIDs do + OutfitterStats_AddStatValue(vStats, vStatID, vValue, pDistribution); + end + end + end + end + end -- for vLineIndex + + return vStats; +end + +function Outfitter_TooltipContainsText(pTooltip, pText) + local vTooltipName = pTooltip:GetName(); + + for vLineIndex = 1, 30 do + local vLeftText = getglobal(vTooltipName .. "TextLeft" .. vLineIndex):GetText(); + + if vLeftText + and string.find(vLeftText, pText) then + return true; + end + end -- for vLineIndex + + return false; +end + +function Outfitter_CanEquipBagItem(pBagIndex, pBagSlotIndex) + local vItemInfo = Outfitter_GetBagItemInfo(pBagIndex, pBagSlotIndex); + + if vItemInfo + and vItemInfo.Level + and UnitLevel("player") < vItemInfo.Level then + return false; + end + + return true; +end + +function Outfitter_BagItemWillBind(pBagIndex, pBagSlotIndex) + local vItemLink = GetContainerItemLink(pBagIndex, pBagSlotIndex); + + if not vItemLink then + return nil; + end + + OutfitterTooltip:SetOwner(OutfitterFrame, "ANCHOR_BOTTOMRIGHT", 0, 0); + OutfitterTooltip:SetBagItem(pBagIndex, pBagSlotIndex); + + local vIsBOE = Outfitter_TooltipContainsText(OutfitterTooltip, ITEM_BIND_ON_EQUIP); + + OutfitterTooltip:Hide(); + + return vIsBOE; +end + +function Outfitter_GenerateSmartOutfit(pName, pStatID, pEquippableItems, pAllowEmptyOutfit) + local vOutfit = Outfitter_NewEmptyOutfit(pName); + + if pStatID == "TANKPOINTS" then + return ; + end + + local vItems = Outfitter_cStatIDItems[pStatID]; + + OutfitterItemList_ResetIgnoreItemFlags(pEquippableItems); + + if vItems then + Outfitter_FindAndAddItemsToOutfit(vOutfit, nil, vItems, pEquippableItems); + end + + Outfitter_AddItemsWithStatToOutfit(vOutfit, pStatID, pEquippableItems); + + if not pAllowEmptyOutfit + and Outfitter_IsEmptyOutfit(vOutfit) then + return nil; + end + + vOutfit.StatID = pStatID; + + return vOutfit; +end + +function Outfitter_ArrayIsEmpty(pArray) + if not pArray then + return true; + end + + for vIndex, vValue in pArray do + return false; + end + + return true; +end + +function OutfitterNameOutfit_Open(pOutfit) + gOutfitter_OutfitToRename = pOutfit; + + if gOutfitter_OutfitToRename then + OutfitterNameOutfitDialogTitle:SetText(Outfitter_cRenameOutfit); + OutfitterNameOutfitDialogName:SetText(gOutfitter_OutfitToRename.Name); + OutfitterNameOutfitDialogCreateUsing:Hide(); + OutfitterNameOutfitDialog:SetHeight(OutfitterNameOutfitDialog.baseHeight - 35); + else + OutfitterNameOutfitDialogTitle:SetText(Outfitter_cNewOutfit); + OutfitterNameOutfitDialogName:SetText(""); + OutfitterDropDown_SetSelectedValue(OutfitterNameOutfitDialogCreateUsing, 0); + OutfitterNameOutfitDialogCreateUsing:Show(); + OutfitterNameOutfitDialog:SetHeight(OutfitterNameOutfitDialog.baseHeight); + OutfitterNameOutfitDialogCreateUsing.ChangedValueFunc = OutfitterNameOutfit_CheckForStatOutfit; + end + + OutfitterNameOutfitDialog:Show(); + OutfitterNameOutfitDialogName:SetFocus(); +end + +function OutfitterNameOutfit_CheckForStatOutfit(pMenu, pValue) + OutfitterNameOutfit_Update(true); +end + +function OutfitterNameOutfit_Done() + local vName = OutfitterNameOutfitDialogName:GetText(); + + if vName + and vName ~= "" then + if gOutfitter_OutfitToRename then + local vWearingOutfit = Outfitter_WearingOutfit(gOutfitter_OutfitToRename); + + if vWearingOutfit then + Outfitter_DispatchOutfitEvent("UNWEAR_OUTFIT", gOutfitter_OutfitToRename.Name, gOutfitter_OutfitToRename) + end + + gOutfitter_OutfitToRename.Name = vName; + gOutfitter_DisplayIsDirty = true; + + if vWearingOutfit then + Outfitter_DispatchOutfitEvent("WEAR_OUTFIT", gOutfitter_OutfitToRename.Name, gOutfitter_OutfitToRename) + end + else + -- New outift + + local vStatID = UIDropDownMenu_GetSelectedValue(OutfitterNameOutfitDialogCreateUsing); + local vOutfit; + + if not vStatID + or vStatID == 0 then + vOutfit = Outfitter_GetInventoryOutfit(vName); + elseif vStatID == "EMPTY" then + vOutfit = Outfitter_NewEmptyOutfit(vName); + else + vOutfit = Outfitter_GenerateSmartOutfit(vName, vStatID, OutfitterItemList_GetEquippableItems(true)); + end + + if not vOutfit then + vOutfit = Outfitter_NewEmptyOutfit(vName); + end + + local vCategoryID = Outfitter_AddOutfit(vOutfit); + + Outfitter_WearOutfit(vOutfit, vCategoryID); + end + end + + OutfitterNameOutfitDialog:Hide(); + + Outfitter_Update(true); +end + +function OutfitterNameOutfit_Cancel() + OutfitterNameOutfitDialog:Hide(); +end + +function OutfitterNameOutfit_Update(pCheckForStatOutfit) + local vEnableDoneButton = true; + local vErrorMessage = nil; + + -- If there's no name entered then disable the okay button + + local vName = OutfitterNameOutfitDialogName:GetText(); + + if not vName + or vName == "" then + vEnableDoneButton = false; + else + local vOutfit = Outfitter_FindOutfitByName(vName); + + if vOutfit + and vOutfit ~= gOutfitter_OutfitToRename then + vErrorMessage = Outfitter_cNameAlreadyUsedError; + vEnableDoneButton = false; + end + end + + -- + + if not vErrorMessage + and pCheckForStatOutfit then + local vStatID = UIDropDownMenu_GetSelectedValue(OutfitterNameOutfitDialogCreateUsing); + + if vStatID + and vStatID ~= 0 + and vStatID ~= "EMPTY" then + local vOutfit = Outfitter_GenerateSmartOutfit("temp outfit", vStatID, OutfitterItemList_GetEquippableItems(true)); + + if not vOutfit + or Outfitter_IsEmptyOutfit(vOutfit) then + vErrorMessage = Outfitter_cNoItemsWithStatError; + end + end + end + + if vErrorMessage then + OutfitterNameOutfitDialogError:SetText(vErrorMessage); + OutfitterNameOutfitDialogError:Show(); + else + OutfitterNameOutfitDialogError:Hide(); + end + + Outfitter_SetButtonEnable(OutfitterNameOutfitDialogDoneButton, vEnableDoneButton); +end + +function Outfitter_SetButtonEnable(pButton, pEnabled) + if pEnabled then + pButton:Enable(); + pButton:SetAlpha(1.0); + pButton:EnableMouse(true); + --getglobal(pButton:GetName().."Text"):SetAlpha(1.0); + else + pButton:Disable(); + pButton:SetAlpha(0.7); + pButton:EnableMouse(false); + --getglobal(pButton:GetName().."Text"):SetAlpha(0.7); + end +end + +function Outfitter_GetOutfitFromListItem(pItem) + if pItem.isCategory then + return nil; + end + + if not gOutfitter_Settings.Outfits then + return nil; + end + + local vOutfits = gOutfitter_Settings.Outfits[pItem.categoryID]; + + if not vOutfits then + -- Error: outfit category not found + return nil; + end + + return vOutfits[pItem.outfitIndex], pItem.categoryID; +end + +function Outfitter_OutfitItemSelected(pMenu, pValue) + local vItem = pMenu:GetParent():GetParent(); + local vOutfit, vCategoryID = Outfitter_GetOutfitFromListItem(vItem); + + if not vOutfit then + Outfitter_ErrorMessage("Outfitter Error: Outfit for menu item " .. vItem:GetName() .. " not found"); + return ; + end + + -- Perform the selected action + + if pValue == "DELETE" then + Outfitter_AskDeleteOutfit(vOutfit); + elseif pValue == "RENAME" then + OutfitterNameOutfit_Open(vOutfit); + elseif pValue == "DISABLE" then + if vOutfit.Disabled then + vOutfit.Disabled = nil; + else + vOutfit.Disabled = true; + end + gOutfitter_DisplayIsDirty = true; + elseif pValue == "BGDISABLE" then + if vOutfit.BGDisabled then + vOutfit.BGDisabled = nil; + else + vOutfit.BGDisabled = true; + end + gOutfitter_DisplayIsDirty = true; + elseif pValue == "INSTDISABLE" then + if vOutfit.InstDisabled then + vOutfit.InstDisabled = nil; + else + vOutfit.InstDisabled = true; + end + gOutfitter_DisplayIsDirty = true; + elseif pValue == "ACCESSORY" then + vOutfit.IsAccessory = true; + Outfitter_UpdateOutfitCategory(vOutfit); + elseif pValue == "PARTIAL" then + vOutfit.IsAccessory = nil; + Outfitter_UpdateOutfitCategory(vOutfit); + elseif string.sub(pValue, 1, 7) == "BINDING" then + Outfitter_SetOutfitBindingIndex(vOutfit, tonumber(string.sub(pValue, 8))); + elseif pValue == "REBUILD" then + Outfitter_AskRebuildOutfit(vOutfit, vCategoryID); + elseif pValue == "UPDATE" then + Outfitter_AskUpdateOutfit(vOutfit, vCategoryID); + elseif pValue == "DEPOSIT" then + Outfitter_DepositOutfit(vOutfit); + elseif pValue == "DEPOSITUNIQUE" then + Outfitter_DepositOutfit(vOutfit, true); + elseif pValue == "WITHDRAW" then + Outfitter_WithdrawOutfit(vOutfit); + elseif pValue == "AUTOEQUIP" then + if vOutfit.AutoEquip then + vOutfit.AutoEquip = nil; + else + vOutfit.AutoEquip = true; + end + elseif pValue == "AUTOUNEQUIP" then + if vOutfit.AutoUnEquip then + vOutfit.AutoUnEquip = nil; + else + vOutfit.AutoUnEquip = true; + end + end + + Outfitter_Update(true); +end + +function OutfitterStatDropdown_OnLoad() + UIDropDownMenu_Initialize(this, OutfitterStatDropdown_Initialize); + UIDropDownMenu_SetWidth(150); + UIDropDownMenu_Refresh(this); +end + +function Outfitter_GetStatIDName(pStatID) + for vStatIndex, vStatInfo in Outfitter_cItemStatInfo do + if vStatInfo.ID == pStatID then + return vStatInfo.Name; + end + end + + return nil; +end + +function OutfitterStatDropdown_Initialize() + local vFrame = getglobal(UIDROPDOWNMENU_INIT_MENU); + + if UIDROPDOWNMENU_MENU_LEVEL == 2 then + for vStatIndex, vStatInfo in Outfitter_cItemStatInfo do + if vStatInfo.Category == UIDROPDOWNMENU_MENU_VALUE then + UIDropDownMenu_AddButton({ text = vStatInfo.Name, value = vStatInfo.ID, owner = vFrame, func = OutfitterDropDown_OnClick }, UIDROPDOWNMENU_MENU_LEVEL); + end + end + else + UIDropDownMenu_AddButton({ text = Outfitter_cUseCurrentOutfit, value = 0, owner = vFrame, func = OutfitterDropDown_OnClick }); + UIDropDownMenu_AddButton({ text = Outfitter_cUseEmptyOutfit, value = "EMPTY", owner = vFrame, func = OutfitterDropDown_OnClick }); + + UIDropDownMenu_AddButton({ text = " ", notCheckable = true, notClickable = true }); + + for vCategoryIndex, vCategoryInfo in Outfitter_cStatCategoryInfo do + UIDropDownMenu_AddButton({ text = vCategoryInfo.Name, owner = vFrame, hasArrow = 1, value = vCategoryInfo.Category }); + end + + if false and IsAddOnLoaded("TankPoints") then + UIDropDownMenu_AddButton({ text = " ", notCheckable = true, notClickable = true }); + UIDropDownMenu_AddButton({ text = Outfitter_cTankPoints, value = "TANKPOINTS", owner = vFrame, func = OutfitterDropDown_OnClick }); + end + end +end + +function OutfitterDropDown_SetSelectedValue(pDropDown, pValue) + UIDropDownMenu_SetText("", pDropDown); -- Set to empty in case the selected value isn't there + + UIDropDownMenu_Initialize(pDropDown, pDropDown.initialize); + UIDropDownMenu_SetSelectedValue(pDropDown, pValue); + + -- All done if the item text got set successfully + + local vItemText = UIDropDownMenu_GetText(pDropDown); + + if vItemText and vItemText ~= "" then + return ; + end + + -- Scan for submenus + + local vRootListFrameName = "DropDownList1"; + local vRootListFrame = getglobal(vRootListFrameName); + local vRootNumItems = vRootListFrame.numButtons; + + for vRootItemIndex = 1, vRootNumItems do + local vItem = getglobal(vRootListFrameName .. "Button" .. vRootItemIndex); + + if vItem.hasArrow then + local vSubMenuFrame = getglobal("DropDownList2"); + + UIDROPDOWNMENU_OPEN_MENU = pDropDown:GetName(); + UIDROPDOWNMENU_MENU_VALUE = vItem.value; + UIDROPDOWNMENU_MENU_LEVEL = 2; + + UIDropDownMenu_Initialize(pDropDown, pDropDown.initialize, nil, 2); + UIDropDownMenu_SetSelectedValue(pDropDown, pValue); + + -- All done if the item text got set successfully + + local vItemText = UIDropDownMenu_GetText(pDropDown); + + if vItemText and vItemText ~= "" then + return ; + end + + -- Switch back to the root menu + + UIDROPDOWNMENU_OPEN_MENU = nil; + UIDropDownMenu_Initialize(pDropDown, pDropDown.initialize, nil, 1); + end + end +end + +function OutfitterScrollbarTrench_SizeChanged(pScrollbarTrench) + local vScrollbarTrenchName = pScrollbarTrench:GetName(); + local vScrollbarTrenchMiddle = getglobal(vScrollbarTrenchName .. "Middle"); + + local vMiddleHeight = pScrollbarTrench:GetHeight() - 51; + vScrollbarTrenchMiddle:SetHeight(vMiddleHeight); +end + +function OutfitterInputBox_OnLoad(pChildDepth) + if not pChildDepth then + pChildDepth = 0; + end + + local vParent = this:GetParent(); + + for vDepthIndex = 1, pChildDepth do + vParent = vParent:GetParent(); + end + + if vParent.lastEditBox then + this.prevEditBox = vParent.lastEditBox; + this.nextEditBox = vParent.lastEditBox.nextEditBox; + + this.prevEditBox.nextEditBox = this; + this.nextEditBox.prevEditBox = this; + else + this.prevEditBox = this; + this.nextEditBox = this; + end + + vParent.lastEditBox = this; +end + +function OutfitterInputBox_TabPressed() + local vReverse = IsShiftKeyDown(); + local vEditBox = this; + + for vIndex = 1, 50 do + local vNextEditBox; + + if vReverse then + vNextEditBox = vEditBox.prevEditBox; + else + vNextEditBox = vEditBox.nextEditBox; + end + + if vNextEditBox:IsVisible() + and not vNextEditBox.isDisabled then + vNextEditBox:SetFocus(); + return ; + end + + vEditBox = vNextEditBox; + end +end + +function OutfitterTimer_AdjustTimer() + local vNeedTimer = false; + + if OutfitterMinimapButton.IsDragging then + vNeedTimer = true; + end + + if gOutfitter_EquippedNeedsUpdate + or gOutfitter_WeaponsNeedUpdate then + vNeedTimer = true; + end + + if vNeedTimer then + OutfitterUpdateFrame:Show(); + else + OutfitterUpdateFrame:Hide(); + OutfitterUpdateFrame.Elapsed = nil; + end +end + +function OutfitterUpdateFrame_OnUpdate(pElapsed) + if OutfitterMinimapButton.IsDragging then + OutfitterMinimapButton_UpdateDragPosition(); + end + + if not OutfitterUpdateFrame.Elapsed then + OutfitterUpdateFrame.Elapsed = 0; + else + OutfitterUpdateFrame.Elapsed = OutfitterUpdateFrame.Elapsed + pElapsed; + + if OutfitterUpdateFrame.Elapsed > 0.25 then + Outfitter_UpdateEquippedItems(); + OutfitterUpdateFrame.Elapsed = 0; + end + end + + OutfitterTimer_AdjustTimer(); +end + +function OutfitterMinimapButton_MouseDown() + -- Remember where the cursor was in case the user drags + + local vCursorX, vCursorY = GetCursorPosition(); + + vCursorX = vCursorX / this:GetEffectiveScale(); + vCursorY = vCursorY / this:GetEffectiveScale(); + + OutfitterMinimapButton.CursorStartX = vCursorX; + OutfitterMinimapButton.CursorStartY = vCursorY; + + local vCenterX, vCenterY = OutfitterMinimapButton:GetCenter(); + local vMinimapCenterX, vMinimapCenterY = Minimap:GetCenter(); + + OutfitterMinimapButton.CenterStartX = vCenterX - vMinimapCenterX; + OutfitterMinimapButton.CenterStartY = vCenterY - vMinimapCenterY; +end + +function OutfitterMinimapButton_DragStart() + if not OutfitterMinimapButton.CursorStartX + or not OutfitterMinimapButton.CursorStartY then + OutfitterMinimapButton.IsDragging = false; + return; + end + + OutfitterMinimapButton.IsDragging = true; + OutfitterTimer_AdjustTimer(); +end + +function OutfitterMinimapButton_DragEnd() + OutfitterMinimapButton.IsDragging = false; + OutfitterTimer_AdjustTimer(); +end + +function OutfitterMinimapButton_UpdateDragPosition() + -- Remember where the cursor was in case the user drags + + local vCursorX, vCursorY = GetCursorPosition(); + + vCursorX = vCursorX / this:GetEffectiveScale(); + vCursorY = vCursorY / this:GetEffectiveScale(); + + if not OutfitterMinimapButton.CursorStartX + or not OutfitterMinimapButton.CursorStartY then + return; + end + + local vCursorDeltaX = vCursorX - OutfitterMinimapButton.CursorStartX; + local vCursorDeltaY = vCursorY - OutfitterMinimapButton.CursorStartY; + + -- + + local vCenterX = OutfitterMinimapButton.CenterStartX + vCursorDeltaX; + local vCenterY = OutfitterMinimapButton.CenterStartY + vCursorDeltaY; + + -- Calculate the angle + + local vAngle = math.atan2(vCenterX, vCenterY); + + -- Set the new position + + OutfitterMinimapButton_SetPositionAngle(vAngle); +end + +function Outfitter_RestrictAngle(pAngle, pRestrictStart, pRestrictEnd) + if pAngle <= pRestrictStart + or pAngle >= pRestrictEnd then + return pAngle; + end + + local vDistance = (pAngle - pRestrictStart) / (pRestrictEnd - pRestrictStart); + + if vDistance > 0.5 then + return pRestrictEnd; + else + return pRestrictStart; + end +end + +function OutfitterMinimapButton_SetPositionAngle(pAngle) + local vAngle = pAngle; + + -- Restrict the angle from going over the date/time icon or the zoom in/out icons + + local vRestrictedStartAngle = nil; + local vRestrictedEndAngle = nil; + + if GameTimeFrame:IsVisible() then + if MinimapZoomIn:IsVisible() + or MinimapZoomOut:IsVisible() then + vAngle = Outfitter_RestrictAngle(vAngle, 0.4302272732931596, 2.930420793963121); + else + vAngle = Outfitter_RestrictAngle(vAngle, 0.4302272732931596, 1.720531504573905); + end + + elseif MinimapZoomIn:IsVisible() + or MinimapZoomOut:IsVisible() then + vAngle = Outfitter_RestrictAngle(vAngle, 1.720531504573905, 2.930420793963121); + end + + -- Restrict it from the tracking icon area + + vAngle = Outfitter_RestrictAngle(vAngle, -1.290357134304173, -0.4918423429923585); + + -- + + local vRadius = 80; + + vCenterX = math.sin(vAngle) * vRadius; + vCenterY = math.cos(vAngle) * vRadius; + + OutfitterMinimapButton:SetPoint("CENTER", "Minimap", "CENTER", vCenterX - 1, vCenterY - 1); + + gOutfitter_Settings.Options.MinimapButtonAngle = vAngle; +end + +function OutfitterMinimapButton_ItemSelected(pMenu, pValue) + local vType = type(pValue); + + if vType == "table" then + local vCategoryID = pValue.CategoryID; + local vIndex = pValue.Index; + local vOutfit = gOutfitter_Settings.Outfits[vCategoryID][vIndex]; + local vDoToggle = vCategoryID ~= "Complete"; + + if vDoToggle + and Outfitter_WearingOutfit(vOutfit) then + Outfitter_RemoveOutfit(vOutfit); + else + Outfitter_WearOutfit(vOutfit, vCategoryID); + end + + if vDoToggle then + return true; + end + else + if pValue == 0 then + -- Open Outfitter + ShowUIPanel(CharacterFrame); + CharacterFrame_ShowSubFrame("PaperDollFrame"); + OutfitterFrame:Show(); + end + end + + return false; +end + +function Outfitter_WearingOutfit(pOutfit) + return OutfitterStack_FindOutfit(pOutfit); +end + +function Outfitter_GetCurrentOutfitInfo() + if not gOutfitter_Initialized then + return "", nil; + end + + local vStackLength = table.getn(gOutfitter_OutfitStack); + + if vStackLength == 0 then + return "", nil; + end + + local vOutfit = gOutfitter_OutfitStack[vStackLength]; + + if vOutfit and vOutfit.Name then + return vOutfit.Name, vOutfit; + else + return Outfitter_cCustom, vOutfit; + end +end + +function Outfitter_CheckDatabase() + local vOutfit; + + if not gOutfitter_Settings.Version then + local vOutfits = gOutfitter_Settings.Outfits[vCategoryID]; + + if gOutfitter_Settings.Outfits then + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vIndex, vOutfit in vOutfits do + if Outfitter_OutfitIsComplete(vOutfit, true) then + Outfitter_AddOutfitItem(vOutfit, "AmmoSlot", 0, 0, "", 0); + end + end + end + end + + gOutfitter_Settings.Version = 1; + end + + -- Versions 1 and 2 both simply add class outfits + -- so just reinitialize those + + if gOutfitter_Settings.Version < 3 then + Outfitter_InitializeClassOutfits(); + gOutfitter_Settings.Version = 3; + end + + -- Version 4 sets the BGDisabled flag for the mounted outfit + + if gOutfitter_Settings.Version < 4 then + local vRidingOutfit = Outfitter_GetSpecialOutfit("Riding"); + + if vRidingOutfit then + vRidingOutfit.BGDisabled = true; + vRidingOutfit.InstDisabled = true; + end + + gOutfitter_Settings.Version = 4; + end + + -- Version 5 adds moonkin form, just reinitialize class outfits + + if gOutfitter_Settings.Version < 5 then + Outfitter_InitializeClassOutfits(); + gOutfitter_Settings.Version = 5; + end + + -- Make sure all outfits have an associated category ID + + if gOutfitter_Settings.Outfits then + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vIndex, vOutfit in vOutfits do + vOutfit.CategoryID = vCategoryID; + end + end + end + + -- Version 6 and 7 adds item sub-code and enchantment codes + -- (7 tries to clean up failed updates from 6) + + if gOutfitter_Settings.Version < 7 then + if not Outfitter_UpdateDatabaseItemCodes() then + gOutfitter_NeedItemCodesUpdated = 5; -- Do up to five attempts at updated the item codes + end + + gOutfitter_Settings.Version = 7; + end + + -- Scan the outfits and make sure everything is in order + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vIndex, vOutfit in vOutfits do + Outfitter_CheckOutfit(vOutfit); + end + end +end + +function Outfitter_CheckOutfit(pOutfit) + if not pOutfit.Name then + pOutfit.Name = "Damaged outfit"; + end + + if not pOutfit.Items then + pOutfit.Items = {}; + end + + for vInventorySlot, vItem in pOutfit.Items do + if not vItem.Code then + vItem.Code = 0; + end + + if not vItem.SubCode then + vItem.SubCode = 0; + end + + if not vItem.Name then + vItem.Name = ""; + end + + if not vItem.EnchantCode then + vItem.EnchantCode = 0; + end + end +end + +function Outfitter_UpdateDatabaseItemCodes() + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + local vResult = true; + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vIndex, vOutfit in vOutfits do + for vInventorySlot, vOutfitItem in vOutfit.Items do + if vOutfitItem.Code ~= 0 then + local vItem = OutfitterItemList_FindItemOrAlt(vEquippableItems, vOutfitItem, false, true); + + if vItem then + vOutfitItem.SubCode = vItem.SubCode; + vOutfitItem.Name = vItem.Name; + vOutfitItem.EnchantCode = vItem.EnchantCode; + vOutfitItem.Checksum = nil; + else + vResult = false; + end + end + end + end + end + + return vResult; +end + +local gOutfitter_PaperDollItemSlotButton_OnClick; + +function Outfitter_HookPaperDollFrame() + gOutfitter_PaperDollItemSlotButton_OnClick = PaperDollItemSlotButton_OnClick; + PaperDollItemSlotButton_OnClick = Outfitter_PaperDollItemSlotButton_OnClick +end + +local Outfitter_cMaxNumQuickSlots = 27; +local Outfitter_cSlotIDToInventorySlot = nil; + +function Outfitter_PaperDollItemSlotButton_OnClick(pButton, pIgnoreModifiers) + -- Build the table to convert from slot ID to inventory slot name + + if not Outfitter_cSlotIDToInventorySlot then + Outfitter_cSlotIDToInventorySlot = {}; + + for _, vInventorySlot in Outfitter_cSlotNames do + local vSlotID = GetInventorySlotInfo(vInventorySlot); + + Outfitter_cSlotIDToInventorySlot[vSlotID] = vInventorySlot; + end + end + + -- + + local vSlotID = this:GetID(); + local vInventorySlot = Outfitter_cSlotIDToInventorySlot[vSlotID]; + local vItemLink = GetInventoryItemLink("player", vSlotID); + local vSlotIsEmpty = vItemLink == nil; + + -- Call the original function + + gOutfitter_PaperDollItemSlotButton_OnClick(pButton, pIgnoreModifiers); + + -- If there's an item on the cursor then open the slots otherwise + -- make sure they're closed + + if not OutfitterQuickSlots:IsVisible() + and (CursorHasItem() or vSlotIsEmpty) then + -- Hide the tooltip so that it isn't in the way + + GameTooltip:Hide(); + + -- Open QuickSlots + + OutfitterQuickSlots_Open(vInventorySlot); + else + OutfitterQuickSlots_Close(); + end +end + +function OutfitterItemList_AddItem(pItemList, pItem) + -- Add the item to the code list + + local vItemFamily = pItemList.ItemsByCode[pItem.Code]; + + if not vItemFamily then + vItemFamily = {}; + pItemList.ItemsByCode[pItem.Code] = vItemFamily; + end + + table.insert(vItemFamily, pItem); + + -- Add the item to the slot list + + local vItemSlot = pItemList.ItemsBySlot[pItem.ItemSlotName]; + + if not vItemSlot then + vItemSlot = {}; + pItemList.ItemsBySlot[pItem.ItemSlotName] = vItemSlot; + end + + table.insert(vItemSlot, pItem); + + -- Add the item to the bags + + if pItem.Location.BagIndex then + local vBagItems = pItemList.BagItems[pItem.Location.BagIndex]; + + if not vBagItems then + vBagItems = {}; + pItemList.BagItems[pItem.Location.BagIndex] = vBagItems; + end + + vBagItems[pItem.Location.BagSlotIndex] = pItem; + + -- Add the item to the inventory + + elseif pItem.Location.SlotName then + pItemList.InventoryItems[pItem.Location.SlotName] = pItem; + end +end + +function Outfitter_GetNumBags() + if gOutfitter_BankFrameOpened then + return NUM_BAG_SLOTS + NUM_BANKBAGSLOTS, -1; + else + return NUM_BAG_SLOTS, 0; + end +end + +function OutfitterItemList_FlushEquippableItems() + gOutfitter_EquippableItems = nil; +end + +function OutfitterItemList_FlushBagFromEquippableItems(pBagIndex) + if gOutfitter_EquippableItems + and gOutfitter_EquippableItems.BagItems[pBagIndex] then + for vBagSlotIndex, vItem in gOutfitter_EquippableItems.BagItems[pBagIndex] do + OutfitterItemList_RemoveItem(gOutfitter_EquippableItems, vItem); + end + + gOutfitter_EquippableItems.NeedsUpdate = true; + gOutfitter_EquippableItems.BagItems[pBagIndex] = nil; + end +end + +function OutfitterItemList_FlushInventoryFromEquippableItems() + if gOutfitter_EquippableItems then + for vInventorySlot, vItem in gOutfitter_EquippableItems.InventoryItems do + OutfitterItemList_RemoveItem(gOutfitter_EquippableItems, vItem); + end + + gOutfitter_EquippableItems.NeedsUpdate = true; + gOutfitter_EquippableItems.InventoryItems = nil; + end +end + +function OutfitterItemList_New() + return { ItemsByCode = {}, ItemsBySlot = {}, InventoryItems = nil, BagItems = {} }; +end + +function OutfitterItemList_RemoveItem(pItemList, pItem) + -- Remove the item from the code list + + local vItems = pItemList.ItemsByCode[pItem.Code]; + + for vIndex, vItem in vItems do + if vItem == pItem then + table.remove(vItems, vIndex); + break ; + end + end + + -- Remove the item from the slot list + + local vItemSlot = pItemList.ItemsBySlot[pItem.ItemSlotName]; + + if vItemSlot then + for vIndex, vItem in vItemSlot do + if vItem == pItem then + table.remove(vItemSlot, vIndex); + break ; + end + end + end + + -- Remove the item from the bags list + + if pItem.Location.BagIndex then + local vBagItems = pItemList.BagItems[pItem.Location.BagIndex]; + + if vBagItems then + vBagItems[pItem.Location.BagSlotIndex] = nil; + end + + -- Remove the item from the inventory list + + elseif pItem.Location.SlotName then + pItemList.InventoryItems[pItem.Location.SlotName] = nil; + end +end + +function OutfitterItemList_GetInventoryOutfit(pEquippableItems) + return pEquippableItems.InventoryItems; +end + +function OutfitterItemList_ResetIgnoreItemFlags(pItemList) + for vItemCode, vItemFamily in pItemList.ItemsByCode do + for _, vItem in vItemFamily do + vItem.IgnoreItem = nil; + end + end +end + +function OutfitterItemList_GetEquippableItems(pIncludeItemStats) + -- If there's a cached copy just clear the IgnoreItem flags and return it + -- (never used cached copy if the caller wants stats) + + if gOutfitter_EquippableItems + and not gOutfitter_EquippableItems.NeedsUpdate + and not pIncludeItemStats then + OutfitterItemList_ResetIgnoreItemFlags(gOutfitter_EquippableItems); + + return gOutfitter_EquippableItems; + end + + if not gOutfitter_EquippableItems + or pIncludeItemStats then + gOutfitter_EquippableItems = OutfitterItemList_New(); + end + + local _, vPlayerClass = UnitClass("player"); + local vStatDistribution = gOutfitter_StatDistribution[vPlayerClass]; + + if not gOutfitter_EquippableItems.InventoryItems + or pIncludeItemStats then + gOutfitter_EquippableItems.InventoryItems = {}; + + for _, vInventorySlot in Outfitter_cSlotNames do + local vItemInfo = Outfitter_GetInventoryItemInfo(vInventorySlot); + + if vItemInfo + and vItemInfo.ItemSlotName + and vItemInfo.Code ~= 0 then + vItemInfo.SlotName = vInventorySlot; + vItemInfo.Location = { SlotName = vInventorySlot }; + + if pIncludeItemStats then + OutfitterItemList_GetItemStats(vItemInfo, vStatDistribution); + end + + OutfitterItemList_AddItem(gOutfitter_EquippableItems, vItemInfo); + end + end + else + for vInventorySlot, vItem in gOutfitter_EquippableItems.InventoryItems do + vItem.IgnoreItem = nil; + end + end + + local vNumBags, vFirstBagIndex = Outfitter_GetNumBags(); + + for vBagIndex = vFirstBagIndex, vNumBags do + local vBagItems = gOutfitter_EquippableItems.BagItems[vBagIndex]; + + if not vBagItems + or pIncludeItemStats then + gOutfitter_EquippableItems.BagItems[vBagIndex] = {}; + + local vNumBagSlots = GetContainerNumSlots(vBagIndex); + + if vNumBagSlots > 0 then + for vBagSlotIndex = 1, vNumBagSlots do + local vItemInfo = Outfitter_GetBagItemInfo(vBagIndex, vBagSlotIndex); + + if vItemInfo + and vItemInfo.Code ~= 0 + and vItemInfo.ItemSlotName + and Outfitter_CanEquipBagItem(vBagIndex, vBagSlotIndex) + and not Outfitter_BagItemWillBind(vBagIndex, vBagSlotIndex) then + vItemInfo.BagIndex = vBagIndex; + vItemInfo.BagSlotIndex = vBagSlotIndex; + vItemInfo.Location = { BagIndex = vBagIndex, BagSlotIndex = vBagSlotIndex }; + + if pIncludeItemStats then + OutfitterItemList_GetItemStats(vItemInfo, vStatDistribution); + end + + OutfitterItemList_AddItem(gOutfitter_EquippableItems, vItemInfo); + end + end -- for vBagSlotIndex + end -- if vNumBagSlots > 0 + else + -- if not BagItems + for vBagSlotIndex, vItem in vBagItems do + vItem.IgnoreItem = nil; + end + end -- if not BagItems + end -- for vBagIndex + + gOutfitter_EquippableItems.NeedsUpdate = false; + + return gOutfitter_EquippableItems; +end + +function OutfitterItemList_SwapLocations(pItemList, pLocation1, pLocation2) + -- if pLocation1.BagIndex then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocations: Swapping bag "..pLocation1.BagIndex..", "..pLocation1.BagSlotIndex); + -- elseif pLocation1.SlotName then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocations: Swapping slot "..pLocation1.SlotName); + -- end + -- if pLocation2.BagIndex then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocations: with bag "..pLocation2.BagIndex..", "..pLocation2.BagSlotIndex); + -- elseif pLocation2.SlotName then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocations: with slot "..pLocation2.SlotName); + -- end +end + +function OutfitterItemList_SwapLocationWithInventorySlot(pItemList, pLocation, pSlotName) + -- if pLocation.BagIndex then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocationWithInventorySlot: Swapping bag "..pLocation.BagIndex..", "..pLocation.BagSlotIndex.." with slot "..pSlotName); + -- elseif pLocation.SlotName then + -- Outfitter_TestMessage("OutfitterItemList_SwapLocationWithInventorySlot: Swapping slot "..pLocation.SlotName.." with slot "..pSlotName); + -- end +end + +function OutfitterItemList_SwapBagSlotWithInventorySlot(pItemList, pBagIndex, pBagSlotIndex, pSlotName) + -- Outfitter_TestMessage("OutfitterItemList_SwapBagSlotWithInventorySlot: Swapping bag "..pBagIndex..", "..pBagSlotIndex.." with slot "..pSlotName); +end + +function OutfitterItemList_FindItemOrAlt(pItemList, pOutfitItem, pMarkAsInUse, pAllowSubCodeWildcard) + local vItem, vIgnoredItem = OutfitterItemList_FindItem(pItemList, pOutfitItem, pMarkAsInUse, pAllowSubCodeWildcard); + + if vItem then + return vItem; + end + + -- See if there's an alias for the item if it wasn't found + + local vAltCode = Outfitter_cItemAliases[pOutfitItem.Code]; + + if not vAltCode then + return nil, vIgnoredItem; + end + + return OutfitterItemList_FindItem(pItemList, { Code = vAltCode }, pMarkAsInUse, true); +end + +function OutfitterItemList_FindItem(pItemList, pOutfitItem, pMarkAsInUse, pAllowSubCodeWildcard) + local vItem, vIndex, vItemFamily, vIgnoredItem = OutfitterItemList_FindItemIndex(pItemList, pOutfitItem, pAllowSubCodeWildcard); + + if not vItem then + return nil, vIgnoredItem; + end + + if pMarkAsInUse then + vItem.IgnoreItem = true; + end + + return vItem; +end + +function OutfitterItemList_FindAllItemsOrAlt(pItemList, pOutfitItem, pAllowSubCodeWildcard, rItems) + local vNumItems = OutfitterItemList_FindAllItems(pItemList, pOutfitItem, pAllowSubCodeWildcard, rItems); + local vAltCode = Outfitter_cItemAliases[pOutfitItem.Code]; + + if vAltCode then + vNumItems = vNumItems + OutfitterItemList_FindAllItems(pItemList, { Code = vAltCode }, true, rItems); + end + + return vNumItems; +end + +function OutfitterItemList_FindAllItems(pItemList, pOutfitItem, pAllowSubCodeWildcard, rItems) + if not pItemList then + return 0; + end + + local vItemFamily = pItemList.ItemsByCode[pOutfitItem.Code]; + + if not vItemFamily then + return 0; + end + + local vNumItemsFound = 0; + + for vIndex, vItem in vItemFamily do + if (pAllowSubCodeWildcard and not pOutfitItem.SubCode) + or vItem.SubCode == pOutfitItem.SubCode then + table.insert(rItems, vItem); + vNumItemsFound = vNumItemsFound + 1; + end + end + + return vNumItemsFound; +end + +function OutfitterItemList_FindItemIndex(pItemList, pOutfitItem, pAllowSubCodeWildcard) + if not pItemList then + return nil, nil, nil, nil; + end + + local vItemFamily = pItemList.ItemsByCode[pOutfitItem.Code]; + + if not vItemFamily then + return nil, nil, nil, nil; + end + + local vBestMatch = nil; + local vBestMatchIndex = nil; + local vNumItemsFound = 0; + local vFoundIgnoredItem = nil; + + for vIndex, vItem in vItemFamily do + if pAllowSubCodeWildcard + and not pOutfitItem.SubCode then + if vItem.IgnoreItem then + vFoundIgnoredItem = vItem; + else + return vItem, vIndex, vItemFamily, nil; + end + + -- If the subcode matches then check for an enchant match + + elseif vItem.SubCode == pOutfitItem.SubCode then + -- If the enchant matches then we're all done + + if vItem.EnchantCode == pOutfitItem.EnchantCode then + if vItem.IgnoreItem then + vFoundIgnoredItem = vItem; + else + return vItem, vIndex, vItemFamily; + end + + -- Otherwise save the match in case a better one can + -- be found + + else + if vItem.IgnoreItem then + if not vFoundIgnoredItem then + vFoundIgnoredItem = vItem; + end + else + vBestMatch = vItem; + vBestMatchIndex = vIndex; + vNumItemsFound = vNumItemsFound + 1; + end + end + end + end + + -- Return the match if only one item was found + + if vNumItemsFound == 1 + and not vBestMatch.IgnoreItem then + return vBestMatch, vBestMatchIndex, vItemFamily, nil; + end + + return nil, nil, nil, vFoundIgnoredItem; +end + +function OutfitterItemList_GetItemStats(pItem, pDistribution) + if pItem.Stats then + return pItem.Stats; + end + + OutfitterTooltip:SetOwner(OutfitterFrame, "ANCHOR_BOTTOMRIGHT", 0, 0); + + if pItem.SlotName then + local vHasItem = OutfitterTooltip:SetInventoryItem("player", GetInventorySlotInfo(pItem.SlotName)); + + if not vHasItem then + OutfitterTooltip:Hide(); + return nil; + end + elseif pItem.BagIndex == -1 then + OutfitterTooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(pItem.BagSlotIndex)); + else + OutfitterTooltip:SetBagItem(pItem.BagIndex, pItem.BagSlotIndex); + end + + local vStats = Outfitter_GetItemStatsFromTooltip(OutfitterTooltip, pDistribution); + + OutfitterTooltip:Hide(); + + if not vStats then + return nil; + end + + pItem.Stats = vStats; + + return vStats; +end + +function Outfitter_IsBankBagIndex(pBagIndex) + return pBagIndex and (pBagIndex > NUM_BAG_SLOTS or pBagIndex < 0); +end + +function OutfitterItemList_GetMissingItems(pEquippableItems, pOutfit) + local vMissingItems = nil; + local vBankedItems = nil; + + for vInventorySlot, vOutfitItem in pOutfit.Items do + if vOutfitItem.Code ~= 0 then + local vItem = OutfitterItemList_FindItemOrAlt(pEquippableItems, vOutfitItem); + + if not vItem then + if not vMissingItems then + vMissingItems = {}; + end + + table.insert(vMissingItems, vOutfitItem); + elseif Outfitter_IsBankBagIndex(vItem.Location.BagIndex) then + if not vBankedItems then + vBankedItems = {}; + end + + table.insert(vBankedItems, vOutfitItem); + end + end + end + + return vMissingItems, vBankedItems; +end + +function OutfitterItemList_CompiledUnusedItemsList(pEquippableItems) + OutfitterItemList_ResetIgnoreItemFlags(pEquippableItems); + + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + for vInventorySlot, vOutfitItem in vOutfit.Items do + if vOutfitItem.Code ~= 0 then + local vItem = OutfitterItemList_FindItemOrAlt(pEquippableItems, vOutfitItem, true); + + if vItem then + vItem.UsedInOutfit = true; + end + end + end + end + end + + local vUnusedItems = nil; + + for vCode, vFamilyItems in pEquippableItems.ItemsByCode do + for vIndex, vOutfitItem in vFamilyItems do + if not vOutfitItem.UsedInOutfit + and vOutfitItem.ItemSlotName ~= "AmmoSlot" + and Outfitter_cIgnoredUnusedItems[vOutfitItem.Code] == nil then + if not vUnusedItems then + vUnusedItems = {}; + end + + table.insert(vUnusedItems, vOutfitItem); + end + end + end + + pEquippableItems.UnusedItems = vUnusedItems; +end + +function OutfitterItemList_ItemsAreSame(pEquippableItems, pItem1, pItem2) + if not pItem1 then + return pItem2 == nil; + end + + if not pItem2 then + return false; + end + + if pItem1.Code == 0 then + return pItem2.Code == 0; + end + + if pItem1.Code ~= pItem2.Code + or pItem1.SubCode ~= pItem2.SubCode then + return false; + end + + local vItems = {}; + local vNumItems = OutfitterItemList_FindAllItemsOrAlt(pEquippableItems, pItem1, nil, vItems); + + if vNumItems == 0 then + -- Shouldn't ever get here + + Outfitter_ErrorMessage("OutfitterItemList_ItemsAreSame: Item not found"); + return false; + elseif vNumItems == 1 then + -- If there's only one of that item then the enchant code + -- is disregarded so just make sure it's the same + + return true; + else + return pItem1.EnchantCode == pItem2.EnchantCode; + end +end + +function OutfitterItemList_InventorySlotContainsItem(pEquippableItems, pInventorySlot, pOutfitItem) + -- Nil items are supposed to be ignored, so never claim the slot contains them + + if pOutfitItem == nil then + return false, nil; + end + + -- If the item specifies and empty slot check to see if the slot is actually empty + + if pOutfitItem.Code == 0 then + return pEquippableItems.InventoryItems[pInventorySlot] == nil; + end + + local vItems = {}; + local vNumItems = OutfitterItemList_FindAllItemsOrAlt(pEquippableItems, pOutfitItem, nil, vItems); + + if vNumItems == 0 then + return false; + elseif vNumItems == 1 then + -- If there's only one of that item then the enchant code + -- is disregarded so just make sure it's in the slot + + return vItems[1].SlotName == pInventorySlot, vItems[1]; + else + -- See if one of the items is in the slot + + for vIndex, vItem in vItems do + if vItem.SlotName == pInventorySlot then + -- Must match the enchant code if there are multiple items + -- in order to be considered a perfect match + + return vItem.EnchantCode == pOutfitItem.EnchantCode, vItem; + end + end + + -- No items in the slot + + return false, nil; + end +end + +function OutfitterQuickSlots_Open(pSlotName) + local vPaperDollSlotName = "Character" .. pSlotName; + + -- Hide the tooltip so that it isn't in the way + + GameTooltip:Hide(); + + -- Position the window + + if pSlotName == "MainHandSlot" + or pSlotName == "SecondaryHandSlot" + or pSlotName == "RangedSlot" + or pSlotName == "AmmoSlot" then + OutfitterQuickSlots:SetPoint("TOPLEFT", vPaperDollSlotName, "BOTTOMLEFT", 0, 0); + else + OutfitterQuickSlots:SetPoint("TOPLEFT", vPaperDollSlotName, "TOPRIGHT", 5, 6); + end + + OutfitterQuickSlots.SlotName = pSlotName; + + -- Populate the items + + local vItems = Outfitter_FindItemsInBagsForSlot(pSlotName); + local vNumSlots = 0; + + if vItems then + for vItemInfoIndex, vItemInfo in vItems do + if vNumSlots >= Outfitter_cMaxNumQuickSlots then + break ; + end + + vNumSlots = vNumSlots + 1; + OutfitterQuickSlots_SetSlotToBag(vNumSlots, vItemInfo.BagIndex, vItemInfo.BagSlotIndex); + end + end + + -- If the slot isn't empty, offer an empty slot to put the item in + + if vNumSlots < Outfitter_cMaxNumQuickSlots + and not Outfitter_InventorySlotIsEmpty(pSlotName) then + local vBagSlotInfo = Outfitter_GetEmptyBagSlot(); + + if vBagSlotInfo then + vNumSlots = vNumSlots + 1; + OutfitterQuickSlots_SetSlotToBag(vNumSlots, vBagSlotInfo.BagIndex, vBagSlotInfo.BagSlotIndex); + end + end + + -- Resize the window and show it + + OutfitterQuickSlots_SetNumSlots(vNumSlots); + + if vNumSlots == 0 then + OutfitterQuickSlots:Hide(); + else + OutfitterQuickSlots:Show(); + end +end + +function OutfitterQuickSlots_Close() + OutfitterQuickSlots:Hide(); +end + +function OutfitterQuickSlots_OnLoad() + table.insert(UIMenus, this:GetName()); +end + +function OutfitterQuickSlots_OnShow() +end + +function OutfitterQuickSlots_OnHide() +end + +function OutfitterQuickSlots_OnEvent(pEvent) +end + +function OutfitterQuickSlotItem_OnLoad() + this.size = 1; -- one-slot container +end + +function OutfitterQuickSlotItem_OnShow() + this:RegisterEvent("BAG_UPDATE"); + this:RegisterEvent("BAG_UPDATE_COOLDOWN"); + this:RegisterEvent("ITEM_LOCK_CHANGED"); + this:RegisterEvent("UPDATE_INVENTORY_ALERTS"); +end + +function OutfitterQuickSlotItem_OnHide() + this:UnregisterEvent("BAG_UPDATE"); + this:UnregisterEvent("BAG_UPDATE_COOLDOWN"); + this:UnregisterEvent("ITEM_LOCK_CHANGED"); + this:UnregisterEvent("UPDATE_INVENTORY_ALERTS"); +end + +function OutfitterQuickSlotItemButton_OnEnter(button) + GameTooltip:SetOwner(button, "ANCHOR_RIGHT"); + + local vBagIndex = button:GetParent():GetID(); + local vBagSlotIndex = button:GetID(); + + local hasItem, hasCooldown, repairCost; + + if vBagIndex == -1 then + hasItem, hasCooldown, repairCost = GameTooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(vBagSlotIndex)); + else + hasCooldown, repairCost = GameTooltip:SetBagItem(vBagIndex, vBagSlotIndex); + end + + if (InRepairMode() and (repairCost and repairCost > 0)) then + GameTooltip:AddLine(TEXT(REPAIR_COST), "", 1, 1, 1); + SetTooltipMoney(GameTooltip, repairCost); + GameTooltip:Show(); + elseif (this.readable or (IsControlKeyDown() and button.hasItem)) then + ShowInspectCursor(); + elseif (MerchantFrame:IsVisible() and MerchantFrame.selectedTab == 1) then + ShowContainerSellCursor(button:GetParent():GetID(), button:GetID()); + else + ResetCursor(); + end +end + +function OutfitterQuickSlots_SetNumSlots(pNumSlots) + if pNumSlots > Outfitter_cMaxNumQuickSlots then + pNumSlots = Outfitter_cMaxNumQuickSlots; + end + + local vBaseWidth = 11; + local vSlotWidth = 42; + + OutfitterQuickSlotsBackEnd1:Show(); + OutfitterQuickSlotsBackEnd2:Show(); + OutfitterQuickSlotsBackStart1:Show(); + OutfitterQuickSlotsBackStart2:Show(); + + for vIndex = 1, pNumSlots do + local vSlotItem = getglobal("OutfitterQuickSlotsItem" .. vIndex); + + vSlotItem:ClearAllPoints(); + + if vIndex == 1 then + vSlotItem:SetPoint("TOPLEFT", "OutfitterQuickSlots", "TOPLEFT", 6, -6); + elseif vIndex == 10 then + vSlotItem:SetPoint("TOPLEFT", "OutfitterQuickSlots", "TOPLEFT", 6, vSlotWidth * -1 - 12); + elseif vIndex == 19 then + vSlotItem:SetPoint("TOPLEFT", "OutfitterQuickSlots", "TOPLEFT", 6, -102); + else + vSlotItem:SetPoint("TOPLEFT", "OutfitterQuickSlotsItem" .. (vIndex - 1), "TOPLEFT", vSlotWidth, 0); + end + + vSlotItem:Show(); + end + + -- Hide the unused slots + + for vIndex = pNumSlots + 1, Outfitter_cMaxNumQuickSlots do + if vIndex == 10 then + OutfitterQuickSlotsBackEnd1:Hide(); + OutfitterQuickSlotsBackStart1:Hide(); + end + if vIndex == 19 then + OutfitterQuickSlotsBackEnd2:Hide(); + OutfitterQuickSlotsBackStart2:Hide(); + end + local vSlotItem = getglobal("OutfitterQuickSlotsItem" .. vIndex); + + vSlotItem:Hide(); + end + + -- Size the frame + + local pNumSlotsTemp = pNumSlots + if pNumSlots > 9 then + pNumSlotsTemp = 9 + end + OutfitterQuickSlots:SetWidth(vBaseWidth + vSlotWidth * pNumSlotsTemp); + + -- Fix the background + + if pNumSlots > 0 then + for vIndex = 1, pNumSlots - 1 do + getglobal("OutfitterQuickSlotsBack" .. vIndex):Show(); + end + + if pNumSlots > 18 then + pNumSlotsTemp = pNumSlots - 2 + elseif pNumSlots > 9 then + pNumSlotsTemp = pNumSlots - 1 + end + + for vIndex = pNumSlotsTemp, Outfitter_cMaxNumQuickSlots - 1 do + getglobal("OutfitterQuickSlotsBack" .. vIndex):Hide(); + end + + if pNumSlots == 19 then + OutfitterQuickSlotsBackEnd2:SetPoint("LEFT", "OutfitterQuickSlotsBackStart2", "RIGHT", 0, 0); + else + OutfitterQuickSlotsBackEnd2:SetPoint("LEFT", "OutfitterQuickSlotsBack" .. (pNumSlotsTemp - 1), "RIGHT", 0, 0); + end + if pNumSlots == 10 then + OutfitterQuickSlotsBackEnd1:SetPoint("LEFT", "OutfitterQuickSlotsBackStart1", "RIGHT", 0, 0); + elseif pNumSlots == 1 then + OutfitterQuickSlotsBackEnd1:SetPoint("LEFT", "OutfitterQuickSlotsBack16", "RIGHT", 0, 0); + elseif pNumSlots < 18 then + OutfitterQuickSlotsBackEnd1:SetPoint("LEFT", "OutfitterQuickSlotsBack" .. (pNumSlots - 2), "RIGHT", 0, 0); + else + OutfitterQuickSlotsBackEnd1:SetPoint("LEFT", "OutfitterQuickSlotsBack16", "RIGHT", 0, 0); + end + if pNumSlots < 9 then + OutfitterQuickSlotsBackEnd:SetPoint("LEFT", "OutfitterQuickSlotsBack" .. (pNumSlots - 1), "RIGHT", 0, 0); + else + OutfitterQuickSlotsBackEnd:SetPoint("LEFT", "OutfitterQuickSlotsBack8", "RIGHT", 0, 0); + end + end +end + +function OutfitterQuickSlots_SetSlotToBag(pQuickSlotIndex, pBagIndex, pBagSlotIndex) + local vQuickSlotItem = getglobal("OutfitterQuickSlotsItem" .. pQuickSlotIndex); + local vQuickSlotItemButton = getglobal("OutfitterQuickSlotsItem" .. pQuickSlotIndex .. "Item1"); + + vQuickSlotItem:SetID(pBagIndex); + vQuickSlotItemButton:SetID(pBagSlotIndex); + + ContainerFrame_Update(vQuickSlotItem); +end + +function Outfitter_RegisterEvent(pFrame, pEvent, pHandler) + if not pFrame.EventHandlers then + pFrame.EventHandlers = {}; + end + + pFrame.EventHandlers[pEvent] = pHandler; + pFrame:RegisterEvent(pEvent); +end + +function Outfitter_UnregisterEvent(pFrame, pEvent) + if pFrame.EventHandlers then + pFrame.EventHandlers[pEvent] = nil; + end + + pFrame:UnregisterEvent(pEvent); +end + +function Outfitter_SuspendEvent(pFrame, pEvent) + if not pFrame.EventHandlers + or not pFrame.EventHandlers[pEvent] then + return ; + end + + pFrame:UnregisterEvent(pEvent); +end + +function Outfitter_ResumeEvent(pFrame, pEvent) + if not pFrame.EventHandlers + or not pFrame.EventHandlers[pEvent] then + return ; + end + + pFrame:RegisterEvent(pEvent); +end + +function Outfitter_DispatchEvent(pFrame, pEvent) + if not pFrame.EventHandlers then + return false; + end + + local vEventHandler = pFrame.EventHandlers[pEvent]; + + if not vEventHandler then + return false; + end + + Outfitter_BeginEquipmentUpdate(); + vEventHandler(pEvent); + Outfitter_EndEquipmentUpdate("Outfitter_DispatchEvent(" .. pEvent .. ")"); + + return true; +end + +function Outfitter_GetPlayerStat(pStatIndex) + local _, vEffectiveValue, vPosValue, vNegValue = UnitStat("player", pStatIndex); + + return vEffectiveValue - vPosValue - vNegValue, vPosValue + vNegValue; +end + +function Outfitter_DepositOutfit(pOutfit, pUniqueItemsOnly) + -- Deselect any outfits to avoid them from being updated when + -- items get put away + + Outfitter_ClearSelection(); + + -- Build a list of items for the outfit + + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + OutfitterItemList_ResetIgnoreItemFlags(vEquippableItems); + + -- Make a copy of the outfit + + local vUnequipOutfit = Outfitter_NewEmptyOutfit(); + + for vInventorySlot, vItem in pOutfit.Items do + vUnequipOutfit.Items[vInventorySlot] = vItem; + end + + -- Subtract out items from other outfits if unique is specified + + if pUniqueItemsOnly then + for vCategoryID, vOutfits in gOutfitter_Settings.Outfits do + for vOutfitIndex, vOutfit in vOutfits do + if vOutfit ~= pOutfit then + local vMissingItems, vBankedItems = OutfitterItemList_GetMissingItems(vEquippableItems, vOutfit); + + -- Only subtract out items from outfits which aren't themselves partialy banked + + if vBankedItems == nil then + Outfitter_SubtractOutfit(vUnequipOutfit, vOutfit, true); + end + end -- if vOutfit + end -- for vOutfitIndex + end -- for vCategoryID + end -- if pUniqueItemsOnly + + -- Build the change list + + OutfitterItemList_ResetIgnoreItemFlags(vEquippableItems); + + local vEquipmentChangeList = Outfitter_BuildUnequipChangeList(vUnequipOutfit, vEquippableItems); + + if not vEquipmentChangeList then + return ; + end + + -- Eliminate items which are already banked + + local vChangeIndex = 1; + local vNumChanges = table.getn(vEquipmentChangeList); + + while vChangeIndex <= vNumChanges do + vEquipmentChange = vEquipmentChangeList[vChangeIndex]; + + if Outfitter_IsBankBagIndex(vEquipmentChange.FromLocation.BagIndex) then + table.remove(vEquipmentChangeList, vChangeIndex); + vNumChanges = vNumChanges - 1; + else + vChangeIndex = vChangeIndex + 1; + end + end + + -- Get the list of empty bank slots + + local vEmptyBankSlots = Outfitter_GetEmptyBankSlotList(); + + -- Execute the changes + + Outfitter_ExecuteEquipmentChangeList2(vEquipmentChangeList, vEmptyBankSlots, Outfitter_cDepositBagsFullError, vExpectedEquippableItems); +end + +function Outfitter_WithdrawOutfit(pOutfit) + local vEquippableItems = OutfitterItemList_GetEquippableItems(); + + -- Build a list of items for the outfit + + OutfitterItemList_ResetIgnoreItemFlags(vEquippableItems); + + local vEquipmentChangeList = Outfitter_BuildUnequipChangeList(pOutfit, vEquippableItems); + + if not vEquipmentChangeList then + return ; + end + + -- Eliminate items which aren't in the bank + + local vChangeIndex = 1; + local vNumChanges = table.getn(vEquipmentChangeList); + + while vChangeIndex <= vNumChanges do + vEquipmentChange = vEquipmentChangeList[vChangeIndex]; + + if not Outfitter_IsBankBagIndex(vEquipmentChange.FromLocation.BagIndex) then + table.remove(vEquipmentChangeList, vChangeIndex); + vNumChanges = vNumChanges - 1; + else + vChangeIndex = vChangeIndex + 1; + end + end + + -- Get the list of empty bag slots + + local vEmptyBagSlots = Outfitter_GetEmptyBagSlotList(); + + -- Execute the changes + + Outfitter_ExecuteEquipmentChangeList2(vEquipmentChangeList, vEmptyBagSlots, Outfitter_cWithdrawBagsFullError, vExpectedEquippableItems); +end + +function Outfitter_TestOutfitCombinations() + local vEquippableItems = OutfitterItemList_GetEquippableItems(true); + local vFilterStats = { ["FireResist"] = true }; + local vOutfit = Outfitter_FindOutfitCombination(vEquippableItems, vFilterStats, Outfitter_OutfitTestEval, {}); +end + +function Outfitter_OutfitTestEval(pOpcode, pParams, pOutfit1, pOutfit2) + if pOpcode == "INIT" then + Outfitter_TestMessage("Outfitter_OutfitTestEval: INIT"); + elseif pOpcode == "COMPARE" then + Outfitter_TestMessage("Outfitter_OutfitTestEval: COMPARE"); + end +end + +function Outfitter_FindOutfitCombination(pEquippableItems, pFilterStats, pOutfitEvalFunc, pOutfitEvalParams) + local vSlotIterators = OutfitterSlotIterators_New(pEquippableItems, pFilterStats); + + Outfitter_DumpArray("vSlotIterators", vSlotIterators); + + local vBestOutfit = nil; + local vNumIterations = 0; + + pOutfitEvalFunc("INIT", pOutfitEvalParams); + + while vSlotIterators:Increment() do + local vOutfit = vSlotIterators:GetOutfit(); + + if pOutfitEvalFunc("COMPARE", pOutfitEvalParams, vBestOutfit, vOutfit) then + vBestOutfit = vOutfit; + end + + vNumIterations = vNumIterations + 1; + + if vNumIterations > 20 then + return vBestOutfit; + end + end + + return vBestOutfit; +end + +function Outfitter_ItemContainsStats(pItem, pFilterStats) + for vStatID, _ in pFilterStats do + if pItem.Stats[vStatID] then + return true; + end + end + + return false; +end + +function OutfitterSlotIterators_New(pEquippableItems, pFilterStats) + local vSlotIterators = { Slots = {} }; + local vNumCombinations = 1; + + for vInventorySlot, vItems in pEquippableItems.ItemsBySlot do + local vNumItems = table.getn(vItems); + + if vInventorySlot ~= "AmmoSlot" + and vNumItems > 0 then + -- Filter the items by stat + + local vFilteredItems = nil; + + if pFilterStats then + vNumItems = 0; + + for vItemIndex, vItem in vItems do + if Outfitter_ItemContainsStats(vItem, pFilterStats) then + if not vFilteredItems then + vFilteredItems = {}; + end + + table.insert(vFilteredItems, vItem); + vNumItems = vNumItems + 1; + end + end + else + vFilteredItems = vItems; + end + + -- Add the filtered list + + if vFilteredItems then + table.insert(vSlotIterators.Slots, { ItemSlotName = vInventorySlot, Items = vItems, Index = 0, MaxIndex = vNumItems }); + + vNumCombinations = vNumCombinations * (vNumItems + 1); + + Outfitter_TestMessage("OutfitterSlotIterators_New: " .. vInventorySlot .. " has " .. vNumItems .. " items. Combinations " .. vNumCombinations); + end + end + end + + vSlotIterators.Increment = OutfitterSlotIterators_Increment; + vSlotIterators.GetOutfit = OutfitterSlotIterators_GetOutfit; + vSlotIterators.NumCombinations = vNumCombinations; + + Outfitter_TestMessage("OutfitterSlotIterators_New: Total combinations " .. vNumCombinations); + + return vSlotIterators; +end + +function OutfitterSlotIterators_Increment(pSlotIterators) + for vSlotIndex, vSlotIterator in pSlotIterators.Slots do + vSlotIterator.Index = vSlotIterator.Index + 1; + + if vSlotIterator.Index <= vSlotIterator.MaxIndex then + return true; + end + + vSlotIterator.Index = 0; + end + + return false; -- Couldn't increment +end + +function OutfitterSlotIterators_GetOutfit(pSlotIterators) + local vOutfit = Outfitter_NewEmptyOutfit(); + + for _, vItems in pSlotIterators.Slots do + -- if vItems.Index > 0 then + -- local vItem = vItems.Items[vItems.Index]; + -- + -- Outfitter_AddOutfitItem(vOutfit, vItems.ItemSlotName, vItem.Code, vItem.SubCode, vItem.Name, vItem.EnchantCode); + -- end + end + + return vOutfit; +end + +function OutfitterStats_AddStatValue(pStats, pStat, pValue, pDistribution) + if not pStats[pStat] then + pStats[pStat] = pValue; + else + pStats[pStat] = pStats[pStat] + pValue; + end + + if not pDistribution then + return ; + end + + local vStatDistribution = pDistribution[pStat]; + + if not vStatDistribution then + return ; + end + + for vSecondaryStat, vFactors in vStatDistribution do + local vSecondaryValue = pValue * vFactors.Coeff; + + if vFactors.Const then + vSecondaryValue = vSecondaryValue + vFactors.Const; + end + + if pStats[vSecondaryStat] then + pStats[vSecondaryStat] = pStats[vSecondaryStat] + vSecondaryValue; + else + pStats[vSecondaryStat] = vSecondaryValue; + end + end +end + +function OutfitterStats_SubtractStats(pStats, pStats2) + for vStat, vValue in pStats2 do + if pStats[vStat] then + pStats[vStat] = pStats[vStat] - vValue; + end + end +end + +function OutfitterStats_AddStats(pStats, pStats2) + for vStat, vValue in pStats2 do + if pStats[vStat] then + pStats[vStat] = pStats[vStat] + vValue; + else + pStats[vStat] = vValue; + end + end +end + +function OutfitterTankPoints_New() + local vTankPointData = {}; + local _, vPlayerClass = UnitClass("player"); + local vStatDistribution = gOutfitter_StatDistribution[vPlayerClass]; + + if not vStatDistribution then + Outfitter_ErrorMessage("Outfitter: Missing stat distribution data for " .. vPlayerClass); + end + + vTankPointData.PlayerLevel = UnitLevel("player"); + vTankPointData.StaminaFactor = 1.0; -- Warlocks with demonic embrace = 1.15 + + -- Get the base stats + + vTankPointData.BaseStats = {}; + + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Strength", UnitStat("player", 1), vStatDistribution); + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Agility", UnitStat("player", 2), vStatDistribution); + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Stamina", UnitStat("player", 3), vStatDistribution); + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Intellect", UnitStat("player", 4), vStatDistribution); + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Spirit", UnitStat("player", 5), vStatDistribution); + + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Health", UnitHealthMax("player"), vStatDistribution); + + vTankPointData.BaseStats.Health = vTankPointData.BaseStats.Health - vTankPointData.BaseStats.Stamina * 10; + + vTankPointData.BaseStats.Dodge = GetDodgeChance(); + vTankPointData.BaseStats.Parry = GetParryChance(); + vTankPointData.BaseStats.Block = GetBlockChance(); + + local vBaseDefense, vBuffDefense = UnitDefense("player"); + OutfitterStats_AddStatValue(vTankPointData.BaseStats, "Defense", vBaseDefense + vBuffDefense, vStatDistribution); + + -- Replace the armor with the current value since that already includes various factors + + local vBaseArmor, vEffectiveArmor, vArmor, vArmorPosBuff, vArmorNegBuff = UnitArmor("player"); + vTankPointData.BaseStats.Armor = vEffectiveArmor; + + Outfitter_TestMessage("------------------------------------------"); + Outfitter_DumpArray("vTankPointData", vTankPointData); + + -- Subtract out the current outfit + + local vCurrentOutfitStats = OutfitterTankPoints_GetCurrentOutfitStats(vStatDistribution); + + Outfitter_TestMessage("------------------------------------------"); + Outfitter_DumpArray("vCurrentOutfitStats", vCurrentOutfitStats); + + OutfitterStats_SubtractStats(vTankPointData.BaseStats, vCurrentOutfitStats); + + -- Calculate the buff stats (stuff from auras/spell buffs/whatever) + + vTankPointData.BuffStats = {}; + + -- Reset the cumulative values + + OutfitterTankPoints_Reset(vTankPointData); + + Outfitter_TestMessage("------------------------------------------"); + Outfitter_DumpArray("vTankPointData", vTankPointData); + + Outfitter_TestMessage("------------------------------------------"); + return vTankPointData; +end + +function OutfitterTankPoints_Reset(pTankPointData) + pTankPointData.AdditionalStats = {}; +end + +function OutfitterTankPoints_GetTotalStat(pTankPointData, pStat) + local vTotalStat = pTankPointData.BaseStats[pStat]; + + if not vTotalStat then + vTotalStat = 0; + end + + local vAdditionalStat = pTankPointData.AdditionalStats[pStat]; + + if vAdditionalStat then + vTotalStat = vTotalStat + vAdditionalStat; + end + + local vBuffStat = pTankPointData.BuffStats[pStat]; + + if vBuffStat then + vTotalStat = vTotalStat + vBuffStat; + end + + -- + + return vTotalStat; +end + +function OutfitterTankPoints_CalcTankPoints(pTankPointData, pStanceModifier) + if not pStanceModifier then + pStanceModifier = 1; + end + + Outfitter_DumpArray("pTankPointData", pTankPointData); + + local vEffectiveArmor = OutfitterTankPoints_GetTotalStat(pTankPointData, "Armor"); + + Outfitter_TestMessage("Armor: " .. vEffectiveArmor); + + local vArmorReduction = vEffectiveArmor / ((85 * pTankPointData.PlayerLevel) + 400); + + vArmorReduction = vArmorReduction / (vArmorReduction + 1); + + local vEffectiveHealth = OutfitterTankPoints_GetTotalStat(pTankPointData, "Health"); + + Outfitter_TestMessage("Health: " .. vEffectiveHealth); + + Outfitter_TestMessage("Stamina: " .. OutfitterTankPoints_GetTotalStat(pTankPointData, "Stamina")); + + -- + + local vEffectiveDodge = OutfitterTankPoints_GetTotalStat(pTankPointData, "Dodge") * 0.01; + local vEffectiveParry = OutfitterTankPoints_GetTotalStat(pTankPointData, "Parry") * 0.01; + local vEffectiveBlock = OutfitterTankPoints_GetTotalStat(pTankPointData, "Block") * 0.01; + local vEffectiveDefense = OutfitterTankPoints_GetTotalStat(pTankPointData, "Defense"); + + -- Add agility and defense to dodge + + -- defenseInputBox:GetNumber() * 0.04 + agiInputBox:GetNumber() * 0.05 + + Outfitter_TestMessage("Dodge: " .. vEffectiveDodge); + Outfitter_TestMessage("Parry: " .. vEffectiveParry); + Outfitter_TestMessage("Block: " .. vEffectiveBlock); + Outfitter_TestMessage("Defense: " .. vEffectiveDefense); + + local vDefenseModifier = (vEffectiveDefense - pTankPointData.PlayerLevel * 5) * 0.04 * 0.01; + + Outfitter_TestMessage("Crit reduction: " .. vDefenseModifier); + + local vMobCrit = max(0, 0.05 - vDefenseModifier); + local vMobMiss = 0.05 + vDefenseModifier; + local vMobDPS = 1; + + local vTotalReduction = 1 - (vMobCrit * 2 + (1 - vMobCrit - vMobMiss - vEffectiveDodge - vEffectiveParry)) * (1 - vArmorReduction) * pStanceModifier; + + Outfitter_TestMessage("Total reduction: " .. vTotalReduction); + + local vTankPoints = vEffectiveHealth / (vMobDPS * (1 - vTotalReduction)); + + return vTankPoints; + + --[[ + Stats used in TankPoints calculation: + Health + Dodge + Parry + Block + Defense + Armor + ]]-- +end + +function OutfitterTankPoints_GetCurrentOutfitStats(pStatDistribution) + local vTotalStats = {}; + + for _, vSlotName in Outfitter_cSlotNames do + local vStats = OutfitterItemList_GetItemStats({ SlotName = vSlotName }); + + if vStats then + for vStat, vValue in vStats do + OutfitterStats_AddStatValue(vTotalStats, vStat, vValue, pStatDistribution); + end + end + end + + return vTotalStats; +end + +function OutfitterTankPoints_Test() + local _, vPlayerClass = UnitClass("player"); + local vStatDistribution = gOutfitter_StatDistribution[vPlayerClass]; + + local vTankPointData = OutfitterTankPoints_New(); + local vStats = OutfitterTankPoints_GetCurrentOutfitStats(vStatDistribution); + + OutfitterStats_AddStats(vTankPointData.AdditionalStats, vStats); + + local vTankPoints = OutfitterTankPoints_CalcTankPoints(vTankPointData); + + Outfitter_TestMessage("TankPoints = " .. vTankPoints); +end + +function Outfitter_TestAmmoSlot() + local vItemInfo = Outfitter_GetInventoryItemInfo("AmmoSlot"); + local vSlotID = GetInventorySlotInfo("AmmoSlot"); + local vItemLink = GetInventoryItemLink("player", vSlotID); + + Outfitter_TestMessage("SlotID: " .. vSlotID); + Outfitter_TestMessage("ItemLink: " .. vItemLink); + + Outfitter_DumpArray("vItemInfo", vItemInfo); +end + +function Outfitter_pfUISkin() + if IsAddOnLoaded( "pfUI" ) and pfUI and pfUI.api and pfUI.env and pfUI.env.C then + pfUI:RegisterSkin( "Outfitter", "vanilla", function() + OutfitterButton:SetPoint( "TOPRIGHT", -28, -40 ) + OutfitterButton:SetNormalTexture("Interface\\Addons\\Outfitter\\Textures\\Outfitter-Button-pfUI") + OutfitterButton:SetPushedTexture("Interface\\Addons\\Outfitter\\Textures\\Outfitter-Button-pfUI") + + pfUI.api.StripTextures( OutfitterFrame ) + pfUI.api.CreateBackdrop( OutfitterFrame, nil, nil, .75 ) + pfUI.api.CreateBackdropShadow( OutfitterFrame ) + OutfitterFrame:SetPoint( "TOPLEFT", OutfitterButtonFrame, "TOPRIGHT", -28, -40 ) + OutfitterFrameTitle:SetPoint( "TOP", 0, -6 ) + OutfitterMainFrameButtonBarBackground:SetTexture( nil ) + + pfUI.api.SkinCloseButton( OutfitterCloseButton ) + OutfitterCloseButton:SetPoint( "TOPRIGHT", -4, -4 ) + + pfUI.api.SkinButton( OutfitterNewButton ) + OutfitterNewButton:SetPoint( "BOTTOMRIGHT", -9, 4 ) + + pfUI.api.SkinButton( OutfitterEnableAll ) + OutfitterEnableAll:SetPoint("TOP", -73, -80) + + pfUI.api.SkinButton( OutfitterEnableNone ) + OutfitterEnableNone:SetPoint("TOP", 18, -80) + + pfUI.api.StripTextures( OutfitterMainFrameScrollbarTrench ) + pfUI.api.SkinScrollbar( OutfitterMainFrameScrollFrameScrollBar ) + + pfUI.api.SkinTab( OutfitterFrameTab1 ) + OutfitterFrameTab1:ClearAllPoints() + OutfitterFrameTab1:SetPoint( "TOPRIGHT", OutfitterFrame, "BOTTOMRIGHT", 0, -6 ) + pfUI.api.SkinTab( OutfitterFrameTab2 ) + OutfitterFrameTab2:ClearAllPoints() + OutfitterFrameTab2:SetPoint( "TOPRIGHT", OutfitterFrameTab1, "TOPLEFT", -6, 0 ) + pfUI.api.SkinTab( OutfitterFrameTab3 ) + OutfitterFrameTab3:ClearAllPoints() + OutfitterFrameTab3:SetPoint( "TOPRIGHT", OutfitterFrameTab2, "TOPLEFT", -6, 0 ) + + pfUI.api.StripTextures( OutfitterNameOutfitDialog ) + pfUI.api.CreateBackdrop( OutfitterNameOutfitDialog ) + OutfitterNameOutfitDialogTitle:SetPoint( "TOP", 0, -8 ) + + pfUI.api.StripTextures( OutfitterNameOutfitDialogName, true, "BACKGROUND" ) + pfUI.api.CreateBackdrop( OutfitterNameOutfitDialogName ) + OutfitterNameOutfitDialogName:SetWidth( 165 ) + + pfUI.api.SkinDropDown( OutfitterNameOutfitDialogCreateUsing ) + OutfitterNameOutfitDialogCreateUsing:SetPoint( "TOPLEFT", OutfitterNameOutfitDialogName, "TOPLEFT", -17, -30 ) + OutfitterNameOutfitDialogCreateUsingTitle:SetPoint( "RIGHT", OutfitterNameOutfitDialogCreateUsing, "LEFT", 5, 0) + + pfUI.api.SkinButton( OutfitterNameOutfitDialogDoneButton ) + pfUI.api.SkinButton( OutfitterNameOutfitDialogCancelButton ) + + pfUI.api.StripTextures( OutfitterCurrentOutfit ) + pfUI.api.CreateBackdrop( OutfitterCurrentOutfit ) + OutfitterCurrentOutfit:SetWidth( 140 ) + + local function skin_checkbox(cb) + pfUI.api.SkinCheckbox( cb ) + local tex = cb:GetCheckedTexture() + tex:ClearAllPoints() + tex:SetPoint( "TOPLEFT", 4, -4 ) + tex:SetPoint( "BOTTOMRIGHT", -4, 4 ) + end + + for i = 0, 13 do + local m = getglobal( "OutfitterItem" .. i .. "OutfitMenu") + pfUI.api.SkinArrowButton( m, "down" ) + + local cb = getglobal( "OutfitterItem" .. i .. "OutfitSelected") + skin_checkbox( cb ) + + local c = getglobal( "OutfitterItem" .. i .. "CategoryExpand") + pfUI.api.SkinCollapseButton( c ) + c.icon.backdrop:SetPoint("TOPLEFT", -2, 1 ) + c.icon.backdrop:SetPoint("BOTTOMRIGHT", 1, -2 ) + end + + OutfitterShowMinimapButton:SetPoint( "TOPLEFT", 15, -90 ) + for _, v in { "ShowMinimapButton", "RememberVisibility", "ShowHotkeyMessages", "ShowCurrentOutfit", "HideDisabledOutfits" } do + local cb = getglobal( "Outfitter" .. v ) + skin_checkbox( cb ) + end + + for _, v in { "Head", "Neck", "Shoulder", "Back", "Chest", "Shirt", "Tabard", "Wrist", "Hands", "Waist", "Legs", "Feet", "Finger0", "Finger1", "Trinket0", "Trinket1", "MainHand", "SecondaryHand", "Ranged", "Ammo" } do + local cb = getglobal( "OutfitterEnable" .. v .. "Slot") + skin_checkbox( cb ) + end + end ) + end +end \ No newline at end of file diff --git a/Outfitter.toc b/Outfitter.toc new file mode 100644 index 0000000..d328d12 --- /dev/null +++ b/Outfitter.toc @@ -0,0 +1,25 @@ +## Interface: 11200 +## Title: Outfitter +## Notes: Outfitter +## Author: |cff5BCEFAL|cffF5A9B8e|cffFFFFFFx|cffF5A9B8i|cff5BCEFAe|r +## Version: 1.6.0 +## OptionalDeps: TankPoints, Ace2 +## X-ClientMods: SuperWoW, ClassicAPI (optional) +## RequiredDeps: +## SavedVariablesPerCharacter: gOutfitter_Settings + +Libs\AceLibrary\AceLibrary.lua +Libs\AceOO-2.0\AceOO-2.0.lua +Libs\AceEvent-2.0\AceEvent-2.0.lua + +OutfitterStrings.lua +OutfitterStrings_de.lua +OutfitterStrings_fr.lua +OutfitterStrings_cn.lua +OutfitterStrings_tw.lua +OutfitterStrings_kr.lua + +BossTrash.lua +OutfitterClientMods.lua +Outfitter.lua +Outfitter.xml diff --git a/Outfitter.xml b/Outfitter.xml new file mode 100644 index 0000000..e69c47e --- /dev/null +++ b/Outfitter.xml @@ -0,0 +1,1774 @@ + + + + + + + OutfitterInputBox_OnLoad(0); + + + OutfitterInputBox_TabPressed(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutfitterScrollbarTrench_SizeChanged(this); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Outfitter_SlotEnableClicked(this, arg1); + + + Outfitter_SlotEnableClicked(this, "LeftButton", 1); + + + GameTooltip_AddNewbieTip(Outfitter_cSlotEnableTitle, 1, 1, 1, Outfitter_cSlotEnableDescription, 1); + + + GameTooltip:Hide(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + this:RegisterForClicks("LeftButtonUp", "RightButtonUp"); + + + OutfitterItem_OnClick(this, arg1); + + + OutfitterItem_OnEnter(this); + + + OutfitterItem_OnLeave(this); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutfitterMainFrameBackground:SetVertexColor(1, 1, 1, 0.20); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getglobal(this:GetName().."Text"):SetText(Outfitter_cShowMinimapButton); + + + Outfitter_SetShowMinimapButton(this:GetChecked()); + + + if this:GetChecked() then + GameTooltip_AddNewbieTip(Outfitter_cShowMinimapButton, 1.0, 1.0, 1.0, Outfitter_cShowMinimapButtonOnDescription, 1); + else + GameTooltip_AddNewbieTip(Outfitter_cShowMinimapButton, 1.0, 1.0, 1.0, Outfitter_cShowMinimapButtonOffDescription, 1); + end + + + GameTooltip:Hide(); + + + + + + + + + + + + + + getglobal(this:GetName().."Text"):SetText(Outfitter_cRememberVisibility); + + + Outfitter_SetRememberVisibility(this:GetChecked()); + + + if this:GetChecked() then + GameTooltip_AddNewbieTip(Outfitter_cRememberVisibility, 1.0, 1.0, 1.0, Outfitter_cRememberVisibilityOnDescription, 1); + else + GameTooltip_AddNewbieTip(Outfitter_cRememberVisibility, 1.0, 1.0, 1.0, Outfitter_cRememberVisibilityOffDescription, 1); + end + + + GameTooltip:Hide(); + + + + + + + + + + + + + + getglobal(this:GetName().."Text"):SetText(Outfitter_cShowHotkeyMessages); + + + Outfitter_SetShowHotkeyMessages(this:GetChecked()); + + + if this:GetChecked() then + GameTooltip_AddNewbieTip(Outfitter_cShowHotkeyMessages, 1.0, 1.0, 1.0, Outfitter_cShowHotkeyMessagesOnDescription, 1); + else + GameTooltip_AddNewbieTip(Outfitter_cShowHotkeyMessages, 1.0, 1.0, 1.0, Outfitter_cShowHotkeyMessagesOffDescription, 1); + end + + + GameTooltip:Hide(); + + + + + + + + + + + + + + getglobal(this:GetName().."Text"):SetText(Outfitter_cShowCurrentOutfit); + + + Outfitter_SetShowCurrentOutfit(this:GetChecked()); + + + + + + + + + + + + + + getglobal(this:GetName().."Text"):SetText(Outfitter_cHideDisabledOutfits); + + + Outfitter_SetHideDisabledOutfits(this:GetChecked()); + + + + + + + OutfitterOptionsFrameBackground:SetVertexColor(1, 1, 1, 0.20); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Outfitter_OnLoad(); + + + Outfitter_OnShow(); + + + Outfitter_OnHide(); + + + Outfitter_OnEvent(event); + + + + + + + + + + + + + + + + + this.SlotName = "HeadSlot"; + + + + + + + + + + + + this.SlotName = "NeckSlot"; + + + + + + + + + + + + this.SlotName = "ShoulderSlot"; + + + + + + + + + + + + this.SlotName = "BackSlot"; + + + + + + + + + + + + this.SlotName = "ChestSlot"; + + + + + + + + + + + + this.SlotName = "ShirtSlot"; + + + + + + + + + + + + this.SlotName = "TabardSlot"; + + + + + + + + + + + + this.SlotName = "WristSlot"; + + + + + + + + + + + + this.SlotName = "HandsSlot"; + + + + + + + + + + + + this.SlotName = "WaistSlot"; + + + + + + + + + + + + this.SlotName = "LegsSlot"; + + + + + + + + + + + + this.SlotName = "FeetSlot"; + + + + + + + + + + + + this.SlotName = "Finger0Slot"; + + + + + + + + + + + + this.SlotName = "Finger1Slot"; + + + + + + + + + + + + this.SlotName = "Trinket0Slot"; + + + + + + + + + + + + this.SlotName = "Trinket1Slot"; + + + + + + + + + + + + this.SlotName = "MainHandSlot"; + + + + + + + + + + + + this.SlotName = "SecondaryHandSlot"; + + + + + + + + + + + + this.SlotName = "RangedSlot"; + + + + + + + + + + + + this.SlotName = "AmmoSlot"; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutfitterNameOutfit_Update() + + + + this:ClearFocus(); + + + OutfitterNameOutfit_Done(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutfitterStatDropdown_OnLoad(); + + + OutfitterStatDropdown_OnLoad(); + + + + + + + + + this.baseHeight = this:GetHeight(); + + + OutfitterNameOutfit_Update(); + + + + + + + + OutfitterUpdateFrame_OnUpdate(arg1); + + + + + + + + + + + + ContainerFrame_OnEvent(); + + + OutfitterQuickSlotItem_OnLoad(); + + + OutfitterQuickSlotItem_OnShow(); + + + OutfitterQuickSlotItem_OnHide(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutfitterQuickSlots_OnLoad(); + + + OutfitterQuickSlots_OnShow(); + + + OutfitterQuickSlots_OnHide(); + + + OutfitterQuickSlots_OnEvent(event); + + + + diff --git a/OutfitterClientMods.lua b/OutfitterClientMods.lua new file mode 100644 index 0000000..54f8cb4 --- /dev/null +++ b/OutfitterClientMods.lua @@ -0,0 +1,157 @@ +-- OutfitterClientMods.lua +-- +-- Optional integration with 1.12.1 client mods. Every helper here has a +-- plain-vanilla fallback, so Outfitter behaves exactly as before when no +-- client mod is installed. +-- +-- SuperWoW : UnitBuff() 3rd return = aura spell ID, IsMounted(), +-- IsSwimming(), UnitExists() 2nd return = GUID +-- ClassicAPI : C_UnitAuras.GetAuraDataByIndex() (spellId + name), +-- IsMounted(), IsSwimming(), UnitGUID() +-- Nampower : detected and reported only. Its item/cast/spell-queue API +-- has no task inside Outfitter that it does better. +-- UnitXP SP3 : detected and reported only. Distance, line of sight and +-- camera functions have no use in an equipment manager. +-- +-- Lua 5.0 (no select(), no #, no varargs expressions). + +Outfitter_ClientMods = { + SuperWoW = false, + ClassicAPI = false, + Nampower = false, + UnitXP = false, + Detected = false, +}; + +local OCM = Outfitter_ClientMods; + +function Outfitter_DetectClientMods() + OCM.SuperWoW = (SUPERWOW_VERSION ~= nil) or (SUPERWOW_STRING ~= nil); + + OCM.ClassicAPI = (CLASSIC_API_VERSION ~= nil) + or (type(C_UnitAuras) == "table" and type(C_UnitAuras.GetAuraDataByIndex) == "function"); + + OCM.Nampower = type(GetNampowerVersion) == "function"; + + OCM.UnitXP = false; + if type(UnitXP) == "function" then + -- UnitXP("nop", "nop") is the documented presence check; it raises if the dll is missing + local vOK = pcall(UnitXP, "nop", "nop"); + OCM.UnitXP = vOK and true or false; + end + + -- Capabilities actually used by Outfitter + + OCM.HasIsMounted = type(IsMounted) == "function" and (OCM.SuperWoW or OCM.ClassicAPI); + OCM.HasIsSwimming = type(IsSwimming) == "function" and (OCM.SuperWoW or OCM.ClassicAPI); + OCM.HasAuraSpellID = OCM.SuperWoW or OCM.ClassicAPI; + OCM.HasGUID = OCM.SuperWoW or (OCM.ClassicAPI and type(UnitGUID) == "function"); + + OCM.Detected = true; +end + +-- Returns texture, spellID[, name] for the player's buff at pIndex (1-based). +-- spellID is nil when no client mod provides it. + +function Outfitter_GetPlayerBuffInfo(pIndex) + if OCM.SuperWoW then + local vTexture, vCount, vSpellID = UnitBuff("player", pIndex); + return vTexture, vSpellID; + end + + if OCM.ClassicAPI then + local vTexture = UnitBuff("player", pIndex); + + if not vTexture then + return nil; + end + + local vOK, vData = pcall(C_UnitAuras.GetAuraDataByIndex, "player", pIndex, "HELPFUL"); + + if vOK and type(vData) == "table" then + -- name lets the caller confirm the two APIs agree on this index + return vTexture, vData.spellId, vData.name; + end + + return vTexture, nil; + end + + return UnitBuff("player", pIndex), nil; +end + +-- Returns true/false when a client mod can answer, nil when unknown + +function Outfitter_ClientIsMounted() + if not OCM.HasIsMounted then + return nil; + end + + local vOK, vResult = pcall(IsMounted); + + if not vOK then + return nil; + end + + return vResult and vResult ~= 0 and true or false; +end + +function Outfitter_ClientIsSwimming() + if not OCM.HasIsSwimming then + return nil; + end + + local vOK, vResult = pcall(IsSwimming); + + if not vOK then + return nil; + end + + return vResult and vResult ~= 0 and true or false; +end + +-- Stable identity for a unit: GUID when available, otherwise name..level + +function Outfitter_GetUnitIdentity(pUnit) + if not UnitExists(pUnit) then + return nil; + end + + if OCM.ClassicAPI and type(UnitGUID) == "function" then + local vOK, vGUID = pcall(UnitGUID, pUnit); + + if vOK and vGUID then + return vGUID; + end + end + + if OCM.SuperWoW then + local vExists, vGUID = UnitExists(pUnit); + + if vGUID then + return vGUID; + end + end + + return (UnitName(pUnit) or "?") .. ":" .. (UnitLevel(pUnit) or 0); +end + +function Outfitter_ClientModsSummary() + if not OCM.Detected then + Outfitter_DetectClientMods(); + end + + local function YesNo(pValue) + if pValue then + return GREEN_FONT_COLOR_CODE .. "yes" .. FONT_COLOR_CODE_CLOSE; + end + return GRAY_FONT_COLOR_CODE .. "no" .. FONT_COLOR_CODE_CLOSE; + end + + DEFAULT_CHAT_FRAME:AddMessage(NORMAL_FONT_COLOR_CODE .. "Outfitter client mod support:" .. FONT_COLOR_CODE_CLOSE); + DEFAULT_CHAT_FRAME:AddMessage(" SuperWoW: " .. YesNo(OCM.SuperWoW) .. " ClassicAPI: " .. YesNo(OCM.ClassicAPI) + .. " Nampower: " .. YesNo(OCM.Nampower) .. " UnitXP SP3: " .. YesNo(OCM.UnitXP)); + DEFAULT_CHAT_FRAME:AddMessage(" Mount detection: " .. (OCM.HasIsMounted and "client flag" or "buff tooltip text")); + DEFAULT_CHAT_FRAME:AddMessage(" Swimming detection: " .. (OCM.HasIsSwimming and "client flag (surface + underwater)" or "breath timer (underwater only)")); + DEFAULT_CHAT_FRAME:AddMessage(" Buff tooltip scans: " .. (OCM.HasAuraSpellID and "cached per spell ID" or "every aura change")); + DEFAULT_CHAT_FRAME:AddMessage(" Target identity: " .. (OCM.HasGUID and "GUID" or "name + level")); +end diff --git a/OutfitterStrings.lua b/OutfitterStrings.lua new file mode 100644 index 0000000..afd9347 --- /dev/null +++ b/OutfitterStrings.lua @@ -0,0 +1,411 @@ +Outfitter_cVersion = "1.6.0"; + +Outfitter_cTitle = "Outfitter"; +Outfitter_cTitleVersion = Outfitter_cTitle .. " " .. Outfitter_cVersion; + +Outfitter_cNameLabel = "Name:"; +Outfitter_cCreateUsingTitle = "Optimize for:"; +Outfitter_cUseCurrentOutfit = "Use Current Outfit"; +Outfitter_cUseEmptyOutfit = "Create Empty Outfit"; + +Outfitter_cOutfitterTabTitle = "Outfitter"; +Outfitter_cOptionsTabTitle = "Options"; +Outfitter_cAboutTabTitle = "About"; + +Outfitter_cNewOutfit = "New Outfit"; +Outfitter_cRenameOutfit = "Rename Outfit"; + +Outfitter_cCompleteOutfits = "Complete wardrobes"; +Outfitter_cPartialOutfits = "Mix-n-match"; +Outfitter_cAccessoryOutfits = "Accessories"; +Outfitter_cSpecialOutfits = "Special occassions"; +Outfitter_cOddsNEndsOutfits = "Odds 'n ends"; + +Outfitter_cNormalOutfit = "Normal"; +Outfitter_cNakedOutfit = "Birthday Suit"; + +Outfitter_cFishingOutfit = "Fishing"; +Outfitter_cHerbalismOutfit = "Herbalism"; +Outfitter_cMiningOutfit = "Mining"; +Outfitter_cSkinningOutfit = "Skinning"; +Outfitter_cFireResistOutfit = "Fire Resist"; +Outfitter_cNatureResistOutfit = "Nature Resist"; +Outfitter_cShadowResistOutfit = "Shadow Resist"; +Outfitter_cArcaneResistOutfit = "Arcane Resist"; +Outfitter_cFrostResistOutfit = "Frost Resist"; + +Outfitter_cArgentDawnOutfit = "Argent Dawn"; +Outfitter_cRidingOutfit = "Riding"; +Outfitter_cDiningOutfit = "Dining"; +Outfitter_cBattlegroundOutfit = "Battleground"; +Outfitter_cABOutfit = "Battleground: Arathi Basin"; +Outfitter_cAVOutfit = "Battleground: Alterac Valley"; +Outfitter_cWSGOutfit = "Battleground: Warsong Gulch"; +Outfitter_cBROutfit = "Battleground: Blood Ring"; +Outfitter_cSGVOutfit = "Battleground: Sunnyglade Valley"; +Outfitter_cSwimmingOutfit = "Swimming"; +Outfitter_cDiscardedStripOutfit = "Outfitter: ignored a saved change that would have unequipped all your gear (left over from a crash or disconnect)"; +Outfitter_cCityOutfit = "Around Town"; +Outfitter_cBossOutfit = "Boss Mobs"; +Outfitter_cLvl63Outfit = "Lvl63+"; +Outfitter_cTrashOutfit = "Trash Mobs"; +Outfitter_cCritterOutfit = "Critters"; + +Outfitter_cBeastTrashOutfit = "Beast Trash Mobs"; +Outfitter_cUndeadTrashOutfit = "Undead Trash Mobs"; +Outfitter_cDemonTrashOutfit = "Demon Trash Mobs"; + +Outfitter_cMountSpeedFormat = "Increases speed by (%d+)%%."; -- For detecting when mounted + +Outfitter_cBagsFullError = "Outfitter: Can't remove %s because all bags are full"; +Outfitter_cDepositBagsFullError = "Outfitter: Can't deposit %s because all bank bags are full"; +Outfitter_cWithdrawBagsFullError = "Outfitter: Can't withdraw %s because all bags are full"; +Outfitter_cItemNotFoundError = "Outfitter: Can't find item %s"; +Outfitter_cItemAlreadyUsedError = "Outfitter: Can't put %s in the %s slot because it's already being used in another slot"; +Outfitter_cAddingItem = "Outfitter: Adding %s to %s outfit"; +Outfitter_cNameAlreadyUsedError = "Error: That name is already being used"; +Outfitter_cNoItemsWithStatError = "Warning: None of your items have that attribute"; + +Outfitter_cEnableAll = "Enable all"; +Outfitter_cEnableNone = "Enable none"; + +Outfitter_cConfirmDeleteMsg = "Are you sure you want to delete the outfit %s?"; +Outfitter_cConfirmUpdateMsg = "Are you sure you want to update the outfit %s to your current outfit?"; +Outfitter_cConfirmRebuildMsg = "Are you sure you want to rebuild the outfit %s?"; +Outfitter_cRebuild = "Rebuild"; +Outfitter_cUpdate = "Update"; +Outfitter_cUpdateToCurrent = "Update to current"; + +Outfitter_cWesternPlaguelands = "Western Plaguelands"; +Outfitter_cEasternPlaguelands = "Eastern Plaguelands"; +Outfitter_cStratholme = "Stratholme"; +Outfitter_cScholomance = "Scholomance"; +Outfitter_cNaxxramas = "Naxxramas"; +Outfitter_cAlteracValley = "Alterac Valley"; +Outfitter_cArathiBasin = "Arathi Basin"; +Outfitter_cWarsongGulch = "Warsong Gulch"; +Outfitter_cBloodRing = "Blood Ring"; +Outfitter_cSunnygladeValley = "Sunnyglade Valley"; +Outfitter_cIronforge = "Ironforge"; +Outfitter_cCityOfIronforge = "City of Ironforge"; +Outfitter_cDarnassus = "Darnassus"; +Outfitter_cStormwind = "Stormwind City"; +Outfitter_cOrgrimmar = "Orgrimmar"; +Outfitter_cThunderBluff = "Thunder Bluff"; +Outfitter_cUndercity = "Undercity"; + +--Instances +Outfitter_cAQ20 = "Ruins of Ahn'Qiraj"; +Outfitter_cAQ40 = "Ahn'Qiraj"; +Outfitter_cZG = "Zul'Gurub"; +Outfitter_cES = "Emerald Sanctum"; +Outfitter_cBM = "The Black Morass"; +Outfitter_cK40 = "The Rock of Desolation"; + +Outfitter_cFishingPole = "Fishing Pole"; +Outfitter_cStrongFishingPole = "Strong Fishing Pole"; +Outfitter_cDarkwoodFishingPole = "Darkwood Fishing Pole"; +Outfitter_cBigIronFishingPole = "Big Iron Fishing Pole"; +Outfitter_cBlumpFishingPole = "Blump Family Fishing Pole"; +Outfitter_cNatPaglesFishingPole = "Nat Pagle's Extreme Angler FC-5000"; +Outfitter_cArcaniteFishingPole = "Arcanite Fishing Pole"; +Outfitter_cBarkskinFisher = "Barkskin Fisher"; + +Outfitter_cArgentDawnCommission = "Argent Dawn Commission"; +Outfitter_cSealOfTheDawn = "Seal of the Dawn"; +Outfitter_cRuneOfTheDawn = "Rune of the Dawn"; + +Outfitter_cWhipOfEncouragement = "Whip of Encouragement"; +Outfitter_cGoblinCarKey = "Goblin Car Key"; +Outfitter_cGnomeCarKey = "Gnome Car Key"; +Outfitter_cCarrotOnAStick = "Carrot on a Stick"; + +Outfitter_cItemStatFormats = { + { Format = "Stamina %+(%d+)", Types = { "Stamina" } }, + { Format = "Intellect %+(%d+)", Types = { "Intellect" } }, + { Format = "Agility %+(%d+)", Types = { "Agility" } }, + { Format = "Strength %+(%d+)", Types = { "Strength" } }, + { Format = "Spirit %+(%d+)", Types = { "Spirit" } }, + { Format = "Armor %+(%d+)", Types = { "Armor" } }, + { Format = "Defense %+(%d+)", Types = { "Defense" } }, + { Format = "Increased Defense %+(%d+)", Types = { "Defense" } }, + + { Format = "%+(%d+) Stamina", Types = { "Stamina" } }, + { Format = "%+(%d+) Intellect", Types = { "Intellect" } }, + { Format = "%+(%d+) Agility", Types = { "Agility" } }, + { Format = "%+(%d+) Strength", Types = { "Strength" } }, + { Format = "%+(%d+) Spirit", Types = { "Spirit" } }, + { Format = "(%d+) Armor", Types = { "Armor" } }, + { Format = "%+(%d+) Attack Power", Types = { "Attack" } }, + + { Format = "All Stats %+(%d+)", Types = { "Stamina", "Intellect", "Agility", "Strength", "Spirit" } }, + + { Format = "Mana %+(%d+)", Types = { "Mana" } }, + { Format = "Health %+(%d+)", Types = { "Health" } }, + + { Format = "%+(%d+) mana every 5 sec.", Types = { "ManaRegen" } }, + { Format = "Restores (%d+) mana per 5 sec.", Types = { "ManaRegen" } }, + + { Format = "%+(%d+) health every 5 sec.", Types = { "HealthRegen" } }, + { Format = "Restores (%d+) health every 5 sec.", Types = { "HealthRegen" } }, + { Format = "Restores (%d+) health per 5 sec.", Types = { "HealthRegen" } }, + + { Format = "Minor Mount Speed Increase", Value = 3, Types = { "Riding" } }, + { Format = "Mithril Spurs", Value = 3, Types = { "Riding" } }, + { Format = "Thorium Spurs", Value = 5, Types = { "Riding" } }, + + { Format = "%+(%d+) Fire Resistance", Types = { "FireResist" } }, + { Format = "%+(%d+) Nature Resistance", Types = { "NatureResist" } }, + { Format = "%+(%d+) Frost Resistance", Types = { "FrostResist" } }, + { Format = "%+(%d+) Shadow Resistance", Types = { "ShadowResist" } }, + { Format = "%+(%d+) Arcane Resistance", Types = { "ArcaneResist" } }, + { Format = "%+(%d+) All Resistances", Types = { "FireResist", "NatureResist", "FrostResist", "ShadowResist", "ArcaneResist" } }, + + { Format = "Weapon Damage %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "Improves your chance to hit by (%d+)%%", Types = { "MeleeHit" } }, + { Format = "Improves your chance to get a critical strike by (%d+)%%", Types = { "MeleeCrit" } }, + { Format = "Increases your chance to dodge an attack by (%d+)%%", Types = { "Dodge" } }, + { Format = "Damage %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "(%d+) Block", Types = { "Block" } }, + { Format = "Block Value %+(%d+)", Types = { "Block" } }, + { Format = "Increases the block value of your shield by (%d+)", Types = { "Block" } }, + + { Format = "Increased Fishing %+(%d+)%.", Types = { "Fishing" } }, + { Format = "Fishing %+(%d+)", Types = { "Fishing" } }, + { Format = "Herbalism %+(%d+)", Types = { "Herbalism" } }, + { Format = "Mining %+(%d+)", Types = { "Mining" } }, + { Format = "Skinning %+(%d+)", Types = { "Skinning" } }, + + { Format = "Improves your chance to get a critical strike with spells by (%d+)%%", Types = { "SpellCrit" } }, + { Format = "Improves your chance to hit with spells by (%d+)%%", Types = { "SpellHit" } }, + { Format = "Increases damage and healing done by magical spells and effects by up to (%d+)", Types = { "SpellDmg", "ShadowDmg", "FireDmg", "FrostDmg", "ArcaneDmg", "NatureDmg", "Healing" } }, + { Format = "Increases healing done by spells and effects by up to (%d+)", Types = { "Healing" } }, + { Format = "Healing Spells %+(%d+)", Types = { "Healing" } }, + { Format = "%+(%d+) Healing Spells", Types = { "Healing" } }, + + { Format = "%+(%d+) Fire Spell Damage", Types = { "FireDmg" } }, + { Format = "%+(%d+) Shadow Spell Damage", Types = { "ShadowDmg" } }, + { Format = "%+(%d+) Frost Spell Damage", Types = { "FrostDmg" } }, + { Format = "%+(%d+) Arcane Spell Damage", Types = { "ArcaneDmg" } }, + { Format = "%+(%d+) Nature Spell Damage", Types = { "NatureDmg" } }, + + { Format = "Increases damage done by Fire spells and effects by up to (%d+)", Types = { "FireDmg" } }, + { Format = "Increases damage done by Shadow spells and effects by up to (%d+)", Types = { "ShadowDmg" } }, + { Format = "Increases damage done by Frost spells and effects by up to (%d+)", Types = { "FrostDmg" } }, + { Format = "Increases damage done by Arcane spells and effects by up to (%d+)", Types = { "ArcaneDmg" } }, + { Format = "Increases damage done by Nature spells and effects by up to (%d+)", Types = { "NatureDmg" } }, +}; + +Outfitter_cAgilityStatName = "Agility"; +Outfitter_cArmorStatName = "Armor"; +Outfitter_cDefenseStatName = "Defense"; +Outfitter_cIntellectStatName = "Intellect"; +Outfitter_cSpiritStatName = "Spirit"; +Outfitter_cStaminaStatName = "Stamina"; +Outfitter_cStrengthStatName = "Strength"; + +Outfitter_cManaRegenStatName = "Mana Regeneration"; +Outfitter_cHealthRegenStatName = "Health Regeneration"; + +Outfitter_cSpellCritStatName = "Spell Critical Strike"; +Outfitter_cSpellHitStatName = "Spell Chance to Hit"; +Outfitter_cSpellDmgStatName = "Spell Damage"; +Outfitter_cFrostDmgStatName = "Frost Spell Damage"; +Outfitter_cFireDmgStatName = "Fire Spell Damage"; +Outfitter_cArcaneDmgStatName = "Arcane Spell Damage"; +Outfitter_cShadowDmgStatName = "Shadow Spell Damage"; +Outfitter_cNatureDmgStatName = "Nature Spell Damage"; +Outfitter_cHealingStatName = "Healing"; + +Outfitter_cMeleeCritStatName = "Melee Critical Strike"; +Outfitter_cMeleeHitStatName = "Melee Chance to Hit"; +Outfitter_cMeleeDmgStatName = "Melee Damage"; +Outfitter_cAttackStatName = "Attack Power"; +Outfitter_cDodgeStatName = "Dodge"; + +Outfitter_cArcaneResistStatName = "Arcane Resistance"; +Outfitter_cFireResistStatName = "Fire Resistance"; +Outfitter_cFrostResistStatName = "Frost Resistance"; +Outfitter_cNatureResistStatName = "Nature Resistance"; +Outfitter_cShadowResistStatName = "Shadow Resistance"; + +Outfitter_cFishingStatName = "Fishing"; +Outfitter_cHerbalismStatName = "Herbalism"; +Outfitter_cMiningStatName = "Mining"; +Outfitter_cSkinningStatName = "Skinning"; + +Outfitter_cOptionsTitle = "Outfitter Options"; +Outfitter_cShowMinimapButton = "Show Minimap Button"; +Outfitter_cShowMinimapButtonOnDescription = "Turn this off if you don't want the Outfitter button on your minimap cluster"; +Outfitter_cShowMinimapButtonOffDescription = "Turn this on if you want the Outfitter button on your minimap cluster"; +Outfitter_cRememberVisibility = "Remember cloak and helm settings"; +Outfitter_cRememberVisibilityOnDescription = "Turn this off if you want to use a single show/hide setting for all cloaks and helms"; +Outfitter_cRememberVisibilityOffDescription = "Turn this on if you want Outfitter to remember your preference for showing or hiding each cloak and helm individually"; +Outfitter_cShowHotkeyMessages = "Show key binding outfit changes"; +Outfitter_cShowHotkeyMessagesOnDescription = "Turn this off if you don't want to see a message when you change outfits using a key binding"; +Outfitter_cShowHotkeyMessagesOffDescription = "Turn this on if you want to see a message when you change outfits using a key binding"; +Outfitter_cShowCurrentOutfit = "Display current outfit in small window"; +Outfitter_cHideDisabledOutfits = "Hide disabled outfits from list"; + +Outfitter_cEquipOutfitMessageFormat = "Outfitter: %s equipped"; +Outfitter_cUnequipOutfitMessageFormat = "Outfitter: %s unequipped"; + +Outfitter_cAboutTitle = "About Outfitter"; +Outfitter_cAuthor = "Designed and written by John Stephen\nUpdated for WoW 1.18.1 Clients by |cff5BCEFAL|cffF5A9B8e|cffFFFFFFx|cffF5A9B8i|cff5BCEFAe|r"; +Outfitter_cTestersTitle = "Beta Testers"; +Outfitter_cTestersNames = "Airmid, Desiree, Fizzlebang, Harper, Kallah and Sumitra"; +Outfitter_cSpecialThanksTitle = "Special thanks for their support to"; +Outfitter_cSpecialThanksNames = "Brian, Dave, Glenn, Leah, Mark, The Mighty Pol, SFC and Forge"; +Outfitter_cGuildURL = ""; +Outfitter_cGuildURL2 = ""; + +Outfitter_cOpenOutfitter = "Open Outfitter"; + +Outfitter_cArgentDawnOutfitDescription = "This outfit will automatically be worn whenever you're in the Plaguelands"; +Outfitter_cRidingOutfitDescription = "This outfit will automatically be worn whenever you're mounted"; +Outfitter_cDiningOutfitDescription = "This outfit will automatically be worn whenever you're eating or drinking"; +Outfitter_cBattlegroundOutfitDescription = "This outfit will automatically be worn whenever you're in a battleground"; +Outfitter_cArathiBasinOutfitDescription = "This outfit will automatically be worn whenever you're in the Arathi Basin battleground"; +Outfitter_cAlteracValleyOutfitDescription = "This outfit will automatically be worn whenever you're in the Alterac Valley battleground"; +Outfitter_cWarsongGulchOutfitDescription = "This outfit will automatically be worn whenever you're in the Warsong Gulch battleground"; +Outfitter_cBloodRingOutfitDescription = "This outfit will automatically be worn whenever you're in the Blood Ring battleground"; +Outfitter_cSunnygladeValleyOutfitDescription = "This outfit will automatically be worn whenever you're in the Sunnyglade Valley battleground"; +Outfitter_cCityOutfitDescription = "This outfit will automatically be worn whenever you're in a friendly major city"; +Outfitter_cBossOutfitDescription = "This outfit will automatically be worn whenever you target level 63+ Boss mobs"; +Outfitter_cLvl63OutfitDescription = "This outfit will automatically be worn whenever you target level 63+ mobs"; +Outfitter_cTrashOutfitDescription = "This outfit will automatically be worn whenever you target level <63 mobs"; +Outfitter_cCritterOutfitDescription = "This outfit will automatically be worn whenever you target a critter"; +Outfitter_cBeastTrashOutfitDescription = "This outfit will automatically be worn whenever you target beasts level <63 mobs"; +Outfitter_cUndeadTrashOutfitDescription = "This outfit will automatically be worn whenever you target undead level <63 mobs"; +Outfitter_cDemonTrashOutfitDescription = "This outfit will automatically be worn whenever you target demons level <63 mobs"; +Outfitter_cSwimmingOutfitDescription = "This outfit will automatically be worn whenever you're swimming (underwater only unless SuperWoW or ClassicAPI is installed)"; + +Outfitter_cKeyBinding = "Key Binding"; + +BINDING_HEADER_OUTFITTER_TITLE = Outfitter_cTitle; + +BINDING_NAME_OUTFITTER_OUTFIT1 = "Outfit 1"; +BINDING_NAME_OUTFITTER_OUTFIT2 = "Outfit 2"; +BINDING_NAME_OUTFITTER_OUTFIT3 = "Outfit 3"; +BINDING_NAME_OUTFITTER_OUTFIT4 = "Outfit 4"; +BINDING_NAME_OUTFITTER_OUTFIT5 = "Outfit 5"; +BINDING_NAME_OUTFITTER_OUTFIT6 = "Outfit 6"; +BINDING_NAME_OUTFITTER_OUTFIT7 = "Outfit 7"; +BINDING_NAME_OUTFITTER_OUTFIT8 = "Outfit 8"; +BINDING_NAME_OUTFITTER_OUTFIT9 = "Outfit 9"; +BINDING_NAME_OUTFITTER_OUTFIT10 = "Outfit 10"; + +Outfitter_cDisableOutfit = "Disable Outfit"; +Outfitter_cDisableOutfitInBG = "Disable Outfit When in Battlegrounds"; +Outfitter_cDisableOutfitInInstance = "Disable Outfit When in Instances"; +Outfitter_cDisabledOutfitName = "%s (Disabled)"; + +Outfitter_cMinimapButtonTitle = "Outfitter Minimap Button"; +Outfitter_cMinimapButtonDescription = "Click to select a different outfit or drag to re-position this button."; + +Outfitter_cDruidClassName = "Druid"; +Outfitter_cHunterClassName = "Hunter"; +Outfitter_cMageClassName = "Mage"; +Outfitter_cPaladinClassName = "Paladin"; +Outfitter_cPriestClassName = "Priest"; +Outfitter_cRogueClassName = "Rogue"; +Outfitter_cShamanClassName = "Shaman"; +Outfitter_cWarlockClassName = "Warlock"; +Outfitter_cWarriorClassName = "Warrior"; + +Outfitter_cBattleStance = "Battle Stance"; +Outfitter_cDefensiveStance = "Defensive Stance"; +Outfitter_cBerserkerStance = "Berserker Stance"; + +Outfitter_cWarriorBattleStance = "Warrior: Battle Stance"; +Outfitter_cWarriorDefensiveStance = "Warrior: Defensive Stance"; +Outfitter_cWarriorBerserkerStance = "Warrior: Berserker Stance"; + +Outfitter_cBearForm = "Bear Form"; +Outfitter_cCatForm = "Cat Form"; +Outfitter_cAquaticForm = "Aquatic Form"; +Outfitter_cTravelForm = "Travel Form"; +Outfitter_cDireBearForm = "Dire Bear Form"; +Outfitter_cMoonkinForm = "Moonkin Form"; + +Outfitter_cGhostWolfForm = "Ghost Wolf"; + +Outfitter_cStealth = "Stealth"; + +Outfitter_cDruidBearForm = "Druid: Bear Form"; +Outfitter_cDruidCatForm = "Druid: Cat Form"; +Outfitter_cDruidAquaticForm = "Druid: Aquatic Form"; +Outfitter_cDruidTravelForm = "Druid: Travel Form"; +Outfitter_cDruidMoonkinForm = "Druid: Moonkin Form"; + +Outfitter_cPriestShadowform = "Priest: Shadowform"; + +Outfitter_cRogueStealth = "Rogue: Stealth"; + +Outfitter_cShamanGhostWolf = "Shaman: Ghost Wolf"; + +Outfitter_cHunterMonkey = "Hunter: Monkey"; +Outfitter_cHunterHawk = "Hunter: Hawk"; +Outfitter_cHunterCheetah = "Hunter: Cheetah"; +Outfitter_cHunterPack = "Hunter: Pack"; +Outfitter_cHunterBeast = "Hunter: Beast"; +Outfitter_cHunterWild = "Hunter: Wild"; + +Outfitter_cMageEvocate = "Mage: Evocate"; + +Outfitter_cAspectOfTheCheetah = "Aspect of the Cheetah"; +Outfitter_cAspectOfThePack = "Aspect of the Pack"; +Outfitter_cAspectOfTheBeast = "Aspect of the Beast"; +Outfitter_cAspectOfTheWild = "Aspect of the Wild"; +Outfitter_cEvocate = "Evocation"; + +Outfitter_cCritter = "Critter"; +Outfitter_cCreatureBeast = "Beast"; +Outfitter_cCreatureUndead = "Undead"; +Outfitter_cCreatureDemon = "Demon"; + +Outfitter_cCompleteCategoryDescripton = "Complete outfits have items specified for every slot and will replace all other outfits when worn."; +Outfitter_cPartialCategoryDescription = "Mix-n-match outfits have only some slots specified, but not all. When equipped, they are added on top of your selcted Complete outfit, replacing any other Mix-n-match or Accessory outfits selected."; +Outfitter_cAccessoryCategoryDescription = "Accessory outfits have only some slots specified, but not all. Unlike mix-n-match, you can select as many Accessory outfits as you like and they will all be combined together and worn on top of your selected Complete and Mix-n-match outfits."; +Outfitter_cSpecialCategoryDescription = "Special Occassion outfits are automatically worn whenever the occassion warrants it. They are worn over all other selected outfits."; +Outfitter_cOddsNEndsCategoryDescription = "Odds 'n ends is a list of items which you haven't used in any of your outfits. This may be useful in ensuring that you're using all of your items or that you're not carrying around excess baggage."; + +Outfitter_cRebuildOutfitFormat = "Rebuild for %s"; + +Outfitter_cTranslationCredit = " "; + +Outfitter_cSlotEnableTitle = "Slot Enable"; +Outfitter_cSlotEnableDescription = "Select this if you want the item in this slot to be equipped when changing to the selected outfit. If not selected then this slot will not be modified when changing to the selected outfit."; + +Outfitter_cFinger0SlotName = "First Finger"; +Outfitter_cFinger1SlotName = "Second Finger"; + +Outfitter_cTrinket0SlotName = "First Trinket"; +Outfitter_cTrinket1SlotName = "Second Trinket"; + +Outfitter_cOutfitCategoryTitle = "Category"; +Outfitter_cBankCategoryTitle = "Bank"; +Outfitter_cDepositToBank = "Deposit all items to bank"; +Outfitter_cDepositUniqueToBank = "Deposit unique items to bank"; +Outfitter_cWithdrawFromBank = "Withdraw items from bank"; + +Outfitter_cMissingItemsLabel = "Missing items: "; +Outfitter_cBankedItemsLabel = "Banked items: "; + +Outfitter_cRepairAllBags = "Outfitter: Repair All Bagged Items"; + +Outfitter_cStatsCategory = "Stats"; +Outfitter_cMeleeCategory = "Melee"; +Outfitter_cSpellsCategory = "Healing and Spells"; +Outfitter_cRegenCategory = "Regeneration"; +Outfitter_cResistCategory = "Resistances"; +Outfitter_cTradeCategory = "Trade Skills"; + +Outfitter_cTankPoints = "TankPoints"; +Outfitter_cCustom = "Custom"; + +Outfitter_cRequiresHerbalism = "Requires Herbalism"; +Outfitter_cRequiresSkinning = "Requires Skinning"; +Outfitter_cRequiresMining = "Requires Mining"; +Outfitter_cAutoEquip = "Auto equip"; +Outfitter_cAutoUnEquip = "Auto unequip"; \ No newline at end of file diff --git a/OutfitterStrings_cn.lua b/OutfitterStrings_cn.lua new file mode 100644 index 0000000..e69de29 diff --git a/OutfitterStrings_de.lua b/OutfitterStrings_de.lua new file mode 100644 index 0000000..69cf689 --- /dev/null +++ b/OutfitterStrings_de.lua @@ -0,0 +1,339 @@ +if GetLocale() == "deDE" then + Outfitter_cTitle = "Outfitter"; + Outfitter_cTitleVersion = Outfitter_cTitle .. " " .. Outfitter_cVersion; + + Outfitter_cNameLabel = "Name:"; + Outfitter_cCreateUsingTitle = "Optimieren f\195\188r:"; + Outfitter_cUseCurrentOutfit = "Benutze derzeitiges Outfit"; + Outfitter_cUseEmptyOutfit = "Erstelle neues Outfit"; + + Outfitter_cOutfitterTabTitle = "Outfitter"; + Outfitter_cOptionsTabTitle = "Einstellungen"; + Outfitter_cAboutTabTitle = "\195\188ber"; + + Outfitter_cNewOutfit = "Neues Outfit"; + Outfitter_cRenameOutfit = "Outfit umbenennen"; + + Outfitter_cCompleteOutfits = "Vollst\195\164ndige Ausr\195\188stungen"; + Outfitter_cPartialOutfits = "Mix-n-match"; + Outfitter_cAccessoryOutfits = "Zusatzgegenst\195\164nde"; + Outfitter_cSpecialOutfits = "Besondere Gelegenheiten"; + + Outfitter_cNormalOutfit = "Normal"; + Outfitter_cNakedOutfit = "Ausgehroben"; + + Outfitter_cFishingOutfit = "Angeln"; + Outfitter_cHerbalismOutfit = "Kr\195\164uterkunde"; + Outfitter_cMiningOutfit = "Bergbau"; + Outfitter_cSkinningOutfit = "K\195\188rschnerei"; + Outfitter_cFireResistOutfit = "Feuerwiderstand"; + Outfitter_cNatureResistOutfit = "Naturwiderstand"; + Outfitter_cShadowResistOutfit = "Schattenwiderstand"; + Outfitter_cArcaneResistOutfit = "Arkanwiderstand"; + Outfitter_cFrostResistOutfit = "Frostwiderstand"; + + Outfitter_cArgentDawnOutfit = "Argentumd\195\164mmerung"; + Outfitter_cRidingOutfit = "Reiten"; + Outfitter_cDiningOutfit = "Ausruhen"; + Outfitter_cBattlegroundOutfit = "Schlachtfeld"; + Outfitter_cBossOutfit = "Boss Mobs"; + Outfitter_cLvl63Outfit = "Lvl63+"; + Outfitter_cTrashOutfit = "Trash Mobs"; + Outfitter_cBeastTrashOutfit = "Beast Trash Mobs"; + Outfitter_cUndeadTrashOutfit = "Undead Trash Mobs"; + Outfitter_cDemonTrashOutfit = "Demon Trash Mobs"; + + Outfitter_cABOutfit = "Schlachtfeld: Arathibecken"; + Outfitter_cAVOutfit = "Schlachtfeld: Alteractal"; + Outfitter_cWSGOutfit = "Schlachtfeld: Warsongschlucht"; + Outfitter_cCityOutfit = "Stadt"; + + Outfitter_cMountSpeedFormat = "Erh\195\182ht Tempo um (%d+)%%."; -- For detecting when mounted + + Outfitter_cBagsFullError = "Outfitter: %s kann nicht enfernt werden da alle Taschen voll sind."; + Outfitter_cItemNotFoundError = "Outfitter: Kann %s nicht finden."; + Outfitter_cAddingItem = "Outfitter: F\195\188ge %s zum %s Outfit."; + Outfitter_cNameAlreadyUsedError = "Fehler: Dieser Name ist bereits vergeben."; + Outfitter_cNoItemsWithStatError = "Warnung: Keines deiner Gegenst\195\164nde hat dieses Attribut."; + + Outfitter_cEnableAll = "Alle aktivieren"; + Outfitter_cEnableNone = "Alle deaktivieren"; + + Outfitter_cConfirmDeleteMsg = "Bist du sicher dass du das %s Outfit l\195\182schen willst?"; + Outfitter_cConfirmRebuildMsg = "Bist du sicher dass du das %s Outfit ver\195\164ndern willst?"; + Outfitter_cRebuild = "Ver\195\164ndern"; + + Outfitter_cWesternPlaguelands = "Westliche Pestl\195\164nder"; + Outfitter_cEasternPlaguelands = "\195\150stliche Pestl\195\164nder"; + Outfitter_cStratholme = "Stratholme"; + Outfitter_cScholomance = "Scholomance"; + Outfitter_cNaxxramas = "Naxxramas"; + Outfitter_cAlteracValley = "Alteractal"; + Outfitter_cArathiBasin = "Arathibecken"; + Outfitter_cWarsongGulch = "Warsongschlucht"; + Outfitter_cIronforge = "Ironforge"; + Outfitter_cDarnassus = "Darnassus"; + Outfitter_cStormwind = "Stormwind"; + Outfitter_cOrgrimmar = "Orgrimmar"; + Outfitter_cThunderBluff = "Thunder Bluff"; + Outfitter_cUndercity = "Undercity"; + + Outfitter_cFishingPole = "Angel"; + Outfitter_cStrongFishingPole = "Starke Angel"; + Outfitter_cBigIronFishingPole = "Gro\195\159e Eisenangel"; + Outfitter_cBlumpFishingPole = "Angel der Familie Blump"; + Outfitter_cNatPaglesFishingPole = "Nat Pagles Extremangler FC-5000"; + Outfitter_cArcaniteFishingPole = "Arkanitangel"; + + Outfitter_cArgentDawnCommission = "Anstecknadel der Argentumd\195\164mmerung"; + Outfitter_cSealOfTheDawn = "Siegel der D\195\164mmerung"; + Outfitter_cRuneOfTheDawn = "Rune der D\195\164mmerung"; + + Outfitter_cCarrotOnAStick = "Karotte am Stiel"; + + Outfitter_cItemStatFormats = { + { Format = "Ausdauer %+(%d+)", Types = { "Stamina" } }, + { Format = "Intelligenz %+(%d+)", Types = { "Intellect" } }, + { Format = "Beweglichkeit %+(%d+)", Types = { "Agility" } }, + { Format = "St\195\164rke %+(%d+)", Types = { "Strength" } }, + { Format = "Willenskraft %+(%d+)", Types = { "Spirit" } }, + { Format = "R\195\188stung %+(%d+)", Types = { "Armor" } }, + { Format = "Verteidigung %+(%d+)", Types = { "Defense" } }, + { Format = "Anlegen: Verteidigung %+(%d+)", Types = { "Defense" } }, + + { Format = "%+(%d+) Ausdauer", Types = { "Stamina" } }, + { Format = "%+(%d+) Intelligenz", Types = { "Intellect" } }, + { Format = "%+(%d+) Beweglichkeit", Types = { "Agility" } }, + { Format = "%+(%d+) St\195\164rke", Types = { "Strength" } }, + { Format = "%+(%d+) Willenskraft", Types = { "Spirit" } }, + { Format = "(%d+) R\195\188stung", Types = { "Armor" } }, + { Format = "%+(%d+) Angriffskraft", Types = { "Attack" } }, + + { Format = "Mana %+(%d+)", Types = { "Mana" } }, + { Format = "Gesundheit %+(%d+)", Types = { "Health" } }, + + { Format = "%+(%d+) Mana alle 5 Sek.", Types = { "ManaRegen" } }, + { Format = "Stellt alle 5 Sek. (%d+) Punkt(e) Mana wieder her.", Types = { "ManaRegen" } }, + + { Format = "%+(%d+) Gesundheit alle 5 Sek.", Types = { "HealthRegen" } }, + { Format = "Stellt alle 5 Sek. (%d+) Punkt(e) Gesundheit wieder her.", Types = { "HealthRegen" } }, + + { Format = "Schwache Reittemposteigerung", Value = 3, Types = { "Riding" } }, + { Format = "Mithrilsporen", Value = 3, Types = { "Riding" } }, + + { Format = "%+(%d+) Feuerwiderstand", Types = { "FireResist" } }, + { Format = "%+(%d+) Naturwiderstand", Types = { "NatureResist" } }, + { Format = "%+(%d+) Frostwiderstand", Types = { "FrostResist" } }, + { Format = "%+(%d+) Schattenwiderstand", Types = { "ShadowResist" } }, + { Format = "%+(%d+) Arkanwiderstand", Types = { "ArcaneResist" } }, + { Format = "%+(%d+) Alle Widerst\195\164nde", Types = { "FireResist", "NatureResist", "FrostResist", "ShadowResist", "ArcaneResist" } }, + + { Format = "Waffenschaden %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "Erh\195\182ht Eure Trefferchance um (%d+)%%", Types = { "MeleeHit" } }, + { Format = "Erh\195\182ht Eure Chance, einen kritischen Schlag zu erzielen, um (%d+)%%", Types = { "MeleeCrit" } }, + { Format = "Erh\195\182ht Eure Chance, einem Angriff auszuweichen, um (%d+)%%", Types = { "Dodge" } }, + { Format = "Schaden %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "(%d+) Blocken", Types = { "BlockAmount" } }, + + { Format = "Erh\195\182ht Angeln um %+(%d+)%.", Types = { "Fishing" } }, + { Format = "Angeln %+(%d+)", Types = { "Fishing" } }, + { Format = "Kr\195\164uterkunde %+(%d+)", Types = { "Herbalism" } }, + { Format = "Bergbau %+(%d+)", Types = { "Mining" } }, + { Format = "K\195\188rschnerei %+(%d+)", Types = { "Skinning" } }, + + { Format = "Erh\195\182ht Eure Chance, einen kritischen Treffer durch Zauber zu erzielen, um (%d+)%%", Types = { "SpellCrit" } }, + { Format = "Improves your chance to hit with spells by (%d+)%%", Types = { "SpellHit" } }, + { Format = "Erh\195\182ht durch Zauber und magische Effekte zugef\195\188gten Schaden und Heilung um bis zu (%d+)", Types = { "SpellDmg", "ShadowDmg", "FireDmg", "FrostDmg", "ArcaneDmg", "NatureDmg", "Healing" } }, + { Format = "Erh\195\182ht durch Zauber und Effekte verursachte Heilung um bis zu (%d+)", Types = { "Healing" } }, + { Format = "Heilzauber %+(%d+)", Types = { "Healing" } }, + { Format = "%+(%d+) Heilzauber", Types = { "Healing" } }, + + { Format = "%+(%d+) Feuerzauberschaden", Types = { "FireDmg" } }, + { Format = "%+(%d+) Schattenzauberschaden", Types = { "ShadowDmg" } }, + { Format = "%+(%d+) Frostzauberschaden", Types = { "FrostDmg" } }, + { Format = "%+(%d+) Arkanzauberschaden", Types = { "ArcaneDmg" } }, + { Format = "%+(%d+) Naturzauberschaden", Types = { "NatureDmg" } }, + + { Format = "Increases damage done by Fire spells and effects by up to (%d+)", Types = { "FireDmg" } }, + { Format = "Increases damage done by Shadow spells and effects by up to (%d+)", Types = { "ShadowDmg" } }, + { Format = "Increases damage done by Frost spells and effects by up to (%d+)", Types = { "FrostDmg" } }, + { Format = "Increases damage done by Arcane spells and effects by up to (%d+)", Types = { "ArcaneDmg" } }, + { Format = "Increases damage done by Nature spells and effects by up to (%d+)", Types = { "NatureDmg" } }, + }; + + Outfitter_cAgilityStatName = "Beweglichkeit"; + Outfitter_cArmorStatName = "R\195\188stung"; + Outfitter_cDefenseStatName = "Verteidigung"; + Outfitter_cIntellectStatName = "Intelligenz"; + Outfitter_cSpiritStatName = "Willenskraft"; + Outfitter_cStaminaStatName = "Ausdauer"; + Outfitter_cStrengthStatName = "St\195\164rke"; + + Outfitter_cManaRegenStatName = "Manaregeneration"; + Outfitter_cHealthRegenStatName = "Gesundheitsregeneration"; + + Outfitter_cSpellCritStatName = "Zauberkritisch"; + Outfitter_cSpellHitStatName = "Spell Chance to Hit"; + Outfitter_cSpellDmgStatName = "Zauberschaden"; + Outfitter_cFrostDmgStatName = "Frostzauberschaden"; + Outfitter_cFireDmgStatName = "Feuerzauberschaden"; + Outfitter_cArcaneDmgStatName = "Arkanzauberschaden"; + Outfitter_cShadowDmgStatName = "Schattenzauberschaden"; + Outfitter_cNatureDmgStatName = "Naturzauberschaden"; + Outfitter_cHealingStatName = "Heilung"; + + Outfitter_cMeleeCritStatName = "Kampfkritisch"; + Outfitter_cMeleeHitStatName = "Kampftrefferchance"; + Outfitter_cMeleeDmgStatName = "Kampfschaden"; + Outfitter_cAttackStatName = "Angriffskraft"; + Outfitter_cDodgeStatName = "Ausweichen"; + + Outfitter_cArcaneResistStatName = "Arkanwiderstand"; + Outfitter_cFireResistStatName = "Feuerwiderstand"; + Outfitter_cFrostResistStatName = "Frostwiderstand"; + Outfitter_cNatureResistStatName = "Naturwiderstand"; + Outfitter_cShadowResistStatName = "Schattenwiderstand"; + + Outfitter_cFishingStatName = "Angeln"; + Outfitter_cHerbalismStatName = "Kr\195\164uterkunde"; + Outfitter_cMiningStatName = "Bergbau"; + Outfitter_cSkinningStatName = "K\195\188rschnerei"; + + Outfitter_cOptionsTitle = "Outfitter Einstellungen"; + Outfitter_cShowMinimapButton = "Zeige Minimapbutton"; + Outfitter_cShowMinimapButtonOnDescription = "Deaktivieren, um den Minimapbutton von Outfitter zu verstecken."; + Outfitter_cShowMinimapButtonOffDescription = "Aktivieren, um den Minimapbutton von Outfitter zu zeigen."; + Outfitter_cRememberVisibility = "Remember cloak and helm settings"; + Outfitter_cRememberVisibilityOnDescription = "Turn this off if you want to use a single show/hide setting for all cloaks and helms"; + Outfitter_cRememberVisibilityOffDescription = "Turn this on if you want Outfitter to remember your preference for showing or hiding each cloak and helm individually"; + + Outfitter_cAboutTitle = "\195\188ber Outfitter"; + Outfitter_cAuthor = "Gestaltet und geschrieben von John Stephen"; + Outfitter_cTestersTitle = "Beta Tester"; + Outfitter_cTestersNames = "Airmid, Desiree, Fizzlebang, Harper, Kallah und Sumitra"; + Outfitter_cSpecialThanksTitle = "Besonderen Dank f\195\188r ihre Unterst\195\188tzung geht an"; + Outfitter_cSpecialThanksNames = "Brian, Dave, Glenn, Leah, Mark, The Mighty Pol, SFC und Forge"; + Outfitter_cGuildURL = "http://www.starfleetclan.com"; + Outfitter_cGuildURL2 = "http://www.forgeguild.com"; + + Outfitter_cOpenOutfitter = "Outfitter \195\182ffnen"; + + Outfitter_cArgentDawnOutfitDescription = "Dieses Outfit wird automatisch beim Betreten der Pestl\195\164nder angelegt."; + Outfitter_cRidingOutfitDescription = "Dieses Outfit wird automatisch beim Reiten angelegt."; + Outfitter_cDiningOutfitDescription = "Dieses Outfit wird automatisch beim Essen und/oder Trinken angelegt."; + Outfitter_cBattlegroundOutfitDescription = "Dieses Outfit wird automatisch beim Betreten eines Schlachtfeldes angelegt."; + Outfitter_cArathiBasinOutfitDescription = "This outfit will automatically be worn whenever you're in the Arathi Basin battleground"; + Outfitter_cAlteracValleyOutfitDescription = "This outfit will automatically be worn whenever you're in the Alterac Valley battleground"; + Outfitter_cWarsongGulchOutfitDescription = "This outfit will automatically be worn whenever you're in the Warsong Gulch battleground"; + Outfitter_cCityOutfitDescription = "This outfit will automatically be worn whenever you're in a friendly major city"; + Outfitter_cBossOutfitDescription = "This outfit will automatically be worn whenever you target level 63+ Boss mobs"; + Outfitter_cLvl63OutfitDescription = "This outfit will automatically be worn whenever you target level 63+ mobs"; + Outfitter_cTrashOutfitDescription = "This outfit will automatically be worn whenever you target level <63 mobs"; + Outfitter_cBeastTrashOutfitDescription = "This outfit will automatically be worn whenever you target beasts level <63 mobs"; + Outfitter_cUndeadTrashOutfitDescription = "This outfit will automatically be worn whenever you target undead level <63 mobs"; + Outfitter_cDemonTrashOutfitDescription = "This outfit will automatically be worn whenever you target demons level <63 mobs"; + + Outfitter_cKeyBinding = "Tastaturbelegung"; + + BINDING_HEADER_OUTFITTER_TITLE = Outfitter_cTitle; + + BINDING_NAME_OUTFITTER_OUTFIT1 = "Outfit 1"; + BINDING_NAME_OUTFITTER_OUTFIT2 = "Outfit 2"; + BINDING_NAME_OUTFITTER_OUTFIT3 = "Outfit 3"; + BINDING_NAME_OUTFITTER_OUTFIT4 = "Outfit 4"; + BINDING_NAME_OUTFITTER_OUTFIT5 = "Outfit 5"; + BINDING_NAME_OUTFITTER_OUTFIT6 = "Outfit 6"; + BINDING_NAME_OUTFITTER_OUTFIT7 = "Outfit 7"; + BINDING_NAME_OUTFITTER_OUTFIT8 = "Outfit 8"; + BINDING_NAME_OUTFITTER_OUTFIT9 = "Outfit 9"; + BINDING_NAME_OUTFITTER_OUTFIT10 = "Outfit 10"; + + Outfitter_cDisableOutfit = "Outfit abschalten"; + Outfitter_cDisableOutfitInBG = "Outfit beim Betreten eines Schlachtfeldes abschalten."; + Outfitter_cDisabledOutfitName = "%s (Abgeschalten)"; + + Outfitter_cMinimapButtonTitle = "Outfitter Minimapbutton"; + Outfitter_cMinimapButtonDescription = "Klicken f\195\188r eine Auswahl an Outfits oder gedr\195\188ckthalten zum bewegen des Buttons."; + + Outfitter_cDruidClassName = "Druide"; + Outfitter_cHunterClassName = "J\195\164ger"; + Outfitter_cMageClassName = "Magier"; + Outfitter_cPaladinClassName = "Paladin"; + Outfitter_cPriestClassName = "Priester"; + Outfitter_cRogueClassName = "Schurke"; + Outfitter_cShamanClassName = "Schamane"; + Outfitter_cWarlockClassName = "Hexenmeister"; + Outfitter_cWarriorClassName = "Krieger"; + + Outfitter_cBattleStance = "Kampfhaltung"; + Outfitter_cDefensiveStance = "Verteidigungshaltung"; + Outfitter_cBerserkerStance = "Berserkerhaltung"; + + Outfitter_cWarriorBattleStance = "Krieger: Kampfhaltung"; + Outfitter_cWarriorDefensiveStance = "Krieger: Verteidigungshaltung"; + Outfitter_cWarriorBerserkerStance = "Krieger: Berserkerhaltung"; + + Outfitter_cBearForm = "B\195\164rengestalt"; + Outfitter_cCatForm = "Katzengestalt"; + Outfitter_cAquaticForm = "Wassergestalt"; + Outfitter_cTravelForm = "Reisegestalt"; + Outfitter_cDireBearForm = "Terrorb\195\164rengestalt"; + Outfitter_cMoonkinForm = "Moonkin Form"; + + Outfitter_cGhostWolfForm = "Geisterwolf"; + + Outfitter_cStealth = "Verstohlenheit"; + + Outfitter_cDruidBearForm = "Druide: B\195\164rengestalt"; + Outfitter_cDruidCatForm = "Druide: Katzengestalt"; + Outfitter_cDruidAquaticForm = "Druide: Wassergestalt"; + Outfitter_cDruidTravelForm = "Druide: Reisegestalt"; + Outfitter_cDruidMoonkinForm = "Druide: Moonkin Form"; + + Outfitter_cPriestShadowform = "Priester: Schattengestalt"; + + Outfitter_cRogueStealth = "Schurke: Verstohlenheit"; + + Outfitter_cShamanGhostWolf = "Schamane: Geisterwolf"; + + Outfitter_cCompleteCategoryDescripton = "Vollst\195\164ndige Outfits haben f\195\188r jeden Inventarslot festgelegte Gegenst\195\164nde, die alles andere ersetzen wenn sie getragen werden."; + Outfitter_cPartialCategoryDescription = "Bei Mix-n-match Outfits sind nur einige Gegenst\195\164nde festgelegt, jedoch nicht alle. Werden diese Outfits ausgew\195\164hlt bleibt das vorherige Outfit erhalten, nur die neuen Gegenst\195\164nde werden ge\195\164ndert."; + Outfitter_cAccessoryCategoryDescription = "Zusatzgegenst\195\164nde-Outfits haben nur einige festgelegte Inventarslots. Anders als beim Mix-n-match kannst du so viele Zusatzgegenst\195\164nde-Outfits erstellen und tragen, sie werden alle miteinander verbunden und \195\188ber bestehenden Outfits getragen."; + Outfitter_cSpecialCategoryDescription = "Besondere Gelegenheit-Outfits werden automatisch angelegt wenn die Situation es verlangt. Sie werden \195\188ber allen anderen Outfits getragen."; + Outfitter_cOddsNEndsCategoryDescription = "Odds 'n ends ist eine Auflistung der Gegenst\195\164nde, die keinem Outfit zugewiesen sind. Mit dieser Funktion kannst du sicherstellen, dass alle Gegenst\195\164nde ihren Platz haben oder dass du keine unn\195\182tigen Gegenst\195\164nde mit dir herumtr\195\164gst."; + + Outfitter_cRebuildOutfitFormat = "%s ge\195\164ndert."; + + Outfitter_cTranslationCredit = "Deutsche \195\156bersetzung: Ani"; + + Outfitter_cSlotEnableTitle = "Slot aktivieren"; + Outfitter_cSlotEnableDescription = "Aktiviere diese Option, damit der Gegenstand in diesem Slot automatisch angelegt wird wenn du zu diesem Outfit wechselst. Ist dieser Slot nicht aktiviert, wird er beim Anlegen eines anderen Outfits nicht ver\195\164ndert."; + + Outfitter_cFinger0SlotName = "Erster Finger"; + Outfitter_cFinger1SlotName = "Zweiter Finger"; + + Outfitter_cTrinket0SlotName = "Erstes Schmuckst\195\188ck"; + Outfitter_cTrinket1SlotName = "Zweites Schmuckst\195\188ck"; + + Outfitter_cOutfitCategoryTitle = "Kategorie"; + Outfitter_cBankCategoryTitle = "Bank"; + Outfitter_cDepositToBank = "Gegenst\195\164nde im Bankfach ablegen"; + Outfitter_cDepositUniqueToBank = "Deposit unique items to bank"; + Outfitter_cWithdrawFromBank = "Gegenst\195\164nde vom Bankfach aufnehmen"; + + Outfitter_cMissingItemsLabel = "Fehlende Gegenst\195\164nde: "; + Outfitter_cBankedItemsLabel = "Gegenst\195\164nde auf der Bank: "; + + Outfitter_cStatsCategory = "Stats"; + Outfitter_cMeleeCategory = "Melee"; + Outfitter_cSpellsCategory = "Healing and Spells"; + Outfitter_cRegenCategory = "Regeneration"; + Outfitter_cResistCategory = "Resistances"; + Outfitter_cTradeCategory = "Trade Skills"; + + Outfitter_cCritter = "Kleintier"; + Outfitter_cCreatureBeast = "Wildtier"; + Outfitter_cCreatureUndead = "Untoter"; + Outfitter_cCreatureDemon = "Dämon"; + Outfitter_cSwimmingOutfit = "Schwimmen"; +end diff --git a/OutfitterStrings_fr.lua b/OutfitterStrings_fr.lua new file mode 100644 index 0000000..056d1aa --- /dev/null +++ b/OutfitterStrings_fr.lua @@ -0,0 +1,349 @@ +if GetLocale() == "frFR" then + Outfitter_cTitle = "Outfitter"; + Outfitter_cTitleVersion = Outfitter_cTitle .. " " .. Outfitter_cVersion; + + Outfitter_cNameLabel = "Nom:"; + Outfitter_cCreateUsingTitle = "Optimiser pour:"; + Outfitter_cUseCurrentOutfit = "Utiliser la tenue actuelle"; + Outfitter_cUseEmptyOutfit = "Cr\195\169er une tenue vide"; + + Outfitter_cOutfitterTabTitle = "Outfitter"; + Outfitter_cOptionsTabTitle = "Options"; + Outfitter_cAboutTabTitle = "A propos"; + + Outfitter_cNewOutfit = "Nouvelle tenue"; + Outfitter_cRenameOutfit = "Renommer la tenue"; + + Outfitter_cCompleteOutfits = "Tenues compl\195\168tes"; + Outfitter_cPartialOutfits = "Mix-n-match"; + Outfitter_cAccessoryOutfits = "Accessoires"; + Outfitter_cSpecialOutfits = "Occasions sp\195\169ciales"; + Outfitter_cOddsNEndsOutfits = "Odds \226\128\153n ends"; + + Outfitter_cNormalOutfit = "Normale"; + Outfitter_cNakedOutfit = "Nu(e)"; + + Outfitter_cFishingOutfit = "P\195\170che"; + Outfitter_cHerbalismOutfit = "Herborisme"; + Outfitter_cMiningOutfit = "Minage"; + Outfitter_cSkinningOutfit = "D\195\169pecage"; + Outfitter_cFireResistOutfit = "R\195\169sistance au feu"; + Outfitter_cNatureResistOutfit = "R\195\169sistance \195\160 la nature"; + Outfitter_cShadowResistOutfit = "R\195\169sistance \195\160 l\226\128\153ombre"; + Outfitter_cArcaneResistOutfit = "R\195\169sistance aux arcanes"; + Outfitter_cFrostResistOutfit = "R\195\169sistance au givre"; + + Outfitter_cArgentDawnOutfit = "L\226\128\153aube d\226\128\153argent"; + Outfitter_cRidingOutfit = "Monture"; + Outfitter_cDiningOutfit = "Diner"; + Outfitter_cBattlegroundOutfit = "Champs de Bataille"; + Outfitter_cABOutfit = "Battleground: Arathi Basin"; + Outfitter_cAVOutfit = "Battleground: Alterac Valley"; + Outfitter_cWSGOutfit = "Battleground: Warsong Gulch"; + Outfitter_cCityOutfit = "Around Town"; + Outfitter_cBossOutfit = "Boss Mobs"; + Outfitter_cLvl63Outfit = "Lvl63+"; + Outfitter_cTrashOutfit = "Trash Mobs"; + Outfitter_cBeastTrashOutfit = "Beast Trash Mobs"; + Outfitter_cUndeadTrashOutfit = "Undead Trash Mobs"; + Outfitter_cDemonTrashOutfit = "Demon Trash Mobs"; + + Outfitter_cMountSpeedFormat = "Augmente la vitesse de (%d+)%%."; -- For detecting when mounted + + Outfitter_cBagsFullError = "Outfitter: Impossible d\226\128\153enlever %s, tous les sacs sont pleins"; + Outfitter_cDepositBagsFullError = "Outfitter: Impossible de d\195\169poser %s. Tous les sacs de la banque sont pleins."; + Outfitter_cWithdrawBagsFullError = "Outfitter: Impossible de r\195\169cup\195\169rer %s. Tous vos sacs sont pleins."; + Outfitter_cItemNotFoundError = "Outfitter: %s est introuvable"; + Outfitter_cItemAlreadyUsedError = "Outfitter: Impossible d\226\128\153 \195\169quiper %s \195\160 la place \226\128\153%s\226\128\153 car il est d\195\169j\195\160 utilis\195\169 \195\160 un autre endroit."; + Outfitter_cAddingItem = "Outfitter: %s ajout\195\169 \195\160 la tenue : %s"; + Outfitter_cNameAlreadyUsedError = "Erreur: Nom existant"; + Outfitter_cNoItemsWithStatError = "Attention: Aucuns de vos objets n\226\128\153a cet attribut"; + + Outfitter_cEnableAll = "Tout activer"; + Outfitter_cEnableNone = "Tout d\195\169sactiver"; + + Outfitter_cConfirmDeleteMsg = "Etes vous s\195\187r de vouloir supprimer la tenue : %s?"; + Outfitter_cConfirmRebuildMsg = "Etes vous s\195\187r de vouloir reconstruire la tenue : %s?"; + Outfitter_cRebuild = "Reconstruire"; + + Outfitter_cWesternPlaguelands = "Maleterres de l\226\128\153ouest"; + Outfitter_cEasternPlaguelands = "Maleterres de l\226\128\153est"; + Outfitter_cStratholme = "Stratholme"; + Outfitter_cScholomance = "Scholomance"; + Outfitter_cNaxxramas = "Naxxramas"; + Outfitter_cAlteracValley = "Vall\195\169e d\226\128\153alterac"; + Outfitter_cArathiBasin = "Bassin d\226\128\153arathi"; + Outfitter_cWarsongGulch = "Goulet des warsong"; + Outfitter_cIronforge = "Ironforge"; + Outfitter_cDarnassus = "Darnassus"; + Outfitter_cStormwind = "Stormwind City"; + Outfitter_cOrgrimmar = "Orgrimmar"; + Outfitter_cThunderBluff = "Thunder Bluff"; + Outfitter_cUndercity = "Undercity"; + + Outfitter_cFishingPole = "Canne \195\160 p\195\170che"; + Outfitter_cStrongFishingPole = "Solide canne \195\160 p\195\170che"; + Outfitter_cBigIronFishingPole = "Grande canne \195\160 p\195\170che en fer"; + Outfitter_cBlumpFishingPole = "Canne \195\160 p\195\170che de la famille Blump"; + Outfitter_cNatPaglesFishingPole = "FC-5000 de Nat Pagle, p\195\170cheur de l\226\128\153extr\195\170me"; + Outfitter_cArcaniteFishingPole = "Canne \195\160 p\195\170che en arcanite"; + + Outfitter_cArgentDawnCommission = "Brevet de l\226\128\153aube d\226\128\153argent"; + Outfitter_cSealOfTheDawn = "Sceau de l\226\128\153aube"; + Outfitter_cRuneOfTheDawn = "Rune de l\226\128\153aube"; + + Outfitter_cCarrotOnAStick = "Carotte et b\195\162ton"; + + Outfitter_cItemStatFormats = { + { Format = "Endurance %+(%d+)", Types = { "Stamina" } }, + { Format = "Intelligence %+(%d+)", Types = { "Intellect" } }, + { Format = "Agilit\195\169 %+(%d+)", Types = { "Agility" } }, + { Format = "Force %+(%d+)", Types = { "Strength" } }, + { Format = "Esprit %+(%d+)", Types = { "Spirit" } }, + { Format = "Armure %+(%d+)", Types = { "Armor" } }, + { Format = "D\195\169fense %+(%d+)", Types = { "Defense" } }, + { Format = "D\195\169fense augment\195\169e de %+(%d+)", Types = { "Defense" } }, + + { Format = "%+(%d+) Endurance", Types = { "Stamina" } }, + { Format = "%+(%d+) Intelligence", Types = { "Intellect" } }, + { Format = "%+(%d+) Agilit\195\169", Types = { "Agility" } }, + { Format = "%+(%d+) Force", Types = { "Strength" } }, + { Format = "%+(%d+) Esprit", Types = { "Spirit" } }, + { Format = "%+(%d+) Armure", Types = { "Armor" } }, + { Format = "%+(%d+) \195\160 la puissance d\226\128\153attaque", Types = { "Attack" } }, + + { Format = "%+(%d+) \195\160 toutes les caract\195\169ristiques", Types = { "Stamina", "Intellect", "Agility", "Strength", "Spirit" } }, + + { Format = "Mana %+(%d+)", Types = { "Mana" } }, + { Format = "Vie %+(%d+)", Types = { "Health" } }, + + { Format = "%+(%d+) points de mana toutes les 5 secondes.", Types = { "ManaRegen" } }, + { Format = "Rends (%d+) points de mana toutes les 5 secondes.", Types = { "ManaRegen" } }, + + { Format = "%+(%d+) points de vie toutes les 5 secondes.", Types = { "HealthRegen" } }, + { Format = "Rends (%d+) points de vie toutes les 5 secondes.", Types = { "HealthRegen" } }, + + { Format = "Augmentation mineure de la vitesse de monture", Value = 3, Types = { "Riding" } }, + { Format = "Eperons en mithril", Value = 3, Types = { "Riding" } }, + + { Format = "%+(%d+) R\195\169sistance Feu", Types = { "FireResist" } }, + { Format = "%+(%d+) \195\160 la r\195\169sistance Feu", Types = { "FireResist" } }, + { Format = "%+(%d+) R\195\169sistance Nature", Types = { "NatureResist" } }, + { Format = "%+(%d+) \195\160 la r\195\169sistance Nature", Types = { "NatureResist" } }, + { Format = "%+(%d+) R\195\169sistance Givre", Types = { "FrostResist" } }, + { Format = "%+(%d+) \195\160 la r\195\169sistance Givre", Types = { "FrostResist" } }, + { Format = "%+(%d+) R\195\169sistance Ombre", Types = { "ShadowResist" } }, + { Format = "%+(%d+) \195\160 la r\195\169sistance Ombre", Types = { "ShadowResist" } }, + { Format = "%+(%d+) R\195\169sistance Arcanes", Types = { "ArcaneResist" } }, + { Format = "%+(%d+) \195\160 la r\195\169sistance Arcanes", Types = { "ArcaneResist" } }, + { Format = "%+(%d+) \195\160 toutes les r\195\169sistances", Types = { "FireResist", "NatureResist", "FrostResist", "ShadowResist", "ArcaneResist" } }, + + { Format = "D\195\169g\195\162ts de l\226\128\153arme %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "Augmente vos chances de toucher de (%d+)%%", Types = { "MeleeHit" } }, + { Format = "Augmente vos chance de faire un coup critique de (%d+)%%", Types = { "MeleeCrit" } }, + { Format = "Augmente vos chances d\226\128\153esquiver une attaque de (%d+)%%", Types = { "Dodge" } }, + { Format = "D\195\169g\195\162ts %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "(%d+) Block", Types = { "BlockAmount" } }, + + { Format = "Augmente la p\195\168che de %+(%d+)%.", Types = { "Fishing" } }, + { Format = "P\195\168che %+(%d+)", Types = { "Fishing" } }, + { Format = "Herborisme %+(%d+)", Types = { "Herbalism" } }, + { Format = "Minage %+(%d+)", Types = { "Mining" } }, + { Format = "D\195\169pecage %+(%d+)", Types = { "Skinning" } }, + + { Format = "Augmente vos chances d\226\128\153infliger des coups critiques avec vos sorts de (%d+)%%", Types = { "SpellCrit" } }, + { Format = "Improves your chance to hit with spells by (%d+)%%", Types = { "SpellHit" } }, + { Format = "Augmente les d\195\169g\195\162ts et les soins produits par les sorts et effets magiques de (%d+) au maximum", Types = { "SpellDmg", "ShadowDmg", "FireDmg", "FrostDmg", "ArcaneDmg", "NatureDmg", "Healing" } }, + { Format = "Augmente les soins prodigu\195\169s par les sorts et effets de (%d+) au maximum", Types = { "Healing" } }, + { Format = "Sorts de soins %+(%d+)", Types = { "Healing" } }, + { Format = "%+(%d+) Sorts de soins", Types = { "Healing" } }, + + { Format = "%+(%d+) aux d\195\169g\195\162ts des sorts de feu", Types = { "FireDmg" } }, + { Format = "%+(%d+) aux d\195\169g\195\162ts des sorts d\226\128\153ombre", Types = { "ShadowDmg" } }, + { Format = "%+(%d+) aux d\195\169g\195\162ts des sorts de givre", Types = { "FrostDmg" } }, + { Format = "%+(%d+) aux d\195\169g\195\162ts des sorts d\226\128\153arcane", Types = { "ArcaneDmg" } }, + { Format = "%+(%d+) aux d\195\169g\195\162ts des sorts de nature", Types = { "NatureDmg" } }, + + { Format = "Augmente les points de d\195\169g\195\162ts inflig\195\169 par les sorts et effets de feu de (%d+) au maximum", Types = { "FireDmg" } }, + { Format = "Augmente les points de d\195\169g\195\162ts inflig\195\169 par les sorts et effets d\226\128\153ombre de (%d+) au maximum", Types = { "ShadowDmg" } }, + { Format = "Augmente les points de d\195\169g\195\162ts inflig\195\169 par les sorts et effets de givre de (%d+) au maximum", Types = { "FrostDmg" } }, + { Format = "Augmente les points de d\195\169g\195\162ts inflig\195\169 par les sorts et effets d\226\128\153arcane de (%d+) au maximum", Types = { "ArcaneDmg" } }, + { Format = "Augmente les points de d\195\169g\195\162ts inflig\195\169 par les sorts et effets de nature de (%d+) au maximum", Types = { "NatureDmg" } }, + }; + + Outfitter_cAgilityStatName = "Agilit\195\169"; + Outfitter_cArmorStatName = "Armure"; + Outfitter_cDefenseStatName = "D\195\169fense"; + Outfitter_cIntellectStatName = "Intelligence"; + Outfitter_cSpiritStatName = "Esprit"; + Outfitter_cStaminaStatName = "Endurance"; + Outfitter_cStrengthStatName = "Force"; + + Outfitter_cManaRegenStatName = "R\195\169g\195\169n\195\169ration de mana"; + Outfitter_cHealthRegenStatName = "R\195\169g\195\169n\195\169ration de vie"; + + Outfitter_cSpellCritStatName = "Coups critiques des sorts"; + Outfitter_cSpellHitStatName = "Spell Chance to Hit"; + Outfitter_cSpellDmgStatName = "D\195\169g\195\162ts des sorts"; + Outfitter_cFrostDmgStatName = "D\195\169g\195\162ts des sorts de givre"; + Outfitter_cFireDmgStatName = "D\195\169g\195\162ts des sorts de feu"; + Outfitter_cArcaneDmgStatName = "D\195\169g\195\162ts des sorts d\226\128\153arcane"; + Outfitter_cShadowDmgStatName = "D\195\169g\195\162ts des sorts d\226\128\153ombre"; + Outfitter_cNatureDmgStatName = "D\195\169g\195\162ts des sorts de nature"; + Outfitter_cHealingStatName = "Soins"; + + Outfitter_cMeleeCritStatName = "Coups critiques"; + Outfitter_cMeleeHitStatName = "Chance de toucher"; + Outfitter_cMeleeDmgStatName = "D\195\169g\195\162ts"; + Outfitter_cAttackStatName = "Puissance d\226\128\153attaque"; + Outfitter_cDodgeStatName = "Esquive"; + + Outfitter_cArcaneResistStatName = "R\195\169sistance aux arcanes"; + Outfitter_cFireResistStatName = "R\195\169sistance au feu"; + Outfitter_cFrostResistStatName = "R\195\169sistance au givre"; + Outfitter_cNatureResistStatName = "R\195\169sistance \195\160 la nature"; + Outfitter_cShadowResistStatName = "R\195\169sistance \195\160 l\226\128\153ombre"; + + Outfitter_cFishingStatName = "P\195\170che"; + Outfitter_cHerbalismStatName = "Herborisme"; + Outfitter_cMiningStatName = "Minage"; + Outfitter_cSkinningStatName = "D\195\169pecage"; + + Outfitter_cOptionsTitle = "Options de Outfitter"; + Outfitter_cShowMinimapButton = "Bouton Minimap"; + Outfitter_cShowMinimapButtonOnDescription = "D\195\169sactivez si vous ne voulez pas le bouton d\226\128\153Outfitter sur votre minimap"; + Outfitter_cShowMinimapButtonOffDescription = "Activez pour afficher le bouton d\226\128\153Outfitter sur la minimap"; + Outfitter_cRememberVisibility = "Remember cloak and helm settings"; + Outfitter_cRememberVisibilityOnDescription = "Turn this off if you want to use a single show/hide setting for all cloaks and helms"; + Outfitter_cRememberVisibilityOffDescription = "Turn this on if you want Outfitter to remember your preference for showing or hiding each cloak and helm individually"; + + Outfitter_cAboutTitle = "A propos d\226\128\153Outfitter"; + Outfitter_cAuthor = "Designed and written by Baylord of Thunderlord"; + Outfitter_cTestersTitle = "Beta Testers"; + Outfitter_cTestersNames = "Airmid, Desiree, Fizzlebang, Harper, Kallah and Sumitra"; + Outfitter_cSpecialThanksTitle = "Special thanks for their support to"; + Outfitter_cSpecialThanksNames = "Brian, Dave, Glenn, Leah, Mark, The Mighty Pol, SFC and Forge"; + Outfitter_cGuildURL = "http://www.starfleetclan.com"; + Outfitter_cGuildURL2 = "http://www.forgeguild.com"; + + Outfitter_cOpenOutfitter = "Ouvrir Outfitter"; + + Outfitter_cArgentDawnOutfitDescription = "Cette tenue sera automatiquement \195\169quip\195\169e quand vous serez dans les Maleterres"; + Outfitter_cRidingOutfitDescription = "Cette tenue sera automatiquement \195\169quip\195\169e quand vous serez sur votre monture"; + Outfitter_cDiningOutfitDescription = "Cette tenue sera automatiquement \195\169quip\195\169e quand vous mangerez ou boirez"; + Outfitter_cBattlegroundOutfitDescription = "Cette tenue sera automatiquement \195\169quip\195\169e quand vous serez dans un Champ de BAtaille"; + Outfitter_cArathiBasinOutfitDescription = "This outfit will automatically be worn whenever you're in the Arathi Basin battleground"; + Outfitter_cAlteracValleyOutfitDescription = "This outfit will automatically be worn whenever you're in the Alterac Valley battleground"; + Outfitter_cWarsongGulchOutfitDescription = "This outfit will automatically be worn whenever you're in the Warsong Gulch battleground"; + Outfitter_cCityOutfitDescription = "This outfit will automatically be worn whenever you're in a friendly major city"; + Outfitter_cBossOutfitDescription = "This outfit will automatically be worn whenever you target level 63+ Boss mobs"; + Outfitter_cLvl63OutfitDescription = "This outfit will automatically be worn whenever you target level 63+ mobs"; + Outfitter_cTrashOutfitDescription = "This outfit will automatically be worn whenever you target level <63 mobs"; + Outfitter_cBeastTrashOutfitDescription = "This outfit will automatically be worn whenever you target beasts level <63 mobs"; + Outfitter_cUndeadTrashOutfitDescription = "This outfit will automatically be worn whenever you target undead level <63 mobs"; + Outfitter_cDemonTrashOutfitDescription = "This outfit will automatically be worn whenever you target demons level <63 mobs"; + + Outfitter_cKeyBinding = "Raccourcis"; + + BINDING_HEADER_OUTFITTER_TITLE = Outfitter_cTitle; + + BINDING_NAME_OUTFITTER_OUTFIT1 = "Tenue 1"; + BINDING_NAME_OUTFITTER_OUTFIT2 = "Tenue 2"; + BINDING_NAME_OUTFITTER_OUTFIT3 = "Tenue 3"; + BINDING_NAME_OUTFITTER_OUTFIT4 = "Tenue 4"; + BINDING_NAME_OUTFITTER_OUTFIT5 = "Tenue 5"; + BINDING_NAME_OUTFITTER_OUTFIT6 = "Tenue 6"; + BINDING_NAME_OUTFITTER_OUTFIT7 = "Tenue 7"; + BINDING_NAME_OUTFITTER_OUTFIT8 = "Tenue 8"; + BINDING_NAME_OUTFITTER_OUTFIT9 = "Tenue 9"; + BINDING_NAME_OUTFITTER_OUTFIT10 = "Tenue 10"; + + Outfitter_cDisableOutfit = "D\195\169sactiver la tenue"; + Outfitter_cDisableOutfitInBG = "D\195\169sactiver la tenue dans les Champs de Bataille"; + Outfitter_cDisabledOutfitName = "%s (D\195\169sactiv\195\169)"; + + Outfitter_cMinimapButtonTitle = "Outfitter"; + Outfitter_cMinimapButtonDescription = "Cliquez pour s\195\169l\195\169ctionner une autre tenue ou d\195\169placez pour changer la position du bouton."; + + Outfitter_cDruidClassName = "Druide"; + Outfitter_cHunterClassName = "Chasseur"; + Outfitter_cMageClassName = "Mage"; + Outfitter_cPaladinClassName = "Paladin"; + Outfitter_cPriestClassName = "Pr\195\170tre"; + Outfitter_cRogueClassName = "Voleur"; + Outfitter_cShamanClassName = "Chaman"; + Outfitter_cWarlockClassName = "D\195\169moniste"; + Outfitter_cWarriorClassName = "Guerrier"; + + Outfitter_cBattleStance = "Posture de combat"; + Outfitter_cDefensiveStance = "Posture d\195\169fensive"; + Outfitter_cBerserkerStance = "Posture berzeker"; + + Outfitter_cWarriorBattleStance = "Guerrier: Posture de combat"; + Outfitter_cWarriorDefensiveStance = "Guerrier: Posture d\195\169fensive"; + Outfitter_cWarriorBerserkerStance = "Guerrier: Posture berzeker"; + + Outfitter_cBearForm = "Forme d\226\128\153ours"; + Outfitter_cCatForm = "Forme de f\195\169lin"; + Outfitter_cAquaticForm = "Forme aquatique"; + Outfitter_cTravelForm = "Forme de voyage"; + Outfitter_cDireBearForm = "Forme d\226\128\153ours redoutable"; + Outfitter_cMoonkinForm = "Fome de s\195\169l\195\169nien"; + + Outfitter_cGhostWolfForm = "Loup fant\195\180me"; + + Outfitter_cStealth = "Camouflage"; + + Outfitter_cDruidBearForm = "Druide: Forme d\226\128\153ours"; + Outfitter_cDruidCatForm = "Druide: Forme de f\195\169lin"; + Outfitter_cDruidAquaticForm = "Druide: Forme aquatique"; + Outfitter_cDruidTravelForm = "Druide: Forme de voyage"; + Outfitter_cDruidMoonkinForm = "Druid: Forme de s\195\169l\195\169nien"; + + Outfitter_cPriestShadowform = "Pr\195\170tre: Forme d\226\128\153ombre"; + + Outfitter_cRogueStealth = "Voleur: Camouflage"; + + Outfitter_cShamanGhostWolf = "Chaman: Loup fant\195\180me"; + + Outfitter_cCompleteCategoryDescripton = "Les tenues compl\195\168tes ont un objet sp\195\169cifi\195\169 pour chaque emplacement et remplaceront toutes les autres tenues quand elles sont activ\195\169es"; + Outfitter_cPartialCategoryDescription = "Les tenues \"Mix-n-match\" ont quelques emplacements sp\195\169cifi\195\169s. Quand on les \195\169quipe, elles vont par-dessus la tenue compl\195\168te s\195\169l\195\169ctionn\195\169e et remplace toutes les tenues \"Mix-n-match\" et Accessoires"; + Outfitter_cAccessoryCategoryDescription = "Les tenues d\226\128\153accessoires ont quelques emplacements sp\195\169cifi\195\169s. Contrairement aux \"Mix-n-Match\", Contrairement aux \"Mix-n-Match\", vous pouvez s\195\169l\195\169ctionner autant d\226\128\153accessoires que vous voulez et ils seront combin\195\169s par-dessus votre tenue compl\195\168te et \"Mix-n-Match\"."; + Outfitter_cSpecialCategoryDescription = "Les tenues sp\195\169ciales sont automatiquement \195\169quip\195\169es dans certaines conditions. Elles remplacent les tenues \195\169quip\195\169es avant."; + Outfitter_cOddsNEndsCategoryDescription = "Les Odds \226\128\153n ends sont des objets que vous n\226\128\153utilisez dans aucune tenue. Ceci peut \195\170tre utile pour v\195\169rifier que vous utilisez tous les objets que vous avez dans l\226\128\153inventaire."; + + Outfitter_cRebuildOutfitFormat = "Reconstruire pour %s"; + + Outfitter_cTranslationCredit = "Traduction fran\195\167aise: Jullye de Kael\226\128\153Thas"; + + Outfitter_cSlotEnableTitle = "Activer l\226\128\153emplacement"; + Outfitter_cSlotEnableDescription = "Cochez la case si vous voulez que l\226\128\153objet de cet emplacement soit automatiquement \195\169quip\195\169 lors du changement de tenue. Si la case n\226\128\153est pas coch\195\169e, l\226\128\153objet ne sera pas modifi\195\169 lors du changement de tenue."; + + Outfitter_cFinger0SlotName = "Premier doigt"; + Outfitter_cFinger1SlotName = "Second doigt"; + + Outfitter_cTrinket0SlotName = "Premier bijou"; + Outfitter_cTrinket1SlotName = "Second bijou"; + + Outfitter_cOutfitCategoryTitle = "Cat\195\169gorie"; + Outfitter_cBankCategoryTitle = "Banque"; + Outfitter_cDepositToBank = "D\195\169poser les objets \195\160 la banque."; + Outfitter_cDepositUniqueToBank = "Deposit unique items to bank"; + Outfitter_cWithdrawFromBank = "R\195\169cup\195\169rer les objets de la banque."; + + Outfitter_cMissingItemsLabel = "Objets manquants: "; + Outfitter_cBankedItemsLabel = "Objets \195\160 la banque: "; + + Outfitter_cStatsCategory = "Stats"; + Outfitter_cMeleeCategory = "Melee"; + Outfitter_cSpellsCategory = "Healing and Spells"; + Outfitter_cRegenCategory = "Regeneration"; + Outfitter_cResistCategory = "Resistances"; + Outfitter_cTradeCategory = "Trade Skills"; + + Outfitter_cCritter = "Bestiole"; + Outfitter_cCreatureBeast = "Bête"; + Outfitter_cCreatureUndead = "Mort-vivant"; + Outfitter_cCreatureDemon = "Démon"; + Outfitter_cSwimmingOutfit = "Natation"; +end diff --git a/OutfitterStrings_kr.lua b/OutfitterStrings_kr.lua new file mode 100644 index 0000000..dbf3ef9 --- /dev/null +++ b/OutfitterStrings_kr.lua @@ -0,0 +1,368 @@ +if GetLocale() == "koKR" then + Outfitter_cTitle = "Outfitter"; + Outfitter_cTitleVersion = Outfitter_cTitle .. " " .. Outfitter_cVersion; + + Outfitter_cNameLabel = "이름:"; + Outfitter_cCreateUsingTitle = "최적화:"; + Outfitter_cUseCurrentOutfit = "현재 장비 세트 사용"; + Outfitter_cUseEmptyOutfit = "빈 장비 세트 만듬"; + + Outfitter_cOutfitterTabTitle = "Outfitter"; + Outfitter_cOptionsTabTitle = "옵션"; + Outfitter_cAboutTabTitle = "정보"; + + Outfitter_cNewOutfit = "신규 장비 세트"; + Outfitter_cRenameOutfit = "장비 세트 이름 변경"; + + Outfitter_cCompleteOutfits = "완비 세트"; + Outfitter_cPartialOutfits = "Mix-n-match"; + Outfitter_cAccessoryOutfits = "보조 장비"; + Outfitter_cSpecialOutfits = "특수 조건"; + Outfitter_cOddsNEndsOutfits = "나머지 장비들"; + + Outfitter_cNormalOutfit = "평상시"; + Outfitter_cNakedOutfit = "벗기"; + + Outfitter_cFishingOutfit = "낚시"; + Outfitter_cHerbalismOutfit = "약초 채집"; + Outfitter_cMiningOutfit = "채광"; + Outfitter_cSkinningOutfit = "무두질"; + Outfitter_cFireResistOutfit = "화염 저항"; + Outfitter_cNatureResistOutfit = "자연 저항"; + Outfitter_cShadowResistOutfit = "암흑 저항"; + Outfitter_cArcaneResistOutfit = "비전 저항"; + Outfitter_cFrostResistOutfit = "냉기 저항"; + + Outfitter_cArgentDawnOutfit = "은빛 여명회"; + Outfitter_cRidingOutfit = "말타기"; + Outfitter_cDiningOutfit = "음식 먹기"; + Outfitter_cBattlegroundOutfit = "전장"; + Outfitter_cABOutfit = "전장: 아라시 분지"; + Outfitter_cAVOutfit = "전장: 알터랙 계곡"; + Outfitter_cWSGOutfit = "전장: 전쟁노래 협곡"; + Outfitter_cCityOutfit = "마을 주변"; + Outfitter_cBossOutfit = "Boss Mobs"; + Outfitter_cLvl63Outfit = "Lvl63+"; + Outfitter_cTrashOutfit = "Trash Mobs"; + Outfitter_cBeastTrashOutfit = "Beast Trash Mobs"; + Outfitter_cUndeadTrashOutfit = "Undead Trash Mobs"; + Outfitter_cDemonTrashOutfit = "Demon Trash Mobs"; + + Outfitter_cMountSpeedFormat = "이동 속도 (%d+)%%만큼 증가"; -- For detecting when mounted + + Outfitter_cBagsFullError = "Outfitter: 가방이 가득 차서 %s|1을;를; 벗을 수 없습니다."; + Outfitter_cDepositBagsFullError = "Outfitter: 가방이 가득 차서 %s|1을;를; 벗을 수 없습니다."; + Outfitter_cWithdrawBagsFullError = "Outfitter: 가방이 가득 차서 %s|1을;를; 벗을 수 없습니다."; + Outfitter_cItemNotFoundError = "Outfitter: %s 아이템을 찾을 수 없습니다."; + Outfitter_cItemAlreadyUsedError = "Outfitter: %s|1은;는; 이미 다른 슬롯에서 사용중이므로 %s 슬롯에 착용할 수 없습니다."; + Outfitter_cAddingItem = "Outfitter: %s|1을;를 %s 세트에 추가합니다."; + Outfitter_cNameAlreadyUsedError = "에러: 사용중인 이름입니다."; + Outfitter_cNoItemsWithStatError = "경고: 해당 능력을 가진 아이템이 없습니다."; + + Outfitter_cEnableAll = "모두 활성화"; + Outfitter_cEnableNone = "모두 비활성화"; + + Outfitter_cConfirmDeleteMsg = "%s 세트를 삭제 하시겠습니까?"; + Outfitter_cConfirmRebuildMsg = "%s 세트를 재구성 하시겠습니까?"; + Outfitter_cRebuild = "Rebuild"; + + Outfitter_cWesternPlaguelands = "서부 역병지대"; + Outfitter_cEasternPlaguelands = "동부 역병지대"; + Outfitter_cStratholme = "스트라솔룸"; + Outfitter_cScholomance = "스칼로맨스"; + Outfitter_cNaxxramas = "낙스라마스"; + Outfitter_cAlteracValley = "알터랙 계곡"; + Outfitter_cArathiBasin = "아라시 분지"; + Outfitter_cWarsongGulch = "전쟁노래 협곡"; + Outfitter_cIronforge = "아이언포지"; + Outfitter_cCityOfIronforge = "아이언포지"; + Outfitter_cDarnassus = "다르나서스"; + Outfitter_cStormwind = "스톰윈드"; + Outfitter_cOrgrimmar = "오그리마"; + Outfitter_cThunderBluff = "썬더 블러프"; + Outfitter_cUndercity = "언더시티"; + + Outfitter_cFishingPole = "낚싯대"; + Outfitter_cStrongFishingPole = "특튼한 낚싯대"; + Outfitter_cBigIronFishingPole = "큰 철재 낚싯대"; + Outfitter_cBlumpFishingPole = "블럼프가의 낚싯대"; + Outfitter_cNatPaglesFishingPole = "네트 페이글의 다낚아 FC-5000"; + Outfitter_cArcaniteFishingPole = "아케이나이트 낚싯대"; + + Outfitter_cArgentDawnCommission = "은빛 여명회 위임봉"; + Outfitter_cSealOfTheDawn = "여명의 문장"; + Outfitter_cRuneOfTheDawn = "여명의 룬"; + + Outfitter_cCarrotOnAStick = "당근 달린 지팡이"; + + Outfitter_cItemStatFormats = { + { Format = "체력 %+(%d+)", Types = { "Stamina" } }, + { Format = "지능 %+(%d+)", Types = { "Intellect" } }, + { Format = "민첩 %+(%d+)", Types = { "Agility" } }, + { Format = "힘 %+(%d+)", Types = { "Strength" } }, + { Format = "정신력 %+(%d+)", Types = { "Spirit" } }, + { Format = "방어도 %+(%d+)", Types = { "Armor" } }, + { Format = "방어 숙련도 %+(%d+)", Types = { "Defense" } }, + { Format = "Increased Defense %+(%d+)", Types = { "Defense" } }, + + { Format = "%+(%d+) 체력", Types = { "Stamina" } }, + { Format = "%+(%d+) 지능", Types = { "Intellect" } }, + { Format = "%+(%d+) 민첩", Types = { "Agility" } }, + { Format = "%+(%d+) 힘", Types = { "Strength" } }, + { Format = "%+(%d+) 정신력", Types = { "Spirit" } }, + { Format = "(%d+) 방어도", Types = { "Armor" } }, + { Format = "%+(%d+) 전투력", Types = { "Attack" } }, + + { Format = "모든 능력치 %+(%d+)", Types = { "Stamina", "Intellect", "Agility", "Strength", "Spirit" } }, + + { Format = "마나 %+(%d+)", Types = { "Mana" } }, + { Format = "생명력 %+(%d+)", Types = { "Health" } }, + + { Format = "매 5초마다 %+(%d+)의 마나", Types = { "ManaRegen" } }, + { Format = "매 5초마다 (%d+)의 마나가 회복됩니다.", Types = { "ManaRegen" } }, + + { Format = "매 5초마다 %+(%d+)의 생명력", Types = { "HealthRegen" } }, + { Format = "매 5초마다 (%d+)의 생명력이 회복됩니다.", Types = { "HealthRegen" } }, + { Format = "Restores (%d+) health per 5 sec.", Types = { "HealthRegen" } }, + + { Format = "최하급 탈것 속도 증가", Value = 3, Types = { "Riding" } }, + { Format = "미스릴 박차", Value = 3, Types = { "Riding" } }, + + { Format = "화염 저항력 %+(%d+)", Types = { "FireResist" } }, + { Format = "자연 저항력 %+(%d+)", Types = { "NatureResist" } }, + { Format = "냉기 저항력 %+(%d+)", Types = { "FrostResist" } }, + { Format = "암흑 저항력 %+(%d+)", Types = { "ShadowResist" } }, + { Format = "비전 저항력 %+(%d+)", Types = { "ArcaneResist" } }, + { Format = "모든 저항력 %+(%d+)", Types = { "FireResist", "NatureResist", "FrostResist", "ShadowResist", "ArcaneResist" } }, + + { Format = "무기 공격력 %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "무기의 적중률이 (%d+)%%만큼 증가합니다.", Types = { "MeleeHit" } }, + { Format = "치명타를 적중시킬 확률이 (%d+)%%만큼 증가합니다.", Types = { "MeleeCrit" } }, + { Format = "공격을 회피할 확률이 (%d+)%%만큼 증가합니다.", Types = { "Dodge" } }, + { Format = "공격력 %+(%d+)", Types = { "MeleeDmg" } }, + { Format = "(%d+)의 피해 방어", Types = { "Block" } }, + { Format = "방어도 %+(%d+)", Types = { "Block" } }, + { Format = "방패의 피해 방어량이 (%d+)만큼 증가합니다.", Types = { "Block" } }, + + { Format = "낚시 숙련도 %+(%d+)%.", Types = { "Fishing" } }, + { Format = "낚시 %+(%d+)", Types = { "Fishing" } }, + { Format = "약초 채집 %+(%d+)", Types = { "Herbalism" } }, + { Format = "채광 %+(%d+)", Types = { "Mining" } }, + { Format = "무두질 %+(%d+)", Types = { "Skinning" } }, + + { Format = "주문이 극대화 효과를 낼 확률이(%d+)%%만큼 증가합니다.", Types = { "SpellCrit" } }, + { Format = "주문의 적중률이 (%d+)%%만큼 증가합니다.", Types = { "SpellHit" } }, + { Format = "모든 주문 및 효과에 의한 피해와 치유량이 최대 (%d+)만큼 증가합니다.", Types = { "SpellDmg", "ShadowDmg", "FireDmg", "FrostDmg", "ArcaneDmg", "NatureDmg", "Healing" } }, + { Format = "모든 주문 및 효과에 의한 치유량이 최대 (%d+)만큼 증가합니다.", Types = { "Healing" } }, + { Format = "치유 주문 %+(%d+)", Types = { "Healing" } }, + { Format = "%+(%d+) 치유 주문", Types = { "Healing" } }, + + { Format = "%+(%d+) 화염 주문 공격력", Types = { "FireDmg" } }, + { Format = "%+(%d+) 암흑 주문 공격력", Types = { "ShadowDmg" } }, + { Format = "%+(%d+) 냉기 주문 공격력", Types = { "FrostDmg" } }, + { Format = "%+(%d+) 비전 주문 공격력", Types = { "ArcaneDmg" } }, + { Format = "%+(%d+) 자연 주문 공격력", Types = { "NatureDmg" } }, + + { Format = "화염 계열의 주문과 효과의 공격력이 최대 (%d+)만큼 증가합니다.", Types = { "FireDmg" } }, + { Format = "암흑 계열의 주문과 효과의 공격력이 최대 (%d+)만큼 증가합니다.", Types = { "ShadowDmg" } }, + { Format = "냉기 계열의 주문과 효과의 공격력이 최대 (%d+)만큼 증가합니다.", Types = { "FrostDmg" } }, + { Format = "비전 계열의 주문과 효과의 공격력이 최대 (%d+)만큼 증가합니다.", Types = { "ArcaneDmg" } }, + { Format = "자연 계열의 주문과 효과의 공격력이 최대 (%d+)만큼 증가합니다.", Types = { "NatureDmg" } }, + }; + + Outfitter_cAgilityStatName = "민첩"; + Outfitter_cArmorStatName = "방어도"; + Outfitter_cDefenseStatName = "방어 숙련도"; + Outfitter_cIntellectStatName = "지능"; + Outfitter_cSpiritStatName = "정신력"; + Outfitter_cStaminaStatName = "체력"; + Outfitter_cStrengthStatName = "힘"; + + Outfitter_cManaRegenStatName = "마나 회복"; + Outfitter_cHealthRegenStatName = "생명력 회복"; + + Outfitter_cSpellCritStatName = "주문 치명타"; + Outfitter_cSpellHitStatName = "주문 적중률"; + Outfitter_cSpellDmgStatName = "주문 공격력"; + Outfitter_cFrostDmgStatName = "냉기 주문 공격력"; + Outfitter_cFireDmgStatName = "화염 주문 공격력"; + Outfitter_cArcaneDmgStatName = "비전 주문 공격력"; + Outfitter_cShadowDmgStatName = "암흑 주문 공격력"; + Outfitter_cNatureDmgStatName = "자연 주문 공격력"; + Outfitter_cHealingStatName = "치유량"; + + Outfitter_cMeleeCritStatName = "근접 치명타"; + Outfitter_cMeleeHitStatName = "근접 적중률"; + Outfitter_cMeleeDmgStatName = "근접 공격력"; + Outfitter_cAttackStatName = "전투력"; + Outfitter_cDodgeStatName = "회피"; + + Outfitter_cArcaneResistStatName = "비전 저항력"; + Outfitter_cFireResistStatName = "화염 저항력"; + Outfitter_cFrostResistStatName = "냉기 저항력"; + Outfitter_cNatureResistStatName = "자연 저항력"; + Outfitter_cShadowResistStatName = "암흑 저항력"; + + Outfitter_cFishingStatName = "낚시"; + Outfitter_cHerbalismStatName = "약초 채집"; + Outfitter_cMiningStatName = "채광"; + Outfitter_cSkinningStatName = "무두질"; + + Outfitter_cOptionsTitle = "Outfitter Options"; + Outfitter_cShowMinimapButton = "미니맵 버튼 표시"; + Outfitter_cShowMinimapButtonOnDescription = "미니맵 버튼을 사용하지 않으려면 끕니다."; + Outfitter_cShowMinimapButtonOffDescription = "미니맵 버튼을 사용하려면 켭니다."; + Outfitter_cRememberVisibility = "망토와 투구 설정 기억"; + Outfitter_cRememberVisibilityOnDescription = "모든 망토와 투구에 대해서 동일한 설정을 하려면 끕니다."; + Outfitter_cRememberVisibilityOffDescription = "각각의 망토와 투구에 대한 설정을 기억하려면 켭니다."; + Outfitter_cShowHotkeyMessages = "단축키로 변경할때 보여주기"; + Outfitter_cShowHotkeyMessagesOnDescription = "단축키로 세트를 변경할때 메시지를 보지 않으려면 끕니다."; + Outfitter_cShowHotkeyMessagesOffDescription = "단축키로 세트를 변경할때 메시지를 보려면 켭니다."; + + Outfitter_cEquipOutfitMessageFormat = "Outfitter: %s 장비됨"; + Outfitter_cUnequipOutfitMessageFormat = "Outfitter: %s 해제됨"; + + Outfitter_cAboutTitle = "Outfitter 정보"; + Outfitter_cAuthor = "Designed and written by John Stephen"; + Outfitter_cTestersTitle = "Beta Testers"; + Outfitter_cTestersNames = "Airmid, Desiree, Fizzlebang, Harper, Kallah and Sumitra"; + Outfitter_cSpecialThanksTitle = "Special thanks for their support to"; + Outfitter_cSpecialThanksNames = "Brian, Dave, Glenn, Leah, Mark, The Mighty Pol, SFC and Forge"; + Outfitter_cGuildURL = "http://www.starfleetclan.com"; + Outfitter_cGuildURL2 = "http://www.forgeguild.com"; + + Outfitter_cOpenOutfitter = "Outfitter 열기"; + + Outfitter_cArgentDawnOutfitDescription = "이 세트는 역병지대에 있을 때 자동으로 착용 됩니다."; + Outfitter_cRidingOutfitDescription = "이 세트는 탈것을 탈 때 자동으로 착용 됩니다."; + Outfitter_cDiningOutfitDescription = "이 세트는 음식을 먹거나 음료를 마실 때 자동으로 착용 됩니다."; + Outfitter_cBattlegroundOutfitDescription = "이 세트는 전장에 있을 때 자동으로 착용 됩니다."; + Outfitter_cArathiBasinOutfitDescription = "이 세트는 아라시 분지에 있을 때 자동으로 착용 됩니다."; + Outfitter_cAlteracValleyOutfitDescription = "이 세트는 알터랙 계곡에 있을 때 자동으로 착용 됩니다."; + Outfitter_cWarsongGulchOutfitDescription = "이 세트는 전쟁노래 협곡에 있을 때 자동으로 착용 됩니다."; + Outfitter_cCityOutfitDescription = "이 세트는 우호적인 대도시에 있을 때 자동으로 착용 됩니다."; + Outfitter_cBossOutfitDescription = "This outfit will automatically be worn whenever you target level 63+ Boss mobs"; + Outfitter_cLvl63OutfitDescription = "This outfit will automatically be worn whenever you target level 63+ mobs"; + Outfitter_cTrashOutfitDescription = "This outfit will automatically be worn whenever you target level <63 mobs"; + Outfitter_cBeastTrashOutfitDescription = "This outfit will automatically be worn whenever you target beasts level <63 mobs"; + Outfitter_cUndeadTrashOutfitDescription = "This outfit will automatically be worn whenever you target undead level <63 mobs"; + Outfitter_cDemonTrashOutfitDescription = "This outfit will automatically be worn whenever you target demons level <63 mobs"; + + Outfitter_cKeyBinding = "단축키"; + + BINDING_HEADER_OUTFITTER_TITLE = Outfitter_cTitle; + + BINDING_NAME_OUTFITTER_OUTFIT1 = "세트 1"; + BINDING_NAME_OUTFITTER_OUTFIT2 = "세트 2"; + BINDING_NAME_OUTFITTER_OUTFIT3 = "세트 3"; + BINDING_NAME_OUTFITTER_OUTFIT4 = "세트 4"; + BINDING_NAME_OUTFITTER_OUTFIT5 = "세트 5"; + BINDING_NAME_OUTFITTER_OUTFIT6 = "세트 6"; + BINDING_NAME_OUTFITTER_OUTFIT7 = "세트 7"; + BINDING_NAME_OUTFITTER_OUTFIT8 = "세트 8"; + BINDING_NAME_OUTFITTER_OUTFIT9 = "세트 9"; + BINDING_NAME_OUTFITTER_OUTFIT10 = "세트 10"; + + Outfitter_cDisableOutfit = "세트 사용 안함"; + Outfitter_cDisableOutfitInBG = "전장에서 사용 안함"; + Outfitter_cDisabledOutfitName = "%s (사용 안함)"; + + Outfitter_cMinimapButtonTitle = "미니맵 버튼"; + Outfitter_cMinimapButtonDescription = "클릭 : 세트 선택, 드래그 : 미니맵 버튼 이동"; + + Outfitter_cDruidClassName = "드루이드"; + Outfitter_cHunterClassName = "사냥꾼"; + Outfitter_cMageClassName = "마법사"; + Outfitter_cPaladinClassName = "성기사"; + Outfitter_cPriestClassName = "사제"; + Outfitter_cRogueClassName = "도적"; + Outfitter_cShamanClassName = "주술사"; + Outfitter_cWarlockClassName = "흑마법사"; + Outfitter_cWarriorClassName = "전자"; + + Outfitter_cBattleStance = "전투 태세"; + Outfitter_cDefensiveStance = "방어 태세"; + Outfitter_cBerserkerStance = "광폭 태세"; + + Outfitter_cWarriorBattleStance = "전사: 전투 태세"; + Outfitter_cWarriorDefensiveStance = "전사: 방어 태세"; + Outfitter_cWarriorBerserkerStance = "전사: 광폭 태세"; + + Outfitter_cBearForm = "곰 변신"; + Outfitter_cCatForm = "표범 변신표범 변신"; + Outfitter_cAquaticForm = "바다표범 변신"; + Outfitter_cTravelForm = "치타 변신"; + Outfitter_cDireBearForm = "광포한 곰 변신"; + Outfitter_cMoonkinForm = "달빛야수 변신"; + + Outfitter_cGhostWolfForm = "늑대 정령"; + + Outfitter_cStealth = "은신"; + + Outfitter_cDruidBearForm = "드루이드: 곰 변신"; + Outfitter_cDruidCatForm = "드루이드: 표범 변신"; + Outfitter_cDruidAquaticForm = "드루이드: 바다표범 변신"; + Outfitter_cDruidTravelForm = "드루이드: 치타 변신"; + Outfitter_cDruidMoonkinForm = "드루이드: 달빛야수 변신"; + + Outfitter_cPriestShadowform = "사제: 어둠의 형상"; + + Outfitter_cRogueStealth = "도적: 은신"; + + Outfitter_cShamanGhostWolf = "주술사: 늑대 정령"; + + Outfitter_cHunterMonkey = "사냥꾼: 원숭이의 상"; + Outfitter_cHunterHawk = "사냥꾼: 매의 상"; + Outfitter_cHunterCheetah = "사냥꾼: 치타의 상"; + Outfitter_cHunterPack = "사냥꾼: 치타 무리의 상"; + Outfitter_cHunterBeast = "사냥꾼: 야수의 상"; + Outfitter_cHunterWild = "사냥꾼: 야생의 상"; + + Outfitter_cMageEvocate = "마법사: 환기"; + + Outfitter_cAspectOfTheCheetah = "치타의 상"; + Outfitter_cAspectOfThePack = "치타 무리의 상"; + Outfitter_cAspectOfTheBeast = "야수의 상"; + Outfitter_cAspectOfTheWild = "야생의 상"; + Outfitter_cEvocate = "환기"; + + Outfitter_cCompleteCategoryDescripton = "모든 슬롯의 아이템에 관한 설정이 들어있는 완전한 장비 세트입니다."; + Outfitter_cPartialCategoryDescription = "Mix-n-match의 장비 세트는 전부가 아닌 일부 슬롯만 가집니다. 장비 세트가 선택되면 이전에 선택되었던 보조 장비 세트 또는 Mix-n-match 세트를 대체하면서, 완비 세트에서 해당 아이템만을 교체합니다."; + Outfitter_cAccessoryCategoryDescription = "보조 장비의 장비 세트는 전부가 아닌 일부 슬롯만 가집니다. Mix-n-match와는 다르게 이전에 선택되었던 보조 장비 세트 또는 Mix-n-match 세트를 대체하지 않고 추가로 완비 세트에서 해당 아이템을 교체합니다."; + Outfitter_cSpecialCategoryDescription = "특수 조건의 장비 세트는 해당하는 조건을 충족시킬 경우 자동으로 착용됩니다."; + Outfitter_cOddsNEndsCategoryDescription = "나머지 장비들의 아이템들은 장비 세트에 한번도 사용되지 않은 아이템들입니다."; + + Outfitter_cRebuildOutfitFormat = "%s 재구성"; + + Outfitter_cTranslationCredit = " "; + + Outfitter_cSlotEnableTitle = "슬롯 활성화"; + Outfitter_cSlotEnableDescription = "슬롯을 활성화 하면 해당 장비 세트를 사용할때 같이 변경됩니다."; + + Outfitter_cFinger0SlotName = "첫번째 손가락"; + Outfitter_cFinger1SlotName = "두번째 손가락"; + + Outfitter_cTrinket0SlotName = "첫번째 장신구"; + Outfitter_cTrinket1SlotName = "두번째 장신구"; + + Outfitter_cOutfitCategoryTitle = "카테고리"; + Outfitter_cBankCategoryTitle = "은행"; + Outfitter_cDepositToBank = "모든 아이템을 은행으로"; + Outfitter_cDepositUniqueToBank = "특정 아이템을 은행으로"; + Outfitter_cWithdrawFromBank = "은행으로부터 아이템 회수"; + + Outfitter_cMissingItemsLabel = "찾을 수 없는 아이템: "; + Outfitter_cBankedItemsLabel = "은행에 있는 아이템: "; + + Outfitter_cRepairAllBags = "Outfitter: 모든 아이템 수리"; + + Outfitter_cStatsCategory = "능력치"; + Outfitter_cMeleeCategory = "근접"; + Outfitter_cSpellsCategory = "주문과 치유"; + Outfitter_cRegenCategory = "회복"; + Outfitter_cResistCategory = "저항"; + Outfitter_cTradeCategory = "전문기술"; + + Outfitter_cTankPoints = "탱크 포인트"; + Outfitter_cCustom = "사용자 설정"; +end diff --git a/OutfitterStrings_tw.lua b/OutfitterStrings_tw.lua new file mode 100644 index 0000000..e69de29 diff --git a/Textures/ButtonBarBackground.blp b/Textures/ButtonBarBackground.blp new file mode 100644 index 0000000000000000000000000000000000000000..b83f9196dac9c6679258d5b743d711800cb9bb93 GIT binary patch literal 6684 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 literal 0 HcmV?d00001 diff --git a/Textures/GuildLogo.blp b/Textures/GuildLogo.blp new file mode 100644 index 0000000000000000000000000000000000000000..649d24ae56e16305ce879df15ea98c5846ce92d9 GIT binary patch literal 88580 zcmeIb4}4U|buT`>*~Z6zCSB=S-$+_*m^JHHn-xwWBj^e5!CZ0ui(>>CJ9-2}&NSt-9)B45k3!MHYV zlQjx9?E9X3cjm7BN^CILVDIcl+C6vfojY^poHOT~IWtrD`%TLOjIm%S5McBJe*?4V zFTe&G@E5~hEB-ziV2APdulV~V{(gNzzK%OI{Glu=Q-XAf{_-i0fjkEC82EJ`9y9v^vpT z-CbVWR;+kk`$|^SbIKR#V*D>zz9J_4{1RYGrdU7lV0Dy zmpDIYtd8m{#LZ=}u$I@ygs{pPi^oM-MFRk&;|DqN)5}}{|EfGRUq$7KNJ&Y93$u*`pAJ?m@XGVx3|lZy+<}@zb4f+L`+mI=@9PjzxACaBTol~ERidal=)Uip#%Su?oLZV6AY>UN-qr(O}puDGYgaHAloY8zsT@) z!|YgG!aseEG0WN#C*H?rQFsSqi9}okCGUeD0)+)Zm)PD0zO@!`e>KwxA01-$B6@#J zERX%cX2zmPSsNiJqr(c0%lyL`dxIFZ?w9awz(>6O zm?`1w#u$qXrrIUkb<*T!aG84kZ*YG{!ZD?MF#CxA<83tyJbB6>A5uaTE|}-ZQv;5$ z$&`SHZ9c1k{zdZQw_1DB9)2#UymX7qp{G0y3|vC^&{(zBBJ0Dm{CxK~(N8KW>FpHp z=XinQ$5%5fw4p1Z=y3-5>D`ecdH>;z(>cd6S|$9i;D?zl9X`LJ{A6V8w9Nmf=RkqS z6?=<*jCbalY%chjfuAieyRin^ua5C?hO!%L=26{=eiPz!Kq|%rZ;#4WT|9hib&L~1 z%QwYDeXOFMmFReXL_h;Vf_!M;sIO9faLopP&QYxw;`5M)!AI$CFYV0eq2Qjh1jTJr zEY$Y$@r=Ac_=t>8Dtw;I*h_*%k)+K3cl5^=k_XuoeFFH-(I?IzKb|myQeM1F`h|!m zJZT^rsXg~U^w*}>w)v`k1XGgj^`Ja_iQ_|iUH!OLC*f+*0{TP(eF!la&611AWLRaS zh^~1llX1AcWJ|MzzYqGEOeMn-K9%X3sHiO9K5UgI5;N-g#7QbEqu_4R|3!x>?;m&b zQ*$JY_fvjXV=&B0@!=q}_@=_FK70Alo3`AWaw2>OW|xV2Q61CjS)B#>0R4TFZ13+L zB{;3{`IL(f;mG_?x%d)FzTV;H$1Rx;dCZc@h|-@;_c0*&)T4au|L{zmkW$M1Q6gXA9%AD0w8R%@|34X{PDeafU(x8Zzkpa|0`o?g}tXb zBpd~OvhSRfAmj%qW{y%%0h<^BkLToD&_LC2*7)-bXY80;T%)LI2$nuVftm%Lzo8oTh!E{Y3CV|rqK2V89iNJ>^m>G>uGgnLe39_MSsl;ecj<3( z$Irn?p(Kb*#?tz1gILNd z!^B%pi-~;_{|2Nhen%y2HM_9tAM#HQ3Ze8X6EK+Hl=qWA^`^nWl!Rw8`fA97VhR5< z3s2%fBrwgpT=q>K3lT- z`yZ0Mo{C2O{#oBs*f*^P+yRUyi8h~~C((c5;zGr*uV$`ztb6$SVgGs1-}hY_axc;N zow}Y`GXG5G>7EYDA8?2sih5oDTd4>}1OJZtw5|2$t?Y801!Sesq@165`uI=q@q>^J zjz`K0L>u}JG5zueco*P*v>_kcPf`EGAR+2w2g(09D0@c;vhPjby(nJGu=S^dLFIAC zWE!?@HGP+aJ6^cud1YYyZ;li#QT_cZl$Ypo9QlTw&?lowUtT~T*=#s>jX(mqGdfjd zufTo?K!2Oh7BSKf=0?L=`yt=|Z$kf7W;KU|c1MPa3QVZkt9YpCrQ==FKS%gn`zLEv zkN++DCmD$>mHh+%Tdm_Hl)s&0d_FQYIVtnu-_wG=`Y!g5;%yk9W%`ZBUI$0-fVMv(Oz>K! z%dT_3FEf00c~ zEDvmKT(~e`LcU=7T$G|ODA9OQm@}ZiZ~Dh={d-q`sTEZ*hB*oc{27hMv-DLjp2T=C zXDltrNs#`}f_qZ(!l{h8c?+APZaA6YtCBbP_TfKftkFc`)^2&f-Ot#>>--01`GM_) z%D=FKULA=Psqwk^ zq*OH?#z2@E;C?6vWl~=! zey&xsYZxEE@3}ml`jxb^ z^V%83{|5B=yK>@XO!S)c{nImKuR*_;@-?~;_Pf}cXr=L-W@k7sS(W3EyUg*Kmq&^- zydM{QS06 z^3vTI9xAeC+A-P(8)3n7$ltbjnQLEB8*4)((fxGU;4@q0e0}}CqhIe7K6G%u1|Px$ zn?bKB1cqnR&Xb%?zdrs@i_cgpo`fU*Q^dD8@_rh>F#IPa{G$}#*tdO5*{}Lu#G622 z@Vtla`iM|}QDFpY83Hv6MI);;*xI%239s!1?^ydK*53r*T;_Y;yqNeA+9OhfQQ6*q zeu=TI-HBESlYIpCSNva>;yXL1k1PBA&tB1MQ;#m4Bk%vo8RwHrEoZBQBk;Fc-2fY* zJZPOLpEM@8B;2q|XC3YBiBf0>@x$0@_;9>!l(hdo8{@v^-YjLVko2mXL) zG_2wap4rEGx{T>*#1>G*QKR0;L+$Ntum{Ln=*1uB;xP9&VfbRfr(Fy-O_+7Pk_s`)U+%t#bu}Q-ZFNA*;{(!h# zsTl~dygi@8LKmxlBvjxpU7lmVtjfMRc((B>BYEL-IKS2II zjAu&Uw<;K$-gu|t2jYK>|4RS2erVs-i3DzNlfJ>?h&P%ce<6J^pB^f^`l?c|Hhz6B zHtfyjRSUDzDTla9$_7~bOpO1&e}nh4(5;vtmH8a@O)5F2msYRp7w5-3m z*IHFnEWi3Akt+;@F?S-#_U~Df^R_IsBr!f7C3WNp!1t7<&Hj;fYC^zkjdE?|k8z zKF>QSq9%ubd~GZ{KM-K&>n|hU9)0Xe&c1u?wdL}C_wTjV{op`fpM;%Hy6Yts|685# z?-dq~$b5HxF310GLmu7|hkq|?&-~~Rwu|iP+(h1t0(=ahy)fW=^v@grUiT?^oCWi+ zL_{7xE(R_deN|zk#>WEx>$+}8et3!EiSF!C<0l6{hj*t{e1YAKc$u7d0r(5CzNlO2 z|8_0x=bZWVr}r7_e(?C?{WO-+M@RnJwRd2DL@$y22^17a@Ga9n@jht)7WiM&%5RkQ zH}*Okwj(LHpOwQMsq_Q8*5G|(cPsg2f#2KLPDbVZ3lN`|jQI2W&y2EA7Xp5X_vyo_ zzH)L8O;8ojwkHo~5s}A-i-Aj)9*Fy^7@}WY{?Cs8F|m5g2=zxINy!fk{z91l${r?r zArc)_1s}e>T$01&)+Y5-uuqu}62W3F$;dX{7=CHbQw zY1caUk0^fT;FoxNw;E3^=m!P@>g4@=i2Q@gl)r!t>8qS$*uRQK|F9^epx>Y@qLpI z?YUmU&Q7y7*gLJ-WAwrP@9v04;lFgpdyTUj1A)A~pY5+azh)8f9>WJ>iJM6yp!F-) zzHHc%KXkFsVbBm9+Cxe@x!vGAgEuJ3z{KJxANFz}Y?^>XWf z;;v@aqF-ac-tAKBhwLS^ADLJu`GeN87A^Jd17lRLo_hE}HGjs2SfzyxZ{+=YEn}}u zO+AI!KyN;v+SGb_==_x+M%b`xPqQma-#k75b)(PX`J6Sq{A80Xf5CuW{rUO>KbEk= z85=*HnNjcthc6pDtpXf*j~;rtd#j4qw{d@aJQbDq^C4aPc7NY~tk!Wqyi#X-_YO>C zyECuvOGIS9-?RMierumQpT=T*wOxLsrbgMvi*_)!uFIDP>~}C=ho=ZRQfe&QSeRlq8arKkx?F+&G zT}_Jrot^qM{e^|fK0$nf27iU(e`^)juzjM^S4`*!iPp9@RUh~}v7SN2`@Xr2&`y_M9_x~GM5AamZe))XBS`}G3qWlB!2b9mu zY-!K(f50I7zvhPPsjn%$XZqV~PQE=^Jjk#2ZU1`n0o*}Ez&+pPmd8IaVGP;jMa6!+ z9PE3{_Z?I70lb3N3p}(|@*C|p9gp7^m9W)kXpy2h%04jqO>Q7wpb_IgohZRD|4@2e z_^NZoKY1%%pGC8+g_Ehn@_l^3sqO9e^#KR|zHV%2BJ&;i_r@YimnwKCukOu>Uvkz! zKiJaV(HL+wlz^k@xIaQZM>oB1=_B9%_jdn#@c_*xT50OKE%}3QHbRl{@w9}Y4>TLo zBj1*=4SfL1{SpcWzd@ZYk}w}IR}DMa_<LH#?1TOc!E4-J4OP`Se+{XDhZ+Ki-Vq zX!f!e^Z%HCsChE>MfpCbPlvxUnU=6I#MXEB7F0^u9@W<+hyDGNZSwc$?B}r`^Otej z@2|k~SlH`~P%6H*jjH4Bf0V74{Cdmv%|4L7Ut-St&g0_}!3XUBDy$JS>U7q&HKXid ztCF!tQ*mW4+kIv^w*OG}wmx9-_A?K1$zS@Au_{v3Yf0F`dU~kS@$7gSG*&rFT7SFj z7TM~z-2WQ1`Axq6zXJ0WW644Jem3Nk!(Ew@usO;qox~R9 z|I=Zw+|j;P=`Yix9Qy-&rW_{XvTm*gKhe`r~bKERWF_4RZ5UzGU{;^iDnpi7wM53t|; zAodfa_419zDg*xi9>eSY0GL|$erErl6(4jXJ~r;Nb+Z4x6iHg_@yEB{En%DFLC$(5 ztBSMhNB&Ov|D83M(c82^&Hq8B;QYM7sC?cWwO17u`TKp+{2=XrBIEza9w;by@9&2y zJLRnX@n-#%&v!9!$>NWqXYesYoEXZK^l$HSwA}T56d#uxKS%aHmJi=2?}vY{qW{G^ z)dFD}PoYl7Wxff1Od%i;vw!aV-)E9$`PS~PE^j>bY=AXunp?8ua`y35_tq;|xRHc_ zSAI+c$1IH3;iP<@F>aN2&seHG4Du>h9+<0j4a=2PeW`xCBgMt?d1ut<+5Y$s>LqOU z7+NB6YKyF|5i(hFlHRQ$eoZd_+q0zZ!b#uW?>)%tdJ*s=-=~jTy!)8*poHyBR6l?Ig6+_?$g&)N;HY!+eu`hn z$}5icARMBbBo#$0Sdf=k{&UT_);E8@hXF}%d3?Of_`qBmCD|X|Y+AEm+js@S|C5qm zoKd}}Yg6a6giVa6I6gqx19mO^>pAf=HfGAB%lz|e|7sW8{Aaea0nfWT=FoW=*gn6V z##4GX{jFJpb4;>H*5}ROY`h}Jd3K>i1F>v80PL4BTU+M4E5-V8zW%}c`_y_MeMm2F zotd#@dl2u_oV;n=_jl|vS7E)6@@I1BGhK;^$!GxnKqLeE8QhXdJ5=)m?0M*LJrtOY zponaGtM$*{?_nU1FG&gSI6gF1t+nuL3?GP16Suy%fM4K`F0fp^-h`0v5bbOg=SrM(NX!9nyQo zA3deU%i3|9J2S5Rj~#PxZ2W4jIhgQM9&?)S3;3<{f4$BAr}%|B$TR3QvDZvx-`kiU zT$;(K{R{v4Ao(w4>x8&&%I49+u#o%eV~**UGCtGe!5`o%NCh0&&MtO%H!j#_#h8ol~YYCe4CoQ(`|(K;FMMV z&`tjQ-RN_A2;r`Z-dP31c_D)-$q&ExoPqsv{Pi>c_L8x2ICxy`_i^+PWA1)<-UIOO zv(WIeNFj~&bQ%D!G_}^XS6v}%d9nJ7yR(^M*PC#?KY>pBBR3U;n<0wd&4|om~_?8)jw9=8Rocde!WUP2Y4L8hnCvMg^@u@XzP{o0HhT zY-~I&+mp_GcFeGXN*>^Rbk=doF=hTUu;hh^D}87^^aHFfh{}BJq_MeZZn2UF^^CuR}y7Ttnvrr}qRUyyAq} z9A0|Yw1fvT+>M_vW3%vq)eq~VI8dmnrG8v!eDc@#e+>JXKps@Y)gg^bWEI5rS0-pjJ-qTwT7zKenPFn$pc%VSSBvun(*JEPV0 zEiMVZcG9U9qNh_TvGe>GvoX3Zo_%CagkEv+YHX5 zj}!$JKb*{5mpp##l+qW*ri^OmSa&<9JuGHL15Pc*-?j0{cb&f9Fuz%k{X*dZ)!?tE z^G)3OLXr_rPU)e!{`7!=e5hu@qNK#v>5RU*D@Pu@mf`Ei_W0*}9?r0eT>lB_3%Td5 zW-=8U_xItvq3r$#uR=b?+grOx9?XY^WYPJb!N8U8I==Gq;?kBE@lQHTB!^KLUJq>*p%WGRD{o07v8H~a{&!%5xg4?ziRx11dbjIOZx*t^hoyoAe zNP*Aqr!v+$W_BrlpL^6=MbmjmjiO8h_02ls`{VKXpl3=nn-|Ivx;Z~DDf~h=pcO>b z25NO@tm#^bABs;1r~D0&PXV8E{NoWsCc`UOa8F9!e>h{WO5AEF{fEvM9?bEdyq2-o z!5yIF=^4n6E(hnO1!y-UvB>Gsu^+OxzK9TXsp5<3Mk!xE4-fMHMa2g^`2Sj|!+z8a z&wn2igC~rN$z-@#(qAU?kIC)5&T$Fvfxe3AYsIfO?1ny?v)=twCbT*6(Ezcv129Yv@&L zq18^c;!AZLvM+VD#K)fj8?gVC{G{2F$w!KJ%X|y*fYFpt_$qmdvEHIcROasl{^N1q zp8Ebt^0)futDnyNWWwDq*|iRY*a3a39s7|45lcii1EdRM4^Q=a=vi3eXclS!M@lxm zTlmVq-^0K=hJW|`T8{ngosex-DgXV+j9F1!?5|Hbl{vc0w4E+Ve~ZEIt*t))Cqa*J zUn_Yr7xZdkL7u!{2ffeu?mS_^Uyt>#VK*NUdwjL2J^joJTj{JTih#8_4}JK`g4vfl zJ=EeXG#>D?7lJr)$XXx| zqg~C}?~aYVCaLiqqsMHA=ietOU-rN`!J5LK#+FydT14+ge$C67j_88yhL&eCW}QeE z_e%Z#2kSYTnmRHe>E&c*+vZ&V{S5ST2M18fe6|tv)IK#S;dzf?zWW(}Jsz)veV)Vb zG=8UqQ1(L==n>PHq0mkr#))-cZ4)2Ogv zn`kqon0VG+V*3FGcSFC{G%QIdFl@2 z!+0{ePvxIr8;j9_68^X63~ftJ{KY8bM|3cilKGHFo6WoSB<1|-FEX$f=)gvJ6Y0El z3-KMlJF+M5PrTIWua-2NWUGlhlPQUQ@#86-&3QDf z;8)<^XLEdiz%MiAP{o_z!a8FGxO5POd#HpZ`b9 zM_~R@z3>;AK=RnF-96HuXztQOYuj5BjLl;;3q*rnVTP=iyLzd;C4q)T4%SCt{_);7 zYkxl9!vMPfb?MyTiWT}bG~dg<3|gwIh{c4}Y_gZPJQbDx_*FC|RHS7zNZLlxE z&dQ&tZ*=1clsx(IOL}wf$Q}i=q*b0PKmH$-KUO@ZUii}~#3yfYg7cv*;7mr;59cvs zLXz4Nz=@354T0t#2y~PG>m7l8eYk?h>S#a5W>%QVoW7g(T7ibc*mBI+%vt(kwtA@Z z>(e_3Yg%2M&@0UlGZRc(UhlH>7pB-Xh<{lo`TNhO%E+>nTw-QY0y!(&*TeXN!D>NZgUw%^Z&yNlo*SvW5-P^s@ zRU*vS8RhBpnIrDY-p>2H0{H9dTe70T#D4V5?#76z1?p>raB6KWRFv*w)fKS@Alcf; zO5%ubll2Qv85QY0{`qi~6TCWz4R2(BV81!+f8iV06?7g><FW&V zOF5^q42qlTwy{ujS-*<6U4Z?!ot*M)V1J+3dW$TN;%jFl&?uq|^w$al-W$!|M*n0H z{yKcUef*z4y$)ks;4$nca(XP1l<<-y3yBO<`rcO#5p0r-aMNcG zy7>xbw0C~k1KeBPNb}VPVGTN`DJ>j3%#xb6RlfFYkKgcSB z2!N91Is44&#IXl02{Xu_V7$ifZWJPN!bkgm{*U7LS7)lc;~%Kfn4`;3GZapI3qT z*ifRieNy7X7&R-$$NYGC92^j*@^|r2VvE%Ogy6tmYA_j<`OaRx`r9MZ`z35c zKF@S-IU`{M+Bn!%(T5KD5n>Piykx+CB*Ym7Gspu0177CW0@Hw*#25GS9qJFvC@~t3 z0$03+{k5|QJzIZev)?=X`*z!#wGSk|THI(u=Egrm{CC^qSamjUpghM-@FFHwbHkpy{vA0nZN&ZMUq#T zn823xH^6V;UkO4Uk-hCdkMk=xL<&dL`cXcL^Q=ytQ4i>luUq4jQCR>RVj7N*RUO2V zX6Ll&_ouVhsGS^Ucggz$V`fis_(65Qy^jyQS|r`?kS7PN4OY(lJRjE)p|9+BQ8A7Y ze|W3vAJRXLp>^K*bwQUNOXn88=lyq=ntXyc(UlNVJ_xa(g|7Ip00(Fl9P$~&lhxm0 z|8mF+NgVigs>pxfUqBQXGgWURANn8kJ(aNj67v@dbnS`#MW@vTk}jDeaaE$TiEB9C zJt=RncCvLFrv3BNImRc%D<)*Vj`v3%_4Ns3)F>}n>IYCd515^and4(p9&p5mwPU_w zMOJ~P(K+~SnsoIXL1;n-v97xzJJ_A{W1^v>rd>R zCeCy4_nXpDKhyE!Rmnb@IkQ#qFQf4{HR#QEqf++Qc_qSQ=g9gw{YE*~x2pO&OCT@K z#8nS)$csqP3tQ#=BtMRAQQ3mdyS-jv8~wHE4gHDxSx&wM{VoS?u-8Dksr-fp3-3SH zk$qdu!T`9RwRLAQqOoy4tb0XYlFsBevfPx1B_=K{d{klW62loMvVW+DX+Ks2^p2m( zekA>0h_s?l`|Cu%{(20K{a4d_hUpnM>7#a4dc=o~T~@6a_T!h0QGHc<*nNk4KO3?- zx6iQ@y<7d*Ptoxe4)^`>c3(e$d|IZs)g6D?oSgku*e+*D_i^Y4*+ld&I@*;yA^l?M z(vfkQ&o;xJ9yuXFfjujjb*y`KI<7qX%TVK~hV=aLeiUe`4FG%V>wUdh7}6F$CjuUx|T zanCoB^&{;#Mst$u8LL#IBgT)NXw9(Ca2Ve-mg5iBM=hQU8>7%La`HL!L+Fc=yak3h zJmFZw5+-?&&iMSwDmm&ml9c&u9cNoJk1B;2`aK&f3aaPXF5dIwe|X{B@_qyDX>aeg z6kO}p&*wL^uV};{|4Dzaa^(Zy>(laS_+v*gUXS?rHppJf!Kbm8RpN$}e1fCBXn+KT zx!1mVm<=n10Q=8X4qHA<_J`%1ies-F?3U9Qg!csNYu5@%vyvY2u!n*7D?X}YZ?q@s zW30j(AD|x47$R0QunNLYN;qph0<0ILAI8%~eUcz4Uktii8M>DU{_NVUa*ivcU*pTy zhrv%G9hoDaxA&Rl>5-s*lZrmHvS97HIsI8mpl5m2&i3VS(RH zb)?k$bjYXli~e}-K;Icl`|GhSJio+umkW|-x%$R4d#&2xV3E=%;NRTPacWq}Bls&q z9q?bu`kLTB><3{<*y8Z7riJo<5`F?-dcIWV6a3<)4HB&38uW)O)Y!0~!~p-wmo+q$ zlt5arV_tsa3MlB1#w;P?BccJiJC#lUkmh?|3eJLgSRx{i9~T3XUL;!124l5j9cI`# z<=-2a9hC%2=d-25k)(v#4*0{bpYy1Mtx;oDGU$68tWo>sV2=OE+^d&EVNm>R5P$oi z;JNxkO-%rIv)0K}n#x}u)9R@{qUmSX%J=DzFA;3OEMaRO8#vwHcR<4SPTG$x>yO0w zQ3m))+<6NGRs(rds)(P;Zn;I??)qDor4=Yh{si}&PRT3wK8E$3BkB%ouif2kg%k|` zBkwro&)3j?H=-k}-y@kg{Hp2+Yh5G z`?7{uiQ8UfObE2M)*r7ie$O+SU3|DtG}M$Z(obA`L_PnSQ_HFS)GRltA9*;B4`ASO zq=(!()9;Hievx+r9|Pqh;70dOn?k(gI_%H9$6p_1_1m?*BPW!>ZQ#7fW2d%k6+u@5 zFw(D&{MJ=hqZl{k)}1b#4;%oud!?P<^YYpAeSiLW9|PypfBw_?{<~!H2fcxktRL}z z3*vul4t-=iIhY-y;UBPh-?yKCQNdNPpS#=J<$2Ncd}+<1E2%6>vOEvU!+Cs2O7On( z__#FjQAPVPwP1D+a-nSS@L|dCX05^c`k$xqpXS3#ImY|frq;&2*)Wg4VNb+mtMdIT zF_EWt!a$xLE)#mFf*Fw0Uli@oj6E4_T)7yr7~3(FUs#QGh^ zs@@@gl2&oF)_rr#d;bD={@?pe|LYsB_#OJjxrlCBsQAl+^Yrp-=|$68=H5Y=(h0wO z9+ntbut%6KkmF7``5OYdo3n!X>q$6kK8gMT12<{)UJw5r`fu%E@d1yUh1=iJaPfADk5_?@M4KP) ze;D|@Uqv^G`Dc*Nva=P`#Xry3n%NB{-$^X&Sw z1Jyb!ZF||K`eS}~`4O})n3k=HVgFjZBqL!Vz6yE8l0N+ZBR}$x4`aVt?1!^yeN7PF z7^MF}@*}?K0M)es`&Tb^<;CnvlpeJDE7p_5*1K4Y!@d;aKOhfVCkEZNP*l#725J_5JMSZnsJ^p6}dQZQN=UwZX zv9Huwp(YgOo`$d->kFU{T)p+Rm#H~1vAp5%1ZP|Zu;Cif$BZOsz$6d$n|^@o4DhwR zIGoI`&u{!V=wWbz&Of9SWbXI@m!1c|jrwN`I468^rhj4wNkm<5LhC5~?^Bntr6F&1&gs}rmfzA_FnsBc07oQza@S@H7A|LkN6Af@6^LG#8G?!_`>#;33=Yd z1mUl}8C(%yvp@#lTE{}cK%n@dVr=>eD=LfS@|FY;j`T-Q1(YX#@EQ$vL!Nt{F$A4=oKG7D8t@z zYO!9jY_^&|u3%g?-Ti*A^p|YZ#cGeMPqeU@h4sc|v8KI}zaINJw1Bac1jYS`@4fcg zZ`=oZh{7UjTzHUcZ5S`S`UTjD9*W=%sA{So*#?{qZW2xC{bu3(#I6m8qe=NfeJAD% z+onDu;RT1F-WK;d)c0kO@O8U5D_tBeyx918&zDcqU=6GK*FIA#zsFGWpfd$~DzRU! z_oVgFzg-rsk^N!rb$C}-S8EV`L3`LboQDDhLB)?}>u9Gf9)Zz-C#QHpf)18OQlBOncJMWq;V{kHmDJ(hqI$JI+&{i@uM-OIc>^)XNiF+T*f3 zWp8O%y`(dJ^W7%xuZDPGFLC&1Q%|jHlI3H6uJU02ZFfqTVLe~lM0j=qMtl1F!D=%U zn0=}Gr`|*Ihf{Ac{k9z@_IJ`%|C`Xq!f+7D{^0{g=q|gn2mS9RT2FQI_GiCL-b6Yv zl&o#|3j!`J!AX%CG#QGsy}M(=-l=PwpV_Yb@2~+`PtO@8Z)kn|-9Mh5_IiId{NqMw zPH1jk-^()CS^4+v=DWKgGVK%FctvjiGsypSo2L6@|I_;7^*w)jpM)LAgS)pMn4X0x z1v)SGL?3v9`u`2}q1YfAW9&X7RJ{0mlk$12SJdu(WVlzsJ)CtV+V3S=3S)-N!1)M) zz}z?2FW>OKH@-g)dl*n1^G1Bpey%!eHY*L{*DBc`B=7sNfxU#Ozwi6d4I#kL(8VmL zU)PS^apq(&TOMiW?mMVF?yX;?EGhs0JM_m?$GXk3JU(P-h!;ysn8yE=IPeJipZnq1 z&+)3O^7|iV(R=aq-x!z;`ky{vhrV|0jmq95dHg-h56J#;V2|0I*nfk(0Z7y6uiI~b z5mq|&dmuZ10RD#>LD#N+gycW@AISr`M)0H^dL9!H1XHq6Ui!bac}o%jTR0D)u&}>B z+y6mlgRWisTUX`ve?lhGS^3w?KJR=DeUBN0n7)Hm)YR-d;&u-85BeAG9z((=__yP! zhvbY?^WX} zVrzF7_P2IZBi3)n#X;y7L3c!0TxXUuD1_POs`B%&hkGkNxpo|9hC3eelmutz7)3_^-lvu!gmK7W$%Y zJgLd@e-HE&6>%kB>c@3vZ2Y4?lKG#9KYDjK5<#>Lowqtm-{F+6ymtssokx4|$T{KX zy?lR*29D(7*+a&vBLg*RLzxF4$=ll6RR4c$3fndJzn~`E3X<^uOs3PbfXM*#JqP~3 zD}x0Jt?I`c`=~Dc#vcsn z>}y~9*%8_MdvON0`n*r!Ti06^XgU-;9iL|L;&ayO4}B;amHc)P{g3ku z6+hm9_>zwJq#Cd1pJ43SL!Diu>yrog1pK-GnZBPzuir6mz;}%1qcC6n(naXL7_*%gZiV&3aLokZ4+zTawnDt%N6m-*DvlKb0_@Ux(RsN|PI;FcU8Jj z_-S@$2bh@3n4v=}4=ed|3iTBUrskv4sNbDpiz(~-MaUx@-yD_jhe03TyK15x@l7sG zKYY^CQf*!Pslqg0^{r+H@niuZ8*riO|E`pWh}U2Xt-H`QtscS6NdJO7sUgui>F?PUy&+uV1I$5f^6kcyS!}C6&K(CR_kH#D~NCF z!cUx}B4|ID&x~;vNwr&4-xy>B=?iRWN>*Py3Hn&VMil(tr#R$8_X&C79>j0=eRXUc z^x)dG|MzY~i?992HyB&!jv#X$G0OwdNqQwxko{=2MRuzq3-!az&&l}DV2VJl)6pL< zyS6XsM~l}Rm3T@OqkjBn&*#3_%dh?E0MV=21h8T`8uk1^y^^&i4{)r$r?h0k);iuT0J{vjLHf^M8r)l{o;z6fMVC@ljscdS6&^ z_&L_sN1Rvx3kO4gr1_~{_=}rb_ueSm8y+WG@z2ws^BK}~o<=sAn7>{*m_i7*mu%!G zx;v*OeDEM+eT9)^<2>(*HOjGH`p+<*RpVX>C++e=aSC29mtsnt4d{=8vbJpVRQojO zGZfDN{kUQ;;#taY_8DxJ0Pit*@#5>Q&EBu=8PF^6TPK)!_JLiX4|{Edu>}oOgIP(l zd`4_cRA(!=>ma`-8Cj|b{L5%B!d;dB6#Jc(Z-1d%$#Vnk{m8e(p6ug-&J%?&C4U{w z*9qE>5x-69V2bcV{01v7cnkVFRT$}AqX+1U^#0qnq5o}a1EfI_6N&b-et0I)&06Z*5=_i@o_f@ecOrk< zU5;3+8zRp8ua#jH7kWU>C`U4(Edqlf=98X6f z!^^0?IB&jVzK0G*>&KL`gKIDM(F~2B&Kuv^A}-nIVMkCpO5QDeV+Eaih1S~%jHV<% zbn?QiXr;AEF|$rJk2e$d6*Z070UjO z(tg^Rxb&w~i%)}Ia*iVxbbiorbI!Od!2th?b_aFvl1}|A;ts_3iUPEQ{HwHmoe&G> z0mNY(7|+sJ!;tL=qW?0wF`F*g{&|<{r)BqJrupiaOApw68A-<|Gv^kpe!2G(KQ`%9=7Qz) zJjc~2%E#`{D_j`#2(t_4fqDBenxI-EOgUb9-|%m?y_XC9(r#E3--i7tLy_?AU&32i zAOcZlam3I5*44^ia=El8i~jQ;k1w{$y#UlV`Fz~E)jttkeWwl?f z2FUc6VQrO=Ph=zApTUOvY(aqRq5qoHLu~NQ-@r}Kn;RF+-DW@{zhnL(uG$Y@Em;V$ z6Gq5R4E`?FmC{4-Z~W@R&v}4|2L5n@vwg4KpB4)}3aePnLq~qYAMjQD9W@9^mfu43 zsbl?M9cR(6Ii^=&z4)hb&VJKB?n5L`>Y*>(_;;cJ_A7Zz1}03ccya9CywZYf{_fWm ztIGHC{r8;(*8a=Uk8ebt&YCz*_XPeiznA#NN9Si7DE4Cg(FeacN&42pFnDP56SbA5 zn2q(!UK&h3T`t>1S8{)!6I|zw$B2K{+H@L!p&_neyzHnR>P_|NvOc9J4DG|;oa`?n zYd$K(gU^}evtNmQhTcUKvuxWBIDV*Vs2{jUNx_J&;W1r23wu+yzqUh`zb%FH6Ykje zXBaJj@mcI3;-T(~TzT>RZC>^K`n>_hY(34_Rec5VeiKht*|NR|e-3;5rf)nzYXcDj z9!A7ad0@`9D*jis_YLK(!T3lYW7H~t_1{1J3z|QMh7`OX`tG{H|L?=u+u6Oz!KD06 z-)AdN-t$i7Q~VmmFnk*IUA*=SA0*j9iH(}<6F)tKSu?6@klnqx4;mZ%DTt*423wq+ zX2`IrR6G^Oc|L`Y-}22UWYuiokgsFx%0P%@oSWXM_MG$kV&D#ZO!$v9gZ9Ai64@)a zuD|o7%O9{bt(_S2u3Pj$w0;fEFf+t&ReiVhzsmdVot$0wlTF{G`C~c{coQ;QDkC0LE9hRsNy~J0X_8f|LdkjME&&n#5PuWS+u_i>s9et zv74>O`M0Y5e1M0(`o%vP!sy_B_y7xqSAFD0@Cxmar+>Sd{SJ;7SNHcG;%xZ9izjh^ z0pwrVwu5>odd>g*_jkNM&y^m)&9q|gfnA(Aw{Gy9nIMAa4)M?<$2UDiV;9Y~8teXw z@7gmm0{K@(ulRqT0Ke!SzqCLeY&xm4srAL*gZz&Y4b8`X4FCS8JqF!d3Jgw6g+IlD zSJV(p>AdOHd;IM^U#p21hZ;WxkK!yEzbLIdYG^$@e_G)J*dgWw^q2b%8AG)8oYIND z?ajG$R=*MZgwL9tV@9Z}sY=nq&Xb&Ne0Fj_s3A;cV!pOw-lkvtDU}t*jP|^v*ny-V ze1u?1syq+8uy9?KcxgNczr=U9(dt}E-#=-Dp7{9Z)%@_hrx^RvrzVRUUG5FC53I*} zViM(VRv&29lw|#JHXiAtO*deEGSY5j<3EJB9c<+$_g@3TD#eVhp+HSfNp%5u?rr(Tfa*>ylW4X>~_}Bf&{vsRn&dnMcA<>RR# z9(sKD#Lt7-3$&i{qYu53h}L=+u-+nc=H74pSl(~<>!By_4XgPM6Y<+aUp(&nD>0t4 z({YLba9xV}E*5gc+@NgNt5bJxmcOY5xxX(YtkqFzjQ#Nra38(}=&`B+w1N2wv23kH z?P-|D7)O1Jx>IO=gDZe_z!TArJdEs?C=WAQzp!%c7v{S6<9WhoqE9>s{VlKvAa6!_ zOXgyAI{>851D@^ubpKzh_Q_XVu<~j54;}bfg@O9JI%Eg!hk?B^(4Ig}z{Ul8U$z0~ zRG!9S$9tadLN4T+ zhK(2#H}6Yx=sX8CJO3zvC8j^ z9R6@)7AODEbFey;^H9!Dw;%~~!8l!bp=Vp=A`>(-OJF?YV&MR*c=-5LuKrH@DXrKI z4wN$2~)rVrG;@)||icuAIj&ak&$uj(I%tPNdIFkIq? zMP>Bad}-xSvI@0p!uy>KHed3?ulFqRMZ=pV~JbdL5YI_-EcyOap84L#AzP-cIA3AGUy~C+>yO;d!1+YK* z^vb{d*78Nrzlk68{^b7hzpv6w=v%XBOj+|pZ}Sx&I=IDa{wy}{FaI7A1&DcT_|Vhi ztARh13|pQwf}ae1y4m=!GbzwE;<%rTf4aK(%0Tdq<he6*p$3~o!k5Kbv7Rqkv@3c#;REb z0SKvCn1R&O2cPTwjVfE8&uSU3VLUzFyRP8MpP9%jtq%rS*<<&wv#S;dOG<(~$a(O; jJ@H2a{J??I5>`UhVTmWMdaM7%Ub}o`lTe4}mB}iB!7-VQ#0yY5#p(XLQhqgo=vdDpw*gM%|7vs~6bIM#6 zGgx4;+&M|wiv#Q>x$Ghckc3Wv95TlM+&$$Iz=!oEK!7nMM`|#;Lq!-uCDst_o}Mvcl-A`8zo~*d7)G?{DaR=B7REdCvAMX`20RT-!7S7 z;`6Wg{2HIvA8=3LBgO||F-$M=5Rxz7@d?pT{wN=m4^gYrT75F(&_2+`2|LHVG32oX>|glK5~pnOn1ga{}fLNqjgP(COhLIji# zAsU)LC?Av$Ap**W5Dm>Aln=^>5CP>wh=%45$_M2`h=B4TL__n3E6s>ng1l4kU%bEFKFSUmepNzk zr^ne53{1^r80GUcM%wu|E#e-5T&cnvJbPH?=&AzO5YgwohPDi zw|qrAI<$BXm$Mj$*O>6e;;a4zfhpn{vxGYWUv7Q#_}0U&5R82P9M(1Ke1FsUJwtwy z0Q!pAGP^jL-qOul&D4!8@rehEQy>1bte;UwULI$EQ+H==00+~9`1cTHdj$NdQ{Of} zPkLs%EedCT@wb7#nch|0>C;2GLm7E559Yt$hy1`@;q$70#Yc6mk7vxkze}09HT^@j z`LUOg-@k9&hxzjdlpFS$49`e_PVOVWw*k~8ybm*z^y%NeL0SLSxv@+HMD8&_t6?jf zn+x^=z5+b#rMZGSes#b;W4LT#vm`cOoE-;0|~3kbe^`sZG@)^84o56piK z?VqJT%l{|YjR@ucHM0-eK2KMlH`gtF6Z0?FK2Efc9%XSHtNptSFVFuDj6K!IH!A(3 zPqh3GvVgq)vv2lr!u~&;^Y?#O{?CK`cg#T__2KJKznPeyr*gxt3*Vg{K zCQWd%zoS`SizeES+P^iKyu5SUb3U|K`&E(F3Ucf4S+~Kc3%g`^P77?f*Z$>U=+I{D=0B`fx3}VSE3PA9{Sw z8s4n<=lEZP@~&daR^NX7pV)uXj*qV`)YfJtzHhC4QQH63Y5#-4An{h<^*i^n8xi>t z>bnN$q?qfrotkapWh(DI7k+U5o1KrhIF2utZx~(b-JM+Z@>|odd%zjP$9NFVA2g36 zY}#DGpCg-IutLWFBz;M5o}M#?KkfMfNZ%3q_j=H%968^+81K1n>eO#DewwGx>8muO z`Z^h!rA)W1hgeiaYJ!y+K#0cLkRP|*I5_KC!6P5JAQkYB|^@dyz(H6K{|H%*=E0h``n z_QuP!u)0;0+VL*Q|jKo)6u$Zbu+-e9i4&bG)RChtm;Gyc63WI*5=Te?xf{Z~j{@k{q891rhe~^_Nuk zNXW0^p?HJ{yp|7%+2i`)#w78he7*c9*$WIDmeuTKeS0oHKa>wME^i;o|2HB($?SF{ zJJO>_d*}8gL;r9u_CaUC#*nnN*^hPnGJ|BO$+vhvE?;Fpdw+wCUE%K>ZrWtlK~5 zGp0CYJ~Q?+aL2gxsktT+l}AvX3$gppHcq~ zFt2~bZ_e=J?%&w|i{)oB=v~?Uf4H7cVpUhh`bH7fH^TTOR$$zr{Psx5ui~M2SOjcu zpRA7`$FtwwKdFAgzQDAUmYJVLwR_qg=xDC?uJ#@x;Q8<5%?@!nK^Z&qb{YxI! z{(}L+^QvEAxAupq{yh`$+cZ0NeLsxvHDuGa9ZsO%9S<(;3 z>mJH@U2%s0qwMqiZid&-9*xMy*#`yr%Mtmce?Hy?kMNG|^FsLr-FJQbjO|Rwas$Wf?AfWp7Oc=%E0ONbGB7Q=9D7_aCe0e&~ey*rH_5Ak1x;pe1K`^cfNf93`c*COuI+f9vKp`P}#*rB!GZx9gsK9IhAnWnOW{ZL+V z{!yQ{?n?##vI73l|7m56-;wZ&;TPq?^JIsH{CO*)SEi?f4G~1r_g}AX#X}HKJUkN= z4ssS??)2SnjN-GjG%6R}8wLLjtXD$3%~RqXFL`}+ zxgY{2NTn@tuRf;C!-pSZzm#pee$ru9t1X^;{Up1eNyPPx53}g&PZRsF;CW7t{qsd$ z&f_!2|MhX-sRQvQ?CUW5)5YqY%bcIOiicI=s9vd;>wWO$(Py9a!sk;bp-f$zSq|2- zNP0a6QOD}Mb+2z(om=?%TW}n%e{q~WfxOm`Cz7v!4Y`ravi`=hThX8HU+ckxiy`O# zVrH;e3fxoc9+_32AC+!QeSaO6gAgp>Lx|6+T)h}T8S)7C%BBc2ZL8L)r9 zKiOectzK^aZ*WleI1}1`g5#p~T?`NUZJEeV|w7(xceE9Hf>-$9b&^=GC=f(ZNXahWaeMF?old1b= z%Kb?Xvpd!5rI&}+`cVgo(yY$Wz@(iS4x%7-Y~p$QvHwV>GgU^Y2WOdgwH$7 z?l%W-y}WVhX}R=%O#QFG+NJ!zZQqB9vp&0XH#CH$!Ncs>N=iR2C@%D$u!^=fHRrbip?>IcD`?@WUSRXmR{)hQ3>s!-* z-|{GoOaHvPQ}?2O(bswHpZb^j)@;Mh|C0Y7qdj^0^{q+ipLh2< z@_)0<_0o>ATJ+r3FJ*mm))!&PI9@HYzu^Px&N5u;TkoT-Z591LvVM6~)BTHPo?qyX zNYak2|2>Urw^F;BHrwZ=y}g^uN7)aN7+Gyw+V8&wxt+K7A7?*+95Medr4jkGxS;!4 z&$|A(S29oP>q6S+xu2=szvL*Z*OO${(?9R=+qe7Y(4O)BhyCWxTmD1$*v(e@n+H9k z`ga7Iq4y8&m)i94Ik&!D0C{`RuJq_KKS>7Oy2^QbgTLaRud*O;X?P@N59?=Jdml98 z`i1Miz=z0GZ4WH@P>B|%-u^!KeA@;B_u2n&lsz?nw}uwBrN)NT=S=z^$p4obtn%6V zeEK=$wjF^%|K_WoLAK8Je)EU7C_8t&FQhLiFU$TV@c+ksybTz%zj8mrqwJQc-kW>; z9RQbR?}g{>L$?R$f#QBwx67sTxAzw8-HF5g0gMG>i!k~0tK|7NRR4m&wDfN_M6P0`&QwiK-7GpnOn1ga{}fLNwGq zln=^>5CP>wh{oLK4~6+lrZC@U>Ha8RHXa0W6D?F-+y3xH6GN6b8_l;z5aXg;MxRql z`X4K|r{2Dlq}UT5d9#H5C9%UK@m`PX`4F){AMka0J~Q=_{%3EL zex_a0f1KUDdGqF^^h@f~I@9y~`E$Di81ET}?}_lDG(wM6mG{TZ^Y5>@Z_~dA{hvSm zNPgu+eBFgSeKMf9Ng4AAuw$4Ux%(uU{dHC9zn>xb7oh*dzT<= zcs?%V_(Z#w>Q?`G>(uG_&aipBslCYE!TlZNemHG>K*&kyXZt!&!PAEpgy$|@Sp430 zcualA#7s}U9w(CiM#H7g!O>U}KAC^7LiZeHBJwbm!+#RtD}Q`KDQ%a*)BP*R6+638%D+-PC0J=&Oc8({^xzZ9gmLk zf%PZ07BjsZ6VCGVm2xXxW%=RV&-;A6Ul6!5`K42s#@92~{*JtV#SK&=U_WrNb+ZQd zln-Ry@uv74pf{1{uTcMd)%%XT4RCx}KPy!*|J#lZOIIm>kzoFz8(-+_V_PeB{Lnh% zw~E82<~8x-v-gpz(dQ5AcTyi`eUq4$ z^zH3^yM+82=VpoW?(S|f>HhP&%WUJ0tv~-oZK2dfdBHaxK7Tcie|FyRC*8l7K17wp zm_Gxa$jVK++FnUpLwVBuSH%6{sQpyN+fx^BH(k^CC*TkICt^O0eaDAyuJ5+eR=VDx z{3m;R_qWit(K5@H-yENL0*^iO2sP$?@34ycFxR`_{d=9x-UlK&;QPMxE4^w*3T)guQRmm6*dNa d!uwZNWbk{|{z_u)hER literal 0 HcmV?d00001 diff --git a/Textures/Icon.blp b/Textures/Icon.blp new file mode 100644 index 0000000000000000000000000000000000000000..85591c8b104b107066266835515223699dcc63c9 GIT binary patch literal 6660 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 N6^7-B&*F&(;6D&DAbbD- literal 0 HcmV?d00001 diff --git a/Textures/MinimapButton.blp b/Textures/MinimapButton.blp new file mode 100644 index 0000000000000000000000000000000000000000..442693cdf7c9e64e1e47b60ebec246b36b21a567 GIT binary patch literal 2564 zcmeHJ|4&m_6u<2tDIr-dwQf!JOCM#-nk}(ttGL8i`LYd}V0pLQ3L{XyY+#l!h)D+l z3}o`vF*ddcm~D0_Sjya{WQOo1V}iqpW@w3?LTETDs%L`pkv?b(^IF1uI zUH@4ucl53SaAJTvJ{im0?yn-;FaW&;B~xO?G?seqUb9S`O;=!DPrkHq(CSC=Vzpwla1?sB2+(rR@z)hcM; zU(8j!nR=aHgXQ2bRXEjeyEOeLl5|sL z)oCKPXpyI!>V+A8qH8HyTz5Pc*c(Avp z79rQScSs1kem`5Bt03Ft>sX-qAv7@OS*Cj2fIhx6x~vALXIV(2;p3POVys)_QU@~h zwMn&*`16-Cy5o*A8A&>X4AX?JC%}YIH{rC)P~=D@q54qs!LcT%x_mn!zEA=lhU)to zttf?F-tF$tp0ZN`p)*Q=%vQ>$^bW$8mH6QIqEL>*5L+ z8k2CltFE3cjNU0>m#e*@uyE%S+~IIo$S$o?nzv|oDaG9qrr zzW2VUm)J4}tXytN z)LnUGwT9$``B%#1%+==liV&WMd&LR*f%>t(0;xg@A3qZ7wAbLwY}SgqkXfvs*v~4~ z?+5r3@=oG}V|GT-M1u9`>nKXpE|faec8Z%-@5p25Z!ppB@;?MX_8eFMKlHiB<7dz4 zhKvXlkOoynO&TQF${l|AgHI2jye@kf^IYAm64JE$%ar)X*OxyzH)x$eCyuE e+SBShdj)AnJwZt$j*M!=dP{%h#!X`;apHfQ?R_=? literal 0 HcmV?d00001 diff --git a/Textures/Outfitter-Button-pfUI.blp b/Textures/Outfitter-Button-pfUI.blp new file mode 100644 index 0000000000000000000000000000000000000000..b937e63f81b97118bdf64994e0e080b000e9c236 GIT binary patch literal 6676 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

5pnp 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 L?Nxe%tY!UAtZS1; literal 0 HcmV?d00001 diff --git a/Textures/OutfitterFrame-Top.blp b/Textures/OutfitterFrame-Top.blp new file mode 100644 index 0000000000000000000000000000000000000000..8319329358c503642a5809081eab1e7f2f0d8390 GIT binary patch literal 88580 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 O1@5`YUzKA-VC+ALM@5eS literal 0 HcmV?d00001 diff --git a/Textures/RepairBags.blp b/Textures/RepairBags.blp new file mode 100644 index 0000000000000000000000000000000000000000..f3a760760cdadc647918cf89893814dcd81d76de GIT binary patch literal 3916 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +