From 289b1792f5dcc22841da01bdf2f115bbebfdde74 Mon Sep 17 00:00:00 2001 From: Garbage Mule Date: Sat, 10 Dec 2011 18:33:04 +0100 Subject: [PATCH] Complete Config-overhaul, as well as preparation and initial classes for JUnit-testing and refactoring of commands. --- MobArena.jar | Bin 203926 -> 219648 bytes resources/plugin.yml | 2 +- resources/plugin_other.yml | 155 -- src/com/garbagemule/MobArena/Arena.java | 1315 +-------------- src/com/garbagemule/MobArena/ArenaMaster.java | 319 +--- .../MobArena/ArenaMasterStandard.java | 397 +++++ .../garbagemule/MobArena/ArenaStandard.java | 1465 +++++++++++++++++ src/com/garbagemule/MobArena/MACommands.java | 9 +- src/com/garbagemule/MobArena/MAUtils.java | 45 +- src/com/garbagemule/MobArena/MobArena.java | 21 +- .../garbagemule/MobArena/MobArenaPlugin.java | 6 + .../MobArena/commands/CommandHandler.java | 123 ++ .../MobArena/commands/MACommand.java | 40 + .../commands/admin/EnableCommand.java | 30 + .../commands/setup/SetRegionCommand.java | 29 + .../commands/user/ArenaListCommand.java | 53 + .../MobArena/commands/user/JoinCommand.java | 53 + .../MobArena/commands/user/LeaveCommand.java | 29 + .../commands/user/NotReadyCommand.java | 29 + .../commands/user/PlayerListCommand.java | 29 + .../MobArena/leaderboards/Leaderboard.java | 8 +- src/com/garbagemule/MobArena/util/Config.java | 177 ++ .../garbagemule/MobArena/util/FileUtils.java | 7 +- .../garbagemule/MobArena/util/WaveUtils.java | 39 +- .../classparsing/ClassIterationStrategy.java | 15 + .../util/classparsing/ClassParser.java | 46 + .../DirClassIterationStrategy.java | 52 + .../JarClassIterationStrategy.java | 62 + .../garbagemule/MobArena/waves/BossWave.java | 9 +- .../MobArena/waves/DefaultWave.java | 7 +- .../MobArena/waves/NormalWave.java | 13 +- .../MobArena/waves/SpecialWave.java | 7 +- .../garbagemule/MobArena/waves/SwarmWave.java | 9 +- 33 files changed, 2839 insertions(+), 1761 deletions(-) delete mode 100644 resources/plugin_other.yml create mode 100644 src/com/garbagemule/MobArena/ArenaMasterStandard.java create mode 100644 src/com/garbagemule/MobArena/ArenaStandard.java create mode 100644 src/com/garbagemule/MobArena/MobArenaPlugin.java create mode 100644 src/com/garbagemule/MobArena/commands/CommandHandler.java create mode 100644 src/com/garbagemule/MobArena/commands/MACommand.java create mode 100644 src/com/garbagemule/MobArena/commands/admin/EnableCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/setup/SetRegionCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/user/ArenaListCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/user/JoinCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/user/LeaveCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/user/NotReadyCommand.java create mode 100644 src/com/garbagemule/MobArena/commands/user/PlayerListCommand.java create mode 100644 src/com/garbagemule/MobArena/util/Config.java create mode 100644 src/com/garbagemule/MobArena/util/classparsing/ClassIterationStrategy.java create mode 100644 src/com/garbagemule/MobArena/util/classparsing/ClassParser.java create mode 100644 src/com/garbagemule/MobArena/util/classparsing/DirClassIterationStrategy.java create mode 100644 src/com/garbagemule/MobArena/util/classparsing/JarClassIterationStrategy.java diff --git a/MobArena.jar b/MobArena.jar index d54f03bfcabd685c916ee2b52335e900f6500c9f..66067b4d86dcae61cb8ff22637aaaa6d99a2a737 100644 GIT binary patch delta 109723 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

U$~5Zf|rX7p=6p~2c%V_8#h z+T1(&aGcCKGEJ#7VcT75m_X}~mfL`&aa$7{9l1+8gALtCar;WZZk)d811I1bdr$BI z5zrs^iKQp;KnVDbyE}4g1?)v|Hua$&76N`CK;saZ_^`y*k8R-~u?dXavJ8_05F&7P z=fZiXG7;TPjfZcMfZq47_MK?sFK3>A1_DRR*&=XJS(r?~3b|@6ldIwy>X@BM_>!7< z$*5B`wAA_Dz9$Nn6-|GdPzR4Ae$!AStI5X~u&>mUjz=74^{VW$`z00Gs&V2nk7ac_ zMh;U*L|#b3L4j$X&lGPXHw2sjkVxopJrSl;8%TY#8zbY2fo9|t+GQ?BcGUqrcg8SX zD9Bp2q_;;atwU=ubca7a>&}LemI(@t&QxQhX9hbr%b1Kyyn5-d^Q7r2)uZM|vb&cZ z-PV=r2%ZKpZcur0h+nZDv6SaLgJ{Qexm%4Ag$#*HBwX?PO**_h!CXfRAhBXjTXOgU z8^9`AFk=cS7ZCEIQQnSf(6 zIGC6(S3+s3pMuk4)VU9ThT9VsNVjT9+ykC7s z6f~cuJra6vMX~w~=|`^x7yy5r3d$++L44>boXYa!R;<$ZQ9|JqS3;mmlaxy|y?kkr zPG-jqw=xxS@5w;pq;!&V9ielgYbss81ox8KFdh^6nbXmPRhGm?6;hI(+AKI}n5{@H z1B2IsfQt+?3)DU@8p^ApZ8qQ~F zhKg7++MN(^TJ?%Zf0&zrx-i5bsnp2%Y^BLKNZ3GX89PDHvlD2wDVZ}Mi>kaYi+Xbs zzjlN#5kS66ewcj=m<8*T9BDVx3i~m5MAnCRgJ}xYM|Ze&;0n4&did={33QM0u=`FB ztWSI7`QTl$hnSeeKjwvm^icdIC=&SrvuT>V1W^F;RMIC)xK9c>0Ap#pnG;PRneBQb z@&zX_p*(2lr`IU0Em$7fowy9yHymLx&JLUzULIL)22Tx7zh00#1xqprOc-(rLV)j`(FNjZd9o0BP{7P0BT{*(eDOSnuj&AhH!d{at z{lbn^|F6d_fN16dxB$iF5z%j}6^_TIlJ*3p^OiCU^0!CsDG%3!Uhq(V{N1L`?-djxK(4)vX#^P9dgz6*E=&_O5Oi>DkzY z1w!`kVf5;a6{RzVwBHu|$5K?4i#{OHzN@gwdpI+a0c0K2H)b+yaVpJm$+P1mkM28$ zzN2x+x@s0CGnM6WD`4Xu^Sv#AI_v^f%pWjsVNr#H^D*w!D;A0nnGVZU(eK!KC=ab) z-Da7YVdr*yyH2NN1SADq&P#i&=o{21i6>E$Vd-T7_`QL=}&_fGA|5rEbo1fntJ zA6t_a2~cB6Nc}C5GDl_?Dj|)?ZnqTaR4`{M?*Hflgpn|;Bq%tcp(P@2Z_J_6!qem| z)g56T;+Fh_7MPi}`KpfIn&BtLC0nxO15~3847UcGBC~eQa@a6p@Ig{mb8}!udJAc7 zvDMLVsGNs7V0b9usG@;P$Vyb$Jc&M8JIo@>1}v5c6v~jp=?1HXyM;v7PK8onxRK;Z zRG`q=c9YuDHD@QNmv{u@;32E-Saq`X(^)f$t6fi3*-m;EVZJJ&k=DtSi78F%U;li~ zjb*j_$*q;Xmw;B5IEP_lO_RQqP5RrrPYltQ@PS@^91Y0Eq7O=5Kl*2_K8*Pg};hR zOqcTtLv@t(>KX`2UG&PPwxu)Vh7cIHA65YUNC_C?3Q8%sr@y=tBhQx8(^523uz*8y z)Zk=KJEFd}+MmC&obrg~B~{lj)~!JF1Q4rD$yjg}gG9j>QE^B%En}p<>Jo{c`ZE6E za%RDchR22Mw6{U^-5DvbgeW%T&L6Cgxn=ASX|H-6t~Wl3ID{nq85$m>E=22aK#P8Y z?FTz_?v8zm4ecwgCyi+Pl}Gg4wzbHnEUe?R=Sb5_!Mc$c@eCbosJEY8#XNi;0^pCQ z#vg<+ce5Hma<~YMICr{|@GXXRwq61!AD?`N!GkT*Q=*7|Q}xb2T2nJs^8iaY>3c}= zGL+!EvQR1)Wwy96OBPEzpnSSuH6r9Y>6}k76`pY{+AE{@CI2hc-M|jE%4)H*N=mN# zIfU(qMoCXSFQFAdTR5@6DnqP~5@2#e6iR2eUB0UlU{8OG`p#0Fysf^P&hFOfu8W7_ zUjI?Fnj?dtw(lx!DD{L8#4|1FL&Pxtz!dw-64_NLIobK4!RfsvP$;tLF?AIuNJU;W7aOrPJk!Bk1 zs#!`2BqS-{=ul}!yE=>=a*ufjO$;c%UxOrKQ_4ex5NFmrFELAx4gq&rgLRC0P$eUV zoVlKSx^u|?8rYXSCsRKNcA_5MABPf-X5U>)H?jdjACQ7n6n!BN1E8-K$Zu(S*Hqj; zaRL(Z%57E=S6aa5cm0qWT7T(QWC1T$SDRIGL+3e`TZAB6rGEsoAjSe?Y;f{`UF-v2 zqyaEQ)DBA48M~x@H!cV7kr3ICsD;8@@G-p2tsFWbw+ze3GS-C$7|X4)%?&MZz%r)Z zb+1jT7gN7g@!!)Z0MvbQuz;3V%A$8x{kQm~C-hs`^gRmK>cVH#bmRUX&LVEFzmfz3 zcS!40w$xEb=jqA5^XjZ(ObxpEotj7@)d@hF)zBWpJ{Z*Wuyj8R1thfzL*{#Z_lcZJ@PvW~g{mrj_(w^|=lSGw#;l1vkWWQ;=E3G^7UF*O4#NHPR>HZ~Q5EY~=6j zmjC&c@{SNN3h>NN^-4iAPin7o#46G>7+7+O%?+;aa?$Q??8+IQ6=4rHGK3txwf@!x zZQ$=vhY@obxyWh2y2WkGaGE_E=d2`t?G|O+ZE|?Zl>hPuiJpHqyMBXqLqpj|C6aRw zp8E?b{V{$j(daTEFZ_Y&{QIL+o_UmqB9b0Z&%Gfr5K#MQ@4jj#Zgd|oCEcBSd|)F; zKp~d1mG3Ph!6(MvKx@5KNVRybxLr%&kO{2Q^8S%$=slL+gy$lNnE%unkj}i|zd5)r z=TK&f|Gixh`FUM_i=1D;XeTju*G2nSbJxZD*w5KV+#;TP8~^+c$Sw8cJN)4b$1Umf z1nf=J2LvDrz+O$(vd?oPe#}`6|>H0>=ChAgp=R9$nzhXoAcj!kSPA~M6bP~SEUm?v60ja*vx=y8WN=x7GgC5?`j zV?pCCoa6#NkgN&aU8t2uuuWXmY3}v509^uPfN=q`diNk}5hm2?ZY#J8+tl)#M7lF7 zs=MMwTp5m)9PrZaw#rr4V%6&&#a5%Z{;2F|UyX}$(#*fuZpE(-82Jff<6u(IJl9Vy z!!SP3zQCw9RT2WE4}yT=a6*FfRmI>YTp*?+U6Zmv7?_<-?ll}o?&RH=R+43TEYTsf)hfWILR;Ngu-9_;5 zPJ=twf>BREecyZT9|%^Zcp0Q<9YoyF0U5`f3;>Wl4|=O{d6jpR8KKy``u6W%yR0OV-CV%iSm0mn#7P;fiYeb?0N%y( zXN>$Fj2`ri@%z;{{Zgy?^5Lfa%a}d{nDq#6_=npp6k8r0^LLS>@cK0c&eQw*+D=J5 z#=0$9Hdf~QO&xBXaHP-iM(Y)|4TFFg?DtbYo;z$bkap#p7x|~|L-^&8cK_a{H9>UX zq^=JD(~vxyu;%?7?Hz(+PJL!oA;bms0`g^Ux~J$4>)VmM!Ge_jf+kwCF5m?~AEBxjxJ52C@I!%oi6S+~KARrKb zQ97=FI!%4fsLl6|S)l*H77qS zc%@Or*rL_wR~aUW{q_^Fgebf&3K2egy~(7=qA)fq+>t|eC*Yf21cFHeQ)-ebGm0yN zIg~#`9t3jO{Yxr)n)vMeON0|zX&8D!Q}1gQiv}?`Yw|)ThTq7%!}IV2;7Exr^Ce5Z z^qb((ny%DIH$`eTszn`fgZwZ}!W3DCW4V;A6z`^`22AauW9lxg+PR1EAm7b|Ai3c& zLTi5xCZDd}iZ7_Y_~$1#Wdvk2l;Q>zo<)k(Qz-Gj0h-56t3c1c#8!vD>{q7$;c6CP;tk%DMeArkAoMvXq#mw=%6tTZ4zg%=9$ElCHd&`0bPt6@)by@>Xk3Q!% zdS8F$-volpf3LT5flvm{$CcXwZh7*Mj&L7c9)T+1=yC%1W3oAFhaA$xpO#65Bi>%qnsurHvwWXh*NPJ5xOuAU`j{9$S8`@0A)CymYKxQ?wXbblrano z0`x)k{@1${TQ$Le#3RZ$ZJs(7h@Ft@7DDUD(xz1fGUlt;iRsKDQgmAY{gSo3I)wo5 z6&ySDl>zf>&b;D|;N*O#efbNGc){M3EKsi7CMlLyoe{KY$(EI$j172jdxGOB2gwGOA%e?M4{Hj%jizKC&%{B@+x7|^cSz6igy{A)c19cvBF`+NmOB-U`R0|E)1%BwGVk5FL zJ0h-`xbxr{VBj9&yXfj0cz)rhDg#WP+%ux)2aA%j6}OG;$g7dp{An7P0Cq*;{Uy*nRoy8g|&V z7G~6vf$(Z-&`%Scy2Deo_!nxIvcOXLWWDamfdNlz6Duvwj1%W1QoODGMQ2S5wLDwcjOT)qUu^& z6?QmJj$X9FBnFpp2xad~>W#~VT?DzxhBt%>)nciBV46;&siCd z*yx|%^)}xCwo!>SeyKl$@QBA_(qnhpV=dTxz1+&>rd5|C7Sh(H)&Vtj0G81guv>TUKz>y#T6pIUpZ%~QElCyq&D0TqSAF~4S}r% zxX}~!IXh$H0OpBs+@ixR48<M$s<}z}a=DHAVmqkS@q7zTWV2sC~qhF?FA-XcF^G zQVzMFZfWAR7z-yOm`#m!H;mI6s~0w>C<$Eb)q z5J;*s<`HzC4gN0Ng&V^!uz!EN;7mUZL%~2mULpRM#KHbw-z$wvC3I1Y&$6ASMWsSF zRS}fs=+c51A8ZMFl+l*NAh980_FqaS+Wvp-%h-;qJwbphpU05c^n*v|?& zR3{1oCNj(6*@7lGw0?mrbZbvfIrB+$9z(#^lW5@MDXw43LR`bzPwRuNzv<9Q#`p&7XM_F%hTZ*P7!7Wzk09X7C zi{NKi3_>;`e=BpqyP2XoARA#U$yy%RVXQ9Uu9sS-liHia^FlJk^zG766>|-qK$CIO zWxQEY;MgZ@oIu+pl{|Es;M>_L&H%|ciWF~N!QO~^oVCv!YdmBew$8CnWvx-6$sy-B zTAD3Zu4iiLN>Fe;9pwk5Hbn5Uc-)(7c$MDGbaxXP+hcC^s=Zt*059W;0d}~9IduNv zXH^w;%Ewsc^b#hsyr5VU&U9;jeI8-@JG5!&pFLkBM2{lJ6SV{KU!vTudC5b*fk(o! zFm|%4l@mb?9P&1Fp0Tl&Pe5xhQ6^16=WNqo#H9vd>d*(jBNalj$XHMt^wuOdYlBki zp5rs{)%LO;jp0Hn01dW?p`C}LJ4+TUqV0VVE{pKw$qNGzk?36HO1H5*g=wF-tbP$J z3ajK4ii^CW0TjYJ5Ys<6P^aTLQGX!gE8@J?%MgePBdoFbT|B_LCIz*>nm3qxd=rf> zS%;lrJiHUfk$zLCFJx45IfvL`+&U(O(o;LWM-%|o7Snvf67KrvVy2T2Yw zB?^j)XlY0^ciSAx!hm72>bLc`@Bvm(mh-sG^`8`;%gw=JiH8Z94s(I;x$l#KUmthu zL8d)U67+r{kp=Cj=`Ors^k?t~bZ_DvP?8L;u&}Oa2&Mp#P*Q^kI#U@EZVCkGh1hJ- z*!{GyEwpRdjvp#FbvUJcq)?L68}@d={JKW-Yg1))WxuXUiuDbCuR^Bl`(7VQ%UaJg zAb97H`dXE~pox=Mo_a#{tGC%`LM%&!8L-Z-Vf(HwQzqP{+0t8YQV!FVczTb{$>Sv7 zff%wC*`xzd(HD7$|3HaT6+FN(BhiW|^j=T==XXQ}-=XBve!}wU78VN`VLh+cUd>%A_ELM#1Iu65=$+hQ$n$K`>X=WI@);QEW zPI1h_;NuMQC~9>9LLISOt+W1=<13-7yWijn>jXp&$R&8U!^cox79+JoD^fD z`3o=y6N@zbWtL(u>fQUKoTR9^U^la5W5CbKmj|aCyCPILGr^R)S<2)|UygeVV<9O- z({V<(!m6bSGusgDXT&Z?)@k&!ADA{;k5yYL-+JUb)n>@6+x)`jcQzI^kJA<$K79C9 z95W&9j6fLX<(KqBJS6JazhQ(aU<(C#m>1wd=)$EM0rHJKim-w3_`&||9blFa=< z{R9^qaFEld5Q(PzF()v)l)aJpaes6~4Px)3B8B^aL}0))JdO#i?K(T^x!rJ5HV^_I z43G@g2Wy8+gHgA_IsL6EMjpG^YeLeTM^MqLS`^~6>7PZ*7~1&FspNXP<|~pn-kdO- zI_znrVWc<8+-&srmzH`7LM&^h%m1 z{^BObQz#~YOE0289AmE-qb=Sg?iNajUp?#x%Fa)61@zs|KYlDH#wM3Vw}f>fzwm`a z!I;=I%qHb4^ktRk;zw`c|M3m~@^eTsaa| z7##u+J%`aB>Rv_iSc5TLhmzVR$G#(I4ER`Iy(0ele1s2@Pe9EXQ@}u%!I6==g|Y$^ zpA8!zV6zYpXS4ivTNu!1m2ja2w%^4W?XJvEtM)`Zw?2xdq&?_$nUP?QY6jp8f(b1y za(-*GF_{$E9Pk7t2hM6OVdJ80G;Og|r)f7;6)kv#WxC79#WO<8G*M=`ltxsjMNvi=F0$}U@4cp_Wr|kyh8)yP(r3Sa??#mboyHEL-n1Q z;J9(htfQ__%&4EdtNg&jF&}8t*JlmaGUTF$m!w)w4&n85xIF*RZTKn zdaHEpRxjI};m)@{>oSqJ;t;o4T#}Elq6zYkxW)+sO!wvE>RawPxp@0Tp8x>fRRVi$ zA1H=6v?(YEX-rNee0>5>p5>k0H;!+apa=rwrMGE>^0b9Gz)(Fxd9B%%#Wb3C1aiV9 zKXthsLEvDqplU?L-zIjr^=sX@OJBQ25?a<{MXd}?DJN{!Z-kZ^6Ei1v0t@W!zkbsy4W?MOcHA9jQvmI{co5}J4v0C zDUf6zS>d3BoM3 zwJl2>ISXTs?#kl@^7l;T_s0Zs%Ys3cB}y+P8c8e8Ty@P0w+195V?$#l=duU-?95b$ zF8iHv+=}Z8W`gomDDh7nNQuP)(^6abr;r59suF7_LBz&iL77&Q^{fhB_9(M=okSI^ zlIbrHA5ljp!^3Z5Mcn{FiT>scic5Nm@5yzH3mcsgCe86Eo1uX?MwB;LC(d0j%JZLF zKhC-Z-$AZGhvHqx_`QRY5jx?aS#YjRfnk9_W7NqX#3WUU<(oE(=A;-m!XMR+JRsIK zli=?-e?YDIrUVgMQVRD_mllP9&wPc-sy2klVwXIkXU75jj}xY;E&_jWm@$tIh*{ro z%q4$eAm5n(`CJly4jD2k_Cy;K#^Jv03U;5QhRH06Yh9*(G=w+J5;6VwH3TP1Zo&I~ zwK)i`uNUhJ`QLe9_S)kw6B-1B;eXo@asS^NA{;^e#j!R}xk3^ZCOR{l)O|#PP8rb= zIXbx3SfNa=Of)>SGDXpVG48LRA4qSp;KK#%pCDfmfT8#HQg(wdT)x>2=YGM{t)1rV zfcJ-2`XKy?mxUlAq;%d#w+=KBoTkV=kbs1bj!1wGimL(QA>P}E3d_KOU&1l>>lq_b zdnnFGLL@&KP%@UqN1L*%-Ld)DA7Q&wpnD3tCj@3fo|y;W;Zqd^-2G%$xVi4ET6@WF864zgj$P&mAJ$lu$&-Bup)BWTP~wV>4(L+?n({dYq@}ebtu>aB zIF^8l{3iD_b+%stQ!dzqh9ena{y6C_M73yHD2ekkh2i4(e7IR@Et-n7-DRZ}Wri#s zD-4}zXc;K1vLZWfAl*HiTDQ6C&!pbwyS(!<{TU$(Qw5_s_ zfI!jOZb`W=F3M3BkDyf5j4xjGuw@&vxiJC6Ur0E$+Z_A!fnCFwf5GBshh{boo31=6 zVt816ZA8b^ADc|oO04x3)8QfKbh^`%m?^Mv!`rquS?Vn^xIzkg`@DQh^LGT|B+ea} zo*}C%qz~i*wF2S~ljI0wnzHrv^G5o|8NpdGhj$74V}|#Po|5B3YEwDJlj%sp^18{&O9y zR4&5os^V;;1s1|U@-UUiJ^7%`6T2-n$MeNS`0K)Q#9t$EYRmH9n175M@|!fCAqh0b z5iXCA4IzcCGxg~23$qdBYR-DAxy%BduwU|S#5ByeZhd|)*pz;IC32>zz`fkZfm7Kl zl)1eK6_cotNSRU@Xme%SL`8kt$8LxK8K#EdUhthtcm#F4`x>_s)LBPaAMek`=L~b^ z76`L{@9FZkS&zRs@`pkF%Nb8+8e)0@6dOr!zlZbr4P8->WdjDfznn?UnNX+|3y?P` zw@Yb6hJewyFaO3}g|*nQqjNbyK%4=|%&HXsgO~niq_hUW1}u;MewlgZZ{C}|#+DHS zlZXtH7eg8%RfQ!Xh0swDQvhQvI7~7enzG`)cH-%2)zPnhYSOFtE%yC6_!!NZesk5X zw$`z=P4DvCsu7XR=gn+D{f>j!ODjOws?WX0_u*tVoBO6W^Cz~k@Cyup)FN*>z0iWj z+Xut2Q(gUfF{N8DjMlp=)&JJNUcVE$|JgsX>Pmb9nq}igwJVjVezE$oGc~aOzQ9dH zooF#7LXbkg6P=W3@K{xWX!zJwA#dPVRv{2Lsh&YFa%`)RH+X!S@kdNO@SIegqR5){ z6_e_R?bHL2TWrlIClxcmim?Ag zj>+rq z8}DJM0Bb4AsQbh)U&_q7m4D!4zQ(ozEYF!`0oSCSQ`km)lCNq2btKY#Z6dd(d(IOm z5Gl$G6$K1MO~GS~RMG4y*3+S!lfv{WCj~Y(jrfaj-^#8Ci^^iQ<%J6z#o5OMElzmQ zCRW@SLH7o0rjs#KHlk!$9vLDkX;U`TWZ8^k^4((88w-j@@eyqhbT%gO6 z>D>x$A7OOa{MTW+QgOggf5{>(#exmrldG@J8x3PP)- zVLT^3$8QbfPIn_CHpsT&W zF}i1YM4UF@$JilnMo!G6uhH*--(U(%BZrc>4Nurd6#bx071vWL%&PsFpq+nzQr=r! zcJ`m3zp&)F@J?8qX6*!v(Kai;F}wEX`FTT*9~d-BY<5RC^8w?oZGXW@bYG`eUn%^Q z@Vw&Zu2IB?rzNWV6InF`#dxg)CvfAKPVXWK@efJ0_xNQn0rW5A9kyc;5K^{h5IeH`j}gN z9LrB2aZjRDp+c^?6Kw zjmZm`{6^wKi5L{oq3rE}Hap~#eA@)Dv)t)`+@Q~!u7`m(0JqN#tvedfpBuX@x! ztABB;ui>m-cdLJOt8ZY{->}=8ZuKqvzU@}u!OC~t>U)1~^?kSc0oH!#RzJe;$8Pl# z{Qljoe(F~L;a2~NrGL5Af4kNHVD>Y&`ng;E0<&MbRn%eXS8f$Gm^$EQ#LXyVnc`-u zn=u%NaV)#sOmj0gW;5K(<7Qqr)3G$l%|_#QjGJZRH_OekfqFI;3ps9zVMqR}!VVAOHm{ei199DmlRl_>76>w~-CunRX;#mb+j`=d^ zZEUrho#dgnDf=K{HEvdm-#SdzXsq5t_py^T*5IN0StBM*n5@;Mc8p$H|@YFeZ1Wo`c0CVyM7 zy)zsvtBr1|j0GcpD^mgBi$al5VhJTP3v15wZ}XRh{gJk^#zZU>X{)G-#@fm@b#8y% z8cLKkM`PhY#jJIdu&QVvNXe+iguiubt-qtmzbPC9LO^Y4>?f3X;t78&AqJpCEu6Jp zW7ksR4n_h-oo912)*5U?C;_leV?PA|QCl4e06<6BzcUzH9mRRfD|C_(j3h#don`d` zAc?@5XsbUFibe#DUWuV0=nw3qB!7Px6b|T`pnqG?DlHHC6I(1=8aslmlw`y^{M#e- z!9*O+Y_P!K_ytCY`8Hw;Fim6Ep=qjyDbeGJXop!(Nw$Dn7VV6*Lb-8EFxUZub#?^& ziD1>1&d63uCKL`aBaK~ek#bTf49F+Pf`C32^hLH+Mgl8C+ky?j?fzIGzC3@3P+%E6 z0QiOiqGXI{kW5(aPr$N_6E#)QNWveA1Y?*1R>f^BX_~UyquUH5P0^a@rcJ=@OlO_s zTM}4xBoW&Q=Q2#bH5~NEWIgaP5Q?_~ab`JdGl*t#<;mKNMRQj<$bpMXsFH8SDfmVI7J!CG!i1-bXPDuFUQtCCVR&NjEkSCbIuVS;1p~0cWPnE&QN%6aY9u%mjBD%$u(Lq{grk1grL%vA;Y?>D6fOfX z*&LGd8D)r2L$D1fLg@>}LjG{*?4ShF*o`phKrp4+2`IaQ&j;rg96HJ1CSG?aVrGZh zOY31?CRBqz5bA`9=B0=AA+Q#T7CXW0k*Iw) z^bs0ejxb2i!(=%EcGZvK0Norp-n6*owPZl7p42Om0?tp(Y2)9CZQs0_T9Ffl& zRJkav93j%tfHVmsj)HTsD=8VDycQM$*A^HeC&)FSZ9*imVCbMgpn69~I2y2zt5K3Qk`kE2?BO|(yho4?nSel!WZ@Wt zIBg{lHKl_WYFK}yS;-in18#pOj;d%l9Begsxpau8MMI081G^Y;Ldu8>zd0J-EcXnY8o`7w5Dqql+J#8~BH0uJQwe{p8DXsf%8XWjq;fMDj{%L{ zq^YOCa0&m`;EEvFqw*>onzfzagcL{#bnO}SfR zH{?nTnApV_g}gjMkMg%0w_%Y-;K{VVj{=2*#>+ zv<5p8;!uAZpQ^Byb%w$Lv8Okf7*8vxZfIE3Fr`4K@&e#YfjBJ+X6oz~b}MjkW%>2F1{=oi7Ns&zm9PO>0F@Q~! z)yIEA(HMxk(9y7xC!^&_$?->KZQ5D`M|@dludqLXJEgN%k@i2czv%2WoXYEvD5pZ5 za-1?zXMe?pH!$}%_9pmeI(rM@-)8TCZW~J1>WWX9qO*6|dpdhx*`zDWlq#Klz&_NK zlawixOdpBPK{7wm*~jdYq(y9s1%pB|{?30sMUa2!?4OvM1vDzNF`0oIWN3L4X-%{Z zJO4{(|7QQu*=IPx&)F9``x0}9l!+SqTIYmQohw|`IpbX8E}d&AFS8CS%huv@H_y%0Vp;ibwhozLc!5&~+2m+5>CpQ|h5 za0VwTOLe6J&?rj~*F3{EwS-zKVbQbiP`- zSmP(@yoT56ypFE{CoKJert^A!vd$ZLBkUVkO!aeQeiJV1S`OCMF~cYoVInqd!Gl@n z&A2+JVCNRht>+tbekv~3Y5a7JZ`Ao29F%UU^Dd%JE0vz~4 zev!^E#^N`yxC?Wa@NbTMtYb$G3SxdKXho$=nWOV>vG+hG)0pu(|F(ZJKDlWncyP7R zKv3hC>HItVa$RY_jgt#gQR*;v1;0{P=Hrf9fW`0flPM{4N*Ic9vI+p#)*p(<2uL+H zYy5jU{{jCY^6n~~|A=3$^J`GVXCK*Fqw^o54tB*vR6^&w`5vABggps{TC(-2^J{T^ ze#${{U5|XffrERWX#;;X7#MDX^BjoUtMi-rEvWl$HNhMvjtC!Z5+=;-R;dSO>%5EK z1{R4tQwnB+`!lm(iyv*80s&LdVaGp!Z?}VGqpVa`>HH4VM0X<5qmtBy&hO%PC++%W z(I`eubbb%2wtM+~I=^4}p2qiq8S7X9$3SIv(4{f~DrHMMa36nH6Le-h>i?55X~3jW zn0v$9&dIvO;nC^*0lr`7-MmLZ9B~%m4MlL_d4}kGI8?5jIkQJW|Z9y5d(D_6BVO@QLJqvXmv1kHpXI*_u6vNTB zHUQW8Bm7ZVP=9}CB3cS2cc`P(A8U_-u{ur!{z}oIFWnRb3pH383GPUUm`)-J{(7*q z6$}DkZCvM%A29FA@;O$5Wij%X|)m~~JzAnpXtGa4xk$Pjc+dgfDwgwKw5L^~6uLgq{3LG)yCzxa0u>PrK#8~u@1VAnJJ=Q{rdny=n=Xy~x~ zJA^e#I{$wq0%UFu#o`IMIsuF(16xHwcq7~VVc76UX2>5dZI1>z!%>|-iycQHt`N9u zr3n-&{wu8XYz{>L5E1D7IjrHJwD4qpp8s0sFW^?>{>=$IUw?zj;zj;jo&Sz^QlfOs z)%i>O_n4apNqDZ#CZTp!!t-=?H0HQpIvG4{MBaZ4{((Kr|G@vK^Oq6jE13He=3d3z zpK;8&Ln=RzO>n6;MKMrbR$~`XRsBWduj~8`{x^-ksq?q^+d6-T|4rxbg0afq{aUxk2NCql!E0Q~nQFD0^pFVsjz?r_TSy|DDuoZZQ5I z{uzG?wH-(TRG*`MS*J9^vCF^E`Ine%#pDqGO6OlIyP$_qYoTb_iV*7Y0T&u|E~>i} zb~|j?n23hPb(f0UpUqCRcjzt#Xk8pDCOCVq=}dHVCO|a@{pd2fT$CJTwo4Z}6++Wp zZdZox@}SNeYb#iXU%RL(+6lfYdZe)NLHvIUBuNFEVZ_-5OV2*pG>>l86*N_ptCfGV zbyqI?aOCz!IoQOmak^_fnv-ARxFhX(98P|M?#go=rMV{Ru1T(=HP>X_RRHqinu3PY zHZb5^Q(e<^*L2qmOpeiAGhKyn2o4|p_n8(p9zD8ima9m26}w7wSE*~Z?kaQ5(Oq-# zES}?v%|%RwbajPQcJ*d6E_yhR;c&*Pp10hH>^Te@90UZ+A=6+%ylq$mK3B-X(&1HE}`N7n;o!2pUzro4aih;FyT;G_J> z}<$qi>_lEll$Q!-p>plHn-StvFmzx?%*eXmM35 zTuL+4Mahg|`dQ&l;Pg?2z9B9?)>*4%#5hZ8MjjEx>w{3d8f|ZUFd$bmUWrd2@(R=6 z@L&Yri-vxK@z=m2k#z4+j1>%dCR=L&@=JE*(%_NH1l0DYk#eKO6_d^uPxl_6?L7 zFUG?nE}tTK9fm(8^M~#`l!H)#H~EoJLcU2bUj{YB{6d^H*Gfue4zrnRgYh_2$EVlE zfp%4--pYpRy2_1>O_dEzlni&Dl++#N6@)A-q`c<8Q4Psxk+mF^T`gX84nvMeYyGI8 zhP6l>aKf9H>I8okXf$FPWwgt`Q#}} z0tf_6(S%UdnL;Ndfn~@=sIFT+g3G^=GjqMTm^bDr9=>JB2RCBXq#hB+l1o;D0h{i= zGTr9X@i4JX$iifkWJqIEY-W~tXY4ytYu@}nkJC>HEUO{+E`yx*;3umNXaBPpoX#4J*afd$9l=97|_}d#v57& z_-%wOIqYecvRTsD!f?!wGFQ`lyNNdInuzgs(~xCxaRQrQxUn2pEHI5xQZF?5V{JkJ zy>k8=m;0)h%jXR8>DB4~J7tjG$0;89Qv-k=Z*G6=#+{K?;~l8nx^oMMb{rfd4qd(35a{^YFmb_U>Npt##h=)To>u|4dfM1{>n?Ps-Xk?0$2W!@B z7dHOXboQonUa(KhI9$P04Z(;Z;kS*78~(})aPXj9F(QpM$e;187sOeYWJ<>>gEN1E60MCAE1jN_B^>d|>&wKFaR zO%(@1ZjBjo1kWa71RE>Nm|$|XxI}?cIAT0%#6VAFLcFp~`;4_FDar!CC{3Zb$ks%` zBn_ncj}i*CW(GdsH9|>gVKBM^M4Tc&>qTf_b1WF&Vszq#KKVA*x<*jjP%q&A#7BQ+ zaeTIaIO}lG8?@mrB!_rx$G3*UXtZfD^Id!9;AeJj(`%$;-H7$+Fz?J$M-ZDs+zx?) zlV(Mx{qWw@jovor^ZWY4J_)z+kIi7>z+mwU7`4L zaY!E~b}2Lju6rQb8Hcedk5uU-b9y!MZL~1>9V@kLxOd(oJ>T#xw4BnSBfPGkE^8Ws z{y3gCdUDZKwYITo4Y*%RYW^F%K;fzBrfHlPzW)xn5XV-3I4s&y-zH0ZqDg8()IrMRPUYGozS?EUw*5$y~F?Dq_m_=Y)XlLOR;c^ZL^>L&Th z!Z78~sIVbXFAb($*b6S9y5dQ%JZ%Qb9|56hSOlL7U4IZHqeQ8fw z)OO}iVsNo%4SN}rg|`$&fWf?ZIc7vRAQjRQFrJ|d#f$aE-G%W~=JZkarzlFf0$5p+Qf(e}{c_VZ1-670(akD+cqOI1DSE97rq9`fY$bdc}FQ zVT8Y2Is#TYt}Ar$ya9hlm#3z9+h7$9>51)J5d`X1|DP#I^K$~}pb5OA%vo3Adjm@1 zBOPaueLgZCq>potHK|DY;me4*KLT0?bKe_xjy2w-Ao-Uz;`fhs2^;0l9}J!uzjKVs zA7fdC@c$$zGr}LuX|7en8N{{=G98m;G1w*eb5&=-)#$5RSp$Fm^qi5nG7db$#_0r^ z2y0wixs6|nLH0ZUMLZ;F>5q_Hrx@6`4;c;BRcjj>s_UA>Pe~lk9WE?v($MCeGQc~6 z=<<5JCkQ6+HUyVsH_i_uMp}Ol>N^<2z+>7Ud=HK;qb1kw-x@R&$&l`7ngfN!g$7m&XDyeGWQ%d4 z;r(8vFqC{LXRPyQYld%b9O9_aaIscI)?5tLL6@k66^;sP>?_N@kI zle~By(;%a zrZ-aupF!DBV4S*M^=yY9nsQ3%JPU&j0G18HW9wf zSP_f1ix+qpH1Hi6qI9-aymOO4jqb&AJRQc`k!F9#Si{{Aq#5Z5>B5H&iKxY64CD?G zpl~i9h9+b{e0rhpu*(K}XWZ&FzPgR_5>#FaRW7SRH?i)2dBcOV$w?WhvASt(eR6g6 za$nQN+BM7Zn!r)*Yuwndwyq8g9t*q%f9}#E?yf|&6TH5fac`2 zz6OB@ueO__rkl2MupuylxI?-_Hm9+^x@z!TM~i9)QJJadk2Ktjf1zS*(pwf$i4P-I zHdI&F;p?h&Px|nLU)fOEGW-uB%_SZV$~J%M$P^_*(Fq}xDEPZr$gLw(8KY!Eng!KA zBrc-DH(Jz7l#-{(v;#zKIY3xTFX7p)9-NjK4p`pBq$ zG8)dPG5sV{A&-%)ZbFL=kZkBYwwvVG*<3q2&d!dvvlHxWo}E3)&Q7$mlk9B1ojrfr z&Q7+o1(2Nr*{R)Rnw_0)1I&QzF_4|vO$zPoEE~4S&K4J`-J}GQ(xQ@nGMkcaQii!X zn44Qv(nscXlljo$*p{NA{eK|^%Ez^21`d$p0nG`$WMMa{xF459$%ZtW&;e3N zR81MHDLI;wD_X`WQ&O*HP8bLJGlia8+u7&H)#UNTnm5eiWqXg7tkFbr(ipULQ6MU583rSWCMIo?IEYh z&*??`$i_Z$27>hv|9-M*h`F@_p*JZ5gxtc>{ zgRBC;JZp_`g_YhfcG36*_qGSp=hbV->cfDi^yWiMzHO00R7E9tfF)K!{Eir#aKBmMJq&kbZ zZKeHWJBm|j582T*@Oyg`jUlT0D>7YECJ91{p*r6pG1Z7A`6V0>4q*M|Kqzi~Uw? z?6=~5N7X zPSiu>I6+~4F4Pq$Qw+LJht*f$yAo#!47yxuohz;*^CSbV6byg3;wCZ`2>h;j=6ny1 z8m#Ui--i>YkNlwdepre9%^K`(pa2KEqNteRVEf7L-6Ru-+k>cn z(nUrk5dgxETl{}oDGAs1ke|Y?y$(2XJp~E8!6Ah70J*URWZ|ZMvR4({8WHg~1MxQ9 zqX|DMBj*q)w@9CE$;u={QDr)11xUVM{A+y*{+j>>?3zT!iO*u}E+7^&+azi-)3{=m-YCV#Lo!=mM2e!hirJFo{;$?1sh zAefy_tOo_Hb{X*QCx7fB9>YwngjW&ynE1b7nx-bw~| z+XToF1t`6Pf>NKvOc!Cr1qJy~I?j^!nZ{0>n7knGqPV|juLhzx{&1b%$4(z4cRGK; zTD4--RPddQ=JSWWtBISo2TN z;=xV#cPb?X#O@} zh1(5+WRxr*=~-Ay2d8AQQ4%1ZN&|lg7+ah}{?SMNg{Sks4b$X5(lnW1XLIaquAQA; zY#5+&uWwJ9A}8wfsgq%PORVY5HdsB?;F!_Z6lJ3V4F^;6ov17|`ffGM=Q@L$mr)$E z40=QXm<GuW=5H&5CPCk&Ln=mO^ezF#J(qq@?A#9hjI$e|=PH!+tTBIAEFr4j~S zrc@aNH^5BrcbJ;#J&`Zfe-bX1M zzEn|&J%k$ShFUz0LTSq<7- zQ*yo}_2?F#WX@jSyEr?ccf>!C%>T?2o!M;t}i=tE>Q3^Y;N zmusxe&}eLil|{X@82(D&uN3}fOD9wMh?C4rzL`1N%uF^j1tNcAs*!qYfPVsd)UdsS ze9<9%SXyTIuyl^;!%iA8Wd4XDj~*GM&BS6dYP9VF51#`LoNRGmg>h`nlI(JhI>8)u zZf%L$PvCY7PhzH2EK?@o3KZIF6*bqsjz>;j>l6ak3UlGQp>emE!TAu zS(wLjwRsEOdG5#Q3E)!Ucj0b0Nb=nMv;vjZB2eIYZlDQjFb1Q^C%M|G^o|qF<94n$koepRXxvzaV*^5&nhvANs6Qnk56+9yI;ndnFt` zi<>RgxXJd6r;|keGd+5q; zvL&T)m9wXw(&&?oDmIcwQW{q~8tF+XjWy23+LXpR=a_3!8ta{7o|w{jva@kXN@Ig_ z%*K?)CdZiM)s)7yPJ-5@G&VcO>`iGr#W`k6O5=ZeXXA#H##5b*r=>KW?xc2iO5;W+ zwP&O>`kg&5OKIF>joI2w11XI`M`%XrrU~&MdWBK z-QIskcXZPQR(Yo=ms{ntMfn`7e6A>;XO+*#GVxjE3q<)tt9+p-e{7Wd=tbT1Vyp0t zZo11VT+&UyS#*G2DuYACz4Tk%Z3pD zq1O%p_fre5TEfZ0XQ~NaETFbqPz(C#brPz45Y$c!s@#G)XAsoc7SuTw)OmxT&b5D_ z&NHEiZxGb^CKT~mP#+G0y1;_^(1QAS5Y&Yh)W;TG7u)8s70<6KwQOUSjNy9WCz!^v zM2BS&jr~L-?HT}|obLMnfw!cG-r%q{rV;N~@kU{g7hxxH7G zbD6vO%5s-+ZM9IFSe}uak<0dyGbWXLay_|xFR9Nj_vU(YU3u)+V~w>b)={4_w6ib`$ZvA297}$%BRm7J3fQ z{VjQ(UfR9To9E2~72cEQ?V-J0Bzs}TSlZu5AH*&P)VtVS;9J~Im(nWQXRPH4k}*K4 z(RLh5#ebS|8u~Y2np6Dyf>eKjG4(m&Uy%gSl+y>ubmC41)|8E-0oxho3PN8leB*BO z{_y`k>sk=K`^25>0s2r&NiTi4?f`wHrL>nmie6<8ee5xkU4xm&yGUm3So#FawnR)8 zr0Yq``Ytv-zMs_zjjzrwWwT59Y_YzjuGyw5@f%=~Lfqse(g7^0A?<(SD_J!InNR~$ z7HpViTtP?%=!Xasf{$Tvzp}~T#JhkDIq{4Y_qHP8VBqf-miQ0E^nlu@7DIAy2_#Po zxxQ*Q@l8Ty22D4TC73-AvU|z=TqdiZzLCrnd8mJSFPWGxs}J5tGV^8a!M%jDyC%tv z16Y<$lG_BZED${x2rPfIa*d4ySn~5_HDJlkm$iUJV_k%)_D%8_!Y70EeJTjSmt^Hq z434xa0b>ihVA>c!cymP4#u*)l(#cVz^ZSxwld8^et-Dn;qqYtT5 z!)vuh|?`I?^;#v-vC~mZn)Zo8w9%P4myp=1ygs z(VT5?)P=90erA83HrtgQ>Dn(c+jlBwg9Dw)t}6t3PITygrQ_eTQs*S7j6AsX4 zTEy{Ae~wZQ=P_o^=%v5FR}@%36W!ilV&EPd&5{%K1%UcO3w1tNZAd|ujT$=j(q~h< zT%=rVOlq@n?{%^qLj>xk7J+*GRUdt>1`OHfi|v@0*zc~H>PM^qI}bUm|(CPBd?Pk*GdR=sq(EfP!m(2zMU3oQVP^% z7VC~Ppo)zPF7c2hr=PxPT%6?E*$GD0$<*%vvdb-GQw(Ie>5!#%yCR(cksK%3l>qi# z<$DI$I0JtS!+phK4V4U) z`a5yVy;f2TZbgZ`oTG{I6&Ww$!ElI8HHN(kT7P6Qpu}K6fs+9a7LM41h5@c`Fa5p1GRb&c`{_!yP?eqYBxuvL=zJh2j>8F3v z@os;kR#f8aCu_}5GuQlfX&=3r`Nj=o4i31VzIBjP7&#ea?5A%lki0_)g1&p{HP@1( z)VoSVKT*?9-&5t2xUPX49Ph{`5I*`VlBp>_6*0%vnsVJ2BnRWTRJq=yo#G203_CuW zmUi%5->0OHeo%+aee}bHEc1;#)<-`QGs1sRqA{n1m=o69#|vH7RHh7`N}j8SesXC) z{kwRT_(UE{jYp2R;*sFC4r&XA`BMgOI04;c-b_+Nj0 z^xw^0v=l9(-FWKK%X{d5c8j*pWE)-~mdcvXMGYA!68H0k@EK>`EoK^p%kd@^VZV^D zFFJ1{Gi|#<0(~ig?n%CuI%FH;=EW2Oer;QIY*1vwG;j+Qbq~pdDl|&BiF-PQ;}upHijV4i z&NwbW9*%E{O9E8_qIF5L z&}2j5;W>~z6%TP|XJzGiCQQXi>{V_yCQ)Z7-SVR1TgB#iTD}fe+`uOHEy90>eq71G zn9yTN#(rTrdWDgljNb+R3D@(WbcK^VN5%94WygE#lMlr|8AvI)U~b*@{Cb_#rVE! zeBYNJ`m*tTU4B&$`-%-L%~K?ACtvgLFU@1c{5Aep_;#|mE8msz{{T=+0|W{H00;;G z+mnj3y>?3l1KX2|vkQEJ1_RrZinEY{2m=w@lZrp&C)NOHA^-qSS^xkklW`dwmn-rD z5P#Kt33yc1+5cH4nUk5DNisu#VI4M;5Ox(cAR0ozXc909ARyu-b3+CuGchw^v1n^; z-M8AhfYn-S8yDItLQK@Uv=-F5*Sc11Yprc6PH+3=Vo0`#pz`=RNcV`XWAliI11O^jGv{L0=K{RY70FNnbCZZ_r;OkAF7{ zfa_bx^=+*C4N|{#)8FA_?|1;v?>%HDeHYpO0Uz&S@s9=Y_!AEQGuFK?=wI;nuh{lC zWb*-b_&ZYnz+V6K0QDi(edMJdqhue`e+l|;K|c}nQ$%pkOApb*IO%7|9Xk>Z#$j3&vU;@Ul0)Jq^JXqruOcAUQ_3;Fjeb~1MsbV)P@sKm=Za4FL z$XRqZNXi0UHiDJnV!A=tFWWlNhTP#=&PPqh!)*`hO{P){1Guans~V7MM9oXZEXM&WkUCwkCc&BoYY}XvV5<<;YQfGBY>i-R1zU&8Jrlk9 zS;5xhh_g^b8w5LBu&`jQf`7FM77-UD$jM zdfC4O>lQ32SPGH#2)0GAt%7Y6Y`b9R3ic(zb_jN!VCM_=W$f}5!7dQ&tAbr9*w+O6 zx?mRxcClcW2zDtd=Q6=A7wihbt`zJl!LAnU8t?=54Z*I(;oro^w|@k?PO$6qPu}n- z!9Nfm>;@0Jk?r)bUF;?-ep|4cv2crE-@)>&`1me9Zo|j-kj?El-}eRkfndFY-67bW zsLs0tyIZi`DB%wU`;lNjE@1btdj;ErzxN5YSFnA8^&zVJJ*=M%;Ntn&CJn;Al zGJY6C^d5AJN8IdD4}UFYKg}cBpK>qz8GBr?p9{8MumgfUA=s0GJtf#L1bbSrX9Rl| z0X~P1=LLH~uongUrC=`!_A9|&7VH(lUKQ*$!Cn{a4Z(gb*qegA?6TG z77Q%=Z^1r65B}844zfdTc37~_1p6FH6i^)zoCr<@XM%IVU4rKco-eptaERvzc!A&^ z!M%bjf)`?iPw*naiv=$c+%I@Q@DYNS3O*7WM+rV!@Sxyh1RpE-IKjsYJ^_@>Cqm%y zkl>R9pDg$k@PA!C6%@m#;o~SQmI+=ic!l881+Nr*hMUiH^I2{_o08({`ugRoYnN=O zS>Di4-MFL~s_Hj|w}fZ+q@uCe_0eQ%0VM^^(T(wNs;66}WNKRTLaiJN$2ZPyPIX7) z8y75sA;Mzl=~Tn<>PTlao}`4XrKB*~k=P0yo79cbM1P!;{G{5wMeU{}P@m}DIJ>oH z^X6!3cC)MmR{34Ao{drHH>JKU(K&l#xVtsHQSI!Bsk0jrt<~LXJZuusorOCoIco5( z^4SnhrZnaYqw#2J5hc95VihH>nnVPItS`@Ds@$ePu7%C1aNFjFa92yXHKt1S&vEm) zpx8vbCV$b{8IDINX)m`+-=*n(y03iQCws7;K z-TW9gKi19X!&>j=$GQ3OZhitKN-_+Z*6f2 zK2`y4alwCchK0j%SR^rc!fkD8GC6h5oOzT~41eVX)w$kpTbY&r@48(La(PcP%?Tj#VNdjH&RlT)oOB=yVXz_{>Bp_5F5NVg2i|^8A>HWn-bCZB!xF|i1G<5 zlWJ&oXINGmjUkXvcArHFp(HQa72Xho3Xk)ILcdRcpztn!j>5Znqr#K;NMW%DS#CjUE9&If#o>4yw9uaD4#lGF>a1C_ zLXF{$8KF%*$y6wkh?k`_(c8NdouP2375XlyQ1~{!UE$~QFDZNnB0CRlc|KBK=6_#7 zpiulOzYro%;a}sYfv#d|cnd5=G)9TvA-il)_}4l3$;Ar41eJLyzf9qm^D7j7CGxyV z6aH%O%Vd|@mI|kUlM6{oN*&CMW`$paB7Oq_UduPa!l;>9;os!nQkX!v*I~W8OF9;; z2(B2!mBO#bxo$w8xe?n(rbpu9o`3dsT--<412Vo@jnvEGJNYhHgA{%fD*W60W`*Cv zzoYP5`F9n58?OTi;)ztZ8jgVazQ-@4B(yRKhOCmlW;BHsO0=PPxKmxE@Z0$c5J2-+ zKpcrCHOdk_j6pX`>!I-PQ_$3?OyJR21d+R?pM=T~6*x&RqGDwsSSuBN2Y~F3%qeRa`RTlVn(EZsy0X4HbZ_(n_sIPZ4(GqKAMCtV#5Qwqk(meOkAN6#iqB z&YS8`Lt0jbj_z(XnMz>tAAgx9fY}gQVZv+c>4qMu*!DD#_waKd;WcR^BA}GQvLtlb z0(}$R+b4m?LrAp&FRo%b9Gy0mYy^veg71a3mG8mFedu<3(E<0N@8u;^;qDYAW3rCb z8>iUREgM3zAJwodf(wY?h5IR?JjlEKhfQ|AbUx+euilmzA>6)cikEt=O zl2l_5^2Rz|1t$Lqe;7O$h(}P$Tlu4u_?CkQbn6aW6~c8yP3gQwrA=YA*hAB(b?6oN zgd>qb_*gA=K1OXCpMSDy-Lpblqp6Ni3PS{&LgARUBBf5j8dlK&! zR7h{>g3Ut;)TcO6QuwQ=+qz({X3Q}*U6YPhPx;J>lh)0ddBXZig+IZc1OwYOYwHVY z>rC{-Q;S0Ddb)N*5?kXt5r&SAR(NZI5>2K1Xejf?IdZg%v&$ zLNQrSm%@L+pLX+S6#guK&dr}!_zV0+h5wSj1pbI@75*#!BKkxRB>tEA(+YouzohV2 zk$MfO*ZCU?|22OTMAZ(5QU@Tpw@gPYGlvUP6@+T2HI{(G2?WYp{B4jJ&y|Mw!F1c0 zZ3_Pl|9>qdb0Pi=o$FaulSy4c(uv3ctuBcTJ!7Sn%AG=n*qhO&CBqf5T#vXmU1;jQ+W z2Xom2=(0}?;j%H!Wl=DHy#(Ct@H96d+Zyif%3NU0hCB%bmjZ3`oPa&zbf=QAV`!Zm zy?;aY-eL9yZFyH?v!SRFa-Rl+oB@Aa%l0nqMAe2z@JKin#sw;=Le6LpZBO)+LH6j3 zCX?ug;rRAc2M}-?0rv8kCD|wKn;~5cd!t*+@VFa<-AJN4lC-zG`NsYDV&x-9rntA3e7!HjF5*g#^^; z$5DC^Ymg?x>N#1ojd28`*QDFSMBbX?&@8;{DgAX z+@qkqd@5OfQhl#n)MoV0-DybbakGfmbsv% z-BFB;7&3tbYc<2OuA&W&ZYGfkr}PUatrazd%>Ie;@|64=TF8z%)}`0Y|GoIJ;ST^ zjqd}3IXQN##=L16+7^LlDk*>}tXHrr{b5&BgbTqvq^5e_P%AfPGhsd!Pv(S!A%_h8 z{Te~@Wb@W9WIp(Yr$Li@?5mU?1SE)d8kIP;)CdTOdqMO+sHq5d4GF^pYw;QhZl6h+ zMz7d4EPCZ`%g`SBYr3f7#uibJFgF;O?lHNdA1jrgf_znl{a6A`K&XIB?+I)^d(PYy zJM1+y;uwwZkeU2BHCLB%d#?PYqh_0)SPp}3zO<=FjPORn-;q!=`AEf`ya2^q8-Sca$;^UTKWO z`FVr&@Z1|!>n>GX+CR&{>!*uPLUXYSI=kyocUv7Q9BYgWjJqIQoQGFRTe|DWmV`O$ zQ!ll}2OYn~Nlmco7W-voss)!a5(sPdLf{I2BSrC4<0B3jPfIG9@RHYnE+<-#3@!fpb#R_%qH2f2iqX4Q9L()sP|8mDf{f7DBE&K{V>c`Lf@JH2XM&n`gqLj1;Zdy&vSih%gwLw1cY7wg$=>YWN0xz@Fc1EYX zIUI`5qd5Sz^es*cXQ8{OZ8Qt&EaN;wkMW~MrHj9~GOZN|p2JZC#g+GOG%z^7$kFH0 z;1&fLx@8kX!_Q!-cU&EOMX*^JY!m8)obDR*nb0&tTGRSiPdDx{MOZZD4&eW`%?Beig;%;8He1rogHU0 zIyov~U}OtqqhV7XX~AI$nM<>>kLey=G(m1gV?o(n82xT4+uW3z*9dHLB)C6T#5rS+ z{9AC(E2of#;^M=Z%fY3ZV>9Gbl;;EvC2lA)Jo2i~_$!p=Q2x6fhbU1^scBZB$}b#U zJN?e?$}%jp;S|JHM0&kd9(%mZ!ldi#?>+`OtAmZ+#yU-yjH_PJ@^9Gf zmdZ9iSe8c_j+xC1259P+;cPg+&fUC9xj8zHI@Sk9z~-5=NMvp-zSUNU`2 z0I4t#xMTMVD+8&i-93cAHW{C%!6=%uh3UK65v-_3cvtFfYNe>p8g3+qEX z8Bcw{1lr-b+$62Rkvt0B9|Y&6GC^^BK5_cm6*>FA$9liWUz@LV;s0?U;{LR+9#x$p z2n|&l1*Mespc9^(6O3h>r#m)Qw_R1|>-$at4nuGG_7As554L6ON_iDAmJd_f-0kBg zAqO*ZI@J#c@qt6V7F|`u2HX0BjYOWlU1_$bl9MgXOZCkzda=Cwj zSeb}f7EWvqmrJ(Ioc6I_85QHKi)cztN;|WB$U9tboCBK)V-b+$W(-I{^=9r`GgS>6 zL)C=?sWpll;i#Ne#s_XlJSE=}O7E4&DGhTv15!QK{+ zSXUZbHG!ENjR7oBO+#P@N}6|{o1_%LswM6tN0gIl)i&g6sZw%#FybhtiTR^t5tBUD z_+Bum9KtT8*(e9Kg?!8qd)f{j7KOiF>T9nPMc!)jccsyE>&o^=WyxC}&FvNkadXGo ztvs6B5;G?ujF-(x1}F>Q8StH=Z4l3VJNfa4Io_NzTVk&G1YNFAVXFkB&jJE?t^S50 z#Y`dkUa_EM_54y?!n_JF|Hz!&nL0hXeS-6&d_Nw_sy4uV{{5A-DJ5=l|Xz)Mc zK3soC?D3`FyCEipZ}jy$5*jR@TbDLidXxPvlp-AXYLp@@vX#U&3_@#SA?(`a7ajYD z{QIQP{uT9PV9AZq#GRgx7K#_}ZJJ_BvG1&G$8G5X2J#lBWxWa~DHyhIc3DJ$P#yvn zg^d(;$=55z*FTE+bpP&EW&woO$^sj<^q?Y-mHiZtgwofd)!zHad{|hxp2L|MRzpbc z9h^dBLW%J7J-~*Lbtk@-$RS)#k216_(mR>Ae`Q5lt{N^B@=eyX!6X=n8&2*myh%K# zF4lfRV@?vKFzoV_nBRD4xbQl?b~EkBJbW3`@GWFh);iWrH>#MnWfC;UVn9d=^LlZ% z&2nP|Y=Q88M~zRWy?}+OhBMt8hg>A;8rP{Yq_J074{|dj*8K)Z4OFGN+)N<+#L6A9 zi*N$<({r$^k*azZ>l)3lSXwtyizUb?T9f?}5zWxVgo1xcT{I!hP!i?w?7R*Z;55It zRSV;xDF#CNeh)8`unJm^EkE~}jvR&Qy6X7Xihz{o7IDgkBuItCAZ&9!p(RH2NOBut z#Rkw*FYDch?e~i60u0P`IrAEan~IDnLH zFzmF~YHe>7b!XB7A|W#fn+O&$-zlAvMkheHr~h64vRpxn+t1;XlFT zc$-_3T19lhq48q90H4Sy#F7i{fVlg3Av6aNXxGOB3+!Kl(SXeOZqpC8=QzdH#fx7hk9TRwUF;|N`1j{`anR?mvXG0=$Fn>3g>J{^ z#_O%mE#Ir3!X*5l8Q(wVY+kP@i)Z|%+di%1X*_Mdcq>2P*;>Bdu@^q!Gq{YNkz2k7 zRWvzPfJ`;fMv(zC5AQk@$4W;^yeipM9=}-63$98qoq%o)I zh2G7kgXOCk!-H0_78h{aNlO_i-i2C16o|j0{F^2GrL|+W+xB|;-eM1+pW*$TG5c39 z!u_3!pN$88htBcim(VRg>;>T)n#YsT?b}DmIzu=8TAuJ}v+u_rSJ1|PO!8cPsRo*n zJSYEvuXJuv8cFtzDC05Tfg8B8)>W*|x4kFdJMrsn2ybes!3H>siCDvnerCcI!kdi{ z$yEmg1gXxW7b@Tlc17OO88h=@RvRqlhshkvE=F4PUgCh9Rdf}^2K87mSQQEt;8u7P z&5^N#KV(dcl%ijOHvte;&EgsV?%*G12syvph0(}OVPIGM{31vM<&&Iz2am)pN6LV@ zPO9UCWaOQ3`&q0INk6r{H;LE+s>hl(2D)~ZaiS^LQg7k+JFX__DiTG)VpfPfa1tcH z^hALVUzzf4;;#$I4|jq!zSMYoLOyJ<9+Y}dvLwB~9HA#kYd~|pIGBe~gpabda1O-j zf?D@4f)qmbDAq@NRL>e*)w^ce9SPUGAI@1Uxq=Dpm#$)EZdHrPOgPgh@b2OMX0tAD zXGQsk&owH_c$1!f6OF5dskNdjL-j7P(CGEYUmJ57@9pn3T;9U^bR+(Yq#I2Jh~6=? z()0Vi;4KNMpnxA8W#Yn8%keAe)#k2?c&xa24nI@-bSoLOw?H6^Kj#shru%He()I#W zE2Xu!fi0pQXE(py(;7b82)}s+dukB4OZ!2u(4AUUQ$gKAnQrx;;9vu4>+S*8jqHwd zx4=!%@gU_N^@1Y}w$i;H_ci&4H1f>&3_W>Q-NLZ*4M1s<7QAh)#Aa?~?s!rsXpr6N zFE|HVW%T|^R@ki-Wp1R1ZgN83<$uBQ!9WPivh9{Xh<@N4R1^GRa=~75w;2Q+#D#z9 z?yPE(x?XL>pt|XiY1Ua525B%=CcSpIv1@C=WX`j^M-p4Q1P z)uDGnUyaXfU|ktDz4or~nB=blVaY|5^28~t{13oSW0xhH;w|Bez%>B>eCz%=%wn^A z7b6`V37u4b3{vVPAqjJsdZ%G$zibDTz{!ukR3mi9^6iT%;04LB*Z*4s0kn%_aPDue zTN2l1atkI}0Nr9oQmf(AL^G; zOhusPo{*|kZR`NPwAC3bI}i;OORj-}>g8QBHJ~6F$~GkzIr%*78!M=}#n?d-zt0qp zctThS5}uTO_}$ihCpm?%x49uTuR<;a)%TGUSECU!XmIeN=Q~7QXE~#<9AK!7SAIwi+hqvKdmTP z^vupSs@NwjE;&-CEVBf$Gb~;b6jNV9qC?`3O+Z#n{Y;0HoUR^Fkg9jK**+yhW4*7= zW*u4&)A_A@yx_t8Y`2GsfJ{}t9nH~^KEvsf2~lJU1}1rNp*O|k%z;}FmZVc8LL4Xo zFFvL)b}7+vy(e7^<@~lMEDWXmu6Kr|qkLmL*o`9mxnQK0KAV;cVSGfCvuMQYoaYJ> zJBokG-cq8ePuq9CE}NledBq>!(^9S$B-RwGFzxV5tr9Q_Wp`N7IqvXsXLn5kOX2?Q z9mQ~mQ(*Ui1@8ylqy9BWC&E)mH4F#_UTy|{yUr*uf%VJ$8;!|g+|iAmvmJH(swKwY_W)R> z1437-pZCVbc1^BdP(1Lkz9A?Bj@95FeI4lKCG1ZUE@)$o+!$$lb&T-{gGkic9Oy9_ z=+HOn$N7j80)&sse7d$3Z~>uyYG}%8$P++1Pf!e$v3o=L2I%>N>K|Na{|v$ss+vY| zJbs5ryVZip@8;4`f9mZoefgK0uq$372+I@gF0=lbh(wH9h5+3Ar(6np+Lg?T7c5R@ zbp4&xb^4aaD#BUQdfxSmOa9?ye6L5t{ZD_7=$-OoXowH-oKIBN2P)Bz^?{(lpsL1# zje)TsCHB6;<4mtdEYhz@P|-&cSJs`nj~(jB!sB+kC#jve%VVzrH~%S4WV#E3uY zf0U6Ptsk-D0|ArBsr7%XikBw@8q6aHREtPg(e{qT`*GSK^$vD3MS3nXk)B z^GDdTL)Xncb-bYCV9iT+2cF#|_8k9IKY?_3ry=~qVjG^#St&U3)xl%^L}ilu9&!m9qkO`5q0UU z<-3Jl22g&B89+HxTcioLSFX~Wqj9U*Z4gAqX&+UA&YY6D$U1o{aPM`(JKhA-t&gfsQ&NL)eY#*3kbZ1^))QOC;c z97m+Js(V{L_h0u4S95WVrC<5z+>(#TfoOar4hZ=6(H(9GTRlGxM<{}nw_n$$fDlwOo&Gx^rQ@|o zbJxu2=`9|m=BJf)|4j#Zema6wN97QSw~Y-o&MDg_hfglbaQdBZZx9moa1NZFBo|Q_VZ|X$)XS|D}m)tK+(a1ZN^-`50 zt+j8|d*2qLw;EA09wH_Mon@eiy8r4z0C4PW@@lVVJbP5Fpt~O?1kslK&wtl!tCPfxy?vLi4BXJG;bfB%Oqo6n{plVf*KiG zNOoa`+kg6z=Zy~<-ggagb3meqlbTV=tQlm?QX*sj4u&9$*QZiPqj!zOy*>PH3UH?f zyLMLm)WXP7{x&!tK&`{Na8zd_kQntzEr^%7ECrWjm z4Ul%%X5j#X)J$^Cw5VI|0(X?Mfmm|@lcFs_4c8){-+OetZE^T>ZqY!38?Q6ZGZoK} zoj`r2YerJc!B*S6jOXZ-=-jjS2&A+!;9g5K?yB0IWxVnQen;{iKah5AVgapGg4JLH z;ZhQsL;(9#(jGsRVJP5X!?H=6^ofUg0Hm#9dfxW;U`9l!cgK&!Ydzb)N%bc~ z;(0n^lahM$)fyGAy0l+s%;pU&zaJuvITa<{5&5vIwtru?wS70+>R9P-1lVy(NJM;x zNCKn1aZftEf68~`Fvy*YfhN|^z;PbG+8TaW*%!g21_z6U*EqhHLM9B*aR8HdfqsZs zJH3aNa)ZXQxkq9eNE=0WaDkpbZ915z|6o)@W^H31Z{!lclWw-%#$e$C|HKL#ZVUKn z2)!rKz7zIz=JZdjhJ?o&2YzyRtRB|f7pC4X5F%yzpD~2Rujx|tX;|Ab7+R~ZYs4Fu z-A%n<;`ON=XrH~?1;x+SAFbKG`{nQS>v;x|@BE|vRdi(M=s(xu^(mgT-|>3{QTM^8 zqUZ0-bb0<3pL)9S$5kLM39<|_hRFxjOQ@Wiim<>u+IxhcF{iJL2Rz76hd%-ln$XU< z!z8JtGLl$?mtH>JL7|q+qKevC!HC-1hj9lfnzj{4l!aK&8!KX!5j5pwPmpgTJw91r zUr|%8iUSHppDwyHh0E^hZ^k@7AtpX#?RqB*7N6HVJ~@O7?}R>UMv>12rjdWR6S~!XGAPhtfDAsoHt~>YY z4}SMBDVp|bcJ5`TLn!fU6(--bU4(q%17v9KwNX_6AH;fzuV_E8WZaw2@>Z1-->_r?1KX*j@qz?%S)iDx72 zyr9&#?|kvT_I_otmZC!*w~DUiyq`RfCPA=*S38ij6B+uBXglXz=^L4|^LJ-#Cw5Fa zXo7g%Pz*>`&(Pre0vDD@3DiCSmS6ne1M|P4zjP0PXlyNmhWQP%HVJF_4YGWo-+AT5 z_~nA{3;&hulT^Ii`^W6p>{o~zu55yKr#>bWMByE9o9Xe%+@^c-b)0F|Ltn(T&#w8v!S+4TBRM{Y*)0j3HM)=rJ)U+sSFXplBAZMbn|*}A@GyF#Gb>EVXnIAWm+3ef z5L3iBE7F->lZ54jR|z#EeZYzy>C_?1INzthV=6wjU^Pac;%pQ{r}u1>t63ec?9?I8 z%b{73%xO&-?UN+d?V@M!$b;}wmFqvYAB>e3P)awcY*ITqU+CK^MVvDML8 zfuY%1fyL<~?Cy>_X)}ZPvJh#4mmP}@p56Lbe|2XSsLa14y))PdWzFE zoT&~&+jig1&_H~@7mHEWpgi`%)&+d0IvU@zG4o(ralHX6?quI;{{zd;2@~JL75{hA zPeW|)q;XuiCneWRs_RwB_S1zCK#*eHztXz^=6pYhHFlr|)g>xh=f254XW|BDTGk0q zbqjUE1T}0T+K`Kn){itBF#DYn6GGELcSMVe5%>NhOjL>krh}##IT@NLWpH;55$aCL z;DG8M9_28PZ}={ud4!>35o*)y{co)Rwskww>@99oz+~G=+$AScs-FThFuB!>HFQzR zV>PuScG@g`4>D#l+Mw)sD%#+q_191BvwPqn(Lj8Z5C&UtYuIOA#w(GOrK4^?f`}OF zXG+YBO{p046)uOuvAEhst4QV?^%0+*TQKLq&&dj}Wn9uNONA{6UX+zv7B6Lbh8mo4*5JVp_W#Lg+SlMO1k zF727#J5oi+_wONDcH{`0C@R0Iz67jdg+ki!LiSc|1-C70w>o1YPNk?i2~(vOQ;Mou zZCtM-2@{(=6p;eX{ziPg`(Fd1g3hOsbe`*Ln~F->`U)qy`pU`?fZls$HS42naWbbV zz6@;DES>OnUQl_)yTd?s+4CA^#|O7&w))o@Y-@{l2mc)k?VQA9s*Eohtuu+*_YG!u zZ^&fK-WAL9Fg*T!txUuuWi%tRiG5To0F(pcr||sw-{dbz?E}15HE02C_Vt_^owgt| zoJZ}LZw|A);cZ&iFGEI{d1GgUEB*<~Y zq{zxA8^}b&&lJdtb@qp1Y*j39)Lb4>UW2CAGe$O4VqehIii{-A5&R+)?%P^MICSZU zDYc7N+s^46FD+orSC@{qM`4%HMt?&s$5;0 zv^LUHAVO8H2e>8K4va~m9gd*aJbBl7`?s5RD_jPyPM(7#5FB{00q8h?Sp>?r$KtTrDdDpbR0@ufx+q$g3r7vI`nG2Ba%<@Xd1-_-_ksyF z)Gl^xL=WYEg2-}^XV`$x)N(wvhK|$Rj~~nLgYZlr>#w}IavlXb)nlhOP&K{|D^XPx zYEvy5=#{$XuUUHFHu|3JQyk~8q^HB>2ruq5u?XJ10=c=~xvRJwVZm_q#d`C#KQ?*! z%mJFILW)U34Pj{7M8iB9F@%>lgx^}Z5B_M2?cP;m25bq9px}!AE9ac&f`o4AO=(`j zR$4q++4Gm?JMl?BYnNbDz2@;gW+qX`u5QuyxR{|ZqnSU%qI{awICJS{*EMw2PpU+l z^&Z200hD}xzS5WBk`?pq1#Bn<@O^ZpyeMTJ%5O=+N;9%)j#O^=TAfivhG`69BLbc% zJe|VI@-CK5DgP=IoYprNwEp~dGRc@RDEp!JWa~U;-u~7VP%GNpuX6!gI5@75%O*N0 zh1#|Chn#!$8n)75VX(Y;`7-U{IPM!ACE#(p3Uu*XK=EjWqhm{sdR6h{d<>X`cAW?$8s|r0$33p(}&&yqyT3ue@)LiA@ z0BY-9v{vht>B4;YFsf;AlUy5arvg~elrxwF=w(*6`^}N`L&iP>_#GgL?!;?p_w|Md zOW0JnwQKfbOa&DXO1pIo;3|v}&?!~^)EH{3?i|+CduKS-&^Qm?D4O0JGSA9qP@tCD zTo)FVz54o3Z{}=zay}%ta#WFbf0C@)0a}agysCR81dlFqNiAHdl!g1`rk+};cer6_ z${p231gVuFgH;uE-YeWi>FGZr>nf_9H#N>2DE?x8???V4yW+UZe2E~ZbffLTe#cr) zUWF}ez+Q8XSd@b;4;tQiKDBH9TSdRI4h($joOw!mAvypjScv^6`ckk-5j_5@JOHBm zTU!lIg0#7;rKPd5yUj{HwYs+`M)W}@CLNW(k`beNlU1ebAE!fbJ$fL$$!D4fy8G9# zfJ~{MW zpokyzcx+3AY4wzo5zqt_qEKu%BmgaG--AQtl?U{6WLu5IB1thdtaOvUpvaD^wLIt`;U1&YiRG$^Foc&2UwW!-Q9DqfTFhclvq#};u zLd_|7zefAo#g1)ICP!Rm^jifitxDZ7cRJwMpJ?P~5Z3IazO=cSQ$=O%DA|hc&cmy2 zY#y&}!Al#a785{{v`uMz*i6;@O*=VhcIk`~F)vr<1O4-N+9kJiE2UT8y7_cw6eRF8L%BXVT8eh8Cz8dN4;UgZn>(b&UxGdC&Y`cl}3z$U3`sX#lr6n zV$SEXd;ft6@;PI2@b`~G-kgQ*x>Emw#W$2^Z-W8SUC40g5KIh02v?9(;Zdq42goex z5(<+&(gx44E0G_J2*pS;4FnF54H}n9W~r%WaYVrbXHzWbVL<#)rRvWcrGe&txS_%a zakwy+60aeI96zi}L6(I}UcaP<%d>5k$w!J1?QC@Om{(HiwgQpqm3yb3 z0--B3ivhOeFY zbFIp~Q-(v+f^#MM_*w{49y7!Od>+6wC%BZdfuQ`wy-(y~I1BepF0PO#Hb)~b^Bee4 zD3QjFC}lajSZ2qQH*`$rWM|THSQckP5CR$htW7hEB{z#SP!!gXRW{V{O^YotA&p!E5J&Q8lEp zgov)f$o(*6OMv0RoQD=te-#0V`n<`q>?!W#dMOczqm(FVMK5)G3gUSR3$(GjT31$|je}3MOIUIwZTKQf^^{;>*v5 zN-afI2Cc^+B+TM&Lt9^m{k?yx3EVC0v;M=)j9hByV5Gt95TAS6##COZLwAYFQ=Tki z))9H1`}RW;Wic=63E#P+T=np~pJ+KNq8{KcY#(R0V>doMWhn5-Q({+hsJ;?@UTJ%?_7fxgKM++eLeU@Vc4ZHi&0f$D(wnW-a1ODZj3LtT!t=)+X5gP zaDM~6V}d-0C+Fcsgk_3v@C8LHc~-YdgM@kS~kr);$qZt5US@$H&Ht4WrbhCv99Uk2X$ zVKCIp7sK5RU-3G@C^me*UsI1y*smhGkau)GM2K9u6+t=lYi_C}S8qbA@@^~oNuu$h z2y~6y&_|n@rf!Cecf*4z^yxA-!((_n9fbuW5bPDT6J{g!vzt# z!#EGg(pKhJqfP3Fr9GDy;VwH$UpB`|O608H;mEjanf58EbkxnicK>mcbhW;DZ{M?L z-r=|HNHD*l+;F}2Pmit-7jU3s$Wi<iJv~+kT%?P7#338W zdxnBkV#Hg4>ud=ekK2OlD>Z{vRzXm_+4L-9O++(Otb}UKJ#1rZF+jwR3n}! z9a(r0zFiWxQROKMCh=ODywEn32jOk7p$}VcruDak{l!e{*yGSSjWF_<9{x4=6vS(c z+%t?=XWhp6EpaqlKWHUz#N6O(uJm01hXwORP4IAE3d9jH|xx#mC8o|$xN!=L%c2c8rt1@lI z{t!p$M_1lkgrm{FXE!$(Pn~1nCsq{Qnn`?yPzG#y)_5YzX$Q%)&L>Xmoz8r))HNUn z5kwTs9}ABh70@;mJPk27G%)+1gqbdoK3g(Rb6T_0Ec}yS+4$K6;LzvqPS#N_YuC?V z370J}aI}2!_NvP_{eb*f&Ig+0roK9Y)hvE z(o93f*}#s`lg}d^ay2cMcEV3UpR=QxTLKu@T$?MnjuH>v)OEtCT2#&utE#g6;*Hou zjd)@q({};*?1tXl4noOle7`WZiRoVtSoF=~DaVJg+BnVbax@|;BlqS$Zm=tB_F)3% zbyTAEU+jh76-7$A`BL*s=ecMI=?3nCDwsb0Y?rOE*1H;9a#no`Lp2|iL^tcIgLQtr zFM7mpar-$W+x_7$@UB?g+ZB@Uh(xPaXk6Rinp!R%I#-g!_E0_ATAg;1iUk zZ^RLzrG#_U5TZF{EyT7g5fHj3@W92K3ZJ0I6 zBrL;Y%F~{kSN@eshiW@ufkX}@u(GLf#40Im@H$pSC|i<8{3Mh_5Ulm^$!j^p;ELEl z6^0Z7ao=@?|LxGFWKS?`Js8R+Jb)nrJp%AP8Y3(0PqW+p&Hi^*sSM26qOiVjW@*7P!5|9) zNf3kL;fikPS}EH7Fic?p&1G&j7z`fw?^Qu$10DmRGDX>XGk{7BbRDB zdZ&xy%<0|9UG7(@zrkY9Vjxqcekbt&c-1|*;=g#07ta~}qBzr;sckvc)nduEQVP|B z%_4cuJ&l%NnQTv0%b2W`e7otJQ06kTV8X7D;%01ofyhmX`X=>JI6aAy?B>%&rWc10uvPCV?1ACY_}M@eod+PnoiXd$78%u zqRn~6spw~z`g^{FoAZoO@wJtzr&hLap=8Hy@ejw@Q`8NiqMvr^?;#;TB=1kxIO-XA z=KYU*X$U~nvq~0ND(S0U6wWIVeWeZsOveDgei2}~GnROOeSF3k zu-5UCNf+`?xhol}@)(v~m66u8?U&852n{An($Muv(aN@M+AmqMfHq0igvg;Pw`oF; zNHU~tVk)p;rpb%khn7U*ZxZ0!LY3&6 zk|e+d8G&<>G6qbInXX=>P>+utn4pJ<`=Vv!gMeiy4>wKdWF%Uuv*-sOV4Ai48$75p zCClgE%HC>BD-DfOlV>IDVnA5xxK^nPDSii4r_40Bvw{oOg;DaJY(8SoyCvuV8!&(< zT{r(uHMe#sr)X3-37>yRbjC$ti&}C>r;vY^wIuQ^JO<>wkcEix$){Iqc8p4TO}4_E zt2`JFE}Kzr&=25TA7F^jhXqUrdJR=oSVA=7oshnhJ72~-8u6DOuC zb`bV?9<`T4uT%=0_HMCM_&Q55;f^`oTB#pd0>o+ZMwwvoo2VWpxgen=p-K?gCXz5V zNuTlKgFse1$*Efk^3lV;;Yk2#+pnl+rom-y6axf$txu{@XVVeN^(QrjK>WyVh4j9# zZSKn3qpAQ%o33tL`ugGMzDZhRMqrJWF}?33rH|P-tkNF!9i(~9^xV%O06Y|*^Q8>q zCGvKLXPGgl8o#LM*J?~tR% z*`c5MN7@h&Nd>-1BHP^}Vf*R?!RQNLW-Z~`f1osVtEYO~-a3s@0{FXM939XPXQ&W1 zA%|lc9c!{$)1Fa6y6VAfH38fvi6@8w``ZH7vwt3@uc`?^Jmsry^2=p0{Z=^tw(s!Y z8juv8*!T{=17&NfzuwlViAGnPF#p72pH;PxBU;oSV zE)gH{k+KfU(;v+e=)h)mr^z)U+1@0^z$E4t!>XSmhNnY|L+gbWS_w1%jg`aHfe*ZwfM`a|3o$_og@bTMofc;y7Nrb@gux=y`Bn%wkPR~{ zrV?KW<+x>-RVAqsX~G)XjLIOYl2`~jpawC8!a=5!U;-JM4x>fN13l0IGb`SJH-HBr z1ffW0ucZr5>9&4aLQ(x1u;XWJ+r>PurAG|=0`AC8yMRwmkF~b4S`RqsH2zFUL0BlG z-*;xNeT*cZCoBEEgLNa>DF#KEie6={2`%nes%Utz`a)jH*&Bs=`?hI48(~!UI@(Ej z$Jj!PIYnRValT*WYrSz>_d0@kSKN^%>DibQL&@nWUz68c(bQSiL@IaIEt&p+7+Xz` zXO>k>kIht5WoUDh?+#p?7hMrHzk>o6TrlLoB%9oNw+TE;+KQC~otRWVH#1Ju^E)Ux zMwx|Xkf(b?amx(0-EAu_q2ZO3tzttoH+qfuffn#ff&VUkK*fJ*dI0UaS*lKaJvv3I z9`Rq!`Y?~M`pRvUY|!6XlX|op_Ya8t_Ac=J8RsU=%=^et&%m^$K3V0Tdq)@#sE-hs zaf&s%e0+q+13R@JRz_XS1a&bugh};ywD{ynE3L+ubrxVaQt2Nd4^kv(2#ySrWzXM2 z98~yJov`sq4Ym<2`1pzI9<+v1!WSWK7^D6EF*`?G($vdh_Rny(TTbacG3|?X!n*9U=E7!9a zBMZ54e+vS)r#MrlqcO2p7n>#|nN%+7YYKf-?$+buE>y9lQA6<%woQno$7ZGucv+Ap zFi|I)0iBY$iZDf{VVSHvu@%5?ta6^{z+kv_{R;*y3rNYcRK*_&(HTl&anKnclXd(qV>*`AnC3*a7?gloEA`K$JX^h%f0ajPx<{o>rO(bW98QTx$3DsPe074pR_ zo}I_L_NtFyPnQ1vZ|PRue8C7slkXi<%3w^VP}MIa#zg=#pS;v;Tx+l`o@MkP)P{8v zxT1(#XZ#qX*e#N?eK59B9Qi`gCpLHJ#T=Ab87QN=(f4Sn!dgn3{!82K~e@Q8Pl0u2;<7DgE3Y&9!Q#iF0^=A8$u~Ey3s5={>7z~ zcsibF;h>W%8K-MEn)4u4NO^8Rwb&d)A=oD{MIZT3zFOnINjj)|@f#ZhTG`X=k_}wrZy6;x_bkes5F;Ib zZOQrIl>FjwVhd`++4G>;LXY+gkgd8r4+4ybr6-2X55VNl&9I{09=GLexN8gJLodrhOgcJO4*XQ zbnkk zFq2jt!ohN~=@!mZ`9M}nOO{|fpNC9QOX8dGQ~LReA!njz>#TM(H}vuY6AhsbF)l9O zF6r_Ohw3ypkUhKr!Y-l-P|SFco;@^h=BpTe#KL5W}U3P`)`?Gqlb1<5PKi` zp($fPxh#ukuZQi@t>u)UwEhoO=M@8!|7BW>O!L424l0qziFeOg4_MmJzq+xkR;9Xcc@<53 zxDelMLn^QtQ{w`;o+<~`E?QYmroui#1P84S>^3a%{Ubfkv%YI=t_TX_TZ>!>{7TQA znpA|4acBOEYH%S`=vHG)h9?*o&XJ;soGIy?3w=CqSQ5q|ppyRK!Ig6Ux_h38h z<+UtoNkllmB5<#tEI1Z;FP!b#_~h{c8i+^Y8^3{c=iTbw{0MAN_*GmFD!pn90&0Sv z_^y2BTBr79NWBX+uxQNd`iw;LF;sz71BP>HOBt6<4Y=Uh8gaj@fgB*Mun!#?8(%24 z;fr3`D86ErdAI^ybra|5CTU26`vr-B(7R+=ZD2bVN&kFa6aRF1<YHd_pt!t}cF&xAzPK8*6(lEzkEZz@>n2-u=2QLWH|%AV zHKsT2pPtm#zm%Srm)1167)H=)>R%4Q-24w9jNQ$kjAcD@IK1t{vI`0+rYg-(9fchU%bH8dZzG^ zO?NKQ%l*vyUEBOqgYf6d+!{-wzCFT$^;S+F@?{TVa&Gxby6OgQ&5_Y<`GJM#AzcoKdIt$#wmi>Fe< zk!;W3d9!;C7s@_U6UgDjM=~4QeP>kr?AfnakXOWiKldqtg^ltn*7@f`V?r5c2u*f~ zEu%i}5a;h4{M8L)cQp&p01aX&s&23OUVx^9nA&P3Z4wD+r?k7vzOqqQ5!KJIC<2j} zYJNl86*EE0bYDD#@(KfdnOeJwXtL@`s1)>_0+~ufRZ{EDWoXD%&eXt`T*>97*Ggfm z7)-YsYy7epW|B|;$UxB1b&5|cn}G%-g;q2nuTaT#GN%^*RD=^~F?!Lr{Wal@2e9a< zkDgCznc=DM6L7A`=yNOF|Cs~>vMqMz3yPGQCDG@R&Mc8-SIMo*DagTU=Zzkc($B21 zbUJC($CvNGHbwBxDWH8LGQO~_G|()g0aNQOzu+EvIdEJAsp%5mpK`WB{@}Tq-q(=0KBw6sczOYFZ;a)wx3SH1c=~`>?Yi z-Gx8bPxG7$%7uB(NJ>J{&kRSCYe$CUi5ufX?RkssRVrUNgm)M38PJFe1zbi%nnl%3 zkM)k#L%Dl#!fmN((xifSx%Rdo1T-ZiJ#_X80c{p{TE4X7p!T#1uYVVEVr?lfc909@ zaiTnOkTQ=4i|>KSC;ApkN+Ep}DuBFP_bu_fD zW~EIq?sX&JdUyMY0UNBSx_oo2u}h>|sWx>0{VzFEDn_lnv{ON z`dBfZDOp)zyDpwV@}MmgQ@$pQ>~Pug*$f^(@5+-&uo$U}MRKNV`lv#h+OEa2n${ke z8eOpSG=|DNOfWNBz$t{v{m>QdS#xniR*{CPb~sEjp&N9TxK9Z@JAai=5R_8;^wZm5 zJ8hl{5eib$ADM0t4AKHHVy=}`g%)DW0+rB|hN=Md3lT_=2 zTqX|Bfidwj!Zl5~t+jt2*RN=3p`e#cDJ|#)Ko*ed=orsn0R1kVAL3dXzZ7C%x^>x^ zQI=$3mvdp0vN{8ZY=tkVT8%VQDo|Mtp%$iuLLE3{>&V{bABP+3F@Ab>JVNhyiAWbs z97!s8T;c-t;qEFBV)6gs{)mT_4m@P`kl5v2dP6;QXcx19)cz z*&cNH0i;n-gI}6tTHEGAo-lS?M}lhoh#le^MYOu90A1pSc6m!xp9U{|YJuL>)UA{) zw-W?MzZBloZr2lgvuuW3hM7?hv&I!ol)Nl0Ci=$x<6)5Xy|!Y2pGZouhG52?*qP21 zShCv*!HIz*n$pQq%0Jgq-Oe@Vt=jaU1ih1AS@e#zs9 zyVJ7=AbO<_+9Q7DpIsCkKOcf}Cs_|Qf6TRaL$|rv14*Esp2|U1v+!L`+4%R1f z#}cH8)DyMO4pvX<2|ADswQEc$+Q2m}{GpNnFyoqCLM{ZV8RybgO+udv&L%{`*ja`8 zkj{8`C6$Hpm2}30LG7m5AifAe?jg%zOM+CwFgoOa7>z)_z1QJXzc2mEiSsw;dfZIn zFcFvX8tW{p>cNJonY0Hq5FT_a0E;?Cv#%8Io#(TZB!R9~A4>NgFP-ozZ8Wqr+7H<-VJ;3M9t>K9+ZNV+NV zFDexKN6A%VqSX~Nj!dUBP4Ye;oJS7A`P!FO4{Wzus+A5*lGV%4V-Gaao@?WT^Zw#? zp=jyy;vJ|KBM|cn7|2=~g=&-=+n3-J3d&@2mEywtV!N*d(hIbH%clBL^1{_DfNBO& zxRY=?Vr&tutr$jlP_6{jNKQ-;8C05+`Bjfr{JJol(Vn*`A8c!8*~bU6;El#>vQv&3 zY16pntxz)WeTIYB8!z2CaH9?v2n6^H;e&=t~3RN`7EM@avN7O$xaxX!2rb;MfxMJ~~AsPY=(4V|e- zL~~N2K(7scy2q9Edw3=e`#H#4IIn{*4^7b^T-qQ-!4}-IXUuwtc`h_GS&-A-22|3q zY~AM%YV;e=sQg5aR%~a4*PFU1^b9&Q1GpqLnSq0xG|#taM0eFQpl0O>{qO9cdVUYI zO-*%moQr883a8R9RV>QTJ_0fNOdErpGvapXkBv-HqM229SAUhDst%NfhHsJ303Xc##g$69I){+Fl&3kBm2;*Tg4;OsH+`csVW7QUtkff`Ke^WUuIxrx- z9$)wG3#@1L&Do1FfC}?Rn|TssbmOe+9ZLUO#a5b+K1LEei+&!6VXcRZ^Pdz)uN+jc z=Fq6KHJwfhURSN+-%vHKk6y`F6cyjVL_d6nNv98dK5$0GpVvkyc@@EFU`);Twe; zqY%nP<05!J_xSF_zs$^%9SpK49v((mi~_zp;aiwJ2!<hlut?+R(}f=@+f~fuhU7mBEo_I6ucP3o>L{=tQ{qPpZOzuh(N?5(niY*nqH* z5Cz@BL&sYKKxkMD*|8W5y@+Q+)-@)!|Dy(Wzt*B&IYp!8P<61K@J$Suj&(3HpnA`n zSkOl-P)wy-bq@Z4N*A53D+0TW7B*c?V>L*)UO_{UmDpPzWrSRzWwE28s*uG$So&Qo z^50S*25S){V|czX^g&>xEFszmkKx~AMp^!6P7@&uKsT4p>14@Y&?hR4+4& z+iAQiJ}X~HU2}GU93)+e8)K$EaZ*0Bep;-4We|;bSU0K4%BuYKuC}^1mP`|_Wmff! z)>Xp_fM`bXn{+33@^)Rukojf_&206|5Tt)ctk#ja7#ihc^QQToc-)KFf}0?7Z+C|{ zO{@*rcpR?;>Xg4Ba?~?coCqGwb}Q*Xl+t*6qDwPPX6@4JCQxkj+L&tdoQAEjd>f<qfKF5cvlqaS4VL z3Ixuv@HY;5j|aQ4XMc#Y+LVyQLsDiq2WN-@<%T_uSp1Fb$H2^BqNKJoL4{_AU*K)q z00cn)V}X3TE3%fX|1s1MqF*Pfy7yLePlrXaXvmJb69d>cE_S2TDelbm>p1VTn2VNd z;;Wb{vj}l-yWy)kDT0lJvpEj`VgFdLI`9&GHrpfU0@oVnGCI;2SmlSl=9P}znb*Os z$SN|&w<$Gcq+ACze)bi%rEPe#IO>Wp0FQ~cmmi~O;J7!#GLa$9ip!$)queg(GftdE zAl}I^uA2lC6OnuC?RWdz!?e#;ufmj1{XW1d*1tO!!f9*-cRB_jY*LNweW^<^yIo@f zzFn>n6^y~E1=SK!080|qdALF?czR-CH+F(34&%V2n$xZJcZdi|B00a0yE<(duu_+& zs~^r>gwsay+H<_1&1PHMuzhEQzD6JoRIdLK%l@K>cNr7=VNS_<)1dFkJn^|jrW`m* z81Kx7;Iy0niW#03NA@Bm6aIcVOl*NQ;_yDtb9~#Lu|*I%+ps@R945KQ|UwoK%csoECGYbTjc^tJl^qIG;=%U&h=miq{9FTBR%3z z-Qq~nPArQyTw&E)hD{*>t2Co=&Vi(xs=6McX~Q* zX5vFdljPMSjON0v=ccDDr}R}7Rkf8BRdMV{71Me;XxZ8Y3OS#D_Q!Mpxw8t4hyXAo$dZIp7Fy$W@^s4|wLca>@QAAu12hzI}9`<3SMJ{v`($4FNzuiT?IHBM6 zD2@T?3EzGqU%4S4-Oz7<7nBEp)Oa6ZdVT04o72q)}iboNl%D1rQ%XU~RhTW8yTxKZ!hf^d|6gq&omi zMi7E4YFtvPQRcg5u@8@;OXk}3dA0qP0;m1|w)WUxg|J;2maxulw)Ov9$Wsc)%hc(^pRnEvQerbMd&ijEHuOq_J(C z%+cK`ML^@&2tyg5-6^G*(j5*JRb z%wHAhB~T`}oFzHMQ`gY?5>|5 z;zOYIa5s{JfsObJ<>W%`>zu(QgdsT&l0lQ|?;TuKhUyZ%n`n zRD!lqwOxRHASaB+B-FNjFrmZYW|$_5m!uDRvfn~sA84zKvM^#sM)Jyb_q{9$iH927 zwzwOrR~lu7Dx!jQTMcY5Q|cOJUdw)049-Q8spV$qE}?|6R$)L1Ad>xRg1%fh@NqId) zQ>a9mlEhTVw2jM5Zz*4^S3<%dXJ#gh?XBrUV`y9&t>j*tKu{kXl~*4PoF_4y+kT5{ zWLg4}+^iY7>FbQcw3YL;n3rlYz|nU~8mTT_kRc#$g+?P>7l5Wi|8k{eHe=w?iqihu$seBj?h`**&Wc>h6k)x5)9=cXvnHb$ zH3McBJWzznlgJg9aQVje_2!}i$iN#*FB}D6?%XSVVRP@~@PnJr5m%lrX4x^+N`q^| z8dm%n3?{=&(uPf3F=(n-pt&VgZ#-ZVc|!s)J6Q*?iaTd*eN+Y@J7HivCbLpkGF(w2 z?V~OFtI*#o#=b5`DdPLOLt6+rOLqy0)CYlA54?!U)?x(nd5>>U<&!s>{!UPNGFSvO z6geVlZ_1{z8*g5zW7$Esu&D&;r$sZ&cR-Z<2Eo9nnMl=*B)LTbdr4L|jIDj-X3B)a z$=lNEnHzep^-9XotQ$8&XfO8M<2Zb#N^s;ggs!XGI}UJrMy?M|+lmO+ywL?+vaq@P zGH5avUm!T7^|&IJr{#;|FTqA1Dt-hcVdS_MXQLI0JSA~NzqLBymB1prM-WQgke+ci z;qPneD}0H6$?D8dSCRZdUYyl*`U6BwRz*`9nL|^01UM$qIuDoHHL|xKgAYKUhPH!J zFOBidNRzYC84qu$<=Owo6w{5+dIAIdqwt~3`DLQSsf16%;Pfw9{LZkoJJ{K zApx#Lo6gKRlw?QN45ebvQR|Ni%Ke$SRH=B%c*O!>PKc?p5ujOn`RX0xTFWh zG6!r#D{h$gPg;y(`{5IM*u?6_vc1u|ncO(IjS z540;n?iQz$Ax`gG=$?w`MkE!Wh1lji6m`gdEOK0vZo93>5cECSS^NlZ>E~1|c|p3j zt*&dU8s`8{?9~OEc3|9;qX(|j7^FARCjxhI-duy^f*&Fc;l8uL-3#AUh`Mg8i?Gsm zqNIw|hkL5keE_T{Dsl{sTSnPtWY9#u`6sv|(g`jBx&b{9MrL(7Aj}*v)a!xAN?U>MlL%$jfw> z70xfiz|V9C@(pA4oa`VAmaX5`neQ8pyOVp=mY^0N6y~G)(!XQUp5VlP>}=~IF1SI5 zT%+z3Rd+@3s({!zX>bI1sK`toMAOH=zTLt%+Y@CwfwDHm;M_PeoZ}~V)4Q?QABIBB z9>adgi0Kwaf}=MVKG5pyi1+pInEsn6A-cr8sO7@(D{O}wyjNEklW{7eIoA}ENy~%w zc<|l-f&UJ{U37%J+~nF8XphkZsGeJh=+LF!<Y@fMhjLCX zBNhb0Bz{D7LP5I+3m2Cj*E}JD(UhRA97NY}0e0c3ieWTwt2h4lSes*~j(U?bdn?On zOA0unz{=7WvET^+F<`pL?h(|Bw1zcp&}NR&E?6HMX?5c{2tlMKb|fud$}cxsZKscjvcO>P^%V``7sNnF*-&NY*GI#G z^ji^dcHw+UakwDWou_$9sC_|}lz6wz>%m;c>22SYG{?x?X&M_KOKEvb+^V}IZ5KTw z*?o(12A8~VU_Mex@-Pm@eNO0h&n#V!JS%2C+p%1mFR_c}v??B_a7N8&nwp6HpzX*N zQIWu>C_V>(7-AiXUW7dINu8Y)h0_+-gM9zRkDW4(qK;NB11&+1nb<_|Z#juXlL{^K zpJCCJV_*uVv#-AeM!BtJ5GvdY4{Ptv-)1Zfjr5XcDP&NEj|MVnR5OnAV$INuQQ(E? z*uW7dz!E0_TUR7d>Fj1BNL^$zu)xS{yFA!DEFT9b+;ICV_2gd-Pn=VBH_V91U6+BS zYLp1s^IJM&nGyo4V|$X7VS0%H>m~;i2ySLIR;hVM^aIY<^2y}cBiZ`4@^@!gS^la}?)lPEPsq-wI&|jdWTXp#H;tW?o|Ou5a5Azg2Kw^&>L*|V zo7)0LxFTIs=u*tQ5JHK|r72;ho9QZ~Av-^988<)=uW3C3{_yF9DcqZw;q>n|r5MvW zVVFc#W68R<>!h73xbU_wQU5`mMQ`G*wFiHla-&7_klBHeBwn_%j|h3kuB25AP2gzF z=R+`u+`jouTj1WTyLF|o(G$*h0I^n>&o=>xfRCSw8)N4qSYz_!;`dG=_{4fVA6oob zd$2L$X_4p3*f#wh+1p1~9TPjXWYsKbNED-)t3^KNr>nA&0W9XZ(4IL%hfWBQloIg- zr52Xv;QSLIr*i#Aco^}l&;$%En%mT6^FKP&`%HP($mMOTA>>NpFXD)n11E&&F>U}E z0eclO27lebg%iAJ{FK6+qi2rv9aNzg9s3d;@<Vo*ft}u&;mW{LP#-*090_;a&ouw~Sds@GXD(q&49PW6H>I9l_R7&UnoJ-@Jz6N1;H77-sx7 z#6EGPORzv2f02s5Yp5>IG*%c7s}0ueSo`9bsq>RNbtp!!Eu>uJnzn@T&T{~41kof3 zQK)rbv)2iobuvs2!2 zu;ydAkF1g3$7XW!$iFK5#MOFGY`&vvKWTp-t2cjE7d>Mu-^VLFlY#EgBpfx9Pvf6(0wj+GpEyElOEgRfcojrz6Q}flXWexvB#qAr`qtY5wpT6uQBsXQSIQQ0m%xc z0BZqNX5Xu3_29zak;&sb$9POx+B)Jn>t#&%_5`OfT~ku5)tH1cEVl%Rdf~ny79T-S zetou@HC~bFnlD2;Zse29OS_zQyC&}2Frx**Mb-7=4nasz_iSO#{pYc-JH?06PiV+; zF~#wlv$X&z?Z$!r#lEnGYBC_gol#8i%=OXPyf|KUbkvqOHQ{~73Z{QA|CA}!&z8{( zQd@mY8=A9OrE`D1msSPPK(-r7-eB`;us&!n7nfva37gnUliW*JfOwr=40H}qoCl=3 zmbs>B_sz#xQDAN!Wh`jmf&SEf>1nhDkI@sZ_cXAP{O#}J!O>ciYE`aembJF>JO0cq zTedFY*{Y}*6$fv)5fu9OiuQ&ySFz#$V8r-#q(JwI8aAYKr_2a=^ZYyek-Jc+8sVC8 zT)B8CC*QZ; zb+{Boxvd!+jM4U^HFzi*Na43m4X0E!L_1ZH6a8#sYl0l!Gse&9VkUi+{979O{XO%k<>G` zDIbrTZV>)&-$V#Vwh+TuCRj(ug8dBs8p(lYASQgU6Lw$e68&a=E@jpz*1kX1!X zKLUUmHY?(#Lx|r_dzqZ|+w}vc2e2&~UrjGox~)l3hr2z=ad@H$ePZ1x8G8DAc}q(# zB;gm`2ZFB*Phcz2blKR;;!oaOj%goxQl~l@=rCwEMc=^@ljZI|KNxwHyE7*_W7z<$ z<1bHH2^L!&PmB;sR!?y_Iv8#37z3ivX&=A(Mlf;5J0)hvOx2qV7}Wj$r-A>GQ3F@PsObKMxaWs#9OEcsn!(S$^mGcuk0Y1l?&SyO!}g(9HM0IE$^a0x zL>IBoIuOlxSt{OUpYE1y72I*Z*?Cbq;uO;pD>}}VXz!1RpFISTl=Ua&zD;7}pRPL0 z(BpswGaV2g9(_t&z!Xp>u!^_}N|qFo!za3j_~8ed4uJ%op@jk)XgO4VKLhJz)b(gh zLwwpgY0Xp50YviwnX2qVzi46U=PMxEQd{=@LM`&Dd{)D)-Pb5y$6J`<;z z&DkJKc0uHXZocHq)+CiRKFiiz9(6^RNX{5_bz%NYo|tRLfl;zIJ2lHRb!vOC0W&?? z)`V76RzA>o#a3|1a>09AdIMmYM~fNT8!vOQd0F(Lje41X`>2Z6cwPkmcOjzpmARq$ zyePhJ`?N@dctvXQyx8n`fCpAio~`jWv7uQVlFQplo*V0CQ$Q#D$8x!B>t7H$y(#arj`>lmPPLeK%ilUjGH_ZGWF0324%}p1b zM4LEw+Owb&t3gIQKCsxo;QqGZXmcul>7QSv7P!yiBu{kRQc!QW%5w(N?`qCAS)tCl z{AExOD(moPu4{TCf$=Whf|9PtZohEE!X zyoh2BEx&bp9`>8%h*7j<(j+5i$tI1G5ZYY%ItXe{Q}jsnZBU*Cps)xD?eGPo++Ec? zB^UO=%UK){Scw2D11<>DCtO6=?J&FwE7NwIl9#2J`?#d&x*_&Gu`z8525o;uD#G|X zvMsse1aO22^Ek~XaGJGDC~(HW3t8_trXYbyzeKUW4T1c85>tt)W!75B>A}nG)YxAfx)S(5`ic^?H&nF?gRB^Uf5is7GOS8cQuDN`{V58n; zl$l>^FBclE=q(zQ`Qp=$#F-dfL8sAuQVb&g{b9Qa^1+K=h@C&xT#K=yRuwmv&xDAy zsGE?oqLw|NUR4Qu(XBTmO_!=UXosn^M@KeTR_qg=z=0(AE;HrQnOxkVmXXyC+fq-v za5oe3N_zqfQsa7`bhvD9x-Xt8FiyFhb>(hNuvliE&AMD}Nt0J-Af%i=Ek$Erl<$Fk z;-xA*)5}b5=Ux4NOhV67_Bk)L_aFqme7zo(_cHV%*h_)E3zX*ua%lX`CiO)@oNa*N zXGfGbT7xYOnaFVXcAEipUiN_ZWk3$OSAFd5%)bG6H6Ty#)1080yFb1&^Wz3QASVy` zdPI?jC(BFd=PbbOzrf^BC|8W3J5vB=Gq+(EMfKi^^k~RjP@JrSVU8TdFL+Ypvx{mP z$F+?}A)}ukdO0eS6gX=A z9^6g8oJ|!wRJp6za&QZ8e_$@NavXEoqI2>TW2x*=n$}HT3b_71jv=@>BK{4rQgX(y z)wttYNc6u0ZKEMdFh?W@+N)wElyWwUky3!6NGVQA5Kn=LTq^~!)dZW;naxH-Q zcGGy}pE&!b_43S&W&F{Px{X+~z=g-yQJAJ~Vu=H9mW-?E0+Egk;XFSmLod#gY~!&@ z*v?f_RwVn9-n_t^ijNb{8g(cbVIlU_GrnvQ_hKeZP`Es431XZhDO%HX8x<`4HvD7t z%G~;2xlH?AckR%y^!>M}De`MXJ__Ij)ft_O*h+E%nayVMmAA_DO;OrQM5Kj_zHkgI zPt()j?3<9pfO%I6QioT>7j$3wBsRp$vGX;#K*ABDO-gr$=?LZTwdEJoi{#%>gKc-o zwAI7noV%ja^&XcmDK1x{KA{0*!y{a4 zg2%MWkHU->rJOHIy03|l%XZSfoP0~(trG2N)vx9?`MZ<<3Y%SY1%KlcmOm}=ItCuT zwKKu*fGP%F`oJGH?#-f$IUFZkiSG+0M&lM5RaXX>a#)c_EEn?QpY;bQ1y2#0=1%Th zlbV8rkYIz(8$_z#XL5P%3(HRn%kT?7O44O{{>M53@A^APuXh36uC27*y)^%RnZ2E# zswP=MOWE6oQo^QE!nVaN?{fuR?{xa#TWL3qrG$-(TR!K-ZI32xuJr)=-(zVv&5JLO z^ZvT;PP*Rp^q(R0pCy?;3ao#huKB6GTWP!IvJUN~w~dQyFY|=DoWxOO0^cpg!_1tYi0 z7vldEf(lx`pIf`Z0|CL}0|8O~M^POw3Je8cFtIgqaY@C3bVb#49Ogur;lUaVpJ1P^4x?V{}4LG~PlcpUJjz0v&jjh(1xeS?SCGrgk+?!6A-zQZ?v ztwZgF+^Y|HIe<(J`J9Iq3?k$`puAHx|I7pu^ceK@+y(C2e@<6;Mfcqg_{DmUd-|G? z`q2jC4@sy#aC?9V_eIs8pQD5bFpmWQDuen4_wepKfWHnxhW7K}zDA0^&94MOKGvWm zhsF?ILwE(<1}*LcA$@0uZ)m{8fMs(WL44^9D^V2&S%9Z<_XnC}YJ>_=@U^r<6>5xC zOqFH|!Uos~a%b1!AQ&K6v8RohvIp=W{xN4v84}1|&8-8+;E(_0==`u*@&f_GhQPt1 zSahZh5t)d!gCiXw!nL63JcT%ycv`o^5H9$!2)52exB_GW;mlmyk&^p~aB(DzhYJXL z8lhwRjR<^kIuEQ29{Vtm1ap_X1Cf-6(g=DJf4#tL-3N)h@z)PSUKY;!)e-cr``Hm5 zVLh8r8A8vr&vbx6e^P(oh}8hYEvEIG;SF3!ODH!2+&lCy)RDG&PLQqkiaOGhH#K#m zI|jiH;3APZ8A)3K!raBQR)=*^G~Ruy!40lCVmcS9nNzt*kf<^$9@#Zy$LHy+cGUFM z$>9p3RF}#u%&P^Z|F(BF0)f>%$`3aL*e?)p00lRHi#)myII97rju%E@)hN%YoXPQbdz zIZpC7_otk$VJCY)LnTSG2?ow|LEUZZ$;V#mgk*}7!7V0b+D_aXXZA}=)=ds0D!ah! z8`Z?qb-9KaaOfQ47i7p#Co(*>i5}IgQF-#>4;Tq%5O!CU0Y-p_L}ADi0ru52l|!ed zsw%~WV1lXl&CPpYR%xNMRVru1qh_hO4zooLJi=()Ez&{I z2JvB4CXzw<2I*mrm?%fq?I0qIG2H8NWP5Cses^U1P+c*-aD0-y$pTc~aYP>lu{svk zCMzan%sVz@#W4V@m}iQ4Nc8~@^4xHxUKoePO2+|%9-}cHDhP%6@;>)N zX$jWB<`S7POdjfiw5Lo6?tv^w9<4DBD_S+lpQ~WHI!OSRr}d@ycK^+8L@-Dm<>8yH zyjeW<6TduE^fS4f=K^MgC$T&XsVS-fm?AM&Rb0SeVcD4tz`fo67XJ`YOeKQh+ zI87x!vKIRdwmX>~nf_|=9*Fu<7WPmT)`^;soUApADojdYvKd<-)i^}-!h#_lmJyQp+1L{4&=#7~pVemg}zJ5d4U`TAf z;e8{B_=aJPQ3A6o=1~HRJFs9%Y`&3wD~LHJ&$I!KHdCqL>kiT3+>T)DN$oVkIZKwP zL2P+>w`j5HYi_C+vgHzHs(l9JaHkOK(TmmhxfB3ciIPv22)yJ0HE=%WJ-Dy(aQdAY za$Pts(rL(yi-Zi;S2jhV*wg{?_g5o28br-VUFYg#{}7Zh6?!gt8^e^0ZVO)Qy;3Dl^uo6zK_O za?(myjR#Ym`jV-gOmGc(TAmHD4#XQtEhd21)hY5JHeeWcQ-Q)T?+HrwxoYgtHCFqu z9A=!ML_YTl!-xP@+ygq~eUs7oqQcxsJ6+St+$_f)pUea^A++^5FLG`P#*B1Cc(em@ z{z5kqtKbqY@dSb;6*8u^>C|0B$~db@S#gS4N4-8Lwt14fwOo>bpalNmr? zyVE|Deu7iB-|7%CAmG*6hCi+#V6Dzwmsh^7I3bKv{!g{ii8n|8&OBqaaLF1ilTl?U z+Fmn9WtrUtM4_v*BqNIQrDLnbJ->L^b!fM8HliSDLdj#agQ(JU?$GZpv~$Rrrj+bL zXPavw)ml&UtD)44Zez@m3{i!xjumi;jjz#VzQbsJRaeN|nt*+!YtM( zMk|jK`P)J=sTA;(HYNg)Y$Q7@2!(aNg~T@@3k`vuH5-9TdG zHuC8s?Ju()8orz|Sz2c7x#Hr)Y3x)cT)CXOOTkKaTQ&FL-x_f)DyC2v7RxWPp_Cb& ztQ%=G2a}2hiR(*Et~N}$veh3Xs_2v0O@U==o=O_N!t96WaTnSkb*L93HuP?9ntfU4&(m zps?Lv8~^Rwp#aE(4ee|34P)_bl#t200NH3PG(5zwm85gse#r zIx@`hyrh+JsNKKa>7|@U)ubBs7-KMS_2tly=a1DpH!3Ey z7LaCtYJelUnlLl~9;hIV;9)uK9yfeb#@`b6TE1bz(jiPY=2@dS7qWfey5tB!^jV?k zmZpdk)sJ&qwE%ES&fV3GDiHim5I_$`IISvW=e5JoZ})a% z$Pt+*`K$R{u-hK()D@*^Pa#8g$i;=p0qWVp77{NZ7!+_Bc0hz9;E8tXaRV~ZN(31W zCv1g)fpVxL_R~ffIjDXTI7nolZ1(mRMwTLt#{?6Gg@&F-e~(kBUO@3Pkcu% z7(3Kwica7ONiP&wPY4dH?G|L&z>zG7Bp|il5+g~8$`7RKUsW8xApZ!Z6g+UU1#68> z>$4vJ1pwChW0d>Uy?>X>6wIF(Ov=+ydV-%BTs$pLbr8>9hT{t{Ss1hlDS2={%hP6x zNe8>!88q%Ig)D%ePebhmNIcs-yyfR%!L z4iIl(DT;S4n4J#Bd&~|~d$34hB&*N~n)4MNaH;9=YeV{?F4DSN7STc&5`r{y_N64F z0z-8ebe7dja#LP|vV_W6tP~mRG?(m3IMN+Bm|RzB0Fe<0g`(VQ8@wVe;(9~C4I=k& zD$EPn-_WgY_ltZF3<&57HeEOj1S4JP`G+iDA_{!*A6QR& zf)sEI$bT3=xNyR;Ei&q&Oq`U-SLffE~M5r>-faEvV zJId?_t8MOM=X?(_@6ffRXF5qI;8ruGy^IB zID^%CiVP$V?xbL4ntMhaEWrpY1@PW$gXgPOe)UlG_TP!4^WKw(G179?8n;^t)E2=5 zejzjasSm7)on0dPg6_ra>%O*8^$y+Xqf_&dZUYoU-u=QX)O!#GmF`5r=cqmN4#2}$ z;Vj54FNR1-gNy$W;^N{7QW5j`E_x11Wrn3Hn(>tzp8O+YE3=z=f}7$s&M;$mUtvGm zXavQEu8m*SMQ6x7@f}E-7szRjuIxDg$YFUI&}H+n8!N)`Y_p`{n)FiBtBki;Y9-f& zltnEyX)>vjN<>oNvV``Sd76bAW9jm4^$7&UdemMg;$X{ZX8D1V?0*HR-$9VMQrL4J zK9iyxxA03Nv#)EcWQQC@8f{IKQ%sgCp!aP0SN?Gg(@oyK@WG7keJZa6b^1pN5ECC| zbuNbra55P@E|FHjOO$~aDGWOD{vq9qkSII2<9Ks>!F9=CP4?@7XfsRrh5-4H!MMISBAhk(9!Z=HI z8k$It-hSAg^_*bxVCtzjDCZgj+_A!+-Mc_fY!M|Lki+-&Gm_i>zIXjM37+goSya__ z&jHW+ni_K2)?w!36n=KqqwX1{Xzhtz&-9@)1fEl@rO7NFh|zPgoM9#BB01!6r#r}L zr)6i*bM?^SF?e^l(r`G2-z`O&13|aO;gue?cYqFGe@Md2X+0*pO^u-kXgAcwk#N!) zBJYtn*v8^^Iz&XjT2>k$t8AQHac1v{^UtaUUUXY@1Oq=~(;KY``NSnTTS{VuU!%v4 zll3VfV99AYCw%BI@kB$pw)5l@q{o}x$*cbih4)R&p%9Zf?}WGLEoc7Y_-)&_#zbV= zm8|Dl>%7nkCnApy_QJOdAZoPM>L-+H#MvFL2@~%T-!KC=1%Se9-lc_AzZQoH9?YdI zYrrAMop?_C)qanjualEYjuRO*RmP(@cCOb;YIr&2sinCk`ph02p{YVt%sJ+cpKW#0 z;bIzbF`FxM3vQ48g-^jzzdhGtm({{8zXaRBqNh#v9KA=EEgjJTSjIZ2lO>jpApc{E zH<=o1)5I}BJa;kuQrA`ow6NCeZ+X3v;m&VBhUlKjHymceX&UqVU@2*jCa%CKL(ahR zkmn6ti(7RHb&urbe*IvlP{Vmu4Q+ZIcW51zM;&l1pzj;eB-E7zM26M=)w2BozHu&3 zBsZ4E3j3spb@Rs`pl@%9UkyP={O?=5lY-M8O+R=_Iul(x^i6Hxi6$OSzLhLY^Njl! zljtqVWUcj%M+pke7hCx!4~NDOJf?_LVS_JX8<~dg$_?ZO)1YUHVj_y!RQ+m{xpqHt zw4m4ccg7_0EX)X-HJbR(mi{+nW&$;|*PiBC(Dq@f6^;5aKsq1#C@%46U3f3!w z-^Bcn9PU3F4O3v8PTLs!Eb%3R_jnFf=IAtSu@l&dYD<1lb}#T+)`ZgC1_FOvj|*aF zOsPK)d>m6;(NZip)i=fAPxE|jQjcu5@coDfahoZ9GKe1M5C6y3JH|)aK3k*dOgyn| z+qP}nw%rpWxzueVzU8|~A)xy8?u}^SO z@7gBXCR29=*mZ>whV2YNV@p==IMNn5gn|idF76@BT$`8gjY|0302Ml{$hm7e-LCm{ zd7G)4$78*$6rqdKihv$nZD$%{+q~*wEGOM}>%_!@F|=KUbo&+G|9oTb_{LYyf!#EJ z!nDH(7}&%hK13!u$sCMfTWR=~wK~OfmM(G%?rAmHb}Yay6z(@FqsPe;K5$IY@HiF< zRH9x%i}`Mrck3;Z0yNvXFl;Jml7ntt(m^;j|CLX7drUsdevELtLbd}R6QP+RZvMHl z+aPOjYwHJLE8IPOADi6A3|X**!t&v@q3&`i7vqCH+ynbyx@pD~nnZMM@x_*9&V!}N z0>QxSyh7-dkX5oFKS8l%Ak-K&%lms|=!oMR^zyNkJY-`EGO(4gbc8vIsMuDfrvIvT z45l9iPzuoz(g`nxBRKW5Glnxv3Y*ZNPm}!@n_*K0Hp-+1k(|5PLiA)1kgP^rA2P+^ zTL65{&%Esf4$j)~Wyl&1`MMFP0-_P~18XHpJWwF>E$$i}7v#s6f8WHJ4SutKz`(wM zl>$;OF91aUa}g_u{P$J--*<3Kr((Y_a;R1Bzz!9v=oMlUwPL;phD5$=k1B00FJHwx zMHk=6MU?cYoyrv$KYAbFYkHwcMw+Q-*YlIVAGC9b3}_zRDztXjn+gHCPa|0+4~!rVO%@uAK?3b{hbqI?4+K-bNLdqn1V&*1-lMf_-1 z4E6vpur_coFus3-6%%s@8%HJyM-x+fi+{f@)p6M`Ea(C*#fnu`v9n9VQw9~r!p<5f zg~#QKq9Uc$tPa@uY_JpN;wkU3UkzY`1HTbbSgui1GX(4GQ$A+;O-=6o-8(?&A>@=x z9R!6hl9o#>@K^e1Kh}sa1O12#XTl*AJ6#mFn-+eep^H^3=}f2v+jhFFcA0WTNy>*c zl%SFHQ;G~KxA8|vq{C6bYMw^Ru*d$s5h;$g?A{_QO%0=m)gIZS-)$%eE(n!-=scFx zp*F9tivJ0FsVkRg3@_P{oRb|bYe@Zhis zN6wg#W<@c05n^ZY5dqP)qN3ZdL?TbYv7JN5k-`g@pxz5!n^K&ADVa7F^lFgeZvWTR0FJ5u~0Ef#C1qOll{+r&@XT6Q6gP2e7M;SI;POned^#wi;2nb@mj1*Q&zPtmw! z7sU57>d(}sioszewG6nV?UBXA;?!9YOh;g1&kfEYKsn4_N<(cX&&D5*{WMXkb+7Q0 z+Q3Mr<6pNG587M3h36Zw(18LPP{9-YHd`^EM{wJ_$+mwa?X$LtDs0Nbs1jz|w8=E_V+K1dw0&g&aUakw`xQ+!i+q>& z?Dy4Ohm^-_wVlQRk>0ke{L_2AZ7{tWn0 zrLS4gtd0}qwCRf)W#EFE_^J*}4ivFU)V}*p=v!OoYakLLRBr=d7>SFPfY3f-I$~RW zT6qLR6qjl#?t2qV%6=y`rD9c?&-L`uHM6(f%~WH+CEu`SeVD0xk(E?4j%1%9oxHRX zdc`710_6OPoLT%1LV6m`+=2r+(#&tgIr(!!gDmd0;{PCMrVPpQh1(jUzAG4x_Obk+e^u0spstD=?!Wbi_} z+h=C`>2@PnbphCih^PTk)n@dN=W#c`*?xnl+gvHMa&(^UIFx-HJC)i5e z;R4JHfKbM2z&6C|#S)d9|l4hz`Cr(r|k) z1-n7^-VG|iz!NfL742H#BJ#(MchQT6L&onN#~f&ZW}I-t89j?s;*>C$045MW4l{m* zx)iV#XSezo-n7qN!?XAjKCJ09oMYE6cU(^fr#s@8jg!4vQ4L-3cU zr(aOE;_hyx5Z(FNz9)xzjfsShLrw*;&E7E;^J3`Swo&pmi^F-okAa=uKUfJzF_t1z z`m2IHYo>qQ*7%oSO5`|ji66u%YE4%-*6JXO5;}=}2v*Ml113-k{YID=+I)P-4FPb6 zS~CCDXaQ?1m1dfiKDLVT++|-?PV^Cqq;NB^GOc-SJs*v2LWrQG%M-%+@WW5}NTsq= zkXAYsy?;qv{ zT-cUF3~-y;;$mD9$@5wg6Xo{2ix`LoZ*`m}ah#>*U;aL37-c$_y8U+h8l%o>0p!{)*3MRbN$ zO4Lusot3U6qBQZTbQ@=5)3juN(zNx)v4&uH6YbpO~}-=H_(LW8NQ*jzyDH&-l8!8oi)_-Z>Xq@(L!=~ zs`hA-D{%L$&neY@b2w2zK%Au(-63NDnW

ig5V2B@u78<%Z|_M{HNhPoJ!P*y9i5 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 SqYD@XjC@$Uuo?@zjQ;`W>8#iQ delta 94965 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

v1A=#W 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 ZVE0y(S!By%VWok82rwMQUI!7y`ad6vvM>Mu diff --git a/resources/plugin.yml b/resources/plugin.yml index 35f45f8..eab0b29 100644 --- a/resources/plugin.yml +++ b/resources/plugin.yml @@ -1,6 +1,6 @@ name: MobArena main: com.garbagemule.MobArena.MobArena -version: 0.94.4.3 +version: 0.94.4.4 softdepend: [Spout,Permissions,MultiVerse,XcraftGate,Towny,Heroes,MagicSpells] commands: ma: diff --git a/resources/plugin_other.yml b/resources/plugin_other.yml deleted file mode 100644 index 4011d0a..0000000 --- a/resources/plugin_other.yml +++ /dev/null @@ -1,155 +0,0 @@ -name: MobArena -main: garbagemule.mobarena.MobArenaPlugin -version: 0.94.3.24 -softdepend: [Spout,Permissions,MultiVerse,XcraftGate,Towny,Heroes,MagicSpells] -commands: - ma: - description: Base command for MobArena - usage: | - YOU HAVE AN ERROR! - Find the error in your server log, copy it into - http://pastebin.com, and then paste the link - in the IRC or on the forums. - mobarena: - description: Base command for MobArena - usage: | - YOU HAVE AN ERROR! - Find the error in your server log, copy it into - http://pastebin.com, and then paste the link - in the IRC or on the forums. -permissions: - mobarena.use: - description: Gives access to usage commands - default: true - children: - mobarena.use.join: true - mobarena.use.spec: true - mobarena.use.leave: true - mobarena.use.join: - default: true - mobarena.use.spec: - default: true - mobarena.use.leave: - default: true - - mobarena.admin: - description: Gives access to all admin commands - default: op - children: - mobarena.admin.enable: true - mobarena.admin.kick: true - mobarena.admin.restore: true - mobarena.admin.force.end: true - mobarena.admin.force.start: true - mobarena.admin.config.reload: true - mobarena.admin.enable: - description: Enable and disable MobArena and/or arenas. - default: false - mobarena.admin.kick: - description: Kick a player from an arena. - default: false - mobarena.admin.restore: - description: Restore a player's inventory. - default: false - mobarena.admin.force.end: - description: Force end an arena. - default: false - mobarena.admin.force.start: - description: Force start an arena. - default: false - mobarena.admin.config.reload: - description: Reload the config-file. - default: false - - mobarena.setup: - description: Gives access to all setup commands - default: op - children: - mobarena.setup.arena: true - mobarena.setup.setarena: true - mobarena.setup.addarena: true - mobarena.setup.delarena: true - mobarena.setup.protect: true - mobarena.setup.editarena: true - mobarena.setup.setregion: true - mobarena.setup.expandregion: true - mobarena.setup.showregion: true - mobarena.setup.setlobbyregion: true - mobarena.setup.expandlobbyregion: true - mobarena.setup.setwarp: true - mobarena.setup.spawnpoints: true - mobarena.setup.addspawn: true - mobarena.setup.delspawn: true - mobarena.setup.containers: true - mobarena.setup.addcontainer: true - mobarena.setup.delcontainer: true - mobarena.setup.leaderboards: true - mobarena.setup.checkdata: true - mobarena.setup.autogenerate: true - mobarena.setup.autodegenerate: true - mobarena.setup.arena: - description: Check which arena is the currently selected arena. - default: false - mobarena.setup.setarena: - description: Select a new arena. - default: false - mobarena.setup.addarena: - description: Add a new arena node. - default: false - mobarena.setup.delarena: - description: Delete an arena. - default: false - mobarena.setup.protect: - description: Turn arena protection on/off. - default: false - mobarena.setup.editarena: - description: Turn editmode on/off. - default: false - mobarena.setup.setregion: - description: Set region points p1/p2. - default: false - mobarena.setup.expandregion: - description: Expand arena region. - default: false - mobarena.setup.showregion: - description: Show arena region. - default: false - mobarena.setup.setlobbyregion: - description: Set lobby region points l1/l2. - default: false - mobarena.setup.expandlobbyregion: - description: Expand lobby region. - default: false - mobarena.setup.setwarp: - description: Set warp points arena/lobby/spectator. - default: false - mobarena.setup.spawnpoints: - description: List all spawnpoints. - default: false - mobarena.setup.addspawn: - description: Add a new spawnpoint. - default: false - mobarena.setup.delspawn: - description: Delete a spawnpoint. - default: false - mobarena.setup.containers: - description: List all containers. - default: false - mobarena.setup.addcontainer: - description: Add a new container. - default: false - mobarena.setup.delcontainer: - description: Delete a container. - default: false - mobarena.setup.leaderboards: - description: Set up leaderboards. - default: false - mobarena.setup.checkdata: - description: Check which points need to be set up. - default: false - mobarena.setup.autogenerate: - description: Auto-generate an arena. - default: false - mobarena.setup.autodegenerate: - description: Auto-degenerate an arena. - default: false \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/Arena.java b/src/com/garbagemule/MobArena/Arena.java index 897c518..69dba39 100644 --- a/src/com/garbagemule/MobArena/Arena.java +++ b/src/com/garbagemule/MobArena/Arena.java @@ -1,67 +1,28 @@ package com.garbagemule.MobArena; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import java.util.concurrent.PriorityBlockingQueue; -import net.minecraft.server.WorldServer; - import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.ContainerBlock; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.entity.Creature; -import org.bukkit.entity.CreatureType; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.entity.Slime; import org.bukkit.entity.Wolf; -import org.bukkit.event.entity.EntityRegainHealthEvent; -import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; import org.bukkit.permissions.PermissionAttachment; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; -import com.garbagemule.MobArena.MAMessages.Msg; import com.garbagemule.MobArena.leaderboards.Leaderboard; import com.garbagemule.MobArena.repairable.Repairable; import com.garbagemule.MobArena.repairable.RepairableComparator; -import com.garbagemule.MobArena.repairable.RepairableContainer; -import com.garbagemule.MobArena.spout.Spouty; -import com.garbagemule.MobArena.util.Delays; -import com.garbagemule.MobArena.util.InventoryItem; -import com.garbagemule.MobArena.util.WaveUtils; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.waves.BossWave; import com.garbagemule.MobArena.waves.Wave; -import com.garbagemule.MobArena.waves.Wave.WaveBranch; -public class Arena +public abstract class Arena { private MobArena plugin; @@ -108,7 +69,7 @@ public class Arena // Other settings protected int minPlayers, maxPlayers, joinDistance; - protected List classes = new LinkedList(); + protected Set classes = new HashSet(); protected Map locations = new HashMap(); protected Map healthMap = new HashMap(); protected Map hungerMap = new HashMap(); @@ -123,6 +84,10 @@ public class Arena protected PriorityBlockingQueue repairQueue; + public Arena() { + + } + /** * Primary constructor. Requires a name and a world. */ @@ -167,556 +132,45 @@ public class Arena repairQueue = new PriorityBlockingQueue(100, new RepairableComparator()); } - public boolean startArena() - { - // Sanity-checks - if (running || lobbyPlayers.isEmpty() || !readyPlayers.containsAll(lobbyPlayers)) - return false; - if (!softRestore && forceRestore && !serializeRegion()) - return false; - - // Store all chest contents. - storeContainerContents(); - - // Populate arenaPlayers and clear the lobby. - arenaPlayers.addAll(lobbyPlayers); - lobbyPlayers.clear(); - readyPlayers.clear(); - - // Assign random classes. - for (Player p : randoms) - assignRandomClass(p); - if (arenaPlayers.isEmpty()) - return false; - - // Teleport players, give full health, initialize maps - for (Player p : arenaPlayers) - { - p.teleport(arenaLoc); - setHealth(p, 20); - p.setFoodLevel(10); - assignClassPermissions(p); - arenaPlayerMap.put(p, new ArenaPlayer(p, this, plugin)); - } - - // Copy the singleWaves Set for polling. - singleWavesInstance = new TreeSet(singleWaves); - - // Start spawning monsters (must happen before 'running = true;') - startSpawning(); - startBouncingSheep(); - - // Set the boolean. - running = true; - - // Spawn pets (must happen after 'running = true;') - spawnPets(); - - // Start logging - log = new ArenaLog(plugin, this); - log.start(); - - // Initialize leaderboards and start displaying info. - leaderboard.initialize(); - leaderboard.startTracking(); - - // Announce and notify. - MAUtils.tellAll(this, Msg.ARENA_START); - - for (MobArenaListener listener : plugin.getAM().listeners) - listener.onArenaStart(this); - - return true; - } + public abstract boolean startArena(); - public boolean endArena() - { - // Sanity-checks. - if (!running || !arenaPlayers.isEmpty()) - { - //System.out.println("Arena was not ended, playercount: " + arenaPlayers.size()); - return false; - } - //else System.out.println("Arena ending..."); - - // Set the boolean. - running = false; - - // Stop tracking leaderboards - leaderboard.stopTracking(); - leaderboard.update(); - - // Finish logging - log.end(); - if (logging != null) - { - log.saveSessionData(); - log.updateArenaTotals(); - } - log.clearSessionData(); - - // Stop spawning. - stopSpawning(); - - // Clean arena floor. - cleanup(); - - // Restore region. - if (softRestore) - restoreRegion(); - else if (forceRestore) - deserializeRegion(); - - // Restore chests - restoreContainerContents(); - - // Announce and clear sets. - MAUtils.tellAll(this, Msg.ARENA_END, true); - arenaPlayers.clear(); - arenaPlayerMap.clear(); - lobbyPlayers.clear(); - readyPlayers.clear(); - notifyPlayers.clear(); - rewardedPlayers.clear(); - classMap.clear(); - - // Notify listeners. - for (MobArenaListener listener : plugin.getAM().listeners) - listener.onArenaEnd(this); - - return true; - } + public abstract boolean endArena(); - public void forceStart() - { - if (running) - return; - - // Set operations. - Set tmp = new HashSet(); - tmp.addAll(lobbyPlayers); - tmp.removeAll(readyPlayers); - - // Force leave. - for (Player p : tmp) - { - plugin.getAM().arenaMap.remove(p); - playerLeave(p); - } - } + public abstract void forceStart(); - public void forceEnd() - { - Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); - Bukkit.getServer().getScheduler().cancelTask(sheepTaskId); - - for (Player p : getAllPlayers()) - playerLeave(p); - - for (Entity e : monsters) - if (e != null) e.remove(); - - if (bossWave != null) - bossWave.clear(); - - arenaPlayers.clear(); - lobbyPlayers.clear(); - readyPlayers.clear(); - - cleanup(); - - spawnTaskId = -1; - sheepTaskId = -1; - } + public abstract void forceEnd(); - public void playerJoin(Player p, Location loc) - { - storePlayerData(p, loc); - MAUtils.sitPets(p); - setHealth(p, 20); - p.setFoodLevel(10); - p.setGameMode(GameMode.SURVIVAL); - movePlayerToLobby(p); - - // Notify listeners. - for (MobArenaListener listener : plugin.getAM().listeners) - listener.onPlayerJoin(this, p); - - if (MobArena.hasSpout && spoutSelect) - Spouty.classSelectionScreen(plugin, this, p); - } + public abstract void playerJoin(Player p, Location loc); - public void playerReady(Player p) - { - readyPlayers.add(p); - - if (minPlayers > 0 && lobbyPlayers.size() < minPlayers) - { - MAUtils.tellPlayer(p, Msg.LOBBY_NOT_ENOUGH_PLAYERS, "" + minPlayers); - return; - } - - startArena(); - } + public abstract void playerReady(Player p); - public void playerLeave(Player p) - { - finishArenaPlayer(p, false); - movePlayerToEntry(p); - discardPlayer(p); - - // Notify listeners. - for (MobArenaListener listener : plugin.getAM().listeners) - listener.onPlayerLeave(this, p); - - // End arena if possible. - endArena(); - } + public abstract void playerLeave(Player p); - public void playerDeath(Player p) - { - finishArenaPlayer(p, true); - - if (specOnDeath) - { - clearPlayer(p); - movePlayerToSpec(p); - } - else - { - movePlayerToEntry(p); - discardPlayer(p); - } - - if (running && spawnThread != null) - spawnThread.updateTargets(); - - MAUtils.tellAll(this, Msg.PLAYER_DIED, p.getName()); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - endArena(); - } - }); - - // Notify listeners. - for (MobArenaListener listener : plugin.getAM().listeners) - listener.onPlayerDeath(this, p); - } + public abstract void playerDeath(Player p); - public void playerSpec(Player p, Location loc) - { - storePlayerData(p, loc); - MAUtils.sitPets(p); - movePlayerToSpec(p); - } - - private void spawnPets() - { - for (Map.Entry entry : petMap.entrySet()) - { - // Remove the bones from the inventory. - Player p = entry.getKey(); - p.getInventory().removeItem(new ItemStack(Material.BONE, entry.getValue())); - - // Spawn wolves, set owner and health, and add to pet set. - for (int i = 0; i < entry.getValue(); i++) - { - Wolf wolf = (Wolf) world.spawnCreature(p.getLocation(), CreatureType.WOLF); - wolf.setTamed(true); - wolf.setOwner(p); - wolf.setHealth(20); - if (hellhounds) - wolf.setFireTicks(32768); - pets.add(wolf); - } - } - } + public abstract void playerSpec(Player p, Location loc); - private void startSpawning() - { - // Set the spawn flags to enable monster spawning. - MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); - - // Start the spawnThread. - spawnThread = new MASpawnThread(plugin, this); - spawnTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, spawnThread, waveDelay, (!waveClear) ? waveInterval : 60); - } + public abstract void playerKill(Player p); - private void stopSpawning() - { - // Stop the spawn thread. - if (spawnThread != null) - { - Bukkit.getServer().getScheduler().cancelTask(spawnThread.getTaskId()); - Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); - Bukkit.getServer().getScheduler().cancelTask(sheepTaskId); - spawnTaskId = -1; - sheepTaskId = -1; - spawnThread = null; - currentWave = null; - } - else System.out.println("--------- THE SPAWNTHREAD IS NULL! ----------"); - - // Restore spawn flags. - MAUtils.setSpawnFlags(plugin, world, spawnMonsters, allowMonsters, allowAnimals); - } + public abstract void restoreInvAndGiveRewardsDelayed(final Player p); - private void startBouncingSheep() - { - sheepTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, - new Runnable() - { - public void run() - { - if (explodingSheep.isEmpty()) return; - - for (LivingEntity e : new LinkedList(explodingSheep)) - { - if (e == null) continue; - - Creature c = (Creature) e; - LivingEntity target = c.getTarget(); - if (target != null && target instanceof Player && MAUtils.distanceSquared((Player) target, e.getLocation()) < 8D) - { - CraftEntity ce = (CraftEntity) e; - CraftWorld cw = (CraftWorld) e.getWorld(); - WorldServer ws = cw.getHandle(); - ws.createExplosion(ce.getHandle(), e.getLocation().getX(), e.getLocation().getY() + 1, e.getLocation().getZ(), 2f, false); - e.remove(); - } - - if (e.isDead()) - { - explodingSheep.remove(e); - continue; - } - - if (Math.abs(e.getVelocity().getY()) < 1) - e.setVelocity(e.getVelocity().setY(0.5)); - } - } - }, waveDelay, 20); - } + public abstract void restoreInvAndGiveRewards(final Player p); - private void updateChunk(Location loc) - { - if (!arenaPlayers.isEmpty() || !world.getName().equals(loc.getWorld().getName())) - return; - - Chunk chunk = world.getChunkAt(loc); - if (!world.isChunkLoaded(chunk)) - world.loadChunk(chunk); - else - world.refreshChunk(chunk.getX(), chunk.getZ()); - } + public abstract void storePlayerData(Player p, Location loc); - public void playerKill(Player p) - { - if (p == null || log.players.get(p) == null) - return; - - arenaPlayerMap.get(p).getStats().kills++; - } + public abstract void storeContainerContents(); - public void restoreInvAndGiveRewardsDelayed(final Player p) - { - final List rewards = log != null && log.players.get(p) != null ? log.players.get(p).rewards : new LinkedList(); - final boolean hadRewards = rewardedPlayers.contains(p); - - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - if (!emptyInvJoin) - MAUtils.restoreInventory(p); - - if (hadRewards) - return; - - MAUtils.giveRewards(p, rewards, plugin); - if (running) - rewardedPlayers.add(p); - } - }); - } + public abstract void restoreContainerContents(); - public void restoreInvAndGiveRewards(final Player p) - { - if (!emptyInvJoin) - MAUtils.restoreInventory(p); - - if (rewardedPlayers.contains(p)) - return; - - final List rewards = (log != null && log.players.get(p) != null) ? - log.players.get(p).rewards : - new LinkedList(); - - MAUtils.giveRewards(p, rewards, plugin); - if (running) - rewardedPlayers.add(p); - } + public abstract void movePlayerToLobby(Player p); - public void storePlayerData(Player p, Location loc) - { - plugin.getAM().arenaMap.put(p, this); - - if (!locations.containsKey(p)) - locations.put(p, loc); - - if (!healthMap.containsKey(p)) - healthMap.put(p, p.getHealth()); - - if (!hungerMap.containsKey(p)) - hungerMap.put(p, p.getFoodLevel()); - - if (!modeMap.containsKey(p)) - modeMap.put(p, p.getGameMode()); - } + public abstract void movePlayerToSpec(Player p); - public void storeContainerContents() - { - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - for (Location loc : containers.values()) - { - BlockState state = world.getBlockAt(loc).getState(); - if (state instanceof ContainerBlock) - containables.add(new RepairableContainer(state, false)); - } - } - }); - } + public abstract void movePlayerToEntry(Player p); - public void restoreContainerContents() - { - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - for (Repairable r : containables) - r.repair(); - } - }); - } + public abstract void repairBlocks(); - public void movePlayerToLobby(Player p) - { - updateChunk(lobbyLoc); - lobbyPlayers.add(p); - p.teleport(lobbyLoc); - } - - public void movePlayerToSpec(Player p) - { - updateChunk(spectatorLoc); - specPlayers.add(p); - p.teleport(spectatorLoc); - } - - public void movePlayerToEntry(Player p) - { - Location entry = locations.get(p); - if (entry == null || p.isDead()) return; - - updateChunk(entry); - p.teleport(entry); - } - - private void clearPlayer(Player p) - { - if (healthMap.containsKey(p)) - { - int health = healthMap.remove(p); - setHealth(p, health); - } - - if (hungerMap.containsKey(p)) - p.setFoodLevel(hungerMap.remove(p)); - - if (modeMap.containsKey(p)) - p.setGameMode(modeMap.remove(p)); - - // Put out fire. - Delays.douse(plugin, p, 3); - - // Remove pets. - removePets(p); - - // readyPlayers before lobbyPlayers because of startArena sanity-checks - readyPlayers.remove(p); - specPlayers.remove(p); - arenaPlayers.remove(p); - lobbyPlayers.remove(p); - classMap.remove(p); - arenaPlayerMap.remove(p); - } - - /** - * Completely remove a player from the arena collections. - * @param p A player - */ - private void discardPlayer(Player p) - { - locations.remove(p); - plugin.getAM().arenaMap.remove(p); - clearPlayer(p); - } - - /** - * Give the player back his inventory and record his last wave. - * Called when a player dies or leaves prematurely. - * @param p A player - * @param dead If the player died or not - */ - private void finishArenaPlayer(Player p, boolean dead) - { - if (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p)) - return; - - removeClassPermissions(p); - MAUtils.clearInventory(p); - - if (dead) restoreInvAndGiveRewardsDelayed(p); - else restoreInvAndGiveRewards(p); - - ArenaPlayer ap = arenaPlayerMap.get(p); - if (ap != null) - ap.setDead(true); - } - - private void setHealth(Player p, int health) - { - // Grab the current health - int current = p.getHealth(); - - // If the health is 20, just leave it at that no matter what. - int regain = health == 20 ? 20 : health - current; - - // Set the health, and fire off the event. - p.setHealth(health); - EntityRegainHealthEvent event = new EntityRegainHealthEvent(p, regain, RegainReason.CUSTOM); - Bukkit.getPluginManager().callEvent(event); - } - - public void repairBlocks() - { - while (!repairQueue.isEmpty()) - repairQueue.poll().repair(); - } - - public void queueRepairable(Repairable r) - { - repairQueue.add(r); - } + public abstract void queueRepairable(Repairable r); @@ -726,138 +180,13 @@ public class Arena // ////////////////////////////////////////////////////////////////////*/ - public void assignClass(Player p, String className) - { - petMap.remove(p); - randoms.remove(p); - classMap.put(p, className); - - MAUtils.clearInventory(p); - - // If random, don't give any items yet. - if (className.equalsIgnoreCase("random")) - { - randoms.add(p); - return; - } - - MAUtils.giveItems(p, classItems.get(className), autoEquip, plugin); - MAUtils.giveItems(p, classArmor.get(className), autoEquip, plugin); - - int pets = MAUtils.getPetAmount(p); - if (pets > 0) petMap.put(p, pets); - } + public abstract void assignClass(Player p, String className); - public void assignRandomClass(Player p) - { - Random r = new Random(); - List classes = new LinkedList(plugin.getAM().classes); - - String className = classes.remove(r.nextInt(classes.size())); - while (!plugin.has(p, "mobarena.classes." + className)) - { - if (classes.isEmpty()) - { - MobArena.info("Player '" + p.getName() + "' has no class permissions!"); - playerLeave(p); - return; - } - className = classes.remove(r.nextInt(classes.size())); - } - - assignClass(p, className); - MAUtils.tellPlayer(p, Msg.LOBBY_CLASS_PICKED, className); - } + public abstract void assignRandomClass(Player p); - public void assignClassPermissions(Player p) - { - Map perms = classPerms.get(classMap.get(p)); - if (perms == null || perms.isEmpty()) return; - - PermissionAttachment pa = p.addAttachment(plugin); - attachments.put(p,pa); - for (Map.Entry entry : perms.entrySet()) - pa.setPermission(entry.getKey(), entry.getValue()); - } + public abstract void assignClassPermissions(Player p); - public void removeClassPermissions(Player p) - { - if (attachments.get(p) == null) return; - - for (PermissionAttachment pa : attachments.values()) - if (pa != null) pa.remove(); - } - - private void cleanup() - { - removeMonsters(); - removeBlocks(); - removePets(); - removeEntities(); - monsters.clear(); - explodingSheep.clear(); - plaguedPigs.clear(); - madCows.clear(); - blocks.clear(); - pets.clear(); - } - - private void removeMonsters() - { - if (bossWave != null) - bossWave.clear(); - for (LivingEntity e : monsters) - if (e != null) e.remove(); - for (LivingEntity e : explodingSheep) - if (e != null) e.remove(); - for (LivingEntity e : plaguedPigs) - if (e != null) e.remove(); - for (LivingEntity e : madCows) - if (e != null) e.remove(); - } - - private void removeBlocks() - { - for (Block b : blocks) - b.setTypeId(0); - } - - private void removePets() - { - for (Wolf w : pets) - { - if (w == null) continue; - - w.setOwner(null); - w.remove(); - } - } - - private void removePets(Player p) - { - for (Wolf w : pets) - { - if (w == null || !(w.getOwner() instanceof Player) || !((Player) w.getOwner()).getName().equals(p.getName())) - continue; - - w.setOwner(null); - w.remove(); - } - petMap.remove(p); - } - - private void removeEntities() - { - if (p1 == null || p2 == null) return; - Chunk c1 = world.getChunkAt(p1); - Chunk c2 = world.getChunkAt(p2); - - for (int i = c1.getX(); i <= c2.getX(); i++) - for (int j = c1.getZ(); j <= c2.getZ(); j++) - for (Entity e : world.getChunkAt(i,j).getEntities()) - if ((e instanceof Item || e instanceof Slime) && inRegion(e.getLocation())) - if (e != null) e.remove(); - } + public abstract void removeClassPermissions(Player p); @@ -867,239 +196,29 @@ public class Arena // ////////////////////////////////////////////////////////////////////*/ - public void load(Configuration config) - { - config.load(); - - String arenaPath = "arenas." + MAUtils.nameArenaToConfig(name) + ".settings."; - String configName = MAUtils.nameArenaToConfig(name); - - enabled = config.getBoolean(arenaPath + "enabled", true); - protect = config.getBoolean(arenaPath + "protect", true); - logging = config.getString(arenaPath + "logging", null); - autoEquip = config.getBoolean(arenaPath + "auto-equip-armor", true); - waveClear = config.getBoolean(arenaPath + "clear-wave-before-next", false); - detCreepers = config.getBoolean(arenaPath + "detonate-creepers", false); - detDamage = config.getBoolean(arenaPath + "detonate-damage", false); - lightning = config.getBoolean(arenaPath + "lightning", true); - forceRestore = config.getBoolean(arenaPath + "force-restore", false); - softRestore = config.getBoolean(arenaPath + "soft-restore", false); - softRestoreDrops = config.getBoolean(arenaPath + "soft-restore-drops", false); - emptyInvJoin = config.getBoolean(arenaPath + "require-empty-inv-join", true); - emptyInvSpec = config.getBoolean(arenaPath + "require-empty-inv-spec", true); - hellhounds = config.getBoolean(arenaPath + "hellhounds", false); - pvp = config.getBoolean(arenaPath + "pvp-enabled", false); - monsterInfight = config.getBoolean(arenaPath + "monster-infight", false); - allowWarp = config.getBoolean(arenaPath + "allow-teleporting", false); - specOnDeath = config.getBoolean(arenaPath + "spectate-on-death", true); - shareInArena = config.getBoolean(arenaPath + "share-items-in-arena", true); - spoutSelect = config.getBoolean(arenaPath + "spout-class-select", true); - joinDistance = config.getInt(arenaPath + "max-join-distance", 0); - minPlayers = config.getInt(arenaPath + "min-players", 0); - maxPlayers = config.getInt(arenaPath + "max-players", 0); - waveDelay = config.getInt(arenaPath + "first-wave-delay", 5) * 20; - waveInterval = config.getInt(arenaPath + "wave-interval", 20) * 20; - specialModulo = config.getInt(arenaPath + "special-modulo", 4); - maxIdleTime = config.getInt(arenaPath + "max-idle-time", 0) * 20; - finalWave = config.getInt(arenaPath + "final-wave", 0); - - everyWaveMap = MAUtils.getArenaRewardMap(config, configName, "every"); - afterWaveMap = MAUtils.getArenaRewardMap(config, configName, "after"); - entryFee = MAUtils.getEntryFee(config, configName); - - p1 = MAUtils.getArenaCoord(config, world, configName, "p1"); - p2 = MAUtils.getArenaCoord(config, world, configName, "p2"); - l1 = MAUtils.getArenaCoord(config, world, configName, "l1"); - l2 = MAUtils.getArenaCoord(config, world, configName, "l2"); - arenaLoc = MAUtils.getArenaCoord(config, world, configName, "arena"); - lobbyLoc = MAUtils.getArenaCoord(config, world, configName, "lobby"); - spectatorLoc = MAUtils.getArenaCoord(config, world, configName, "spectator"); - spawnpoints = MAUtils.getArenaSpawnpoints(config, world, configName); - spawnpointsBoss = MAUtils.getArenaBossSpawnpoints(config, world, configName); - containers = MAUtils.getArenaContainers(config, world, configName); - leaderboard = new Leaderboard(plugin, this, config); - - // NEW WAVES - singleWaves = WaveUtils.getWaves(this, config, WaveBranch.SINGLE); - recurrentWaves = WaveUtils.getWaves(this, config, WaveBranch.RECURRENT); - - classes = plugin.getAM().classes; - classItems = plugin.getAM().classItems; - classArmor = plugin.getAM().classArmor; - classPerms = plugin.getAM().classPerms; - - // Determine if the arena is properly set up. Then add the to arena list. - setup = MAUtils.verifyData(this); - lobbySetup = MAUtils.verifyLobby(this); - } + public abstract void load(Config config); - public void restoreRegion() - { - Collections.sort(repairables, new RepairableComparator()); - - for (Repairable r : repairables) - r.repair(); - } + public abstract void restoreRegion(); - public void serializeConfig() - { - String coords = "arenas." + configName() + ".coords."; - Configuration config = plugin.getMAConfig(); - - config.setProperty("arenas." + configName() + ".settings.enabled", enabled); - config.setProperty("arenas." + configName() + ".settings.protect", protect); - if (p1 != null) config.setProperty(coords + "p1", MAUtils.makeCoord(p1)); - if (p2 != null) config.setProperty(coords + "p2", MAUtils.makeCoord(p2)); - if (l1 != null) config.setProperty(coords + "l1", MAUtils.makeCoord(l1)); - if (l2 != null) config.setProperty(coords + "l2", MAUtils.makeCoord(l2)); - if (arenaLoc != null) config.setProperty(coords + "arena", MAUtils.makeCoord(arenaLoc)); - if (lobbyLoc != null) config.setProperty(coords + "lobby", MAUtils.makeCoord(lobbyLoc)); - if (spectatorLoc != null) config.setProperty(coords + "spectator", MAUtils.makeCoord(spectatorLoc)); - for (Map.Entry entry : spawnpoints.entrySet()) - config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); - for (Map.Entry entry : spawnpointsBoss.entrySet()) - config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); - - config.save(); - } + public abstract void serializeConfig(); - public void deserializeConfig() - { - Configuration config = plugin.getMAConfig(); - config.load(); - load(config); - } + public abstract void deserializeConfig(); - public boolean serializeRegion() - { - int x1 = (int) p1.getX(); - int y1 = (int) p1.getY(); - int z1 = (int) p1.getZ(); - int x2 = (int) p2.getX(); - int y2 = (int) p2.getY(); - int z2 = (int) p2.getZ(); - - HashSet set = new HashSet(); - int[] buffer; - for (int i = x1; i <= x2; i++) - { - for (int j = y1; j <= y2; j++) - { - for (int k = z1; k <= z2; k++) - { - buffer = new int[4]; - buffer[0] = i; - buffer[1] = j; - buffer[2] = k; - buffer[3] = world.getBlockAt(i,j,k).getTypeId(); - set.add(buffer); - } - } - } - - try - { - new File(plugin.getDataFolder() + File.separator + "regions").mkdir(); - File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); - if (regionFile.exists()) - regionFile.createNewFile(); - - FileOutputStream fos = new FileOutputStream(regionFile); - ObjectOutputStream oos = new ObjectOutputStream(fos); - oos.writeObject(set); - oos.close(); - } - catch (Exception e) - { - MobArena.warning("Could not create region file. The arena will not be started!"); - e.printStackTrace(); - return false; - } - return true; - } + public abstract boolean serializeRegion(); - @SuppressWarnings("unchecked") - public boolean deserializeRegion() - { - HashSet set = new HashSet(); - try - { - File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); - if (!regionFile.exists()) - return false; - - FileInputStream fis = new FileInputStream(regionFile); - ObjectInputStream ois = new ObjectInputStream(fis); - set = (HashSet) ois.readObject(); - ois.close(); - } - catch (Exception e) - { - MobArena.warning("Could not find region file. The arena cannot be restored!"); - e.printStackTrace(); - return false; - } - - for (int[] buffer : set) - world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeId(buffer[3]); - - return true; - } + public abstract boolean deserializeRegion(); /** * Check if a location is inside of the cuboid region * that p1 and p2 span. */ - public boolean inRegion(Location loc) - { - if (!loc.getWorld().getName().equals(world.getName()) || !setup) - return false; - - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); - - // Check the lobby first. - if (lobbySetup) - { - if ((x >= l1.getBlockX() && x <= l2.getBlockX()) && - (z >= l1.getBlockZ() && z <= l2.getBlockZ()) && - (y >= l1.getBlockY() && y <= l2.getBlockY())) - return true; - } - - // Returns false if the location is outside of the region. - return ((x >= p1.getBlockX() && x <= p2.getBlockX()) && - (z >= p1.getBlockZ() && z <= p2.getBlockZ()) && - (y >= p1.getBlockY() && y <= p2.getBlockY())); - } + public abstract boolean inRegion(Location loc); /** * Check if a location is inside of the arena region, expanded * by 'radius' blocks. Used with explosions. */ - public boolean inRegionRadius(Location loc, int radius) - { - if (!loc.getWorld().getName().equals(world.getName()) || !setup) - return false; - - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); - - // Check the lobby first. - if (lobbySetup) - { - if ((x + radius >= l1.getBlockX() && x - radius <= l2.getBlockX()) && - (z + radius >= l1.getBlockZ() && z - radius <= l2.getBlockZ()) && - (y + radius >= l1.getBlockY() && y - radius <= l2.getBlockY())) - return true; - } - - return ((x + radius >= p1.getBlockX() && x - radius <= p2.getBlockX()) && - (z + radius >= p1.getBlockZ() && z - radius <= p2.getBlockZ()) && - (y + radius >= p1.getBlockY() && y - radius <= p2.getBlockY())); - } + public abstract boolean inRegionRadius(Location loc, int radius); @@ -1109,355 +228,73 @@ public class Arena // ////////////////////////////////////////////////////////////////////*/ - public boolean inArena(Player p) - { - return arenaPlayers.contains(p); - } + public abstract boolean inArena(Player p); - public boolean inLobby(Player p) - { - return lobbyPlayers.contains(p); - } + public abstract boolean inLobby(Player p); - public boolean isRunning() - { - return running; - } + public abstract boolean isRunning(); - public boolean isPvpEnabled() - { - return pvp; - } + public abstract boolean isPvpEnabled(); - public boolean isLightningEnabled() - { - return lightning; - } + public abstract boolean isLightningEnabled(); - public boolean isBossWave() - { - return bossWave != null; - } + public abstract boolean isBossWave(); - public String configName() - { - return MAUtils.nameArenaToConfig(name); - } + public abstract String configName(); - public String arenaName() - { - return name; - } + public abstract String arenaName(); - public MobArena getPlugin() - { - return plugin; - } + public abstract MobArena getPlugin(); - public World getWorld() - { - return world; - } + public abstract World getWorld(); - public Wave getWave() - { - return currentWave; - } + public abstract Wave getWave(); - public void setWave(Wave wave) - { - currentWave = wave; - } + public abstract void setWave(Wave wave); - public void setBossWave(BossWave bossWave) - { - this.bossWave = bossWave; - } + public abstract void setBossWave(BossWave bossWave); - public List getClasses() - { - return classes; - } + public abstract Set getClasses(); - public List getAllSpawnpoints() - { - ArrayList result = new ArrayList(spawnpoints.size() + spawnpointsBoss.size()); - result.addAll(spawnpoints.values()); - result.addAll(spawnpointsBoss.values()); - return result; - } + public abstract List getAllSpawnpoints(); - public List getSpawnpoints() - { - return new ArrayList(spawnpoints.values()); - } + public abstract List getSpawnpoints(); - public Location getBossSpawnpoint() - { - if (spawnpointsBoss.isEmpty()) - { - List points = WaveUtils.getValidSpawnpoints(this, getLivingPlayers()); - return points.get(MobArena.random.nextInt(points.size())); - } - - return new ArrayList(spawnpointsBoss.values()).get(MobArena.random.nextInt(spawnpointsBoss.size())); - } + public abstract Location getBossSpawnpoint(); - public int getPlayerCount() - { - return spawnThread.getPlayerCount(); - } + public abstract int getPlayerCount(); - public void addBlock(Block b) - { - blocks.add(b); - } + public abstract void addBlock(Block b); - public void addMonster(LivingEntity e) - { - monsters.add(e); - } + public abstract void addMonster(LivingEntity e); - public void addExplodingSheep(LivingEntity e) - { - explodingSheep.add(e); - } + public abstract void addExplodingSheep(LivingEntity e); - public List getAllPlayers() - { - List result = new LinkedList(); - result.addAll(arenaPlayers); - result.addAll(lobbyPlayers); - result.addAll(specPlayers); - return result; - } + public abstract List getAllPlayers(); - public List getLivingPlayers() - { - List result = new LinkedList(); - result.addAll(arenaPlayers); - return result; - } + public abstract List getLivingPlayers(); - public Set getArenaPlayers() - { - return arenaPlayers; - } + public abstract Set getArenaPlayers(); - public Collection getArenaPlayerSet() - { - return arenaPlayerMap.values(); - } + public abstract Collection getArenaPlayerSet(); - public List getArenaPlayerStatistics(Comparator comparator) - { - List list = new ArrayList(); - - for (ArenaPlayer ap : arenaPlayerMap.values()) - list.add(ap.getStats()); - - Collections.sort(list, comparator); - return list; - } + public abstract List getArenaPlayerStatistics(Comparator comparator); - public List getNonreadyPlayers() - { - List result = new LinkedList(); - result.addAll(lobbyPlayers); - result.removeAll(readyPlayers); - return result; - } + public abstract List getNonreadyPlayers(); - public Set getMonsters() - { - Set tmp = new HashSet(monsters); - tmp.addAll(explodingSheep); - return tmp; - } + public abstract Set getMonsters(); - public Set getPets() - { - return pets; - } + public abstract Set getPets(); - public void resetIdleTimer() - { - if (maxIdleTime <= 0 || !running) - return; - - // Reset the previousSize, cancel the previous timer, and start the new timer. - spawnThread.setPreviousSize(getMonsters().size()); - Bukkit.getServer().getScheduler().cancelTask(spawnThread.getTaskId()); - int id = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - // Make sure to remove any dead/removed entities first. - List ms = new LinkedList(monsters); - for (Entity e : ms) - if (e.isDead()) - monsters.remove(e); - - // Compare the current size with the previous size. - if (monsters.size() < spawnThread.getPreviousSize() || spawnThread.getPreviousSize() == 0 || bossWave != null) - { - resetIdleTimer(); - return; - } - - // Clear all player inventories, and "kill" all players. - List ps = new LinkedList(arenaPlayers); - for (Player p : ps) - { - MAUtils.clearInventory(p); - MAUtils.tellPlayer(p, Msg.FORCE_END_IDLE); - playerDeath(p); - } - } - }, maxIdleTime); - spawnThread.setTaskId(id); - } + public abstract void resetIdleTimer(); - public void addTrunkAndLeaves(Block b) - { - final int x = b.getX(); - final int y = b.getY(); - final int z = b.getZ(); - - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, - new Runnable() - { - public void run() - { - List result = new LinkedList(); - for (int i = x-2; i <= x+2; i++) - for (int j = y; j <= y+10; j++) - for (int k = z-2; k <= z+2; k++) - if (world.getBlockAt(i,j,k).getType() == Material.LOG || world.getBlockAt(i,j,k).getType() == Material.LEAVES) - result.add(world.getBlockAt(i,j,k)); - - if (running) blocks.addAll(result); - } - }, 10); - } + public abstract void addTrunkAndLeaves(Block b); - public boolean canAfford(Player p) - { - if (entryFee.isEmpty()) - return true; - - PlayerInventory inv = p.getInventory(); - for (ItemStack stack : entryFee) - { - // Economy money - if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) - { - //if (plugin.Methods.hasMethod() && !plugin.Method.getAccount(p.getName()).hasEnough(stack.getAmount())) - if (plugin.Method != null && !(plugin.Method.getAccount(p.getName()).balance() >= stack.getAmount())) - return false; - } - // Normal stack - else - { - if (!inv.contains(stack.getTypeId(), stack.getAmount())) - return false; - } - } - - return true; - } + public abstract boolean canAfford(Player p); - public boolean takeFee(Player p) - { - if (entryFee.isEmpty()) - return true; - - PlayerInventory inv = p.getInventory(); - InventoryItem[] items = InventoryItem.parseItemStacks(inv.getContents()); - InventoryItem[] fee = InventoryItem.parseItemStacks(entryFee); - - // Take some economy money - for (InventoryItem item : InventoryItem.extractAllFromArray(MobArena.ECONOMY_MONEY_ID, fee)) - if (plugin.Method != null) - plugin.Method.getAccount(p.getName()).subtract(item.getAmount()); - - // Take any other items - for (InventoryItem item : fee) - InventoryItem.removeItemFromArray(item, items); - - // Turn everything back into ItemStacks - for (int i = 0; i < items.length; i++) - inv.setItem(i, items[i].toItemStack()); - - return true; - } + public abstract boolean takeFee(Player p); - public boolean canJoin(Player p) - { - if (!enabled) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_ENABLED); - else if (!setup || recurrentWaves.isEmpty()) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_SETUP); - else if (edit) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_EDIT_MODE); - else if (running && (notifyPlayers.contains(p) || notifyPlayers.add(p))) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_IS_RUNNING); - else if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) - MAUtils.tellPlayer(p, Msg.JOIN_ALREADY_PLAYING); - else if (!plugin.has(p, "mobarena.arenas." + configName())) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_PERMISSION); - else if (maxPlayers > 0 && lobbyPlayers.size() >= maxPlayers) - MAUtils.tellPlayer(p, Msg.JOIN_PLAYER_LIMIT_REACHED); - else if (joinDistance > 0 && !inRegionRadius(p.getLocation(), joinDistance)) - MAUtils.tellPlayer(p, Msg.JOIN_TOO_FAR); - else if (emptyInvJoin && !MAUtils.hasEmptyInventory(p)) - MAUtils.tellPlayer(p, Msg.JOIN_EMPTY_INV); - else if (!canAfford(p))// || !takeFee(p)) - MAUtils.tellPlayer(p, Msg.JOIN_FEE_REQUIRED, MAUtils.listToString(entryFee, plugin)); - else return true; - - return false; - } + public abstract boolean canJoin(Player p); - public boolean canSpec(Player p) - { - if (!enabled) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_ENABLED); - else if (!setup) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_SETUP); - else if (edit) - MAUtils.tellPlayer(p, Msg.JOIN_ARENA_EDIT_MODE); - else if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) - MAUtils.tellPlayer(p, Msg.SPEC_ALREADY_PLAYING); - else if (emptyInvSpec && !MAUtils.hasEmptyInventory(p)) - MAUtils.tellPlayer(p, Msg.SPEC_EMPTY_INV); - else if (joinDistance > 0 && !inRegionRadius(p.getLocation(), joinDistance)) - MAUtils.tellPlayer(p, Msg.JOIN_TOO_FAR); - else return true; - - return false; - } - - /** - * The "perfect equals method" cf. "Object-Oriented Design and Patterns" - * by Cay S. Horstmann. - */ - public boolean equals(Object other) - { - if (this == other) return true; - if (other == null) return false; - if (getClass() != other.getClass()) return false; - - // Arenas must have different names. - if (other instanceof Arena && ((Arena)other).name.equals(name)) - return true; - - return false; - } - - public String toString() - { - return ((enabled && setup) ? ChatColor.GREEN : ChatColor.GRAY) + configName(); - } + public abstract boolean canSpec(Player p); } diff --git a/src/com/garbagemule/MobArena/ArenaMaster.java b/src/com/garbagemule/MobArena/ArenaMaster.java index 33f5b97..601ffff 100644 --- a/src/com/garbagemule/MobArena/ArenaMaster.java +++ b/src/com/garbagemule/MobArena/ArenaMaster.java @@ -2,32 +2,28 @@ package com.garbagemule.MobArena; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; //import com.garbagemule.ArenaPlugin.Master; -public class ArenaMaster //implements Master +public abstract class ArenaMaster //implements Master { - private MobArena plugin; - private Configuration config; protected Arena selectedArena; // Settings protected boolean enabled, updateNotify; // Classes - protected List classes; + protected Set classes; protected Map> classItems, classArmor; protected Map> classPerms; //protected Map>> classBonuses; @@ -44,131 +40,40 @@ public class ArenaMaster //implements Master - /** - * Default constructor. - */ - public ArenaMaster(MobArena instance) - { - plugin = instance; - config = plugin.getMAConfig(); - arenas = new LinkedList(); - arenaMap = new HashMap(); - } - - - /*///////////////////////////////////////////////////////////////////////// // // Arena getters // /////////////////////////////////////////////////////////////////////////*/ - public List getEnabledArenas() - { - List result = new LinkedList(); - for (Arena arena : arenas) - if (arena.enabled) - result.add(arena); - return result; - } + + public abstract List getEnabledArenas(); - public List getPermittedArenas(Player p) - { - List result = new LinkedList(); - for (Arena arena : arenas) - if (plugin.has(p, "mobarena.arenas." + arena.configName())) - result.add(arena); - return result; - } + public abstract List getPermittedArenas(Player p); - public Arena getArenaAtLocation(Location loc) - { - for (Arena arena : arenas) - if (arena.inRegion(loc)) - return arena; - return null; - } + public abstract Arena getArenaAtLocation(Location loc); - public List getArenasInWorld(World world) - { - List result = new LinkedList(); - for (Arena arena : arenas) - if (arena.world.equals(world)) - result.add(arena); - return result; - } + public abstract List getArenasInWorld(World world); - public List getAllPlayers() - { - List result = new LinkedList(); - for (Arena arena : arenas) - result.addAll(arena.getAllPlayers()); - return result; - } + public abstract List getAllPlayers(); - public List getAllPlayersInArena(String arenaName) - { - Arena arena = getArenaWithName(arenaName); - return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); - } + public abstract List getAllPlayersInArena(String arenaName); - public List getAllLivingPlayers() - { - List result = new LinkedList(); - for (Arena arena : arenas) - result.addAll(arena.getLivingPlayers()); - return result; - } + public abstract List getAllLivingPlayers(); - public List getLivingPlayersInArena(String arenaName) - { - Arena arena = getArenaWithName(arenaName); - return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); - } + public abstract List getLivingPlayersInArena(String arenaName); - public Arena getArenaWithPlayer(Player p) - { - return arenaMap.get(p); - } + public abstract Arena getArenaWithPlayer(Player p); - public Arena getArenaWithPlayer(String playerName) - { - return arenaMap.get(Bukkit.getServer().getPlayer(playerName)); - } + public abstract Arena getArenaWithPlayer(String playerName); - public Arena getArenaWithSpectator(Player p) - { - for (Arena arena : arenas) - { - if (arena.specPlayers.contains(p)) - return arena; - } - return null; - } + public abstract Arena getArenaWithSpectator(Player p); - public Arena getArenaWithMonster(Entity e) - { - for (Arena arena : arenas) - if (arena.monsters.contains(e)) - return arena; - return null; - } + public abstract Arena getArenaWithMonster(Entity e); - public Arena getArenaWithPet(Entity e) - { - for (Arena arena : arenas) - if (arena.pets.contains(e)) - return arena; - return null; - } + public abstract Arena getArenaWithPet(Entity e); - public Arena getArenaWithName(String configName) - { - for (Arena arena : arenas) - if (arena.configName().equals(configName)) - return arena; - return null; - } + public abstract Arena getArenaWithName(String configName); @@ -178,140 +83,26 @@ public class ArenaMaster //implements Master // /////////////////////////////////////////////////////////////////////////*/ - public void initialize() - { - config.load(); - loadSettings(); - loadClasses(); - loadArenas(); - config.save(); - } + public abstract void initialize(); /** * Load the global settings. */ - public void loadSettings() - { - if (config.getKeys("global-settings") == null) - { - config.setProperty("global-settings.enabled", true); - config.setProperty("global-settings.update-notification", true); - } - - enabled = config.getBoolean("global-settings.enabled", true); - updateNotify = config.getBoolean("global-settings.update-notification", true); - } + public abstract void loadSettings(); /** * Load all class-related stuff. */ - public void loadClasses() - { - classes = config.getKeys("classes"); - if (classes == null) - { - config.setProperty("classes.Archer.items", "wood_sword, bow, arrow:128, grilled_pork"); - config.setProperty("classes.Archer.armor", "298,299,300,301"); - config.setProperty("classes.Knight.items", "diamond_sword, grilled_pork:2"); - config.setProperty("classes.Knight.armor", "306,307,308,309"); - config.setProperty("classes.Tank.items", "iron_sword, grilled_pork:3, apple"); - config.setProperty("classes.Tank.armor", "310,311,312,313"); - config.setProperty("classes.Oddjob.items", "stone_sword, flint_and_steel, netherrack:2, wood_pickaxe, tnt:4, fishing_rod, apple, grilled_pork:3"); - config.setProperty("classes.Oddjob.armor", "298,299,300,301"); - config.setProperty("classes.Chef.items", "stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:3, cookie:12"); - config.setProperty("classes.Chef.armor", "314,315,316,317"); - classes = config.getKeys("classes"); - } - classItems = MAUtils.getClassItems(config, "items"); - classArmor = MAUtils.getClassItems(config, "armor"); - classPerms = MAUtils.getClassPerms(config); - } + public abstract void loadClasses(); /** * Load all arena-related stuff. */ - public void loadArenas() - { - arenas = new LinkedList(); - - if (config.getKeys("arenas") == null) - createArenaNode("default", Bukkit.getServer().getWorlds().get(0)); - - for (String configName : config.getKeys("arenas")) - { - String arenaPath = "arenas." + configName + "."; - String worldName = config.getString(arenaPath + "settings.world", null); - World world; - if (worldName == null || worldName.equals("")) - { - MobArena.warning("Could not find the world for arena '" + configName + "'. Using default world! Check the config-file!"); - world = Bukkit.getServer().getWorlds().get(0); - } - else world = Bukkit.getServer().getWorld(worldName); - - Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world); - arena.load(config); - arenas.add(arena); - } - - selectedArena = arenas.get(0); - } + public abstract void loadArenas(); - public Arena createArenaNode(String configName, World world) - { - config.setProperty("arenas." + configName + ".settings.world", world.getName()); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.enabled", true); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.protect", true); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.entry-fee", ""); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.logging", false); - config.setProperty("arenas." + configName + ".settings.clear-wave-before-next", false); - config.setProperty("arenas." + configName + ".settings.detonate-creepers", false); - config.setProperty("arenas." + configName + ".settings.detonate-damage", false); - config.setProperty("arenas." + configName + ".settings.lightning", true); - config.setProperty("arenas." + configName + ".settings.auto-equip-armor", true); - config.setProperty("arenas." + configName + ".settings.force-restore", false); - config.setProperty("arenas." + configName + ".settings.soft-restore", false); - config.setProperty("arenas." + configName + ".settings.soft-restore-drops", false); - config.setProperty("arenas." + configName + ".settings.require-empty-inv-join", true); - config.setProperty("arenas." + configName + ".settings.require-empty-inv-spec", true); - config.setProperty("arenas." + configName + ".settings.hellhounds", false); - config.setProperty("arenas." + configName + ".settings.pvp-enabled", false); - config.setProperty("arenas." + configName + ".settings.monster-infight", false); - config.setProperty("arenas." + configName + ".settings.allow-teleporting", false); - config.setProperty("arenas." + configName + ".settings.spectate-on-death", true); - config.setProperty("arenas." + configName + ".settings.share-items-in-arena", true); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.player-limit", 0); - config.setProperty("arenas." + configName + ".settings.max-join-distance", 0); - config.save(); - config.load(); - config.setProperty("arenas." + configName + ".settings.repair-delay", 5); - config.setProperty("arenas." + configName + ".settings.first-wave-delay", 5); - config.setProperty("arenas." + configName + ".settings.wave-interval", 20); - config.setProperty("arenas." + configName + ".settings.special-modulo", 4); - config.setProperty("arenas." + configName + ".settings.max-idle-time", 0); - config.save(); - config.load(); - - Arena arena = new Arena(MAUtils.nameConfigToArena(configName), world); - arena.load(config); - return arena; - } + public abstract Arena createArenaNode(String configName, World world); - public void removeArenaNode(String configName) - { - config.removeProperty("arenas." + configName); - config.save(); - } + public abstract void removeArenaNode(String configName); @@ -325,73 +116,27 @@ public class ArenaMaster //implements Master * Update one, two or all three of global settings, classes * and arenas (arenas with deserialization). */ - public void update(boolean settings, boolean classes, boolean arenalist) - { - boolean tmp = enabled; - enabled = false; - - for (Arena arena : arenas) - arena.forceEnd(); - - config.load(); - if (settings) loadSettings(); - if (classes) loadClasses(); - if (arenalist) deserializeArenas(); - config.save(); - - enabled = tmp; - } + public abstract void update(boolean settings, boolean classes, boolean arenalist); /** * Serialize the global settings. */ - public void serializeSettings() - { - String settings = "global-settings."; - config.setProperty(settings + "enabled", enabled); - config.save(); - } + public abstract void serializeSettings(); /** * Serialize all arena configs. */ - public void serializeArenas() - { - for (Arena arena : arenas) - arena.serializeConfig(); - } + public abstract void serializeArenas(); /** * Deserialize all arena configs. Updates the arena list to * include only the current arenas (not ones added in the * actual file) that are also in the config-file. */ - public void deserializeArenas() - { - // Get only the arenas in the config. - List strings = config.getKeys("arenas"); - if (strings == null) - return; - - // Get their Arena objects. - List configArenas = new LinkedList(); - for (String s : strings) - if (getArenaWithName(s) != null) - configArenas.add(getArenaWithName(s)); - - // Remove all Arenas no longer in the config. - arenas.retainAll(configArenas); - - for (Arena arena : arenas) - arena.deserializeConfig(); - - // Make sure to update the selected arena to a valid one. - if (!arenas.contains(selectedArena) && arenas.size() >= 1) - selectedArena = arenas.get(0); - } + public abstract void deserializeArenas(); - public void updateSettings() { update(true, false, false); } - public void updateClasses() { update(false, true, false); } - public void updateArenas() { update(false, false, true); } - public void updateAll() { update(true, true, true); } + public abstract void updateSettings(); + public abstract void updateClasses(); + public abstract void updateArenas(); + public abstract void updateAll(); } diff --git a/src/com/garbagemule/MobArena/ArenaMasterStandard.java b/src/com/garbagemule/MobArena/ArenaMasterStandard.java new file mode 100644 index 0000000..90c0cbd --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaMasterStandard.java @@ -0,0 +1,397 @@ +package com.garbagemule.MobArena; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +//import org.bukkit.util.config.Configuration; + +import com.garbagemule.MobArena.util.Config; + +//import com.garbagemule.ArenaPlugin.Master; + +public class ArenaMasterStandard extends ArenaMaster +{ + private MobArena plugin; + //private Configuration config; + private Config config; + //protected Arena selectedArena; + + // Settings + //protected boolean enabled, updateNotify; + + // Classes + //protected Set classes; + //protected Map> classItems, classArmor; + //protected Map> classPerms; + //protected Map>> classBonuses; + //protected Map arenaMap; + + // Location map + //protected Map locations = new HashMap(); + + // Arena list + //protected List arenas; + + // Listeners + //protected Set listeners = new HashSet(); + + + + /** + * Default constructor. + */ + public ArenaMasterStandard(MobArenaPlugin instance) + { + plugin = (MobArena) instance; + config = plugin.getMAConfig(); + arenas = new LinkedList(); + arenaMap = new HashMap(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Arena getters + // + /////////////////////////////////////////////////////////////////////////*/ + + public List getEnabledArenas() + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (arena.enabled) + result.add(arena); + return result; + } + + public List getPermittedArenas(Player p) + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (plugin.has(p, "mobarena.arenas." + arena.configName())) + result.add(arena); + return result; + } + + public Arena getArenaAtLocation(Location loc) + { + for (Arena arena : arenas) + if (arena.inRegion(loc)) + return arena; + return null; + } + + public List getArenasInWorld(World world) + { + List result = new LinkedList(); + for (Arena arena : arenas) + if (arena.world.equals(world)) + result.add(arena); + return result; + } + + public List getAllPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getAllPlayers()); + return result; + } + + public List getAllPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public List getAllLivingPlayers() + { + List result = new LinkedList(); + for (Arena arena : arenas) + result.addAll(arena.getLivingPlayers()); + return result; + } + + public List getLivingPlayersInArena(String arenaName) + { + Arena arena = getArenaWithName(arenaName); + return (arena != null) ? arena.getLivingPlayers() : new LinkedList(); + } + + public Arena getArenaWithPlayer(Player p) + { + return arenaMap.get(p); + } + + public Arena getArenaWithPlayer(String playerName) + { + return arenaMap.get(Bukkit.getServer().getPlayer(playerName)); + } + + public Arena getArenaWithSpectator(Player p) + { + for (Arena arena : arenas) + { + if (arena.specPlayers.contains(p)) + return arena; + } + return null; + } + + public Arena getArenaWithMonster(Entity e) + { + for (Arena arena : arenas) + if (arena.monsters.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithPet(Entity e) + { + for (Arena arena : arenas) + if (arena.pets.contains(e)) + return arena; + return null; + } + + public Arena getArenaWithName(String configName) + { + for (Arena arena : arenas) + if (arena.configName().equals(configName)) + return arena; + return null; + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Initialization + // + /////////////////////////////////////////////////////////////////////////*/ + + public void initialize() + { + config.load(); + loadSettings(); + loadClasses(); + loadArenas(); + config.save(); + } + + /** + * Load the global settings. + */ + public void loadSettings() + { + if (config.getKeys("global-settings") == null) + { + config.setProperty("global-settings.enabled", true); + config.setProperty("global-settings.update-notification", true); + } + + enabled = config.getBoolean("global-settings.enabled", true); + updateNotify = config.getBoolean("global-settings.update-notification", true); + } + + /** + * Load all class-related stuff. + */ + public void loadClasses() + { + classes = config.getKeys("classes"); + if (classes == null) + { + config.setProperty("classes.Archer.items", "wood_sword, bow, arrow:128, grilled_pork"); + config.setProperty("classes.Archer.armor", "298,299,300,301"); + config.setProperty("classes.Knight.items", "diamond_sword, grilled_pork:2"); + config.setProperty("classes.Knight.armor", "306,307,308,309"); + config.setProperty("classes.Tank.items", "iron_sword, grilled_pork:3, apple"); + config.setProperty("classes.Tank.armor", "310,311,312,313"); + config.setProperty("classes.Oddjob.items", "stone_sword, flint_and_steel, netherrack:2, wood_pickaxe, tnt:4, fishing_rod, apple, grilled_pork:3"); + config.setProperty("classes.Oddjob.armor", "298,299,300,301"); + config.setProperty("classes.Chef.items", "stone_sword, bread:6, grilled_pork:4, mushroom_soup, cake:3, cookie:12"); + config.setProperty("classes.Chef.armor", "314,315,316,317"); + classes = config.getKeys("classes"); + } + classItems = MAUtils.getClassItems(config, "items"); + classArmor = MAUtils.getClassItems(config, "armor"); + classPerms = MAUtils.getClassPerms(config); + } + + /** + * Load all arena-related stuff. + */ + public void loadArenas() + { + arenas = new LinkedList(); + + if (config.getKeys("arenas") == null) + createArenaNode("default", Bukkit.getServer().getWorlds().get(0)); + + for (String configName : config.getKeys("arenas")) + { + String arenaPath = "arenas." + configName + "."; + String worldName = config.getString(arenaPath + "settings.world", null); + World world; + if (worldName == null || worldName.equals("")) + { + MobArena.warning("Could not find the world for arena '" + configName + "'. Using default world! Check the config-file!"); + world = Bukkit.getServer().getWorlds().get(0); + } + else world = Bukkit.getServer().getWorld(worldName); + + Arena arena = new ArenaStandard(MAUtils.nameConfigToArena(configName), world); + arena.load(config); + arenas.add(arena); + } + + selectedArena = arenas.get(0); + } + + public Arena createArenaNode(String configName, World world) + { + config.setProperty("arenas." + configName + ".settings.world", world.getName()); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.enabled", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.protect", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.entry-fee", ""); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.logging", false); + config.setProperty("arenas." + configName + ".settings.clear-wave-before-next", false); + config.setProperty("arenas." + configName + ".settings.detonate-creepers", false); + config.setProperty("arenas." + configName + ".settings.detonate-damage", false); + config.setProperty("arenas." + configName + ".settings.lightning", true); + config.setProperty("arenas." + configName + ".settings.auto-equip-armor", true); + config.setProperty("arenas." + configName + ".settings.force-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore", false); + config.setProperty("arenas." + configName + ".settings.soft-restore-drops", false); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-join", true); + config.setProperty("arenas." + configName + ".settings.require-empty-inv-spec", true); + config.setProperty("arenas." + configName + ".settings.hellhounds", false); + config.setProperty("arenas." + configName + ".settings.pvp-enabled", false); + config.setProperty("arenas." + configName + ".settings.monster-infight", false); + config.setProperty("arenas." + configName + ".settings.allow-teleporting", false); + config.setProperty("arenas." + configName + ".settings.spectate-on-death", true); + config.setProperty("arenas." + configName + ".settings.share-items-in-arena", true); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.player-limit", 0); + config.setProperty("arenas." + configName + ".settings.max-join-distance", 0); + config.save(); + config.load(); + config.setProperty("arenas." + configName + ".settings.repair-delay", 5); + config.setProperty("arenas." + configName + ".settings.first-wave-delay", 5); + config.setProperty("arenas." + configName + ".settings.wave-interval", 20); + config.setProperty("arenas." + configName + ".settings.special-modulo", 4); + config.setProperty("arenas." + configName + ".settings.max-idle-time", 0); + config.save(); + config.load(); + + Arena arena = new ArenaStandard(MAUtils.nameConfigToArena(configName), world); + arena.load(config); + return arena; + } + + public void removeArenaNode(String configName) + { + config.removeProperty("arenas." + configName); + config.save(); + } + + + + /*///////////////////////////////////////////////////////////////////////// + // + // Update and serialization methods + // + /////////////////////////////////////////////////////////////////////////*/ + + /** + * Update one, two or all three of global settings, classes + * and arenas (arenas with deserialization). + */ + public void update(boolean settings, boolean classes, boolean arenalist) + { + boolean tmp = enabled; + enabled = false; + + for (Arena arena : arenas) + arena.forceEnd(); + + config.load(); + if (settings) loadSettings(); + if (classes) loadClasses(); + if (arenalist) deserializeArenas(); + config.save(); + + enabled = tmp; + } + + /** + * Serialize the global settings. + */ + public void serializeSettings() + { + String settings = "global-settings."; + config.setProperty(settings + "enabled", enabled); + config.save(); + } + + /** + * Serialize all arena configs. + */ + public void serializeArenas() + { + for (Arena arena : arenas) + arena.serializeConfig(); + } + + /** + * Deserialize all arena configs. Updates the arena list to + * include only the current arenas (not ones added in the + * actual file) that are also in the config-file. + */ + public void deserializeArenas() + { + // Get only the arenas in the config. + Set strings = config.getKeys("arenas"); + if (strings == null) + return; + + // Get their Arena objects. + List configArenas = new LinkedList(); + for (String s : strings) + if (getArenaWithName(s) != null) + configArenas.add(getArenaWithName(s)); + + // Remove all Arenas no longer in the config. + arenas.retainAll(configArenas); + + for (Arena arena : arenas) + arena.deserializeConfig(); + + // Make sure to update the selected arena to a valid one. + if (!arenas.contains(selectedArena) && arenas.size() >= 1) + selectedArena = arenas.get(0); + } + + public void updateSettings() { update(true, false, false); } + public void updateClasses() { update(false, true, false); } + public void updateArenas() { update(false, false, true); } + public void updateAll() { update(true, true, true); } +} diff --git a/src/com/garbagemule/MobArena/ArenaStandard.java b/src/com/garbagemule/MobArena/ArenaStandard.java new file mode 100644 index 0000000..bb0d87e --- /dev/null +++ b/src/com/garbagemule/MobArena/ArenaStandard.java @@ -0,0 +1,1465 @@ +package com.garbagemule.MobArena; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.PriorityBlockingQueue; + +import net.minecraft.server.WorldServer; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.ContainerBlock; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.entity.Creature; +import org.bukkit.entity.CreatureType; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Wolf; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.permissions.PermissionAttachment; +//import org.bukkit.util.config.Configuration; + +import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.leaderboards.Leaderboard; +import com.garbagemule.MobArena.repairable.Repairable; +import com.garbagemule.MobArena.repairable.RepairableComparator; +import com.garbagemule.MobArena.repairable.RepairableContainer; +import com.garbagemule.MobArena.spout.Spouty; +import com.garbagemule.MobArena.util.Config; +import com.garbagemule.MobArena.util.Delays; +import com.garbagemule.MobArena.util.InventoryItem; +import com.garbagemule.MobArena.util.WaveUtils; +import com.garbagemule.MobArena.waves.BossWave; +import com.garbagemule.MobArena.waves.Wave; +import com.garbagemule.MobArena.waves.Wave.WaveBranch; + +public class ArenaStandard extends Arena +{ + private MobArena plugin; + /* + // Setup fields + protected String name; + protected World world; + protected boolean enabled, protect, running, setup, lobbySetup, autoEquip, forceRestore, softRestore, softRestoreDrops, emptyInvJoin, emptyInvSpec, pvp, monsterInfight, allowWarp; + + protected boolean edit, waveClear, detCreepers, detDamage, lightning, hellhounds, specOnDeath, shareInArena, spoutSelect; + protected Location p1, p2, l1, l2, arenaLoc, lobbyLoc, spectatorLoc; + protected Map spawnpoints, spawnpointsBoss, containers; + protected String logging; + + // Wave/reward/entryfee fields + protected int spawnTaskId, sheepTaskId, waveDelay, waveInterval, specialModulo, spawnMonstersInt, maxIdleTime, finalWave; + protected MASpawnThread spawnThread; + protected Map> everyWaveMap, afterWaveMap; + protected Map classMap; + protected Map> classItems, classArmor; + protected Map> classPerms; + protected Map attachments; + protected List entryFee; + + // Player sets + protected Set arenaPlayers, lobbyPlayers, readyPlayers, specPlayers; + + // Wave stuff + protected TreeSet singleWaves, singleWavesInstance; + protected TreeSet recurrentWaves; + protected BossWave bossWave; + protected Wave currentWave; + + // Arena sets/maps + protected Set hasPaid, rewardedPlayers, notifyPlayers, randoms; + protected Set monsters, explodingSheep, plaguedPigs, madCows; + protected Set blocks; + protected Set pets; + protected Map petMap; + protected LinkedList repairables, containables; + + // Spawn overriding + protected int spawnMonsters; + protected boolean allowMonsters, allowAnimals; + + // Other settings + protected int minPlayers, maxPlayers, joinDistance; + protected List classes = new LinkedList(); + protected Map locations = new HashMap(); + protected Map healthMap = new HashMap(); + protected Map hungerMap = new HashMap(); + protected Map modeMap = new HashMap(); + + // Logging + protected ArenaLog log; + protected Map arenaPlayerMap; + protected Leaderboard leaderboard; + + protected MAListener eventListener; + + protected PriorityBlockingQueue repairQueue; + */ + + /** + * Primary constructor. Requires a name and a world. + */ + public ArenaStandard(String name, World world) + { + if (world == null) + throw new NullPointerException("[MobArena] ERROR! World for arena '" + name + "' does not exist!"); + + this.name = name; + this.world = world; + plugin = (MobArena) Bukkit.getServer().getPluginManager().getPlugin("MobArena"); + + arenaPlayers = new HashSet(); + lobbyPlayers = new HashSet(); + notifyPlayers = new HashSet(); + readyPlayers = new HashSet(); + specPlayers = new HashSet(); + rewardedPlayers = new HashSet(); + hasPaid = new HashSet(); + monsters = new HashSet(); + explodingSheep = new HashSet(); + plaguedPigs = new HashSet(); + madCows = new HashSet(); + blocks = new HashSet(); + pets = new HashSet(); + petMap = new HashMap(); + classMap = new HashMap(); + randoms = new HashSet(); + repairables = new LinkedList(); + containables = new LinkedList(); + attachments = new HashMap(); + arenaPlayerMap = new HashMap(); + + running = false; + edit = false; + + allowMonsters = world.getAllowMonsters(); + allowAnimals = world.getAllowAnimals(); + spawnMonsters = MAUtils.getSpawnMonsters(world); + + eventListener = new MAListener(this, plugin); + repairQueue = new PriorityBlockingQueue(100, new RepairableComparator()); + } + + public boolean startArena() + { + // Sanity-checks + if (running || lobbyPlayers.isEmpty() || !readyPlayers.containsAll(lobbyPlayers)) + return false; + if (!softRestore && forceRestore && !serializeRegion()) + return false; + + // Store all chest contents. + storeContainerContents(); + + // Populate arenaPlayers and clear the lobby. + arenaPlayers.addAll(lobbyPlayers); + lobbyPlayers.clear(); + readyPlayers.clear(); + + // Assign random classes. + for (Player p : randoms) + assignRandomClass(p); + if (arenaPlayers.isEmpty()) + return false; + + // Teleport players, give full health, initialize maps + for (Player p : arenaPlayers) + { + p.teleport(arenaLoc); + setHealth(p, 20); + p.setFoodLevel(10); + assignClassPermissions(p); + arenaPlayerMap.put(p, new ArenaPlayer(p, this, plugin)); + } + + // Copy the singleWaves Set for polling. + singleWavesInstance = new TreeSet(singleWaves); + + // Start spawning monsters (must happen before 'running = true;') + startSpawning(); + startBouncingSheep(); + + // Set the boolean. + running = true; + + // Spawn pets (must happen after 'running = true;') + spawnPets(); + + // Start logging + log = new ArenaLog(plugin, this); + log.start(); + + // Initialize leaderboards and start displaying info. + leaderboard.initialize(); + leaderboard.startTracking(); + + // Announce and notify. + MAUtils.tellAll(this, Msg.ARENA_START); + + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaStart(this); + + return true; + } + + public boolean endArena() + { + // Sanity-checks. + if (!running || !arenaPlayers.isEmpty()) + { + //System.out.println("Arena was not ended, playercount: " + arenaPlayers.size()); + return false; + } + //else System.out.println("Arena ending..."); + + // Set the boolean. + running = false; + + // Stop tracking leaderboards + leaderboard.stopTracking(); + leaderboard.update(); + + // Finish logging + log.end(); + if (logging != null) + { + log.saveSessionData(); + log.updateArenaTotals(); + } + log.clearSessionData(); + + // Stop spawning. + stopSpawning(); + + // Clean arena floor. + cleanup(); + + // Restore region. + if (softRestore) + restoreRegion(); + else if (forceRestore) + deserializeRegion(); + + // Restore chests + restoreContainerContents(); + + // Announce and clear sets. + MAUtils.tellAll(this, Msg.ARENA_END, true); + arenaPlayers.clear(); + arenaPlayerMap.clear(); + lobbyPlayers.clear(); + readyPlayers.clear(); + notifyPlayers.clear(); + rewardedPlayers.clear(); + classMap.clear(); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onArenaEnd(this); + + return true; + } + + public void forceStart() + { + if (running) + return; + + // Set operations. + Set tmp = new HashSet(); + tmp.addAll(lobbyPlayers); + tmp.removeAll(readyPlayers); + + // Force leave. + for (Player p : tmp) + { + plugin.getAM().arenaMap.remove(p); + playerLeave(p); + } + } + + public void forceEnd() + { + Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); + Bukkit.getServer().getScheduler().cancelTask(sheepTaskId); + + for (Player p : getAllPlayers()) + playerLeave(p); + + for (Entity e : monsters) + if (e != null) e.remove(); + + if (bossWave != null) + bossWave.clear(); + + arenaPlayers.clear(); + lobbyPlayers.clear(); + readyPlayers.clear(); + + cleanup(); + + spawnTaskId = -1; + sheepTaskId = -1; + } + + public void playerJoin(Player p, Location loc) + { + storePlayerData(p, loc); + MAUtils.sitPets(p); + setHealth(p, 20); + p.setFoodLevel(10); + p.setGameMode(GameMode.SURVIVAL); + movePlayerToLobby(p); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerJoin(this, p); + + if (MobArena.hasSpout && spoutSelect) + Spouty.classSelectionScreen(plugin, this, p); + } + + public void playerReady(Player p) + { + readyPlayers.add(p); + + if (minPlayers > 0 && lobbyPlayers.size() < minPlayers) + { + MAUtils.tellPlayer(p, Msg.LOBBY_NOT_ENOUGH_PLAYERS, "" + minPlayers); + return; + } + + startArena(); + } + + public void playerLeave(Player p) + { + finishArenaPlayer(p, false); + movePlayerToEntry(p); + discardPlayer(p); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerLeave(this, p); + + // End arena if possible. + endArena(); + } + + public void playerDeath(Player p) + { + finishArenaPlayer(p, true); + + if (specOnDeath) + { + clearPlayer(p); + movePlayerToSpec(p); + } + else + { + movePlayerToEntry(p); + discardPlayer(p); + } + + if (running && spawnThread != null) + spawnThread.updateTargets(); + + MAUtils.tellAll(this, Msg.PLAYER_DIED, p.getName()); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + endArena(); + } + }); + + // Notify listeners. + for (MobArenaListener listener : plugin.getAM().listeners) + listener.onPlayerDeath(this, p); + } + + public void playerSpec(Player p, Location loc) + { + storePlayerData(p, loc); + MAUtils.sitPets(p); + movePlayerToSpec(p); + } + + private void spawnPets() + { + for (Map.Entry entry : petMap.entrySet()) + { + // Remove the bones from the inventory. + Player p = entry.getKey(); + p.getInventory().removeItem(new ItemStack(Material.BONE, entry.getValue())); + + // Spawn wolves, set owner and health, and add to pet set. + for (int i = 0; i < entry.getValue(); i++) + { + Wolf wolf = (Wolf) world.spawnCreature(p.getLocation(), CreatureType.WOLF); + wolf.setTamed(true); + wolf.setOwner(p); + wolf.setHealth(20); + if (hellhounds) + wolf.setFireTicks(32768); + pets.add(wolf); + } + } + } + + private void startSpawning() + { + // Set the spawn flags to enable monster spawning. + MAUtils.setSpawnFlags(plugin, world, 1, allowMonsters, allowAnimals); + + // Start the spawnThread. + spawnThread = new MASpawnThread(plugin, this); + spawnTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, spawnThread, waveDelay, (!waveClear) ? waveInterval : 60); + } + + private void stopSpawning() + { + // Stop the spawn thread. + if (spawnThread != null) + { + Bukkit.getServer().getScheduler().cancelTask(spawnThread.getTaskId()); + Bukkit.getServer().getScheduler().cancelTask(spawnTaskId); + Bukkit.getServer().getScheduler().cancelTask(sheepTaskId); + spawnTaskId = -1; + sheepTaskId = -1; + spawnThread = null; + currentWave = null; + } + else System.out.println("--------- THE SPAWNTHREAD IS NULL! ----------"); + + // Restore spawn flags. + MAUtils.setSpawnFlags(plugin, world, spawnMonsters, allowMonsters, allowAnimals); + } + + private void startBouncingSheep() + { + sheepTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, + new Runnable() + { + public void run() + { + if (explodingSheep.isEmpty()) return; + + for (LivingEntity e : new LinkedList(explodingSheep)) + { + if (e == null) continue; + + Creature c = (Creature) e; + LivingEntity target = c.getTarget(); + if (target != null && target instanceof Player && MAUtils.distanceSquared((Player) target, e.getLocation()) < 8D) + { + CraftEntity ce = (CraftEntity) e; + CraftWorld cw = (CraftWorld) e.getWorld(); + WorldServer ws = cw.getHandle(); + ws.createExplosion(ce.getHandle(), e.getLocation().getX(), e.getLocation().getY() + 1, e.getLocation().getZ(), 2f, false); + e.remove(); + } + + if (e.isDead()) + { + explodingSheep.remove(e); + continue; + } + + if (Math.abs(e.getVelocity().getY()) < 1) + e.setVelocity(e.getVelocity().setY(0.5)); + } + } + }, waveDelay, 20); + } + + private void updateChunk(Location loc) + { + if (!arenaPlayers.isEmpty() || !world.getName().equals(loc.getWorld().getName())) + return; + + Chunk chunk = world.getChunkAt(loc); + if (!world.isChunkLoaded(chunk)) + world.loadChunk(chunk); + else + world.refreshChunk(chunk.getX(), chunk.getZ()); + } + + public void playerKill(Player p) + { + if (p == null || log.players.get(p) == null) + return; + + arenaPlayerMap.get(p).getStats().kills++; + } + + public void restoreInvAndGiveRewardsDelayed(final Player p) + { + final List rewards = log != null && log.players.get(p) != null ? log.players.get(p).rewards : new LinkedList(); + final boolean hadRewards = rewardedPlayers.contains(p); + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + if (!emptyInvJoin) + MAUtils.restoreInventory(p); + + if (hadRewards) + return; + + MAUtils.giveRewards(p, rewards, plugin); + if (running) + rewardedPlayers.add(p); + } + }); + } + + public void restoreInvAndGiveRewards(final Player p) + { + if (!emptyInvJoin) + MAUtils.restoreInventory(p); + + if (rewardedPlayers.contains(p)) + return; + + final List rewards = (log != null && log.players.get(p) != null) ? + log.players.get(p).rewards : + new LinkedList(); + + MAUtils.giveRewards(p, rewards, plugin); + if (running) + rewardedPlayers.add(p); + } + + public void storePlayerData(Player p, Location loc) + { + plugin.getAM().arenaMap.put(p, this); + + if (!locations.containsKey(p)) + locations.put(p, loc); + + if (!healthMap.containsKey(p)) + healthMap.put(p, p.getHealth()); + + if (!hungerMap.containsKey(p)) + hungerMap.put(p, p.getFoodLevel()); + + if (!modeMap.containsKey(p)) + modeMap.put(p, p.getGameMode()); + } + + public void storeContainerContents() + { + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (Location loc : containers.values()) + { + BlockState state = world.getBlockAt(loc).getState(); + if (state instanceof ContainerBlock) + containables.add(new RepairableContainer(state, false)); + } + } + }); + } + + public void restoreContainerContents() + { + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + for (Repairable r : containables) + r.repair(); + } + }); + } + + public void movePlayerToLobby(Player p) + { + updateChunk(lobbyLoc); + lobbyPlayers.add(p); + p.teleport(lobbyLoc); + } + + public void movePlayerToSpec(Player p) + { + updateChunk(spectatorLoc); + specPlayers.add(p); + p.teleport(spectatorLoc); + } + + public void movePlayerToEntry(Player p) + { + Location entry = locations.get(p); + if (entry == null || p.isDead()) return; + + updateChunk(entry); + p.teleport(entry); + } + + private void clearPlayer(Player p) + { + if (healthMap.containsKey(p)) + { + int health = healthMap.remove(p); + setHealth(p, health); + } + + if (hungerMap.containsKey(p)) + p.setFoodLevel(hungerMap.remove(p)); + + if (modeMap.containsKey(p)) + p.setGameMode(modeMap.remove(p)); + + // Put out fire. + Delays.douse(plugin, p, 3); + + // Remove pets. + removePets(p); + + // readyPlayers before lobbyPlayers because of startArena sanity-checks + readyPlayers.remove(p); + specPlayers.remove(p); + arenaPlayers.remove(p); + lobbyPlayers.remove(p); + classMap.remove(p); + arenaPlayerMap.remove(p); + } + + /** + * Completely remove a player from the arena collections. + * @param p A player + */ + private void discardPlayer(Player p) + { + locations.remove(p); + plugin.getAM().arenaMap.remove(p); + clearPlayer(p); + } + + /** + * Give the player back his inventory and record his last wave. + * Called when a player dies or leaves prematurely. + * @param p A player + * @param dead If the player died or not + */ + private void finishArenaPlayer(Player p, boolean dead) + { + if (!arenaPlayers.contains(p) && !lobbyPlayers.contains(p)) + return; + + removeClassPermissions(p); + MAUtils.clearInventory(p); + + if (dead) restoreInvAndGiveRewardsDelayed(p); + else restoreInvAndGiveRewards(p); + + ArenaPlayer ap = arenaPlayerMap.get(p); + if (ap != null) + ap.setDead(true); + } + + private void setHealth(Player p, int health) + { + // Grab the current health + int current = p.getHealth(); + + // If the health is 20, just leave it at that no matter what. + int regain = health == 20 ? 20 : health - current; + + // Set the health, and fire off the event. + p.setHealth(health); + EntityRegainHealthEvent event = new EntityRegainHealthEvent(p, regain, RegainReason.CUSTOM); + Bukkit.getPluginManager().callEvent(event); + } + + public void repairBlocks() + { + while (!repairQueue.isEmpty()) + repairQueue.poll().repair(); + } + + public void queueRepairable(Repairable r) + { + repairQueue.add(r); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Items & Cleanup + // + ////////////////////////////////////////////////////////////////////*/ + + public void assignClass(Player p, String className) + { + petMap.remove(p); + randoms.remove(p); + classMap.put(p, className); + + MAUtils.clearInventory(p); + + // If random, don't give any items yet. + if (className.equalsIgnoreCase("random")) + { + randoms.add(p); + return; + } + + MAUtils.giveItems(p, classItems.get(className), autoEquip, plugin); + MAUtils.giveItems(p, classArmor.get(className), autoEquip, plugin); + + int pets = MAUtils.getPetAmount(p); + if (pets > 0) petMap.put(p, pets); + } + + public void assignRandomClass(Player p) + { + Random r = new Random(); + List classes = new LinkedList(plugin.getAM().classes); + + String className = classes.remove(r.nextInt(classes.size())); + while (!plugin.has(p, "mobarena.classes." + className)) + { + if (classes.isEmpty()) + { + MobArena.info("Player '" + p.getName() + "' has no class permissions!"); + playerLeave(p); + return; + } + className = classes.remove(r.nextInt(classes.size())); + } + + assignClass(p, className); + MAUtils.tellPlayer(p, Msg.LOBBY_CLASS_PICKED, className); + } + + public void assignClassPermissions(Player p) + { + Map perms = classPerms.get(classMap.get(p)); + if (perms == null || perms.isEmpty()) return; + + PermissionAttachment pa = p.addAttachment(plugin); + attachments.put(p,pa); + for (Map.Entry entry : perms.entrySet()) + pa.setPermission(entry.getKey(), entry.getValue()); + } + + public void removeClassPermissions(Player p) + { + if (attachments.get(p) == null) return; + + for (PermissionAttachment pa : attachments.values()) + if (pa != null) pa.remove(); + } + + private void cleanup() + { + removeMonsters(); + removeBlocks(); + removePets(); + removeEntities(); + monsters.clear(); + explodingSheep.clear(); + plaguedPigs.clear(); + madCows.clear(); + blocks.clear(); + pets.clear(); + } + + private void removeMonsters() + { + if (bossWave != null) + bossWave.clear(); + for (LivingEntity e : monsters) + if (e != null) e.remove(); + for (LivingEntity e : explodingSheep) + if (e != null) e.remove(); + for (LivingEntity e : plaguedPigs) + if (e != null) e.remove(); + for (LivingEntity e : madCows) + if (e != null) e.remove(); + } + + private void removeBlocks() + { + for (Block b : blocks) + b.setTypeId(0); + } + + private void removePets() + { + for (Wolf w : pets) + { + if (w == null) continue; + + w.setOwner(null); + w.remove(); + } + } + + private void removePets(Player p) + { + for (Wolf w : pets) + { + if (w == null || !(w.getOwner() instanceof Player) || !((Player) w.getOwner()).getName().equals(p.getName())) + continue; + + w.setOwner(null); + w.remove(); + } + petMap.remove(p); + } + + private void removeEntities() + { + if (p1 == null || p2 == null) return; + Chunk c1 = world.getChunkAt(p1); + Chunk c2 = world.getChunkAt(p2); + + for (int i = c1.getX(); i <= c2.getX(); i++) + for (int j = c1.getZ(); j <= c2.getZ(); j++) + for (Entity e : world.getChunkAt(i,j).getEntities()) + if ((e instanceof Item || e instanceof Slime) && inRegion(e.getLocation())) + if (e != null) e.remove(); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Initialization & Checks + // + ////////////////////////////////////////////////////////////////////*/ + + public void load(Config config) + { + config.load(); + + String arenaPath = "arenas." + MAUtils.nameArenaToConfig(name) + ".settings."; + String configName = MAUtils.nameArenaToConfig(name); + + enabled = config.getBoolean(arenaPath + "enabled", true); + protect = config.getBoolean(arenaPath + "protect", true); + logging = config.getString(arenaPath + "logging", null); + autoEquip = config.getBoolean(arenaPath + "auto-equip-armor", true); + waveClear = config.getBoolean(arenaPath + "clear-wave-before-next", false); + detCreepers = config.getBoolean(arenaPath + "detonate-creepers", false); + detDamage = config.getBoolean(arenaPath + "detonate-damage", false); + lightning = config.getBoolean(arenaPath + "lightning", true); + forceRestore = config.getBoolean(arenaPath + "force-restore", false); + softRestore = config.getBoolean(arenaPath + "soft-restore", false); + softRestoreDrops = config.getBoolean(arenaPath + "soft-restore-drops", false); + emptyInvJoin = config.getBoolean(arenaPath + "require-empty-inv-join", true); + emptyInvSpec = config.getBoolean(arenaPath + "require-empty-inv-spec", true); + hellhounds = config.getBoolean(arenaPath + "hellhounds", false); + pvp = config.getBoolean(arenaPath + "pvp-enabled", false); + monsterInfight = config.getBoolean(arenaPath + "monster-infight", false); + allowWarp = config.getBoolean(arenaPath + "allow-teleporting", false); + specOnDeath = config.getBoolean(arenaPath + "spectate-on-death", true); + shareInArena = config.getBoolean(arenaPath + "share-items-in-arena", true); + spoutSelect = config.getBoolean(arenaPath + "spout-class-select", true); + joinDistance = config.getInt(arenaPath + "max-join-distance", 0); + minPlayers = config.getInt(arenaPath + "min-players", 0); + maxPlayers = config.getInt(arenaPath + "max-players", 0); + waveDelay = config.getInt(arenaPath + "first-wave-delay", 5) * 20; + waveInterval = config.getInt(arenaPath + "wave-interval", 20) * 20; + specialModulo = config.getInt(arenaPath + "special-modulo", 4); + maxIdleTime = config.getInt(arenaPath + "max-idle-time", 0) * 20; + finalWave = config.getInt(arenaPath + "final-wave", 0); + + everyWaveMap = MAUtils.getArenaRewardMap(config, configName, "every"); + afterWaveMap = MAUtils.getArenaRewardMap(config, configName, "after"); + entryFee = MAUtils.getEntryFee(config, configName); + + p1 = MAUtils.getArenaCoord(config, world, configName, "p1"); + p2 = MAUtils.getArenaCoord(config, world, configName, "p2"); + l1 = MAUtils.getArenaCoord(config, world, configName, "l1"); + l2 = MAUtils.getArenaCoord(config, world, configName, "l2"); + arenaLoc = MAUtils.getArenaCoord(config, world, configName, "arena"); + lobbyLoc = MAUtils.getArenaCoord(config, world, configName, "lobby"); + spectatorLoc = MAUtils.getArenaCoord(config, world, configName, "spectator"); + spawnpoints = MAUtils.getArenaSpawnpoints(config, world, configName); + spawnpointsBoss = MAUtils.getArenaBossSpawnpoints(config, world, configName); + containers = MAUtils.getArenaContainers(config, world, configName); + leaderboard = new Leaderboard(plugin, this, config); + + // NEW WAVES + singleWaves = WaveUtils.getWaves(this, config, WaveBranch.SINGLE); + recurrentWaves = WaveUtils.getWaves(this, config, WaveBranch.RECURRENT); + + classes = plugin.getAM().classes; + classItems = plugin.getAM().classItems; + classArmor = plugin.getAM().classArmor; + classPerms = plugin.getAM().classPerms; + + // Determine if the arena is properly set up. Then add the to arena list. + setup = MAUtils.verifyData(this); + lobbySetup = MAUtils.verifyLobby(this); + } + + public void restoreRegion() + { + Collections.sort(repairables, new RepairableComparator()); + + for (Repairable r : repairables) + r.repair(); + } + + public void serializeConfig() + { + String coords = "arenas." + configName() + ".coords."; + Config config = plugin.getMAConfig(); + + config.setProperty("arenas." + configName() + ".settings.enabled", enabled); + config.setProperty("arenas." + configName() + ".settings.protect", protect); + if (p1 != null) config.setProperty(coords + "p1", MAUtils.makeCoord(p1)); + if (p2 != null) config.setProperty(coords + "p2", MAUtils.makeCoord(p2)); + if (l1 != null) config.setProperty(coords + "l1", MAUtils.makeCoord(l1)); + if (l2 != null) config.setProperty(coords + "l2", MAUtils.makeCoord(l2)); + if (arenaLoc != null) config.setProperty(coords + "arena", MAUtils.makeCoord(arenaLoc)); + if (lobbyLoc != null) config.setProperty(coords + "lobby", MAUtils.makeCoord(lobbyLoc)); + if (spectatorLoc != null) config.setProperty(coords + "spectator", MAUtils.makeCoord(spectatorLoc)); + for (Map.Entry entry : spawnpoints.entrySet()) + config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); + for (Map.Entry entry : spawnpointsBoss.entrySet()) + config.setProperty(coords + "spawnpoints." + entry.getKey(), MAUtils.makeCoord(entry.getValue())); + + config.save(); + } + + public void deserializeConfig() + { + Config config = plugin.getMAConfig(); + config.load(); + load(config); + } + + public boolean serializeRegion() + { + int x1 = (int) p1.getX(); + int y1 = (int) p1.getY(); + int z1 = (int) p1.getZ(); + int x2 = (int) p2.getX(); + int y2 = (int) p2.getY(); + int z2 = (int) p2.getZ(); + + HashSet set = new HashSet(); + int[] buffer; + for (int i = x1; i <= x2; i++) + { + for (int j = y1; j <= y2; j++) + { + for (int k = z1; k <= z2; k++) + { + buffer = new int[4]; + buffer[0] = i; + buffer[1] = j; + buffer[2] = k; + buffer[3] = world.getBlockAt(i,j,k).getTypeId(); + set.add(buffer); + } + } + } + + try + { + new File(plugin.getDataFolder() + File.separator + "regions").mkdir(); + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (regionFile.exists()) + regionFile.createNewFile(); + + FileOutputStream fos = new FileOutputStream(regionFile); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(set); + oos.close(); + } + catch (Exception e) + { + MobArena.warning("Could not create region file. The arena will not be started!"); + e.printStackTrace(); + return false; + } + return true; + } + + @SuppressWarnings("unchecked") + public boolean deserializeRegion() + { + HashSet set = new HashSet(); + try + { + File regionFile = new File(plugin.getDataFolder() + File.separator + "regions" + File.separator + configName() + ".tmp"); + if (!regionFile.exists()) + return false; + + FileInputStream fis = new FileInputStream(regionFile); + ObjectInputStream ois = new ObjectInputStream(fis); + set = (HashSet) ois.readObject(); + ois.close(); + } + catch (Exception e) + { + MobArena.warning("Could not find region file. The arena cannot be restored!"); + e.printStackTrace(); + return false; + } + + for (int[] buffer : set) + world.getBlockAt(buffer[0], buffer[1], buffer[2]).setTypeId(buffer[3]); + + return true; + } + + /** + * Check if a location is inside of the cuboid region + * that p1 and p2 span. + */ + public boolean inRegion(Location loc) + { + if (!loc.getWorld().getName().equals(world.getName()) || !setup) + return false; + + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + // Check the lobby first. + if (lobbySetup) + { + if ((x >= l1.getBlockX() && x <= l2.getBlockX()) && + (z >= l1.getBlockZ() && z <= l2.getBlockZ()) && + (y >= l1.getBlockY() && y <= l2.getBlockY())) + return true; + } + + // Returns false if the location is outside of the region. + return ((x >= p1.getBlockX() && x <= p2.getBlockX()) && + (z >= p1.getBlockZ() && z <= p2.getBlockZ()) && + (y >= p1.getBlockY() && y <= p2.getBlockY())); + } + + /** + * Check if a location is inside of the arena region, expanded + * by 'radius' blocks. Used with explosions. + */ + public boolean inRegionRadius(Location loc, int radius) + { + if (!loc.getWorld().getName().equals(world.getName()) || !setup) + return false; + + int x = loc.getBlockX(); + int y = loc.getBlockY(); + int z = loc.getBlockZ(); + + // Check the lobby first. + if (lobbySetup) + { + if ((x + radius >= l1.getBlockX() && x - radius <= l2.getBlockX()) && + (z + radius >= l1.getBlockZ() && z - radius <= l2.getBlockZ()) && + (y + radius >= l1.getBlockY() && y - radius <= l2.getBlockY())) + return true; + } + + return ((x + radius >= p1.getBlockX() && x - radius <= p2.getBlockX()) && + (z + radius >= p1.getBlockZ() && z - radius <= p2.getBlockZ()) && + (y + radius >= p1.getBlockY() && y - radius <= p2.getBlockY())); + } + + + + /*//////////////////////////////////////////////////////////////////// + // + // Getters & Misc + // + ////////////////////////////////////////////////////////////////////*/ + + public boolean inArena(Player p) + { + return arenaPlayers.contains(p); + } + + public boolean inLobby(Player p) + { + return lobbyPlayers.contains(p); + } + + public boolean isRunning() + { + return running; + } + + public boolean isPvpEnabled() + { + return pvp; + } + + public boolean isLightningEnabled() + { + return lightning; + } + + public boolean isBossWave() + { + return bossWave != null; + } + + public String configName() + { + return MAUtils.nameArenaToConfig(name); + } + + public String arenaName() + { + return name; + } + + public MobArena getPlugin() + { + return plugin; + } + + public World getWorld() + { + return world; + } + + public Wave getWave() + { + return currentWave; + } + + public void setWave(Wave wave) + { + currentWave = wave; + } + + public void setBossWave(BossWave bossWave) + { + this.bossWave = bossWave; + } + + public Set getClasses() + { + return classes; + } + + public List getAllSpawnpoints() + { + ArrayList result = new ArrayList(spawnpoints.size() + spawnpointsBoss.size()); + result.addAll(spawnpoints.values()); + result.addAll(spawnpointsBoss.values()); + return result; + } + + public List getSpawnpoints() + { + return new ArrayList(spawnpoints.values()); + } + + public Location getBossSpawnpoint() + { + if (spawnpointsBoss.isEmpty()) + { + List points = WaveUtils.getValidSpawnpoints(this, getLivingPlayers()); + return points.get(MobArena.random.nextInt(points.size())); + } + + return new ArrayList(spawnpointsBoss.values()).get(MobArena.random.nextInt(spawnpointsBoss.size())); + } + + public int getPlayerCount() + { + return spawnThread.getPlayerCount(); + } + + public void addBlock(Block b) + { + blocks.add(b); + } + + public void addMonster(LivingEntity e) + { + monsters.add(e); + } + + public void addExplodingSheep(LivingEntity e) + { + explodingSheep.add(e); + } + + public List getAllPlayers() + { + List result = new LinkedList(); + result.addAll(arenaPlayers); + result.addAll(lobbyPlayers); + result.addAll(specPlayers); + return result; + } + + public List getLivingPlayers() + { + List result = new LinkedList(); + result.addAll(arenaPlayers); + return result; + } + + public Set getArenaPlayers() + { + return arenaPlayers; + } + + public Collection getArenaPlayerSet() + { + return arenaPlayerMap.values(); + } + + public List getArenaPlayerStatistics(Comparator comparator) + { + List list = new ArrayList(); + + for (ArenaPlayer ap : arenaPlayerMap.values()) + list.add(ap.getStats()); + + Collections.sort(list, comparator); + return list; + } + + public List getNonreadyPlayers() + { + List result = new LinkedList(); + result.addAll(lobbyPlayers); + result.removeAll(readyPlayers); + return result; + } + + public Set getMonsters() + { + Set tmp = new HashSet(monsters); + tmp.addAll(explodingSheep); + return tmp; + } + + public Set getPets() + { + return pets; + } + + public void resetIdleTimer() + { + if (maxIdleTime <= 0 || !running) + return; + + // Reset the previousSize, cancel the previous timer, and start the new timer. + spawnThread.setPreviousSize(getMonsters().size()); + Bukkit.getServer().getScheduler().cancelTask(spawnThread.getTaskId()); + int id = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + // Make sure to remove any dead/removed entities first. + List ms = new LinkedList(monsters); + for (Entity e : ms) + if (e.isDead()) + monsters.remove(e); + + // Compare the current size with the previous size. + if (monsters.size() < spawnThread.getPreviousSize() || spawnThread.getPreviousSize() == 0 || bossWave != null) + { + resetIdleTimer(); + return; + } + + // Clear all player inventories, and "kill" all players. + List ps = new LinkedList(arenaPlayers); + for (Player p : ps) + { + MAUtils.clearInventory(p); + MAUtils.tellPlayer(p, Msg.FORCE_END_IDLE); + playerDeath(p); + } + } + }, maxIdleTime); + spawnThread.setTaskId(id); + } + + public void addTrunkAndLeaves(Block b) + { + final int x = b.getX(); + final int y = b.getY(); + final int z = b.getZ(); + + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, + new Runnable() + { + public void run() + { + List result = new LinkedList(); + for (int i = x-2; i <= x+2; i++) + for (int j = y; j <= y+10; j++) + for (int k = z-2; k <= z+2; k++) + if (world.getBlockAt(i,j,k).getType() == Material.LOG || world.getBlockAt(i,j,k).getType() == Material.LEAVES) + result.add(world.getBlockAt(i,j,k)); + + if (running) blocks.addAll(result); + } + }, 10); + } + + public boolean canAfford(Player p) + { + if (entryFee.isEmpty()) + return true; + + PlayerInventory inv = p.getInventory(); + for (ItemStack stack : entryFee) + { + // Economy money + if (stack.getTypeId() == MobArena.ECONOMY_MONEY_ID) + { + //if (plugin.Methods.hasMethod() && !plugin.Method.getAccount(p.getName()).hasEnough(stack.getAmount())) + if (plugin.Method != null && !(plugin.Method.getAccount(p.getName()).balance() >= stack.getAmount())) + return false; + } + // Normal stack + else + { + if (!inv.contains(stack.getTypeId(), stack.getAmount())) + return false; + } + } + + return true; + } + + public boolean takeFee(Player p) + { + if (entryFee.isEmpty()) + return true; + + PlayerInventory inv = p.getInventory(); + InventoryItem[] items = InventoryItem.parseItemStacks(inv.getContents()); + InventoryItem[] fee = InventoryItem.parseItemStacks(entryFee); + + // Take some economy money + for (InventoryItem item : InventoryItem.extractAllFromArray(MobArena.ECONOMY_MONEY_ID, fee)) + if (plugin.Method != null) + plugin.Method.getAccount(p.getName()).subtract(item.getAmount()); + + // Take any other items + for (InventoryItem item : fee) + InventoryItem.removeItemFromArray(item, items); + + // Turn everything back into ItemStacks + for (int i = 0; i < items.length; i++) + inv.setItem(i, items[i].toItemStack()); + + return true; + } + + public boolean canJoin(Player p) + { + if (!enabled) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_ENABLED); + else if (!setup || recurrentWaves.isEmpty()) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_SETUP); + else if (edit) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_EDIT_MODE); + else if (running && (notifyPlayers.contains(p) || notifyPlayers.add(p))) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_IS_RUNNING); + else if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) + MAUtils.tellPlayer(p, Msg.JOIN_ALREADY_PLAYING); + else if (!plugin.has(p, "mobarena.arenas." + configName())) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_PERMISSION); + else if (maxPlayers > 0 && lobbyPlayers.size() >= maxPlayers) + MAUtils.tellPlayer(p, Msg.JOIN_PLAYER_LIMIT_REACHED); + else if (joinDistance > 0 && !inRegionRadius(p.getLocation(), joinDistance)) + MAUtils.tellPlayer(p, Msg.JOIN_TOO_FAR); + else if (emptyInvJoin && !MAUtils.hasEmptyInventory(p)) + MAUtils.tellPlayer(p, Msg.JOIN_EMPTY_INV); + else if (!canAfford(p))// || !takeFee(p)) + MAUtils.tellPlayer(p, Msg.JOIN_FEE_REQUIRED, MAUtils.listToString(entryFee, plugin)); + else return true; + + return false; + } + + public boolean canSpec(Player p) + { + if (!enabled) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_ENABLED); + else if (!setup) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_NOT_SETUP); + else if (edit) + MAUtils.tellPlayer(p, Msg.JOIN_ARENA_EDIT_MODE); + else if (arenaPlayers.contains(p) || lobbyPlayers.contains(p)) + MAUtils.tellPlayer(p, Msg.SPEC_ALREADY_PLAYING); + else if (emptyInvSpec && !MAUtils.hasEmptyInventory(p)) + MAUtils.tellPlayer(p, Msg.SPEC_EMPTY_INV); + else if (joinDistance > 0 && !inRegionRadius(p.getLocation(), joinDistance)) + MAUtils.tellPlayer(p, Msg.JOIN_TOO_FAR); + else return true; + + return false; + } + + /** + * The "perfect equals method" cf. "Object-Oriented Design and Patterns" + * by Cay S. Horstmann. + */ + public boolean equals(Object other) + { + if (this == other) return true; + if (other == null) return false; + if (getClass() != other.getClass()) return false; + + // Arenas must have different names. + if (other instanceof ArenaStandard && ((ArenaStandard)other).name.equals(name)) + return true; + + return false; + } + + public String toString() + { + return ((enabled && setup) ? ChatColor.GREEN : ChatColor.GRAY) + configName(); + } +} diff --git a/src/com/garbagemule/MobArena/MACommands.java b/src/com/garbagemule/MobArena/MACommands.java index bfe18ad..b2fce4c 100644 --- a/src/com/garbagemule/MobArena/MACommands.java +++ b/src/com/garbagemule/MobArena/MACommands.java @@ -73,6 +73,11 @@ public class MACommands implements CommandExecutor private MobArena plugin; private ArenaMaster am; + public MACommands() + { + + } + public MACommands(MobArena plugin, ArenaMaster am) { this.plugin = plugin; @@ -1029,7 +1034,7 @@ public class MACommands implements CommandExecutor } StringBuffer buffy = new StringBuffer(); - List spawnpoints = plugin.getMAConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.spawnpoints"); + Set spawnpoints = plugin.getMAConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.spawnpoints"); if (spawnpoints != null) { @@ -1101,7 +1106,7 @@ public class MACommands implements CommandExecutor } StringBuffer buffy = new StringBuffer(); - List containers = plugin.getMAConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.containers"); + Set containers = plugin.getMAConfig().getKeys("arenas." + am.selectedArena.configName() + ".coords.containers"); if (containers != null) { diff --git a/src/com/garbagemule/MobArena/MAUtils.java b/src/com/garbagemule/MobArena/MAUtils.java index 9fc223a..999818e 100644 --- a/src/com/garbagemule/MobArena/MAUtils.java +++ b/src/com/garbagemule/MobArena/MAUtils.java @@ -33,11 +33,12 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Wolf; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import org.getspout.spoutapi.SpoutManager; import org.getspout.spoutapi.player.SpoutPlayer; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.EntityPosition; import com.garbagemule.MobArena.util.InventoryItem; @@ -136,7 +137,7 @@ public class MAUtils // ///////////////////////////////////////////////////////////////////// */ - public static Map getArenaContainers(Configuration config, World world, String arena) + public static Map getArenaContainers(Config config, World world, String arena) { Map containers = new HashMap(); String arenaPath = "arenas." + arena + ".coords.containers"; @@ -153,7 +154,7 @@ public class MAUtils /** * Grab all the spawnpoints for a specific arena. */ - public static Map getArenaSpawnpoints(Configuration config, World world, String arena) + public static Map getArenaSpawnpoints(Config config, World world, String arena) { Map spawnpoints = new HashMap(); String arenaPath = "arenas." + arena + ".coords.spawnpoints"; @@ -168,7 +169,7 @@ public class MAUtils return spawnpoints; } - public static Map getArenaBossSpawnpoints(Configuration config, World world, String arena) + public static Map getArenaBossSpawnpoints(Config config, World world, String arena) { Map spawnpoints = new HashMap(); String arenaPath = "arenas." + arena + ".coords.spawnpoints"; @@ -186,7 +187,7 @@ public class MAUtils /** * Returns a map of classnames mapped to lists of ItemStacks. */ - public static Map> getClassItems(Configuration config, String type) + public static Map> getClassItems(Config config, String type) { Map> result = new HashMap>(); @@ -196,11 +197,11 @@ public class MAUtils return result; } - public static Map> getClassPerms(Configuration config) + public static Map> getClassPerms(Config config) { Map> result = new HashMap>(); - List classes = config.getKeys("classes"); + Set classes = config.getKeys("classes"); if (classes == null) return result; for (String c : classes) @@ -224,7 +225,7 @@ public class MAUtils return result; } - public static List getEntryFee(Configuration config, String arena) + public static List getEntryFee(Config config, String arena) { return makeItemStackList(config.getString("arenas." + arena + ".settings.entry-fee", null)); } @@ -276,7 +277,7 @@ public class MAUtils * type of wave ("after" or "every") and the config-file. If * no keys exist in the config-file, an empty map is returned. */ - public static Map> getArenaRewardMap(Configuration config, String arena, String type) + public static Map> getArenaRewardMap(Config config, String arena, String type) { String arenaPath = "arenas." + arena + ".rewards.waves."; Map> result = new HashMap>(); @@ -297,7 +298,7 @@ public class MAUtils } } - List waves = config.getKeys(arenaPath + type); + Set waves = config.getKeys(arenaPath + type); if (waves == null) return result; for (String n : waves) @@ -313,7 +314,7 @@ public class MAUtils return result; } - public static List getAllowedCommands(Configuration config) + public static List getAllowedCommands(Config config) { String commands = config.getString("global-settings.allowed-commands"); if (commands == null) @@ -768,7 +769,7 @@ public class MAUtils /** * Create a Location object from the config-file. */ - public static Location getArenaCoord(Configuration config, World world, String arena, String coord) + public static Location getArenaCoord(Config config, World world, String arena, String coord) { //config.load(); String str = config.getString("arenas." + arena + ".coords." + coord); @@ -778,9 +779,9 @@ public class MAUtils } /** - * Save an arena location to the Configuration. + * Save an arena location to the Config. */ - public static void setArenaCoord(Configuration config, Arena arena, String coord, Location loc) + public static void setArenaCoord(Config config, Arena arena, String coord, Location loc) { if (coord.equals("arena") || coord.equals("lobby") || coord.equals("spectator")) loc.setY(loc.getY() + 1); @@ -795,7 +796,7 @@ public class MAUtils fixLobby(config, loc.getWorld(), arena); } - public static boolean delArenaCoord(Configuration config, Arena arena, String coord) + public static boolean delArenaCoord(Config config, Arena arena, String coord) { if (config.getString("arenas." + arena.configName() + ".coords." + coord) == null) return false; @@ -806,7 +807,7 @@ public class MAUtils return true; } - public static void fixRegion(Configuration config, World world, Arena arena) + public static void fixRegion(Config config, World world, Arena arena) { if (arena.p1 == null || arena.p2 == null) return; @@ -839,7 +840,7 @@ public class MAUtils arena.load(config); } - private static void fixLobby(Configuration config, World world, Arena arena) + private static void fixLobby(Config config, World world, Arena arena) { if (arena.l1 == null || arena.l2 == null) return; @@ -932,12 +933,12 @@ public class MAUtils return false; } - public static double getDouble(Configuration config, String path) + public static double getDouble(Config config, String path) { return getDouble(config, path, 0D); } - public static double getDouble(Configuration config, String path, double def) + public static double getDouble(Config config, String path, double def) { Object o = config.getProperty(path); if (o instanceof Double) @@ -947,12 +948,12 @@ public class MAUtils return def; } - public static int getInt(Configuration config, String path) + public static int getInt(Config config, String path) { return getInt(config, path, 0); } - public static int getInt(Configuration config, String path, int def) + public static int getInt(Config config, String path, int def) { Object o = config.getProperty(path); if (o instanceof Integer) @@ -1638,7 +1639,7 @@ public class MAUtils world.getBlockAt(entry.getKey().getLocation(world)).setTypeId(entry.getValue()); } - Configuration config = plugin.getMAConfig(); + Config config = plugin.getMAConfig(); config.removeProperty("arenas." + name); config.save(); diff --git a/src/com/garbagemule/MobArena/MobArena.java b/src/com/garbagemule/MobArena/MobArena.java index 253764b..84d243c 100644 --- a/src/com/garbagemule/MobArena/MobArena.java +++ b/src/com/garbagemule/MobArena/MobArena.java @@ -14,10 +14,11 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.PluginManager; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.listeners.MagicSpellsListener; import com.garbagemule.MobArena.spout.Spouty; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.FileUtils; import com.garbagemule.register.payment.Method; import com.garbagemule.register.payment.Methods; @@ -26,9 +27,10 @@ import com.garbagemule.register.payment.Methods; * MobArena * @author garbagemule */ -public class MobArena extends JavaPlugin +public class MobArena extends JavaPlugin implements MobArenaPlugin { - private Configuration config; + //private Configuration config; + private Config config; private ArenaMaster am; // Economy stuff @@ -54,7 +56,7 @@ public class MobArena extends JavaPlugin desc = getDescription(); dir = getDataFolder(); arenaDir = new File(dir, "arenas"); - if (!dir.exists()) dir.mkdir(); + if (!dir.exists()) dir.mkdirs(); if (!arenaDir.exists()) arenaDir.mkdir(); // Create default files and initialize config-file @@ -71,8 +73,9 @@ public class MobArena extends JavaPlugin setupMagicSpells(); // Set up the ArenaMaster and the announcements - am = new ArenaMaster(this); + am = new ArenaMasterStandard(this); am.initialize(); + System.out.println(am.arenas); MAMessages.init(this); // Register event listeners @@ -99,7 +102,7 @@ public class MobArena extends JavaPlugin private void loadConfig() { File file = new File(dir, "config.yml"); - config = new Configuration(file); + config = new Config(file); config.load(); config.setHeader(getHeader()); } @@ -199,8 +202,10 @@ public class MobArena extends JavaPlugin pm.registerEvent(Event.Type.CUSTOM_EVENT, new MagicSpellsListener(this), Priority.Normal, this); } - public Configuration getMAConfig() { return config; } - public ArenaMaster getAM() { return am; } // More convenient. + public Config getMAConfig() { return config; } + public ArenaMaster getAM() { return am; } // More convenient. + + @Override public ArenaMaster getArenaMaster() { return am; } /*public HeroManager getHeroManager() diff --git a/src/com/garbagemule/MobArena/MobArenaPlugin.java b/src/com/garbagemule/MobArena/MobArenaPlugin.java new file mode 100644 index 0000000..c15256d --- /dev/null +++ b/src/com/garbagemule/MobArena/MobArenaPlugin.java @@ -0,0 +1,6 @@ +package com.garbagemule.MobArena; + +public interface MobArenaPlugin +{ + public ArenaMaster getArenaMaster(); +} diff --git a/src/com/garbagemule/MobArena/commands/CommandHandler.java b/src/com/garbagemule/MobArena/commands/CommandHandler.java new file mode 100644 index 0000000..ed2f642 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/CommandHandler.java @@ -0,0 +1,123 @@ +package com.garbagemule.MobArena.commands; + +import java.io.File; +import java.util.*; + +import org.bukkit.command.*; +import org.bukkit.entity.Player; + +import com.garbagemule.MobArena.*; +import com.garbagemule.MobArena.util.classparsing.*; + +public class CommandHandler implements CommandExecutor +{ + /* COMMAND_PATH is an incomplete package-name for all commands in MobArena, + * hence the trailing dot, and the COMMAND_TYPES array contains all the + * different types of commands (the sub-folders). Both are used in the + * loadCommands() method. */ + private static final String COMMAND_PATH = "com.garbagemule.MobArena.commands."; + private static final String[] COMMAND_TYPES = new String[]{"user", "admin", "setup"}; + + private MobArenaPlugin plugin; + private Map commands; + + public CommandHandler(MobArenaPlugin plugin) { + this.plugin = plugin; + this.commands = new HashMap(); + loadCommands(); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (args.length == 0) { + sender.sendMessage("You need arguments, pal!"); + return true; + } + + // Grab the command from the map, and if null, didn't work. + MACommand command = commands.get(args[0]); + if (command == null) { + System.out.println("Command '" + label + "' not recognized"); + return true; + } + + // Cast if sender is a Player, null otherwise. + Player p = (sender instanceof Player) ? (Player) sender : null; + + // If null, must be console. + if (p == null) { + if (!command.executeFromConsole(plugin, sender, args)) { + sender.sendMessage("Can't use that command from the console."); + } + return true; + } + + // Otherwise, check permissions + if (!p.hasPermission(command.getPermission())) { + sender.sendMessage("No permission"); + return true; + } + + // Execute! + command.execute(plugin, p, trimFirstArg(args)); + + return true; + } + + /** + * Since Java doesn't support pointer arithmetic, this method + * attempts to remove the first element of a String[] object + * by creating a new array of the same size -1 and copying all + * the elements over. + * @param args a String[] to trim + * @return a String[] with the same elements except for the very first + */ + private String[] trimFirstArg(String[] args) { + String[] result = new String[args.length - 1]; + for (int i = 0; i < result.length; i++) { + result[i] = args[i+1]; + } + return result; + } + + /** + * Load all of the MobArena commands from either the jar or the bin + * folder into the commands-map. Each one of a commands' names/aliases + * is added to the map, such that both "/ma join" and "/ma j" work, for + * instance. + */ + private void loadCommands() { + // Prepare a strategy for the class parser. + ClassIterationStrategy strategy = null; + File f = new File("plugins" + File.separator + "MobArena.jar"); + + try { + // If jar exists, use it - otherwise, use bin. + strategy = (f.exists()) ? new JarClassIterationStrategy(f) : + new DirClassIterationStrategy(new File("bin")); + + // Create a new ClassParser with the given strategy. + ClassParser parser = new ClassParser(strategy); + + // Iterate through all three folders, user/admin/setup + for (String type : COMMAND_TYPES) { + Collection> classes = parser.getClasses(COMMAND_PATH + type); + + for (Class c : classes) { + // Make sure the class is indeed an instance of MACommand + Object obj = c.newInstance(); + if (!(obj instanceof MACommand)) + continue; + + // Then cast, and add for each command name/alias + MACommand command = (MACommand) obj; + for (String name : command.getNames()) { + commands.put(name, command); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/com/garbagemule/MobArena/commands/MACommand.java b/src/com/garbagemule/MobArena/commands/MACommand.java new file mode 100644 index 0000000..b8b3400 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/MACommand.java @@ -0,0 +1,40 @@ +package com.garbagemule.MobArena.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import com.garbagemule.MobArena.MobArenaPlugin; + +public interface MACommand +{ + /** + * Get an array of names/aliases for this command. + * Every command must have at least one name/alias to work. + * @return a String[] of names/aliases + */ + public String[] getNames(); + + /** + * Get the permission required to execute this command. + * If there is no permission required, the method returns + * the empty string. + * @return a permission or null + */ + public String getPermission(); + + /** + * Execute the implementing command with the input Player as the executor. + * @param sender The Player executing the command + * @param args A list of arguments + * @return true, if the command was executed successfully, false otherwise + */ + public boolean execute(MobArenaPlugin plugin, Player sender, String... args); + + /** + * Execute the implementing command with the console as the executor. + * @param sender The console executing the command + * @param args A list of arguments + * @return true, if the command was executed successfully, false otherwise + */ + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args); +} diff --git a/src/com/garbagemule/MobArena/commands/admin/EnableCommand.java b/src/com/garbagemule/MobArena/commands/admin/EnableCommand.java new file mode 100644 index 0000000..2d83d6c --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/admin/EnableCommand.java @@ -0,0 +1,30 @@ +package com.garbagemule.MobArena.commands.admin; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import com.garbagemule.MobArena.*; +import com.garbagemule.MobArena.commands.*; + +public class EnableCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "enable" }; + } + + @Override + public String getPermission() { + return "mobarena.admin.enable"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + return false; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/setup/SetRegionCommand.java b/src/com/garbagemule/MobArena/commands/setup/SetRegionCommand.java new file mode 100644 index 0000000..32e77e6 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/setup/SetRegionCommand.java @@ -0,0 +1,29 @@ +package com.garbagemule.MobArena.commands.setup; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class SetRegionCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "setregion" }; + } + + @Override + public String getPermission() { + return "mobarena.setup.setregion"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + return false; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/user/ArenaListCommand.java b/src/com/garbagemule/MobArena/commands/user/ArenaListCommand.java new file mode 100644 index 0000000..b2ac3a6 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/user/ArenaListCommand.java @@ -0,0 +1,53 @@ +package com.garbagemule.MobArena.commands.user; + +import java.util.List; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class ArenaListCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "arenas" , "list" }; + } + + @Override + public String getPermission() { + return "mobarena.use.arenalist"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + // Grab the arena master. + ArenaMaster am = plugin.getArenaMaster(); + + // Get the arenas. + List arenas = am.getEnabledArenas(); + + String msg = "Available arenas: "; + if (arenas.size() == 0) { + sender.sendMessage(msg + ""); + return true; + } + + // Enumerate arenas. + for (Arena a : arenas) { + msg += a.configName() + ", "; + } + + // Trim off the trailing comma. + msg = msg.substring(0, msg.length() - 2); + + // Send the message! + sender.sendMessage(msg); + return true; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/user/JoinCommand.java b/src/com/garbagemule/MobArena/commands/user/JoinCommand.java new file mode 100644 index 0000000..7da9ce2 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/user/JoinCommand.java @@ -0,0 +1,53 @@ +package com.garbagemule.MobArena.commands.user; + +import java.util.*; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class JoinCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "join" , "j" }; + } + + @Override + public String getPermission() { + return "mobarena.use.join"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + // Grab the arena master + ArenaMaster am = plugin.getArenaMaster(); + + // Get all enabled arenas. + List arenas = am.getEnabledArenas(); + + // If no arena was specified, and multiple arenas are available, notify. + if (args.length < 1 && arenas.size() > 1) { + sender.sendMessage("There are more than one arena. Pick one, damnit!"); + return false; + } + + // If only one arena, pick it no matter what, otherwise, look for name. + Arena arena = arenas.size() == 1 ? arenas.get(0) : am.getArenaWithName(args[0]); + + // If null, no arena was found. + if (arena == null) { + sender.sendMessage("The arena '" + args[0] + "' does not exist."); + return false; + } + + sender.sendMessage("You've joined arena '" + arena.configName() + "'!"); + return true; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/user/LeaveCommand.java b/src/com/garbagemule/MobArena/commands/user/LeaveCommand.java new file mode 100644 index 0000000..5e015d8 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/user/LeaveCommand.java @@ -0,0 +1,29 @@ +package com.garbagemule.MobArena.commands.user; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class LeaveCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "leave" , "l" }; + } + + @Override + public String getPermission() { + return "mobarena.use.leave"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + return true; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/user/NotReadyCommand.java b/src/com/garbagemule/MobArena/commands/user/NotReadyCommand.java new file mode 100644 index 0000000..f08a272 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/user/NotReadyCommand.java @@ -0,0 +1,29 @@ +package com.garbagemule.MobArena.commands.user; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class NotReadyCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "notready" , "check" }; + } + + @Override + public String getPermission() { + return "mobarena.use.notready"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + return true; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/commands/user/PlayerListCommand.java b/src/com/garbagemule/MobArena/commands/user/PlayerListCommand.java new file mode 100644 index 0000000..ac656c8 --- /dev/null +++ b/src/com/garbagemule/MobArena/commands/user/PlayerListCommand.java @@ -0,0 +1,29 @@ +package com.garbagemule.MobArena.commands.user; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import com.garbagemule.MobArena.commands.*; +import com.garbagemule.MobArena.*; + +public class PlayerListCommand implements MACommand +{ + @Override + public String[] getNames() { + return new String[] { "who" , "players" }; + } + + @Override + public String getPermission() { + return "mobarena.use.playerlist"; + } + + @Override + public boolean execute(MobArenaPlugin plugin, Player sender, String... args) { + return true; + } + + @Override + public boolean executeFromConsole(MobArenaPlugin plugin, CommandSender sender, String... args) { + return false; + } +} diff --git a/src/com/garbagemule/MobArena/leaderboards/Leaderboard.java b/src/com/garbagemule/MobArena/leaderboards/Leaderboard.java index 9a9068e..d5eacba 100644 --- a/src/com/garbagemule/MobArena/leaderboards/Leaderboard.java +++ b/src/com/garbagemule/MobArena/leaderboards/Leaderboard.java @@ -10,13 +10,13 @@ import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.ArenaPlayer; import com.garbagemule.MobArena.ArenaPlayerStatistics; import com.garbagemule.MobArena.MobArena; -import com.garbagemule.MobArena.util.ConfigUtils; +import com.garbagemule.MobArena.util.Config; public class Leaderboard { @@ -54,7 +54,7 @@ public class Leaderboard * @param arena The arena to which this leaderboard belongs. * @param config The config-file in which the location is specified. */ - public Leaderboard(MobArena plugin, Arena arena, Configuration config) + public Leaderboard(MobArena plugin, Arena arena, Config config) { this(plugin, arena); @@ -64,7 +64,7 @@ public class Leaderboard if (coords != null) { // Grab the top left sign. - topLeft = ConfigUtils.parseLocation(arena.getWorld(), coords); + topLeft = Config.parseLocation(arena.getWorld(), coords); // If it is a sign, validate. if (topLeft.getBlock().getState() instanceof Sign) diff --git a/src/com/garbagemule/MobArena/util/Config.java b/src/com/garbagemule/MobArena/util/Config.java new file mode 100644 index 0000000..c1275c6 --- /dev/null +++ b/src/com/garbagemule/MobArena/util/Config.java @@ -0,0 +1,177 @@ +package com.garbagemule.MobArena.util; + +import java.io.File; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +public class Config +{ + private YamlConfiguration config; + private File configFile; + + public Config(File configFile) { + this.config = new YamlConfiguration(); + this.configFile = configFile; + + config.options().indent(4); + } + + public boolean load() { + try { + config.load(configFile); + return true; + } + catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public boolean save() { + try { + config.save(configFile); + return true; + } + catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public void setHeader(String header) { + config.options().header(header); + } + + + + /////////////////////////////////////////////////////////////////////////// + // // + // GETTERS // + // // + /////////////////////////////////////////////////////////////////////////// + + public Object getProperty(String path) { + return config.get(path); + } + + public boolean getBoolean(String path) { + return config.getBoolean(path); + } + + public boolean getBoolean(String path, boolean def) { + return config.getBoolean(path, def); + } + + public int getInt(String path) { + return config.getInt(path); + } + + public int getInt(String path, int def) { + return config.getInt(path, def); + } + + public String getString(String path) { + String result = config.getString(path); + return result != null ? result : null; + } + + public String getString(String path, String def) { + return config.getString(path, def); + } + + public Set getKeys(String path) { + if (config.get(path) == null) + return null; + + ConfigurationSection section = config.getConfigurationSection(path); + return section.getKeys(false); + } + + @SuppressWarnings("unchecked") + public List getStringList(String path, List def) { + if (config.get(path) == null) + return def != null ? def : new LinkedList(); + + List list = config.getStringList(path); + return (List) list; + } + + + + /////////////////////////////////////////////////////////////////////////// + // // + // MUTATORS // + // // + /////////////////////////////////////////////////////////////////////////// + + public void set(String path, Object value) { + config.set(path, value); + } + + public void setProperty(String path, Object value) { + this.set(path, value); + } + + public void remove(String path) { + this.set(path, null); + } + + public void removeProperty(String path) { + this.remove(path); + } + + + + /////////////////////////////////////////////////////////////////////////// + // // + // UTILITY METHODS // + // // + /////////////////////////////////////////////////////////////////////////// + + public static Location parseLocation(World world, String coords) + { + String[] parts = coords.split(","); + if (parts.length != 5) + throw new IllegalArgumentException("Input string must contain x, y, z, yaw and pitch"); + + Integer x = getInteger(parts[0]); + Integer y = getInteger(parts[1]); + Integer z = getInteger(parts[2]); + Float yaw = getFloat(parts[3]); + Float pitch = getFloat(parts[4]); + + if (x == null || y == null || z == null || yaw == null || pitch == null) + throw new NullPointerException("Some of the parsed values are null!"); + + return new Location(world, x, y, z, yaw, pitch); + } + + private static Integer getInteger(String s) + { + try + { + return Integer.parseInt(s.trim()); + } + catch (Exception e) {} + + return null; + } + + private static Float getFloat(String s) + { + try + { + return Float.parseFloat(s.trim()); + } + catch (Exception e) {} + + return null; + } + +} diff --git a/src/com/garbagemule/MobArena/util/FileUtils.java b/src/com/garbagemule/MobArena/util/FileUtils.java index 94ae6aa..6205495 100644 --- a/src/com/garbagemule/MobArena/util/FileUtils.java +++ b/src/com/garbagemule/MobArena/util/FileUtils.java @@ -9,10 +9,9 @@ import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.util.HashSet; -import java.util.List; import java.util.Set; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.MobArena; @@ -41,10 +40,10 @@ public class FileUtils * Download all necessary libraries. * @param config The MobArena config-file */ - public static void fetchLibs(Configuration config) + public static void fetchLibs(Config config) { // Get all arenas - List arenas = config.getKeys("arenas"); + Set arenas = config.getKeys("arenas"); if (arenas == null) return; // Add all the logging types diff --git a/src/com/garbagemule/MobArena/util/WaveUtils.java b/src/com/garbagemule/MobArena/util/WaveUtils.java index c0e3a99..d2fc686 100644 --- a/src/com/garbagemule/MobArena/util/WaveUtils.java +++ b/src/com/garbagemule/MobArena/util/WaveUtils.java @@ -4,12 +4,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.Set; import java.util.TreeSet; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; @@ -80,7 +81,7 @@ public class WaveUtils /** * Grab and process all the waves in the config-file for the arena. */ - public static TreeSet getWaves(Arena arena, Configuration config, WaveBranch branch) + public static TreeSet getWaves(Arena arena, Config config, WaveBranch branch) { // Determine the branch type of the wave, and grab the appropriate comparator String b = branch.toString().toLowerCase(); @@ -88,7 +89,7 @@ public class WaveUtils // Grab the waves from the config-file String path = "arenas." + arena.configName() + ".waves." + b; // waves.yml, change to either "waves." + b, or simply b - List waves = config.getKeys(path); + Set waves = config.getKeys(path); // If there are any waves, process them if (waves != null) @@ -122,7 +123,7 @@ public class WaveUtils * Get a single wave based on the config-file, the path, and branch * @return A Wave object if it is well defined, null otherwise. */ - private static Wave getWave(Arena arena, Configuration config, String path, String name, WaveBranch branch) + private static Wave getWave(Arena arena, Config config, String path, String name, WaveBranch branch) { // Grab the wave type, if null or not well defined, return null WaveType type = WaveType.fromString(config.getString(path + "type")); @@ -177,13 +178,13 @@ public class WaveUtils * the node 'wave'. * Any other requirements are type-specific, and thus we check if the * type is well-defined. - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param branch The branch of the wave * @param type The wave type * @return true, only if the entire wave-node is well-defined. */ - private static boolean isWaveWellDefined(Configuration config, String path, WaveBranch branch, WaveType type) + private static boolean isWaveWellDefined(Config config, String path, WaveBranch branch, WaveType type) { // This boolean is used in the "leaf methods" boolean wellDefined = true; @@ -254,13 +255,13 @@ public class WaveUtils * Check if a wave type in the config-file is well-defined. * The method calls the appropriate sub-method to check if the type * is well-defined. - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param type The wave type * @param wellDefined Pass-through boolean for "leaf methods". * @return true, only if the entire wave-node is well-defined. */ - private static boolean isTypeWellDefined(Configuration config, String path, WaveType type, boolean wellDefined) + private static boolean isTypeWellDefined(Config config, String path, WaveType type, boolean wellDefined) { if (type == WaveType.DEFAULT) return isDefaultWaveWellDefined(config, path, wellDefined); @@ -278,12 +279,12 @@ public class WaveUtils * Check if a default wave is well-defined. * The default waves have an optional wave growth node. Otherwise, * they share nodes with special waves. - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param wellDefined Pass-through boolean for "leaf methods". * @return true, only if the entire wave-node is well-defined. */ - private static boolean isDefaultWaveWellDefined(Configuration config, String path, boolean wellDefined) + private static boolean isDefaultWaveWellDefined(Config config, String path, boolean wellDefined) { // OPTIONAL: Wave growth String growth = config.getString(path + "growth"); @@ -299,12 +300,12 @@ public class WaveUtils /** * Check if a special wave is well-defined. * The special waves have no unique nodes. - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param wellDefined Pass-through boolean for "leaf methods". * @return true, only if the entire wave-node is well-defined. */ - private static boolean isSpecialWaveWellDefined(Configuration config, String path, boolean wellDefined) + private static boolean isSpecialWaveWellDefined(Config config, String path, boolean wellDefined) { return isNormalWaveWellDefined(config, path, wellDefined); } @@ -314,15 +315,15 @@ public class WaveUtils * There are no REQUIRED nodes for default or special wave types, besides * the ones for the branch they belong to. * The only OPTIONAL node is (currently) 'monsters' - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param wellDefined Pass-through boolean for "leaf methods". * @return true, wellDefined is true. */ - private static boolean isNormalWaveWellDefined(Configuration config, String path, boolean wellDefined) + private static boolean isNormalWaveWellDefined(Config config, String path, boolean wellDefined) { // OPTIONAL: Monsters - List monsters = config.getKeys(path + "monsters"); + Set monsters = config.getKeys(path + "monsters"); if (monsters != null) { for (String monster : monsters) @@ -341,12 +342,12 @@ public class WaveUtils /** * Check if a swarm wave is well defined - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param wellDefined Pass-through boolean for "leaf methods". * @return true, wellDefined is true. */ - private static boolean isSwarmWaveWellDefined(Configuration config, String path, boolean wellDefined) + private static boolean isSwarmWaveWellDefined(Config config, String path, boolean wellDefined) { // REQUIRED: Monster type String monster = config.getString(path + "monster"); @@ -374,12 +375,12 @@ public class WaveUtils /** * Check if a boss wave is well defined. - * @param config Config-file Configuration + * @param config Config-file Config * @param path The absolute path of the wave * @param wellDefined Pass-through boolean for "leaf methods". * @return true, wellDefined is true. */ - private static boolean isBossWaveWellDefined(Configuration config, String path, boolean wellDefined) + private static boolean isBossWaveWellDefined(Config config, String path, boolean wellDefined) { // REQUIRED: Monster type String monster = config.getString(path + "monster"); diff --git a/src/com/garbagemule/MobArena/util/classparsing/ClassIterationStrategy.java b/src/com/garbagemule/MobArena/util/classparsing/ClassIterationStrategy.java new file mode 100644 index 0000000..b0baded --- /dev/null +++ b/src/com/garbagemule/MobArena/util/classparsing/ClassIterationStrategy.java @@ -0,0 +1,15 @@ +package com.garbagemule.MobArena.util.classparsing; + +import java.util.Collection; + +public interface ClassIterationStrategy +{ + /** + * Given a package, e.g. com.garbagemule.MobArena.commands.user, the + * concrete strategy will return a collection of qualified class names + * either from a directory or a jar file. + * @param packagePath path from which to extract classes + * @return a list of qualified class names or null + */ + public Collection getClassesFromPackage(String packagePath); +} diff --git a/src/com/garbagemule/MobArena/util/classparsing/ClassParser.java b/src/com/garbagemule/MobArena/util/classparsing/ClassParser.java new file mode 100644 index 0000000..e194614 --- /dev/null +++ b/src/com/garbagemule/MobArena/util/classparsing/ClassParser.java @@ -0,0 +1,46 @@ +package com.garbagemule.MobArena.util.classparsing; + +import java.util.*; + +public class ClassParser +{ + private ClassIterationStrategy strategy; + + public ClassParser(ClassIterationStrategy strategy) { + this.strategy = strategy; + } + + /** + * Using an iteration strategy provided in the constructor, this method tries + * to iterate through all classes within a given "package". + * @param packagePath a package path, e.g. com.garbagemule.MobArena.commands.user + * @return a list of Class objects + */ + public Collection> getClasses(String packagePath) { + Collection> result = new LinkedList>(); + + for (String classname : strategy.getClassesFromPackage(packagePath)) { + Class c = makeClass(classname); + + if (c != null) { + result.add(c); + } + } + + return result; + } + + /** + * Get a class using its qualified (full package) name. + * @param qualifiedName qualified name of a class + * @return a Class object, or null if the class could not be made. + */ + private static Class makeClass(String qualifiedName) { + try { + return Class.forName(qualifiedName); + } + catch (Exception e) { + return null; + } + } +} diff --git a/src/com/garbagemule/MobArena/util/classparsing/DirClassIterationStrategy.java b/src/com/garbagemule/MobArena/util/classparsing/DirClassIterationStrategy.java new file mode 100644 index 0000000..177ac31 --- /dev/null +++ b/src/com/garbagemule/MobArena/util/classparsing/DirClassIterationStrategy.java @@ -0,0 +1,52 @@ +package com.garbagemule.MobArena.util.classparsing; + +import java.io.*; +import java.util.*; + +public class DirClassIterationStrategy implements ClassIterationStrategy +{ + private File baseDir; + + /** + * Dir iterator. The input file must be a directory, whose + * contents are iterated over upon calling the implemented + * method. This dir could be bin/ or build/. + * @param file a directory + * @throws Exception + */ + public DirClassIterationStrategy(File baseDir) throws Exception { + this.baseDir = baseDir; + } + + @Override + public Collection getClassesFromPackage(String packagePath) { + // The resulting list. + Collection result = new LinkedList(); + + // Convert to an actual path. + String path = packageToPath(packagePath); + + // Make a new dir from it. + File dir = new File(baseDir, path); + + for (File f : dir.listFiles()) { + String name = f.getName(); + String absolutePath = f.getAbsolutePath(); + + if (absolutePath.contains(path) && name.endsWith(".class")) { + result.add( packagePath + "." + stripExtension(name) ); + } + } + + return result; + } + + private String stripExtension(String file) { + int dot = file.lastIndexOf("."); + return file.substring(0, dot); + } + + private String packageToPath(String path) { + return path.replace(".", File.separator); + } +} diff --git a/src/com/garbagemule/MobArena/util/classparsing/JarClassIterationStrategy.java b/src/com/garbagemule/MobArena/util/classparsing/JarClassIterationStrategy.java new file mode 100644 index 0000000..f7713b9 --- /dev/null +++ b/src/com/garbagemule/MobArena/util/classparsing/JarClassIterationStrategy.java @@ -0,0 +1,62 @@ +package com.garbagemule.MobArena.util.classparsing; + +import java.io.*; +import java.util.*; +import java.util.jar.*; + +public class JarClassIterationStrategy implements ClassIterationStrategy +{ + private JarFile jarFile; + + /** + * Jar iterator. The input file is turned into a JarFile object, + * which is later used to extract a list of entries to iterate + * over. The implemented method filters through the entries and + * returns any matches. + * @param file a jar file + * @throws Exception + */ + public JarClassIterationStrategy(File file) throws Exception { + this.jarFile = new JarFile(file); + } + + @Override + public Collection getClassesFromPackage(String packagePath) { + // The resulting list. + Collection result = new LinkedList(); + + // Convert to an actual path. + String path = packageToPath(packagePath); + + // Grab the entries from the jar file. + Enumeration entries = jarFile.entries(); + + /* Iterate through all the entries in the jar file, and + * if a file starts with the package path and ends with + * .class, we have a match, in which case we strip the + * extension and convert to a package representation. */ + while (entries.hasMoreElements()) { + String entry = entries.nextElement().getName(); + + if (entry.startsWith(path) && entry.endsWith(".class")) { + result.add( pathToPackage( stripExtension(entry) ) ); + } + } + + // Return the resulting list. + return result; + } + + private String stripExtension(String file) { + int dot = file.lastIndexOf("."); + return file.substring(0, dot); + } + + private String packageToPath(String path) { + return path.replace(".", "/"); + } + + private String pathToPackage(String path) { + return path.replace("/", "."); + } +} diff --git a/src/com/garbagemule/MobArena/waves/BossWave.java b/src/com/garbagemule/MobArena/waves/BossWave.java index ae6b70b..b9421a6 100644 --- a/src/com/garbagemule/MobArena/waves/BossWave.java +++ b/src/com/garbagemule/MobArena/waves/BossWave.java @@ -12,11 +12,12 @@ import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.entity.Creature; import org.bukkit.entity.LivingEntity; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.WaveUtils; public class BossWave extends AbstractWave @@ -30,20 +31,20 @@ public class BossWave extends AbstractWave private boolean lowHealthAnnounced = false, abilityAnnounce; // Recurrent - public BossWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) + public BossWave(Arena arena, String name, int wave, int frequency, int priority, Config config, String path) { super(arena, name, wave, frequency, priority); load(config, path); } // Single - public BossWave(Arena arena, String name, int wave, Configuration config, String path) + public BossWave(Arena arena, String name, int wave, Config config, String path) { super(arena, name, wave); load(config, path); } - private void load(Configuration config, String path) + private void load(Config config, String path) { setType(WaveType.BOSS); abilityTask = -1; diff --git a/src/com/garbagemule/MobArena/waves/DefaultWave.java b/src/com/garbagemule/MobArena/waves/DefaultWave.java index c357d2e..55eceef 100644 --- a/src/com/garbagemule/MobArena/waves/DefaultWave.java +++ b/src/com/garbagemule/MobArena/waves/DefaultWave.java @@ -6,24 +6,25 @@ import java.util.Map; import java.util.Random; import org.bukkit.Location; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.WaveUtils; public class DefaultWave extends NormalWave { // Recurrent - public DefaultWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) + public DefaultWave(Arena arena, String name, int wave, int frequency, int priority, Config config, String path) { super(arena, name, wave, frequency, priority, config, path); load(config, path, WaveType.DEFAULT); } // Single - public DefaultWave(Arena arena, String name, int wave, Configuration config, String path) + public DefaultWave(Arena arena, String name, int wave, Config config, String path) { super(arena, name, wave, config, path); load(config, path, WaveType.DEFAULT); diff --git a/src/com/garbagemule/MobArena/waves/NormalWave.java b/src/com/garbagemule/MobArena/waves/NormalWave.java index 8f40c2a..88722d0 100644 --- a/src/com/garbagemule/MobArena/waves/NormalWave.java +++ b/src/com/garbagemule/MobArena/waves/NormalWave.java @@ -1,13 +1,14 @@ package com.garbagemule.MobArena.waves; -import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.WaveUtils; public abstract class NormalWave extends AbstractWave @@ -16,13 +17,13 @@ public abstract class NormalWave extends AbstractWave private Map probabilities = new TreeMap(); // Recurrent - public NormalWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) + public NormalWave(Arena arena, String name, int wave, int frequency, int priority, Config config, String path) { super(arena, name, wave, frequency, priority); } // Single - public NormalWave(Arena arena, String name, int wave, Configuration config, String path) + public NormalWave(Arena arena, String name, int wave, Config config, String path) { super(arena, name, wave); } @@ -34,7 +35,7 @@ public abstract class NormalWave extends AbstractWave * @param path The absolute path of the wave * @param type DEFAULT or SPECIAL */ - public void load(Configuration config, String path, WaveType type) + public void load(Config config, String path, WaveType type) { // Set type and (for DEFAULT) growth. setType(type); @@ -43,7 +44,7 @@ public abstract class NormalWave extends AbstractWave // Load monsters int prob; - List monsters = config.getKeys(path + "monsters"); + Set monsters = config.getKeys(path + "monsters"); if (monsters != null && !monsters.isEmpty()) { for (String m : config.getKeys(path + "monsters")) diff --git a/src/com/garbagemule/MobArena/waves/SpecialWave.java b/src/com/garbagemule/MobArena/waves/SpecialWave.java index dc47bc6..47efa31 100644 --- a/src/com/garbagemule/MobArena/waves/SpecialWave.java +++ b/src/com/garbagemule/MobArena/waves/SpecialWave.java @@ -6,24 +6,25 @@ import java.util.Map; import java.util.Random; import org.bukkit.Location; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.WaveUtils; public class SpecialWave extends NormalWave { // Recurrent - public SpecialWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) + public SpecialWave(Arena arena, String name, int wave, int frequency, int priority, Config config, String path) { super(arena, name, wave, frequency, priority, config, path); load(config, path, WaveType.SPECIAL); } // Single - public SpecialWave(Arena arena, String name, int wave, Configuration config, String path) + public SpecialWave(Arena arena, String name, int wave, Config config, String path) { super(arena, name, wave, config, path); load(config, path, WaveType.SPECIAL); diff --git a/src/com/garbagemule/MobArena/waves/SwarmWave.java b/src/com/garbagemule/MobArena/waves/SwarmWave.java index ed2ec1f..bf9e1f9 100644 --- a/src/com/garbagemule/MobArena/waves/SwarmWave.java +++ b/src/com/garbagemule/MobArena/waves/SwarmWave.java @@ -4,11 +4,12 @@ import java.util.List; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; -import org.bukkit.util.config.Configuration; +//import org.bukkit.util.config.Configuration; import com.garbagemule.MobArena.Arena; import com.garbagemule.MobArena.MAUtils; import com.garbagemule.MobArena.MAMessages.Msg; +import com.garbagemule.MobArena.util.Config; import com.garbagemule.MobArena.util.WaveUtils; public class SwarmWave extends AbstractWave @@ -17,20 +18,20 @@ public class SwarmWave extends AbstractWave private SwarmAmount amount; // Recurrent - public SwarmWave(Arena arena, String name, int wave, int frequency, int priority, Configuration config, String path) + public SwarmWave(Arena arena, String name, int wave, int frequency, int priority, Config config, String path) { super(arena, name, wave, frequency, priority); load(config, path); } // Single - public SwarmWave(Arena arena, String name, int wave, Configuration config, String path) + public SwarmWave(Arena arena, String name, int wave, Config config, String path) { super(arena, name, wave); load(config, path); } - private void load(Configuration config, String path) + private void load(Config config, String path) { // Set the wave type setType(WaveType.SWARM);