infon/0000700000076400001440000000000010603315310011716 5ustar dividuumusersinfon/gfx/0000700000076400001440000000000010552756357012531 5ustar dividuumusersinfon/gfx/theme.png0000600000076400001440000024134510544730134014336 0ustar dividuumusersPNG  IHDRXXfbKGD pHYs  ~tIME  6U9 IDATx{|\}ji%I /HdHpB9q`f{*Oz!Īk}+z*,;RO!` q=6wAN 2 `qWӇ'N]2CBF!;ݫ%;=LxI\0|./]w_Gh~?\v.:R) !n0X+Y `c<^*l}m\ RnNn @2!/OBZ 勞6LBۛTi4&ЯУ6'0E%> 1Z&/vStBl\: ܱo׿t9'x$k2]AW/}T?<뮀{=8 8~8֏_)#՝R1SJ>#blU3_sc3~ܡE7u?C[}y'"^ii4WOKWS:ZVms*7|2Φ2|yC>mTI>?l?չy5]ߓLWzrp4'ln6f>ߓKDt`[@ D$Ӱ!x:Wc#XqM3?k%#MMMV:<"7ѓU*_yMrCJwC i3ٖM1Z:4lp:|FO.{^ӧ%usVFg5X݉͋B\)!"6!yM6,Н&JJUѨ|>k)ai݁RJr-B{T寪}WFKezn /0Ν/mlۺW֥*pppU%ѯzOw-JY3#]2Wned{.y{ݖq咷mVr)?N92;>H9;H.uV[5X93`ōq|@K OZ!W=NHJ2N zx@ qY_#h͵sϭc (y4 .'gKb5k+ӛ[]^^[n[.Ǖͯz/ǕkY^k7i.ew8>|,l7C:LuΙq-%╽qhNlD3K,Sw=X_ͰWd0'{S/e*vS|&8 0 G⛺~|sqn|qb5?D?&O4fpvfkTKDī&1)9~L9ߟYr8St{._>'|?er8rP!hgbU/ i{MJL=\W_}u5)oiܸ ?yC!a~ $1R 7-2L~j#XPo3ѯX>Ob{oYrs0222?~)K8~xm!=g{N!g$1R.[dw.|>g\QfB OƊw܉vX;V /y;v_B!A A Ӥk`=5(X02V0Wm@$AII `||| =&&&00`I&&&0>>_BȻ׵.9K2X`56)93})gҽ&%}uu;Lٳg1Fb !.1X_'-'zԚ|Y{Z.\˗r8>>{X,U/Rljjp5\tG~'&&f~|nU/?<\ZZhWWW+/CB!3XC( -E!7g=/6ꫛ1Xp… [7lyUW%ҭXB<8z\|񩧞G)Olko}[;_{5@UUU+P]]7xcQ}5ī+[o Os=+VH)Ŋ+߿㓟7oO?}w@#ƻz]7o'?߿ҏnߺu+{9ر;v@=??MUo|=n݊###۷n݊7|/~ o[~76/-{ۇ7x#%H!}kvtk*ž[p|=ὸeC}[b^'[OQJ-_|s=Zk՝%_wb%~?I/̙3_(**ZXu}X_h,>e+~~?V`q@m |8+=eB!g>.Xc7v:}PCߗB笗륔ْR.YvYv<)2WNK_u]-31K ?zUucccǖ-+C=AXlll:ɡ=8^=B98-6<`acTalš+ynۦ&fexy軪1pe\AʍSyoH)oBkwmc{rKLi?9B/_'?H2(^uWօ^`W`/j/ijqCUdGg_xa1Ef;n(ιb_E!kwqǟ؃{4? !SM;y?fc}rF$\ٺun,)Wf8,v,ZbMNNv !66XJSUJ}CHla#R@SӺ7yc# 7}3f᦮?wWECm N]뛃fNXY9Ds322Qj%%%h4TWWW聢"4066~DsE!do|ۺa/ct}Io;;Ӟt-H)!Z)sU/ܙ{c%%%Fc _LW9s~6f( E2Wcs7vB!'9 C6)3Y/ЫE6HRM>b$yZEEfΜBEEŲ* "G^=ݤ/**z୷޺_B!g?­`%-%dqzdoͼAL5TD+VgRE]{`ƌoٳ^B!4X5(`-m`L:џ0ws"Ԕt]]]^nBȻi}"dt:B֭[-|ZJ-[BfAj=koBVmk?7Egy-3>u5ۀ6 |L=^nBȻc7bRʘMJT+b<7v}׫&B^{mO>{Ūkֿ[s}^G~qZ<ƏK/|O@<uJ?2o$|By,! RXsU~ Vē343)1lfBOCD. C BUBpm$9G7 |CJ)`,c륔yυO}S?={G^񱮮u3@=2)󎎎K/ґ?=zϟz4}`߾}5G DBzMMM#G<^BYfy1`-\`^N@9.?p @LWl|XK<0__Z|9~D4o,X`mTֱ5X7|s2PTTYt>v}qeee_IJO?}Ղ >s؈ Gy]?O|Խ.ۺm@DN"p_o#[qsZaq]rA~T{ӟxs=VX-)'N@z_y{ !|&7dɒxQQ_쇵l;</yӦM/?U#3G~.V|k2}z+U<"{L1@I GgFbN7bP@aa+3X-}j ̃?хBٍitk{d޼AnۼS6`(|+ '~Bvmv.Z W* qe (J{>͸zHyXB|O?O+Vr>.I!l47ٳk֭?8/wW΂!,z0}kX{ )?54pC5z{ ˮImpތKڹsg@Who{[am%=7&'~Rû8ڝBޅQ|嗍ysfܘܢKk KV '^|1H H "C)Ln/Xk6J) hJ?,NM;p/W]J,q9ti!orM YSSeXP~Z=_|_Wcc$iSHͶlyLp{e{%l:W1sΩuOzbB 9xwwF!uCxp9jk?=;ҿ444`Ν =!Fur3Nvy=Lrq,!P)^O樷Lr>Om&G)=۠`ڑFΝ;QRRRյ7S}}}=~BȻɀ$nZyn)$s֋7|/3) Li&S}EEŐ='|p$T},$O<B!g.:lϔ\BRԜ|S`X?sC~ǎY !rKcZ/ kzRʬUUUO8'NjB!EuY]Ye^4*MZ .~x뭷n~'B9; VX/6xV4;M!r&V\;BB!,Z---hmmE(R;{*>!' !|RJF 8I㤤R !5%!B$d Bؾ};/^hr',$rm%cBi2m qB![pCAڊp8+WIZaw#*>!"(,R(PdB%J%BD:)J[((Bm&!BN7r mWc6]K/,MQ d˧ e U$I)b6a&d$B!+': IDATXSfljV m (Rm+%qWRN !&m#5.R =&B!5Xun;rJtwwfT!.>o!JiB06+10OQ,B!dЗ񲤍ZS1_qy3yj}F|S%K WvMgGRB;zUkXsZs^_D8ŋS>R XQ"؃AJc@xh@a?Q(|RJǥBLLNFY/vqLkp夀0E!LNQlMIm]N>-mNSnXQ"!DIs+-(*+.( 巤RʸbRJ9˱x_9H)eL*!2 8EF|׍n6-}@{1ɘƱc3JT A;e>E8i?5X b1/Kq{|)CX݆j-Bk\.xLIY &] ,Yصk1tX#BI)gbp鬂،BR|0`Ę*;BpثdAGx@0rT1 kV8/yB!dj̦+¥PׁY܅=+BU$,(( "jQ)eD=;`R !`2ƥcB1| !Rʸh!2Tnk֠uFV`as59/(+(PsbmcUkn+Hx4tMM::>>(1ǃT.B!ӊfX[lߞa>~d !LJJf<%V%- +( (XmRVh!BNքQ}B2 (&hm 42L>X.OL{epr8?FB!Nf`K ''T^X2,NOJIi'0W uŤOJB!NKj .&mdS+/'֮B`b" 4 i*O<^@;!BN[`ёXLX !bR 1ؓ*GVYScD CԌ !r:'sX4&KE$@ёRؓN,IQ-52QBI{fLL67^B! X~5[[[6MaaM0i(weŶRdH8T q) ! ) /~BJ9nImR !BNGՒ*AkJq)03  VTVON>yX1X]' !F/ǎQ@ʉi&B!SoMa,BQe3F"hp\89m`YWk021 Eeq4`B!%eds\knǭ.O3q2X kX^X|111Q?xМ9qt qX݋Rʱɂh@ >l;f'B.%ft%r9/I:1TyP[[[.>qP- b<JO}BH~_,(q2"5^#^F2,er<^LeZm$6oތN7s` rҧ)P HJY$t jf!ls6R.A \1E!,Wj=]\K3Y>Ha j/P(T݇jfT3`s(͕`\B!tD5 6};잒TXfo^Y,4ah>{U +B!cl)3#u.gsWQk\B! !`hU$̤L6Y)r7 mBP{jR+.k&&"Bș09=Sn8.nV!BHz 񸠹la: r'B!'9+T阞B!X:Sv0WKBB!$|nAUH!R3\H`Pj$BI6XR(+'i.V!#}mjOWF|R9fr| !=$k3T#sq\9n}FrnXruZ\']~n7g:f^&t#k3{{N&璎Amxrz@&7T3'>"]4*ǙʰeR~:#KENk@rSruX .6̃ːhT\%ӛT|㥾z,"Z60L#k{P6x=|F:gYxrշerpK%n۩:S&"@SEΤG^#^FƼ~or)'_fr_m;σN!30.yel7 !Bzp֠{w>X]v!BRfhUB!:!BrGcHqX]\B!ăjɣN!O7WAl2L!BȻ a?-ثr5k֠݅B!Iܖ.ѶmfB!L5X-5k$.BZXB!`=9hkkƍhkkKcB!g/.3>B^qlذXx1h"^YBȻU:Dy-;y<Xs^)S+5݁>^zBٍWc%'Ö˵L,c#/;B!)*K('65ih{!"]l^M訙WFh"ԶwB! 4\T* `{B!$nNX[0u >X]v!B V3*!BɍEUV!BHcU՘:uCaurgB!cbflߞr'BqdTPB!$`ՙfiP[[kj[ B!gח֭sӯfB!L5X-FנI B!$!)TVV"'m3'j$BNO2])}>ͅqg=6EuN944**%B@t3ItyxIΈd[[٩)SS֜VqV+tJ˖B9jTۦ>O/ROKJ˖B94.Hts*3]T&k7oB|XB`ٲexxB!7MMMR7 ̃Jt^kWy}n6oތDf݄lBy itNcT@#7oFGG"B`&֠X3UG!n< fV !BHn,:!BrG\S7xVa7B!$jI߹f5}ӦMN!\ ۶mK- B!Ċ`7n۶ x>aÆ ~ ]H!m5k`ʕD"hkkC(B]]]ģYB!S Vz&ݍ:twwcѢENV!!BH2Bjܗ,YP(ۭI#k憊 HΤ9ǝ~N+Agg'^{5̟?_җ裏;f͚u +B!aɔdH۶t %lq{t5H}1\yҗ;wuBn&| _+0}\ !3Q>Ln6RmrT&*cLW>X 6oތh4xꩧQYYF^BȻ۴fCmsJ7܎Gߞ1`uh?/xG ׅm!33k\6x+r945jh%wfU8;!BNSØK,Wj=Q+B!,QOvR` };fB!8#`3B!$7VEXB!#VuY {n,>"τB! V+Mmŋ:AB!խފ[o5aH'B!)e^\=~*.$BI6\B!B!_˖-KZ*$BjZo W{{;vڕUH!(H$뮻.%PXr%o](XBفa U sqys:-5;***O&, 9u7b˖-H!̀df(tL39?>hԕһm6aؼ9i>^Bفnr](ICmsJ7f-X .6MS$k$M#!B̚n~Ft2m^ Vv}iN__&KB9I]{.n<7tM-5jh%Dp⡇\n 6lgs'B`vzAfݻXf 3<4gΜ?GF!n&֠X ?UG!n< fV !BHn,:!BrGu*`u6uMaurgB!& BB!G|N+| !pWL!BȻ !ЛQXCq! ѝKBB!$|n37[nJ¯~NլBB!dSJzV#!BHJ\SV#!r"tܦo7}gMWOkp2PB!IҍׅGESKgj-'?kzb+A5xB!g/zǫjڜ [6&.rr7M7Xr_c#/=B!e階rd`Mڮ6dKBy`v*=k7WdkLmv 6͝B!gaܥ2Xg"BqA=Ef5S%`7B!!l6Y%B!V* BeDFQZZF144TTT $*ߏ $)Mf`޼y袋<-2I﫩/TTTsE|~ֿlIIl_gSqbb}X (..Ob4(++KlSga֬Y(//϶`0O@8  b||ԿϦ/..R  qCFDeeebj4Uño>$Ld~Eai M׫F4I7*_M?vU~UUUR8F۷UtuWZZx^^ް|U#J:V'~N|~nVJޫ^5Tj_AA`bbh`I  Q\\د4ľT\B^52z~`0th4*_{8rM}8vFѤrҫSǭҗN9/,?#z]t}~3TzuJk~~d鍋j`(jjjPUU87wh4Y3t)q0{ ވZs J?o޼D#83~޼yFάCOUwq94Ro^?*ң NeeeR9Ο8H}r͓yYeMUJ0w ވ草,((Hh4([OoP(șu8;fSo^? IG4'=F1oM֌.ļytR %5\􃃃yMon3N"NTyNr7ԛ窧qϫ^ջ{7c/cgW;L},CAAA"o3G/5kjkk].N-'}4M᫼T79Et)_zL[h6yիzwN9]?^ ϮSwJ74V`FF&IqxW">WUU%95&^+ݭukU{2q=z])C?wEw[:>:Hw2ަ^~toI`gWhh4)FF&FGݤ1*pȅό4)}iii BIW+ݭukU{I A?)C?p8Yo~/REʴ靌ׯaDzyvJLyrғi`FլnI*a qkrl̴zcnTlhh(a".袤YițSTMoF".^NuJo6pBGc^??e1ǒs՜ܜ~-P(bq,IQ=lӸ7+,ތ9E\D-MG?s9egWNx$#~/\CCCسgϟ}%E$TTBOI9R sN/|VE0],tʉFL*_ӔK[ZZI6|+:jJ4G u]YYW^yeJî}@ip n^X׿,cbbs:S IDAT100r}܇a/--uKQ8|_*` :ȑ#xb̩Q7 mő#Gȑ#(..Fqq1 <v*3siih~8|p^~?_eP^ |Dӂ4nyRy8CrҥKK/9>}wөԧr(<v+kEUUՔq@n-g[nܔ^4-4qVS]rNӻT:88ĕԛĭT!'c^??ީ_mQYmm-݋)f; %=~-݉h4/uf'>GAnQ0hf[CY_S@TZZ7dr*_Qz3GGFM4Px$So]seEB(J4z##,z4Hdͱkn=SZZUI׿BX MnĹ 8RvJש2j\;ӈEu*K.O29jA0U9U[闹Szps)=7fy|X O6G_.(n̺f2 H?ks~ϟ={$?[J}Gͱfz5>E7j9ߔ>DXNt*Oխa>ͥ1ǣMd7fRc7fT]5nz!>vXZr2q)X{LS q맺訊̸?[U]iM*d]qAKb2M.ty|h! #U Wc>\7N^/|+ՠB՘&>11E1f #}jIͩ<'w``6e斗^o7;fBRs1s`u}&׏]cVz-;~n4MMMMR1/l8_u`"H5=8FȄ~Ϟ=UueOWy󒺗~o]4*’ij<ީlW^=m̮Z':(>Hr0:M`j~~q_t)^y啤n2voR,]41|:q5`Ȅ~`` ѸE&tϚ5kJlv_9r$UITq͈^s.1{ϭa65^?p8QÉϏ}1oՉg͚uZ,kdtWYY4VƜ*jlԼy`)]r^ʯI,}wM)Mf٨ME0.5^>pr13wjr*i3&̓r꥗^7WN(>ߋ> &1J7=B*}0Dqq1f͚fa&tq7!4T;rȔR/U#GcF]5h*a~*o|s~odSj_* <̔R轔oNנJ:2ЙcȤ|e"'uisVxSo9u]]]fٜgmqs,i.\U_7Wj[o>?U?2<!4Du-ЋS1"TI$9?rz1ƍfv*FGz擌^0dSݪW_SgeicZZZd$qX|q̙3D"C}ob:r?JJJ0o
    χıc0<<3f$ [ݛ(//DZc{ť^ئ4[ ٖ_UUNwy8p@)zI}Jo1$O:\>lxx83ԿϦu}6UW]E5TC0%)PVVC%5رcD"JG:VKT8Tod`Fo͉FcW%8?v옫#pԫlLm>|UȔlܝj n<5N/߬ݴ8nyH28z[gWdd UcߴFΌ.KjPRRDrҏ%5 */xmfm*i(9=}/Yw)~#7~٘i\5(n,x'ccc7o^RT,4nzM K7#yN/TQ K7ׯo?Ow/g22zCdvS*(y#2.ĉ\83ޘ-D# IQ=lӸ7+,ތ9E\D-MG?75ip[;KLq#Ɯ;cܹ٫s?~ǎKj̨`YQz=bGT>UUUI|P (++(J.BU~h4:|1qSKS:u~Μ9]DJdӬ́^)zbp[{M3022 $q+zTƬ(L2|jjj"Ҫ'@H_NE8WUU Rސzu_Q?Tj:u뾶ֱH̉iVUr/z}{UU~x18ϭ|26zzqږΈxMZ}eOv@Q|)fncǎ%Pz_˪1VX^CdžQ,@QQQ"ev"1@ٖ7JG|>xJL*@D[WYtat| :~{]`Ix#H4$Q$*Ҏeq9N9+TT)}Sq SGJU>8Rđ٥*Eʖm(HE@I;;3ssC{.*`fs^ϿW m 6"<HwbIāk2Cn?G-@}5E"~ePٿѮ֬;WqE0epy\mW_=Ծֵw?wӅ.rKlEW/N%w`ͣZdo@gWܼ~ww[8s! Ǯ?vT7mwW#wܺʯE5-ea LVw%עTBq5Xź}ܩ ]yT[m슛ommݢcxu58wN] 7mwW#w/,"ԝ4Xw T܃:w^'0iA|VuLeowO3gz{?zKVCbL{Y/eblZ]dor\Z0.*X馌q}n7%߉݇m;/b9JqTP:hmUNJ/YyâB]{8KVϲ~Q.s]mgRT"{;XWOj\="qQJ7e68^JUU<3w{Wy?|[mN?s?' 4>hoq;`pH+ӭuu H)z|#9wuu喱T Nڿ 7%(ݕ]M+wuĺlQs@ǹjkk^-b(T܅(DZ{CeyOZ\;FXt3 Nڿ ]梛 F72&n?X8~Qppn1׾ $k ^~.{qm&{MouoRJngoAܢc9qPAF-}VVn4"jo?',ѵz}?l,wUE [NwAv?dEn^!WLkY-QV ?etz fCZte?3m'xtަkro'MӅ`[g*]-P\؅'w \C6{"s/'ǃ9}w.cՐ|J[rĽRv%dWeSNw5.gqWnZpe}dY2 3"hAStTJyKzP?YPoﯳgϲʕ+Wq.cp|J[r]m~Q®\TeSwpwٸ>{{{->EwUkotIwcE㷀ݒnuc~(cwC;9!.^hbG .u=w6K?/jP1ȣXи@}PQܝ^s/[vkp p{Vܭ e6bkM{==/~e]߉m;w,<(ھ|e 1šs~{fmI!eY>ٌ0 Bll6*|c ٬_)Վ}6(mצ1mAG;β,m̎Ŏ~gweY2L }eN'IۯӝQ8b6QE{R ۟?BPY8_Qq܎A'LI@dnZtm}mɮ}߉meYRUQ!h6DQ>=; m$RʶM۞*8n֚l)˒l^2 tlA(f Bm6ڱ)l6c2Z6hʲ<쳔e1m|I8f<82x?~g,x"Of2Pr9ؔ,Bfooq |+d/km}MᲽCz<)wkokb찶CzoSwA.>O/؟߉o?_8yRJs˛} m܂ h}ߧ( jٕ <yA o.#`Rq@A]ׇ6Y_EЎǎ߶Q%u]vjM㘢(ZnwO/Le|sccc^z!A@׻_q4/~~E+++!?8xǵkZgø I666xZu9EQp8lNBRR%= gx IDATcʼ$YK(󒝝!f}}$iڗe^}|gc~۔eI)kkkmۃPWt ǻ?N=6X>|0lBvAl0 }[am()e;4Bk>YAӾcDm=;vo1 \D( ˲v3wy(t/Q)-mgS~|S[ !|r_I)988`yyc wڿ=cL[&7ZYgyhYdRE?0gϞÍ7U%2.\8X`=Wq}pqt#˲lb>ˇ>!ۯ}1\M;W}߇r,;o?>X_g+~d @æ3lP~ߦ_\ڷmljľ۠t;F@kݮrd2i ]vPY,vPYpbشҏ1h_y'yygpBr+ ' y=A ݝ=]@}0dkk}H-լq^ka:jٝ{C)E]<,il:' -)裏"^5PlJɀ2or;;;dSn {$Io޴GE^~} r_ϛ zꩶo9;D/{=ޯp,p{}ủ{Xm u]m`(WtABJIcnaD,cp# hQ8nռ.cs1@ז"kkg\voccVEu]'.]j;Zkkްl[0eY;fӂE,I[7LZ^7X]]ܹs>Vs,#MS)q)n~y3͸qFmiۥK(}oomZjS6{wx|K\A"{wQ/bVlӵ7IwNsOws%=禲J?/|KvOs,[+ >,K`} g훶ۖVw66myޡhv\6T ]M+cs 8\= NyM6K)[MOZY;ٚyDQ q̞w4@Պ-8 :- ҂=}!˲MvvviA~gmm !Z .^ȇ?a8zן>}av^UUk=|swX nX6=o{붷]w?Is뼔 RVytuT^y1f d-AoZ\G?,pgkk_:k@`~ˎ4eMz^Pni~ \l)$7@`u$Ͳ,Y^^CcS`6XG7vZ[Vs;qWZe'ڶ իdYƙ3g8wo~enܸy$Ij\ ( xVi\0ڡUzy쐦)+++m꘬l_maEp <(U\ۻƮv D.cb>\~H]P2awm{n|o, ^y^Hӟ4AiH[+7`eʲd4yꩧZˮDLӔ\~M+L&:uO\twyM irYN>͛oٮ&tElн/\F#VWWy'YZZjE/_W_m5Z,(,_^L]mW9JkkkC|բ"{[xqRZ`mm}^{5+m$wu:2~[^Y1i;;;UI\rxNwޖeXTq^m *[Y|P ԗոI[dڕ\vn'wykc7xլmr&Fs[ vieGl?v-Z邌[&^cz[W-e~W}$iuRM; 888ࡇmɇl ~[{l6qpph4j۶5_cNՀz=Z-[?+|xbni{{]`-]>sʕv-bCI ?| n}W,gtم,B`pN7[o=v'ܷ2E(iVACO2sݯPeEO-یt n6ȭmMwK%J]-`~n-@wS^@ݽ-`۲kg.26@’' ڪVoSrB0d}zmra :u 6 {Vtow׹~:i@æ2(\@lo41{{{Fڻl+[ZZbw[z]ə3gbQXkc >ůطC mew?K~wɳ}۱mQJ73 ].=w?w+?r϶on$65JM v{и{aFo'zOnwYۮ+B:&[Gʂr Pcw`4uY_)mr_u^uײe666vL+++z;tW\aww]pp,(w˕+Wqu{n?щH>ߋfI 6s+z>vN16L*V67mbfAI2$N5j9ZgQ@#ǔ@tz@u$}xAT+TfDU+lK`ԇ0aWdj! J()D)j< XRuGf^ߠg5ɴ@)Հ"?0 ҝgipwPᛜ*QCBAiN*Ɠ%0fVdEdSƘƬx42^ k5o"GAxu<_ K1 겢 R O1腒:YQ" H)0|#f 9eUU! 5aꚪ(KfL>6Tf\l"j{G` `U 4 5PhԼ8%Q |HǺe)`A&Ы9Rh`žΟW r:un |zӦ֤c&ubiBdcHvu dZԊA2԰R4Kc5}e7Ic'F C:;@lb2QIhdQB͐aȮTQjÓx K[%g}&\6rVʚp!BAԌ|8p$ػ-TZVhmrOkx .V4Q!{(J&LsCob:H>H$[ww .]f J0N?AX~zmx^">KUxfyLq\CB Gzj ߢ ,{/Q?^9O!5u4Au`gO:c:ޣ12dvMaq@UYYCQbߔH)e(`* B_y o& JΤnGib0XR~PO+ c:Eab6ѹj 2SǕTo~璟yJYe)W W`2^*B%5EY IAm ̩r|O0S YCkq8Y'rf 9E"Pc^@2%'5^$kKd }*&+`eQVsG %PT5F `HtQY?b/+cva )y-hخk к$|=@ӃMI5 SrzP?5HH~:׻1O/XN[yy?i%$דuwAW'u:MIKt  UҲ^en:&i3q Ŗ7T2a k_0~&eil4N)4@g ~S_\{UHW-ʆ IDAT_AM9 mz:$oԟJAV %. 11KM%3I6 z72\6xш3 .# yTos ?I+T"YuU0V-(NJ u'"L( B1zr 8EK "QTo4_?ƙ_A v LLzLrL)Osz=W_FO;x0AUxux 3T EU*k `WPB}c|̠S!]fGKV#TyVz9=x A뚲6BPjfahtLY^cReM-$E]Aғ,+JUS *33oL-Ɠ!Oʼ6/̪{?Zρ)f;Msr~fpW 7,QyѲ '9+fHSwn2UɠI%kqhH翧eT7}Atht)ߎMFnJHSM4HY%`æ e(KA5$R40HRݰTM1EJjBs5$h@XI6 od>L5sjxevK'`]⩏?:5#6%|zwGQk'x6^iD*qD Q\Óg_1fx/QL?dztm7LX%Q#LA="D+f5,8QB~/g>~u>}έRTkJDK/ǟg࿡bR@^5)$aj?|b^"_,Ք)+2=r@'+[%LQjR+! $?*M|}_7XZY ^ZMjz}%/ e%=Cb<-Pa>U _>)2X c2A+fW 过7[#,g%'QO/@EjZғ>F S/@RI=B>E- @A?hLe(Lti&X_@WD`@ Ax恭/<-7齄_h35JeY){ͼ$Ơ4 If+tJu*9K֒mIRT9 ZoX9J"#I &n5# jhKd)4GaW*6=_L /0J!7 tDOc<8h&tþ&kX /@v5= >a x}}6Cn\4s~`lc#`C_`*[.S9 |(I A9331ު`=ӼSPMK峯+Uf Qeb:߇`z3ұGˬ@>CGYׁ~< T/ xr@*8C> Rqa4z+p%@ )^5eye Qrey@] e(*"$1ae-CW/<:O9~ůK$S[|kSш(Q2z L% ƃ`VނehG$,a)e"h/ ~/LntS~3$) '3LwjԬJ QTCEd"(JGO#K B /( QoPQ0EUK|6DOjj程6 Eͬl#H1+ %R AzAĀ) %BqNTғD@z5LM^ SS15 ' Be|A xS#@a.:9e2!qtbtIᚳP>2N~ߊ\ߤ[hjqS>"Y[o-(ڟ }`Et:щ)?iْ ը;nᑴ֨aLzuP%9ZQıj JT0? 0*Z+.\^:)PJ3Ds9-M٨9T:]MvkH\5/1/iRMPFۀuAڹ۶ܑK|m-?W?.ߚ-Q;*¾Tה{xfWe C U^ =R-={_Td~Ef4bkD?AL^x}DG`2Q,ďP7AoFCCћC|; '"36c擬F׸~]ֽߥ/E};(kL˨cqB(F)EFߥ?Xj$MS.m]^'7Kb/̿! ^ak:RYc '#q+Ԍ8/:_|ʢ䗑k8fvCܧ0-}A0rkʅ5&^L %ÊBM ,R4k4d*x⚲Rz,޸dh),sƕ.vح-KrRSh=8]p!!x %_6VTl@>MϘF3PIT&N9S $/ `jCVPy(H0TTE'ɊSC`*I>BG;aK)4eQ΃j@sQ e+!o$aM9R4* |^&ذPMqؖ!iV*q%I*X2iZk1lEԊA)C5f}&8[$*+a/=rS}P!g/(u,Qx~lF1{&&+<,̨MzL#2%d~|s?x?`O)L;ȇߢ_1ߡe1YĢb1 WiAY7b$iU9X4<ͦsYm#VzޖR CzM#4a2Hn fEb^jʎAۂЮ M~^5F5(?E(,#ҹû dXQ CF4IFs抸2Jlo*3E @%{BkWSƐd¦iJs jҸsA#݈O3F3Ywbw:wqRFޞo1MxWyľ X1t %ՈoKTxQd%@2RXE`||y_=d,y='{ij2>E2rg1_&WO =#>aP_EB1(?e_|a$Iy ˿ ՏRmSJ# J0Q5d&YȃW9+AwanT)ҨJ[fmq%t͐T@ܔ IH$)@p`z B0ƀ^]{*#M9?fF*#l hN=|0]^:՟juZz0xD4O@8$RQNDȫ#@7yh) P jGy&0lvB xO y9hW @8a('ͣ1(XAS8N PH04^Cc@G"zR%~*R=C8 C>R)r#v0;,.)F*:)1gͬVDS)riq3VK9z E򹃂tV.؁F)?pṟ:of˂: `ЊΖ5&?S< oE+0(xi $)UQ-"b!4x^4BГ;lB*ϣ:4Aa4ՀA&Bә`xƃ2@8  4 ?inQ4CK;ٙW_}Ϻ g§=oC[ ${AI At/p6'͠$Rs4|dz ?8D!y)c/ 4!UpĀn   ^88A &„!S?D^4S)|k8ē0{A,{e+f jJJi#&/`W& (N E D8LɀkTƃp刁x B8<,x]H|tN@3A`LH> Hk&  5ph$P:U<s@"f`[OqZJcY (M hѸ4f5#_r phEɲ6J-"vwxfХ|R xy2/H fqW54~ Lm' !tv o7MjۖAtH넦jHAZ@7 XNj,4c a %E7}qu䣈H! fx!y8 %4xfƀa&a"6J5qg-Z{@ ?o@xŶB+Wb8\!0 r^0a@7Ay/P( " jhj0dP|F1{A`:֯uxs0( fɧ V4jSHf29q!#PpqC {2<&G1]H# ћ%mRS@àz kជz|%@"OܥBJ zANo6(;EDCAs+1  #>3/sD0 g(@aJ8Ӏnz!iiL딐HV@kTHx(  U݀2!:<> @7H0tP H%tPS@)!aj">S sI8D$!SȋZCc&^S;_IBNpHΆ9.9c'B{}oZhGvXeBtC-Ts荫Pvy)&K JʭSV- l;VdU+zJR1{8RB,*|@5K$n` ,UE$+$՞h/Y${BkMh^NGʍ9QmUIQڎ> pnA+󅡦z=.n%uǹz։c! HVtƀxCt<UCBrRt b0'qPGHDw<Cї6w #N0[ wk09 zjq$HB0Po頞w M#P'cgza@4ũhi۱iBRxd [ <4Dh:I:Ndi%v0Fz7@Lț8i! xA2PD0^*1g$lOB&LDQ7z:k0t|4+= 02[A=<2i bBÀq"F Bp`@ p^pjDF'd2@`apF4 ݀$PGDR?<"HF0h!mFAc_ d4LeyG2J$PBO#DE2AF FjrW5qM`Huh` V(0A&a8JaEԎX8ʻ+Ja{]*e&'ڂy?K*CuXV5{aK0y]|P Y. Y1lZ)! ւvbjV#aFP=f Ω(|bQ >IB,TC4c-m `*k&b4h+HS/omĔtw[$Cx^jz1TkЯCyp5f\ g!V~nX D-LǔwKb腞_:ց-b'+ơ<ұ"_Hmw+/R\-;b33Ea$<>1>bJƒ+;+_ta䘎0|N̻ŴPPLlYb﷟EQu-BeZ4Ew$vpZϧ`wuf\a[Fpv@#yCL`1 #/%}b=r QZ(-W-?sHn4vK_VsktenyߒG,eVJ{oge;X;Dvvu۠*3R`|.9 YDܙbyxNt|Pβbrb&6K_" ϩE^ذ}*"FP%YkWxO]Q`SyS,x"2{~VN`72v8dd7ӿx!Fgȯc1p!h98fl FG8pDh?7҉ -~$t71sO&0|~0?bIa\a_bŽIh1stuXQbv2β0UfL<ƺnXv{m5j`:r+ܧ.M 8q^_\>#,*Ï⽷3x8dF  \8&|ʥmuqj:$mϝ[Na8 FA!c :v@RR}-3pw{S;֪` Klo" c%=..\L[@n+WF5BHݥV( Smls'z]Z~ %B /nq/oPfQӸu^{AhNT!XKދbɛ6f rFB!Wfq>S'X!էqw{3 G_⫣犖9?'+hر9N\%Bz/V~̚#%I4w6̬Վ#e`x'20j&c炻[fӌɮiZ ȅa7ƻl`0L`1ϸcY|/7pX~秳hg6S;ϩwUЙmY3IJKs.aW5K>t:DG3!X~O=~-1 4Z:C4Owb0 X dYbFׇPEcw7K[(*pDvEQvsίrQ_θ{(#y3&GD^lSQ{.c)6mh^[JT(QY}M̉~!*PCx2$^Q ixn\u1ƥش/<6`|TXFQ'O}9ד|M /?sxuBh[SF|x}şEA}=iR,o;cÜۿp-NV':iL.4 `'|3v=^}fy,(c0 X0gAGZ(>^I~dY~;k⣎Q"gM Roj7Z*?&?32yfw>x{],ߨ(ʖ^}h~e[öw=9sSNt},ߥAB-1ٷ! EQz)7Y[ˑEx`O|I%?%6-oY7Cn^1Mύ[C_}*Ev% :woCJEQF$0SF_|='b2ӟFE1#]si ;7T[ #xk˺[7 Muy= z$l\-3~pǵ6nGa/=Ϳ2.P7/>Oseav1  ']pr,eno?bܜ]x>Ue5N۹E =.fV-n?QX>z71'z``Ud.,O0^Qe,{z >at8mʲ|;um^vI!D^l(; G s، |F=g}WYߺp{o?zy;.3+OT$ԑ+:,q^_i=z=+$?Ɠ)Qٴ*CEQn/(⡋ڒ ϯnB/LïwVzԖICEҮK[o3g-g!`0r'<UTeeشsX05`I(fYl[<F(!|d:#^t͊i=<~C֥;~.v8z|N?[ωloBS_--?@RL05]`. ig;*cmH<-!DQ!=Ք971c让;z[CcSF>sNx}o^'OƥW)Zؚ }xگ g]J7lMrXt_32:hאWNĜ襇O"_s6{f -5ts&#׍t+BfBO9& CG5="n.X}{k&aEO]&]|8Ay;mDCV>~gtI{۷q`!@PlQJ /v[5 ; u[7iǺ_W.Jkio(\լXY*ml/X4Q0 ɩPY.RphfOz({&6.m,Tzx߱'߉I45<>"Nvx#gh/5vu8h^6vV.h盖` 4BDl5v1]`Yo."s3= -UQeoeY8yۧh+.!}q-Ҽ-?1TaD%D-.ey\ȝOX` ~'WqX{ӛH5h홥躰oツpwk8qy˗ֽX ~e=,=Y@&%gZ 8TO"M6_C/c0*& .r[0)p.̓WNtmʕQ/GS.Vl=a*WvʵcRٿ",SGDt(m6=1?f7 znp4ͧ t77 l˲,(ʪ2ɧ\0cKƺi밾'8 K[&TߟAǤVlbOWŭx7^7k=0~V5;kH0?ߜ 8?pb|6"!q#~^ꕗ{}EQ2Qqxݶ +6:fHO12yDkxk>&%o4_W>pF@;ploQfm}'tL?~(3a]ﱴG_{Ҕ̬?~ZtLLzz+1in3{1{7rªZ"+= *VvmRʒ6WpuKJn\n))Ϭ9Q 8m<0IQ.y٦WpU[8p3'}M 5Og $lliډ-ú00گ nĖnPGp5xvʲ|׵"+EIW+nʲĪCGi>wY0д厛 1 IDATEH&aEhT}Yto(}}qSj#oC7(J2UGL[盆 03MX*HL0N|X/8 lOzy[ۻncЌ(qpoCBJBXoc0V {+zUZRJXI=M%KT-b+wUct+$k@C5ǩU[jW(R9,OZ !¼<d5GC7/ {t)2ndA/S}N_>pw}.=d=;E!I-_\):~mI֋9cY^Ω ^=!.ҥ?o̜>7mCO3L|a380p ȵ_'_sޞUә_զn?8_Q[2_NCݡ7xޖ/6=8bg(Ў 6FEQTG?~ɡdAmVliLE|!_˲ۚ|A7`*gY>㖷@VEآq35[5|(ecN[Do Ǯ.NIѨMIa{C8] q6]f"$܃/sO˭e( =~пNqI_,+&m_>L̞8g[]@+8xy覯)4pQq1#mx}Q7~ E|U5vs؄b0dª{[fFy뇊lN;F3Ů,HNV_eREQv;?ދ9{9y6iHG >(e{9h9r,o%/xk;u0v5a)>c[2 XBs,Oʖw[e풍K'[)1_^yn􌾫fz|BmJ +n@ȟwŖ+[674<>a'%`0r{0ZHn6ٰ$&lKE,|E>o_ѲtAcJ|DrR}BiXֶF{VuO(LA',ZniwNL.ZcR@lȃ0 X ji֘v s:^sEoq_xtqyOM:lMsҳu]Mq/~| 86.oY[*gvhJ4Q_qe, 3Bs=#Ofqs9=~(ʊM>QDXx&k](\'MύĨW<w)e9 9E/X"wgB"hOwBe }i`0b0D(+z#VH~eҕC<6| coX j2"DBXZ}*Y[x1 `F?ņ"x~k(?4)C`00>b0]݅*'f򷗲|>%W,7g+_dU*`0 pDY+"J7h(my+o`U`A.`zn @-DIXCҖ˧px*tg+/RMW0zo^nʨXႩ{mWjݶ(׎J.Z\)7V{5R1ԦZO-ǩ(nϭzZZ0~)t XE,I(*$* ! =.c0jxS)j5[*hwd]:m6kGr YžWۇնRʵmnՔ_X.RB07ur[shOSnVy͕O=vrjvCF; b3<X2i+,GѝQ[xS&jAjoO7msޫM?>MDC,&_rcѨ9Z}P=WRJ _jgOݫ ZJyj+/OSΩ+zVi!Qў`nް@Sэ^j҇մPnEVSvaA>8{r[NxaqZqAkǸcǪрZR9,E2"ɟqvy쓟w+\P*k`K0>bPc0>0.?Q(B2.|&V]†CMa&?n~I)k 2eWaZO/Eeʇ`(,`0{l<[Тimr0`5MK|`0="قڟG mɷF9~PSXYLgxX֫|q{?Pଡ>.ߋX&ȉ@J՗`0 p<|#bE?.D>Rz[9%.4[EU~V:x@^,xoP`0 Gz-rͨb {_*;,hQgƞ3>K! 0Q9RVvyC{s>l8;Bg5 ,`Q[ړ~ϷpjO_) Re۷\jRv*{5 `+_p-F"IOra8X%8 ˥/"sBW0(g9ϛ}_KYÕp1Xv`0 FTZx,j򨥼biʉR"Ԃɕz#}SU)_#Y@mwn<,4'XZey9`0`}PyRVՖvB7cQLP\왐3~KΰaN9F?9a 3QȅxpIqG FGdѳYl桞7ӑ`0zYV,XzX-ЭEǸRIsCs8!KmKQHsHX,sCqbgs0rÉ5plrC%̼aB')0б`0:ZJJby {J}}Vnz\Yn:9>"lX.7ωe2͜;%@F>v*QH6ESX¬1dgX-Ͱ Mrxd.T֨y 7T`0>>b">B*;:o6 |Ӹ#l ۏ)ovD#x|n,Sj@s8]- 'ӣ:̛x8*DCɏ Kb0 Q_ô@[&g&-IltP 9qE` 'wRԞhCfZ!;gZXTvݴ#(9!gr5 `0*|^tآưbK\Gx{ δ̂}xqݰ5aA[q~8[>*tF:8f `0X[qQڅ'iqwS`y̷.iNlTv/Ȑ`43 r8EX`'`0CC)}u`0 F}` `0b0 ``0  ,`0 X `0 b :+-gf1jYj[ kR*mKUT}ݴ~5Jq>2DSZw7msӞj !=B+Cj K_0 |i.fp-}q>{V=Dh?i˫y^} -|x+8P+*P PbSmn/uTՔS.Ru.ur,KS)Mk9^OnύzR㽧%oCx=KTznIz\Ɛw: POK[,*KUVýf]U'US:UߛCڭ(׶JR\]cj*'qL[Q;Vz_K֊cay ayP TQ|y*|Vssx)}q|xBh0Q)obZaGT@gvOZ?tc;Hxn}ljy,e(7t?YEϹ{jnxC\}E,KBHBM៛>*&> "U`O$JÅM7Eǽ 2? (5_ jn}!9w?:}8/XSV׏`0>To?*L`}`0 ǀ,9?ZRV췯 Bcory6{hK>>Dߔ*U$Z* PBRIZxP4#f3EYimnmc l^e FP 4DPCNoCDsvq_޼^˪TUV|n݈8'e/ٱw"H$['h7s+DLf@P_V%qUVY1@ld- 'J$D"l\ @XIQT  @+F+TKڜ`E1!6J>$+H$-*aU2DP ` `RJ(r#4@D[akXJo+@/xۘ//7y>D"H$7RUoj~yo^Ff1.8U8*#32`Xh&GV=Q(B"5'| y%H?/6]O[x$D"Ht:~OWN)œUrP1Pk@N2ZQ0@@5Q]B&U+@f d1`XLTǘD`U ^)(}7Re\+6aD@?p$D"H_"b*Qf9N#6UB2Pr  ?OLHib UH7w}Otx2σ`5KsFF""&FRD|BT%ӔLsqQt?ʥ?zdooXkor?U"   Vu( Q}?yO5$Ux/y/| Ě*5{( IDAT*ԔH$D"q}Ѻׯ'(BG}S` `Ea ]kyD#2LpQH@^rBw{/ոm^0,^}el xU @-ip˷̛L~Bl WcqϜ_MdJFD5B0 ("@**XL$D"qcruXi^nTn~?c,P'@nL\T<'$d^4j9G`^ܾR0 ߾ox/.F,(lA2("FckÇ~{y}r8:w~Dj0\3 50 (S&S'H$#@7*Yg:Dbژfyc{/Q|xO[? A%*(B5S ^{h:f :PY&Ʊۻq@6*Ld** T!B5iCd"[]'_7@%<aĆ2HiDBl]47XxW~QߞD"H$d=H͎<7#2vT\8i3_>0k}o.*v%(eyEGYuK{[_+;y 7O#ѥح4T5_r?6*_^ЈT=H$g@[o_>7?x0~Mo9ϺQb~j6e)c&a!&|%ګ v`U&*h@ulH+g!;ΫF߉@#(GKUM[ՄLP1jC |ֻ?'o;Wg^ 鑘H$D"q'U{/䞷. ^ׯ- "kfEjZZaa&c2Oϟg/UQs1j Z!2c:'H7#?C8= ;F8S\"Kp# oz/_}?Fp.{[>QFP}H$D"Oy _2hC_U_U?)?ig0&"L5Bzk2rF,pI/x JMCC;к|$?wqd !1 w @ZRdw'++ /Ў^8e &D"5P`!OD=,o|91rbwk֎1ug2)ptVGwCWCP @ⶈDh`ͺӟcttzW)j][WwDr4GDyGF_MNwF{$\~D"HtmD(CJDv: -V#s"PgtTs $Yֹ5a_Tր 0I_,s4E ږS.1,'w>}K<2b](Tue$D"LVwgZYB60ۧ?q>[&0b+;%W 8Hwa'#{e#h]B6hre3u68ezc8/&/KQ;*9ێMUiL8D@ij<`%D"MwCHb0cJ x@O *CqʵQxm$y(jD<١n]z_ifÄP: SyE{d_wzVE)1RE">D"H$7]\5 *VXfTDZwg;gO_]), d!".`\/?'SL/^#D|1t$W䇦n{v҉GDJFRA8xh*ӐH$DYG*Vڠ ʠCz]yR^%-We 1~uH(Df`V*]_~eB^!WJ֧o"Bq8Cnʌ$WD"H$Iv'nrQ]5]HA_\,xq{jr1"ʜD"H&r#4ҷD"H$O`雉(AQP[~B=&TDY ((_%D"x~Dx_b&%'$SS$S+X DH$Di,j$yx"(TlF4C M˃D"H$MLm{[ âIޣ'D1흐,˷RJqO$D" ~,j3-?!3MPR3BT@ND"H$O`T1LHZ#" FJ@$@)*H$SÁ= hBIL#b2ic6+ڻD"H$66ٽ!39L%X%CLFD"Hڰa@o|F@{TuK,׶TjAmG5̤w}sD"H$OGo]q?vD l3`'2*dȬ* + Y"p-Za] B"a[avaOƤaOT}jD1!hP,}D?XD"H$zTooDe޾ b╏zם 0L ME"14g9|m7gW|@RT*D0++#Eÿ1<$WD"H$&J$D"HN H$D" V"H$DD"H$$XD"H$'̑Z >ƾz}ik> k77 Wta i[T@^[*բH$ij,KAu+Xg6_{ s/ |z>tLH$3H$[7 WԾV냾&c~"agDf5·[ 6rg@04/X3 QBL:e³ D"xւT->CbyhrZ2:G} 3hN׽KeU~(PYBvқ^48X02bʘ`AV"Tj Z((1E*u)WH$DpY-0p0(b(/ײ;ts kZnO|2X5H%\!Z019{b\\nB`-,26TAG f* ekkJmź 8N'3k"ܙ o3 ۯ_?}|a?,lma/Q"HVDG@Xtaȹ](:rb=9ܡ,w`!.U- ynCc"); gqPy}x2pDtgbŰmmEQW:8K='sB#qUtύGzaj"*B#-DM7X,ё+H$͂Az4,LFYXSXZU2,F$@ȋNUtS#ALcI G \qgA2EQCL\ep)CMN6Jrai1/X@qw2ŎETD&!hFh27k@בJFe: \wjkID"(X8P>h&XdZaלXj*VdRUɞvl[:!"-}ݲ#ijGM W]J I˂,yhsZr^qxu`y7뉺cIg6ˆQKخԑ%V}3kCM{{;t߹2T{ڙJ;0A@yU9ňpJtqVўhE_zfa;ML&rC`IEZ9 ٔEcp uמ = 6]@ombrS ):vB2 5hxN7>$ˏ&reZrACZn7\.FNKCrAޘO}B0CDh ȈʈhMlNqea5'5r 2䴖|ߑ+Bȼ͏F lt>Qb aA%T M%y<,zuXHbK>5UpW>_ObA/zHo(bxǕ&qYW;I9YD"kcRu$"UR-K ]z12BEwˉBls 2h"v`V .Al"Lj$43҅lddދsmf;k0wkHAyiMkͽݦ4 Wr0'}ER$+H$6:mPI'W!cٍڊlab7;JP mԣOzaꨂN3\]\sqm~F+gMU~%gHKcl.rb=R+W)?|]>2JY@>f3Q6Zq_fbZViͳi_Ju!<| EѼ|S年9Ŭ"Tu{DxP72K%$YD"x I V`{uqv}  vs(Pm s>n털=W br\j&ђe%Y%"hJ#j5Y6[Ս&3HFJ'㵥]ј1ʖ)nc (UxETAQQ AImdRaڷ\|jbi\"0 Q1o]~s%s QVMIY#!G0fP=Q+ 7]6u;of$+eD"H$ue@(#0'.D^L{ IDATu_US(j$60ARǘ{ݾŝwFnϖ Ǖ-r6XXD2C!jzUT1jcNb2zQ~I[iRG n&+K68c9Ζn4 m"? qJZ+$&VkF`9*Dȉ2aQs>F!jl:Vԣra?z$ QvHM#k  G9;* g˹ȸenA#ꨨci: X$V(c5Jj6"zY" bY~Ru#uMsw>aagSD"8b%6]kNTxi+~:kky./H`v~$G/^q{ѫa~yAAz8}ʍL*ZQWqtt/TS ([Ɋ]rΩo Z20`T&8Xh0V#aR”5* t0P'zbg E9 9#i >bR8ju{uPgj5V-up^Xx?VبEAɨ'6ͨ,3šF AQQeK{u;U~Pc/NeVgCV1ED"l 9@m91B} [+ZRhp<:憊)s`4D{ղ qoyou{RӥqSXU*Uj 6Z9qTXKRk5B%]d`xssQ'аX_D^@B!kثN#P):mHP0-Y˙RR?3d2YKdu}DY8ޛ7Ҹԭm7Xb _(q+ ;HNCRj7׽p4XdYd psuuZEݛԺ;'STZݮQj( 8VTT}0b%D.X/3Dd)LE&+=ǜu 6'qۿ-`sSn)ڙJ,Ɔڨẍ́jbY91bh:^2>xZPV` "De_LK{{!nxa w3팦Jk T9TP#0s#)Vڻ rcp ~i(/~.MN5n դUdF+IZ-8^Z^;^w Fc!R‡(iнwG!^ةŽ2^87qM'/1Fk6v7i,h`2^ Z ^1yuox73XhF1*}h[u<{N/-TV )`5²WUD"H<#Xյڅ4l *w{c[t 2# m!TUݑ (V/N^jd AG^s7lr>񉵌W-$re&1QjrfN.dax)C~|TFTf& 9Xv;KP @2X vޔvR KOOBw/i8NTw** ]!^skSC'LJN֗-XzHEUy~`G)Y0*K(uVmUqޮsirHV63Ye0 h漖|W˹l9m̜8J$0Dm<-AT:AVO^tEΐm&Rg]Ś"V{&],] E&ȭDmͳRŹw-dh`r^ rJGn;V~Xz%Hۢ*#wHhKdQA5zf7jw*-&D/XYL1"˅=m@)w]Da5ڃ"LJlTѮ3PU#^grjnn;amU-usʖW" "@51Bu~|O:ϑ2njYi,QkMy%vM D 454 G=Qc1|BLS߄ ^r$+Zr $ urrÍ&s l`)j;95pc9V&z;`{4|h {0m)ԽLI2 2jQD4&!&nr6DvA.9aP뀰si|sЭ tˉ+u lOR|sVv hZc"Tn=DǬ X2'TdDLl5*mEtXx:rz39>WuY.6Cnx&߄5(kW4w-<4N#^(W>Dzl2T`1"hAUmTP$[D"xF (Y+d8fi×b  h@ӚIx<40BL6eXDVs|il$C\dJH M,8L׺mh3ոW^lLmx"0͉͢`)4LRC Q]zL@]#Z0m:fysÄ3pNn)]IE+]FsUd6K k"^KDcs|2TKz'b!Z2Z||9ϭEX'fi/WE({t' ^^'**ƨuc =< j\Ÿ[Yp3cWS0ߟM&XuԶ0&"h=DD,H hBA𱞓eKVm%jpzw \-V5uC\/9 _SSޙ i*|S~rj Nhrd rpCڛ(zhd s'MfF ]wtN6UFB0g6yD(9,H23L\WVq ݭ``h` Nևm"ʖU0wW\Dj]3C79Xʦz4m(LU"H$,\C"'jdf֛q%@{@KZX9131gDk  Y%4gK|1V:$v\<00߉l0`ӊ s& /[Ӹ~8y^JmBc ,i?14~v k%k;<sS/# ]8*с8;Y>m@nHso\ 5xm@,ꄹ#tsbW.'ΉLhz$29[ܟy6NGfvN-.r«Kʫ5nA RR+Qnx {V@[SCnn*@k ,}7Q>Nz\``hеͨ#2jmy>oU^|#o^tWxyqg3H$nI<ϼ<vNG#|5(&;ވ2I :f |liأ S0nV޽GYrvUGgFi I@!cqk&cl1Ąq1+,.;&{o ;@M` dBh4~{~}L<$0a>T5w0l!`auY5؀HslnTɪåsH# \@>80;s͵:87HdlbԹfSٽpsl9}bL0b/6d QY50- N.N2HҀ q"Y*%"_"7?IS4D$M骉hVUzNjQذ) !sĤ ;ҍ&Iuc6W A.h1Y $IrHVh}U*VEI4U\sX fkHtX݀0G" DҲER8$NP~ ){M^0!= kO']"N sK>Jc˫al{мX Vt! 4g!"8(rfՁA=H]p"O5|HjB py} 5H"±È`@D%J"i@sO*FD $K΀4ID\ZޡU+U({KUgEjՒEMU!+A&&:D XI0PEDD]La{UR$"pg > b @v,\ K2FI:0ՔDlT`jEj*k fZ~_ι r9ˎ3 L4tO\[jBDD:pm4|e0DXB0B]Ig`PC àMvl}Ru8'H-cs+)f UUjՅ PX`YGlXWNH/+d&n1:מch8 t,21lzb '\&`& Oa3e0VP:E5+WEtcK#_8(fp q1Wi33n .ga1J|*tv>;䜽@&5]756 U@( f_bdNoPQҪxbLgCv""'N̽Osl j9WJ;8qΣkQ?lZZ)4/{F̛=);{jy,4aNHrEv )2$d53p 0߃ 4/ E-l0)OOMCE}(#OAP-Ú=%{M ;rh0ЇS1M2m)$]^,Ѽ = LcS Iٕ>ۉ?h6xMi l6͓`z6'N^ެ6P L˦G̎W9u@Ź]=Z*,q!I%4 lwsZn@쩖3-WKjg[NVϖp~F'AIDtɡ5z0Z!VV/NUظj?eC]Dmm2cŲїnltc5NU#Q-[Dцm -rOtqM;f\XiH6[ ځe( Ga*)rc!4cC(Ѥ7qi5J7X+ Vv89DI=iYى+""6`lUu ZV+6jY kΌ2"f%qϒӍ(g6nހt,l,Ga@ި4-`y Ex%"+WE@`!b0z86aV@BPF;e>(FDP Xbz "A,B!_F}s抠("PDѤhfq&@&b?X%>j>F+|B: HMpHe ^\2XCnκ!jV6zfٞs:tP^+^Hc]\.AT/?*B8*>yp1FzWp4`IcPA.#[!l 6>U.R b@{(Ķz$-fvے2YKG~(FHynyȿ,9zkxvJ ,Xx_{CRKRw2T#>AamM8+4E ^465\RVb@((V0ӳZ=PФ |7$ E즛_3*Wh({K6=7kaPPx 95ཹe匛j>:b0s iGl%UCD|xJC> busX ôlGzkH {.Kȏ.[sW <C\atA{-dS,8)wGt_TZhXBhG763Wm {}Vvdj3s9̇/PE^ (`I憪N,1amn'ax܅s\)!.&X(Y1UMB}||youi[kI&PXf I;+ĐK}Z HV+"U_@::;+ Pt&aA8v0Gs|ɺV㹖Yg0Q72nY]^5ݹi]\{JsQOD8sXVϚ& !EAӵa3/siĉBěmYˤfvk0, s֦(nceEXMRk4f|Z7 Fmt,w7=}Tv|&$1' pվzR\٣upߡGCBhBuwR F-gk1%~r|HvȒ.ѢDtъ@+X9uT"Zmev:C]纜 b@n`t 7Ӑ wtvG4I1Gy,iZcf>"v.yt/Ɏٙ4KD9D뵦Nvɓv+u yDmƠuL~;>8$ѓ`Aࠐt!S$_kocσoO$9gc'¯ǟ)v7{?}m{k×ohтҭ ?k f䛃yK9df?؛ok_8 P햟Ν~=..1k~RLjX*RUR #>÷zJ;KeOu Mg˃ntrW4q.u_zroɫ>]ޛhTݑqt7x]wEE4fxnvl+.LK?S5[U>k.qN'5'Y&׿3do{<5UQ+VK>UMMa(_<G_o[9?pW_{W_8A}L\se f_Diuc\j ;.]+l/;°7=>!XCᛯc?т!`݄`ӢLNt7D+G4ARDDjUo/]f4B ֍:kKß@vD8>/wgC{>r9>, jvtPwߢZ[K]/yg(Zf4rײ-|=M!Z}HA՜ "CgY(>fdG:6b=r>jٔ`\PQ~ڀhfԜjluX$qN\x3'Y O[435 ]Eժf 9X*οu`{s;~/I$ΕC_yڋ р`fWA0GUp"_;~Oʠ(UkP7hŠ*.[qPqeH娈C_n|/bZ?x^xpa-(c|hYkctu1Cr_8gqh0Ӈz^}蓗G5hjǷ^1XY["6x*q^Њ\}DHԜLgv=Y͖?VR}pu"X ]rMv5ϝ9r>h}-b>|Zq&ݵ峟{8yPG{C*@9kX:g1o%?{C`]c׆QBDj= N\ vJh; ?/zUhk(hx3_^ *oi[2̋-#u"(W-zՎkXvu`o_@X&_Jvh }Db[y UD/dÝ?[u7R\^ ?_Ε*=wY?-Ͽ6'?I#?9犈) X^0KQNV@1G0 15ݸ覀$ƍ ]YTlq1D,I{ᾝW>y~+` Mlbzu=0`\E?J>`5,v~\@^UQ/(R.cgo@[keg,mUGW,"VWk xR 0ZzZ|NH~w!cC]C,<#.Tw5OcT+[T e\ٍ +pEEaV}X9p=e=T~-6`)$`=HVt~=m#aEX**g\zwYּꫳ~RkߪdkX. 0?鞽ͽl 65^ ]d?bX눩0^ e @V[ִNq^ܝeoT܁ GwQ So <H!*W?_Q5B㕪М؇|P)jeɖ 'sjmS-]<0n"YvLA X> C+oǂe覊dj~jGDDt2.~g6U3cX=P b}(/x]g?/}n@w7IJg;QBbg׾*w{n5_s<~@> 9E5 aGǵ~l8^)!`X @n~.ڡ!y[@] S{ شr <αj[?܍?xNЇ?7FGW^[FpßW%'Wz5iU-XcUdjGQUD7oWO&^l޵{~oyˋg _773~xǮoګx7?c񊫯s~v <QƟn`耥7U p>FxF@7F.>0b,8glkwu?;oU;w  U oox վmlUE$T>Éc/ N8/>9}' R`9Ǝ^ | L?Fc^̹^1_?C[Ӥ5QV:G70zLTJyOBv왙9{ϯK.@X`@W`ݛԮG>C|E*3[UknE<| 6q<*?ZrXkԿiX~88g|k/LTl00 O~?SuC?7g-nدgugչxʍ0 {9[5K:V~w]esɿ9s,%/<OۦvE⥥_ni8"7=|dwѡC`UW ~e]w>ձ` Nls0zEOvN{\?;Mmg1)~f'9 WgQ +XDDt`WNR>N{F o4shnt ~1Z`^$qc_soSطx0y<د-+WDDtKOɅew{暣U7ܰ"t{[巾?ߕ;·WmοW <+wq\\Ju/}&SW}Nu׷ڟN뼜@EDDOW ?T0ϡV^w`p1xii@޽RСG/e_K/JG]htk/x avZ".WZ%I.^Z ]k^bMY9ғ}ѹ:^? G\ (6>UJyaNP>? y?}!"""{~`FY+bU:4<"U4W3T'VƂnc&""C8w,H]R~ܵ0zp5 XWz_|S} `$`-1] P _U@B q ʾC=~?-|+Zzpi9W%sCIW-<= 6qh'W\>mrL)d,6ap鮆H._'MwT}Ino ή,ԹD1f۝y?f-e-8bSY2OW^ZWocgc15psd֪}$P @p :O%LEw><{b)b%"YsoXt|Itn ̰֢q~й*yڨruU0xcH!W3_$e qD)bP>AX `*,fqY8ҔUۆPԾ,)=Ke܅}9ѓ/f<#VVg hNWsL;H>BObo):F>u>33» 6aCdNB0DXA"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""#$$%&"$#"""#$$%&"$#"""#$$%&&'&&%$#""""#$$%&&'&&%$#""""#$%&&''(''&&%$#"""#$%&&''(''&&%$#"""#$&&'')('()('&&$#""""#$&&'')('()('&&$#""""#$&&&%%&'&''&&%%&$#""""#$&%$%&''&'('%$%&$#""""#$%&%$$$$%&&&%%$$$%$#""""#$%%%'('('%%%$#""""$%&$##$%&$##$%$""""$%&$$&'('&$$&%$""""#$&$##$$##$$"""#$&'%%'%$%'%%'&$"""$%'$####$%#""""$%'('%$%&%%&%$%'(&%#"""#$&)&$CC$%&$""#$&)&('&''$$('''()'&$""#%&(&%#BA#%'&%#""#%&(%&('('%%'()('('&%#""#$&''&&$#CC#%%&%$#""#$&'&$%&('&'%$%&()('&'&%$#""#$&'('(%$$##$%&&%$#""#$&''%&''(')(&'()('&%&%$#""$%&(()(&%$#$%#$%&''&%$#"$%&(&)(&()(&'()('&%$%&%$#"#$&''(&%&%#$%&$#%&''('&$#""#$&''(&%'(&%&'('()'&('&$#""!"$%&(&%$&'$%'('$'()('&&$"!""!"$%&(&%$&''&'('&'()('&&$"!""!#$&')'&'(('(')'()*'&%$#!""!#$&')'&'(('(')'()*'&%$#!""!"#%&'(')*'&%'(()*('&$#"!""!"#%&'(')*'&%'(()*('&$#"!""!"$%&''()'&$&'((''&%$"!""!"$%&''()'&$&'((''&%$"!""!#$%&&''('%'(''&&%$#!$%""!#$%&&''('%'(''&&%$#!$%""$$!"#$$%&&''&('&&%$$#"!$%'""$$!"#$$%&&''&('&&%$$#"!$%'""%%$!!"#$$%&&&'&%$$#"!!$'&$""%%$!!"#$$%&&&'&%$$#"!!$'&$""$'$!!"#$$$%&$$#"!!$%&%#"""""""""""$'$!!"#$$$%&$$#"!!$%&%#"""""""""""""#$%$!!!"#$$#"!!$%&%$" "#$%&'&%$ """#$%$!!!"#$$#"!!$%&%$" "#$%&'&%$ """"""!! "#'$$$!!!!!!$%&'$#" #$%&(&%$ """"""!! "#'$$$!!!!!!$%&'$#" #$%&(&%$ """"&'&%$##"! "$%$%%$$%&'%#" "$%&'&%$ """"&'&%$##"! "$%$%%$$%&'%#" "$%&'&%$ $'&%'%'(&%$#"! #$%('%$$%&(&$" "#%&%&%$ $'&%'%'(&%$#"! #$%('%$$%&(&$" "#%&%&%$ $%'$&%$%'&&%$#! #$'%$$%&)%$" $%&'%&' $%'$&%$%'&&%$#! #$'%$$%&)%$" $%&'%&' !!$$&'$&'()'&%#"! #%'%$%&'%$# "$&(%$%&%$ !!$$&'$&'()'&%#"! #%'%$%&'%$# "$&(%$%&%$ !!$$$%&'(&'&%$#""$'(%$$$$$$$$$$$$$%&'&$#" #$%&'%&'$ !!$$$%&'(&'&%$#""$'(%$$%&'&$#" #$%&'%&'$ !!$%&&%&(&$$! #%'%$%%&'('&'('&$%&&%$" $%$$%&'($ !!$%&&%&(&$$! #%'%$$$%&&%$" $%$$%&'($ !!$&'&'*'%$"!#$%$&&'(%%%%%%%%%%&%$# "$&'%$%(&% !!$&'&'*'%$"!#$%$#%&%$# "$&'%$%(&% !!$$%&()(&$#!#$'$%%%%$$$$$$$$$$%%$#" #%'(&%&&%&$ !!$$%&()(&$#!#$'$$%%$#" #%'(&%&&%&$ !!$%%$%&'(&%"!#%%$$$$$$$%$" "$&%'&'%$%$ !!$%%$%&'(&%"!#%%$$%$" "$&%'&'%$%$ !!!!$$%&&%$%&''&! #'$$%&&&$# #%&'%&'%&% !!!!$$%&&%$%&''&! #'$$%&&&$# #%&'%&'%&% !!!!$%&'('&%&'&$#!"$%$$%'&%# "%(%$%(&(% !!!!$%&'('&%&'&$#!"$%$$%'&%# "%(%$%(&(% !!!$$%&')'%'&%#! #%$$%&%$" %&'%&'('%$!!!$$%&')'%'&%#! #%$$%&%$" %&'%&'('%$!!!$%&'(&(&(&$"!"$%%$$$%%&&%$" #%&%&('&%$!!!$%&'(&(&(&$"!"$%%$$$%%&&%$" #%&%&('&%$!!!$%$&'%&)'&#! #$%&%%$$%&&'(&%#" "#%$%&'%""""!!!$%$&'%&)'&#! #$%&%%$$%&&'(&%#" "#%$%&'%""""!!$%&&%&'('&%"!"$%&'&%$$%%&'%'&%$" "#"""""!!$%&&%&'('&%"!"$%&'&%$$%%&'%'&%$" "#"""""!!$('&')'&%$! $%%&%'&%$$$%&'(&%$#" ""!!$('&')'&%$! $%%&%'&%$$$%&'(&%$#" ""!!$%&'('&%$#!"$%&%(&%$$%&'(&%$" "!!$%&'('&%$#!"$%&%(&%$$%&'(&%$" "!$%&'&%$#! $%&)('%$$%&'&%$#"!$%&'&%$#! $%&)('%$$%&'&%$#"!!"""""$#"!#$%('&%$$%%&'()&%$"!!"""""$#"!#$%('&%$$%%&'()&%$"!!""! $%&'&%$$%&''&'&%$"!!""! $%&'&%$$%&''&'&%$"!"!"$%''%$$%&'(&%&'&%"!"!"$%''%$$%&'(&%&'&%""#$%&('&%$$%&'('&'(&%""#$%&('&%$$%&'('&'(&%""$%&'&&%$$%&'&%&'&%""$%&'&&%$$%&'&%&'&%""%&'%('%$$%&'(''(&%""%&'%('%$$%&'(''(&%""%&('&)&%$$$%&)(&'&%""%&('&)&%$$$%&)(&'&%""%&'&%('&%$%&&%&%""%&'&%('&%$%&&%&%""%&%''&%$$$%&''&%%""%&%''&%$$$%&''&%%""$%'(&%$$$$$$$$$%&&%&('&%""$%'(&%$$%&&%&('&%""%&&'(&%$$$$%%&%%&%%%&&'()'&%""%&&'(&%$$%&'()'&%""%&'%&'&%$%&%%&%&%%%&&&'&&'&%""%&'%&'&%$$%%&&'&%""%&(&'('%&(%$$$$$$$$$%&'&%&&%""%&(&'('%$$%&'&%&&%"""%('&'((&&$$%&'&'&%"""%('&'(&%$$$%&'&'&%""%'&%&'&%$$%&'('&&%""%'&%&'&%$$%&'('&&%""%&'&'&%$$%&'&%%""%&'&'&%$$%&'&%%""%%&'('&%$$%&'&%$%""%%&'('&%$$%&'&%$%"##%&'%&&%$$%&&%$#$"##%&'%&&%$$%&&%$#$"""#%&&'&%$$%%$#"#"""#%&&'&%$$%%$#"#"""!"#%&(%$$%&%#" """!"#%&(%$$%&%#" """! !"#%&(%$$%&%$" """"! !"#%&(%$$%&%$" ""$%$# !"#%&'%$$%#" """"$%$# !"#%&'%$$%#" """""""%%$# !"#%&%$$%#" "#$&$""""%%$# !"#%&%$$%#" "#$&$"""$&%$" !"#%$$%" "#$&%$""$&%$" !"#%$$%" "#$&%$""$'&%$# !"## "$%'%$"""$'&%$# !"## "$%'%$"""&%$%$" "$%'&$""""""&%$%$" "$%'&$""""! ""%&%&%#" !"##$##""! "#%'&%$"""! ""%&%&%#" !"##$##""! "#%'&%$""" ""$%&'&%# !"#$$%$$$#"! "$&%%$"""" ""$%&'&%# !"#$$%$$$#"! "$&%%$"""" ""$$%%$" "#$%&'&%&$#" #%'&$"""" ""$$%%$" "#$%&'&%&$#" #%'&$"""" ""$%&$# "$%&%&%$%&$# $%&%$"""" ""$%&$# "$%&%&%$%&$# $%&%$""""!$&'%$ "#$%$%$#$$#" $&%&$""""!$&'%$ "#$%$%$#$$#" $&%&$"""" "%%&&%# #$&$#$%$%$"! $''&$"""" "%%&&%# #$&$#$%$%$"! $''&$""""! ""$&'&'$" #$%&$%'%$#"! $%&%$""""! ""$&'&'$" #$%&$%'%$#"! $%&%$""""!"$%'&%&# "#$%$%&'%$#" #$%&$""""!"$%'&%&# "#$%$%&'%$#" #$%&$"""" !"$&&%$%" "$%$#$%&'%$# "$&%$""" !"$&&%$%" "$%$#$%&'%$# "$&%$""" ""$%%$&%$ !#$&%$%&%&'$# #%'%$""" ""$%%$&%$ !#$&%$%&%&'$# #%'%$""" !""$'&%'%# !"%$#""#$$%%%" "$%&%$""" !""$'&%'%# !"%$#""#$$%%%" "$%&%$""" ""$%&'&%$" "#$""!!""#$$$"! $%%$"""" ""$%&'&%$" "#$""!!""#$$$"! $%%$"""" !""$&%&%$# !"" !""##" #$&%$""" !""$&%&%$# !"" !""##" #$&%$""" $'&%$#" ! "$%'$" $'&%$#" ! "$%'$"%$#" !"####"! "#$%&$%$#" !"####"! "#$%&$"""""" !"###$$$$###"! "#$%&"""""" !"###$$$$###"! "#$%&" !!#$$$%%%%$$$##"! """""" !!#$$$%%%%$$$##"! """"""!"#$%%%$&&&%%%$$##"! ""!"#$%%%$&&&%%%$$##"! """#$%&&%$%&'(&$%%$$#"!"""#$%&&%$%&'(&$%%$$#"!""#$%&'%$%&'(&%%%&%%$#"""#$%&'%$%&'(&%%%&%%$#"""$%&'&%$%&('&$%&'&&%$#""$%&'&%$%&('&$%&'&&%$#""%&'&%$#$%'&%$%'(''&%$""%&'&%$#$%'&%$%'(''&%$""%&'&&%$%'&%$%&('%%'&%""%&'&&%$%'&%$%&('%%'&%""'&'&&%&&%$#$%&%$$%&%""'&'&&%&&%$#$%&%$$%&%""&%&'&%'(&%$%&'&&%$%""&%&'&%'(&%$%&'&&%$%""&$%&%$%'(&%&(&%&&%&""&$%&%$%'(&%&(&%&&%&""%$$&$#$('(&'&%$%&&'""%$$&$#$('(&'&%$%&&'""&%$&%$%'%'(&%$#$%'(""&%$&%$%'%'(&%$#$%'(""'&%&&%&('%'(&%$%&((""'&%&&%&('%'(&%$%&((""&%&('&'&)$%'(&%&'&'""&%&('&'&)$%'(&%&'&'""%$%&)(&%)'$%''&'&%&""%$%&)(&%)'$%''&'&%&""$#$%&&%$%($%'('&%$%""$#$%&&%$%($%'('&%$%""%$%&'%$#$%%&&'&%$#$""%$%&'%$#$%%&&'&%$#$""&%&'(&%$%&&&%&'&%$%""&%&'(&%$%&&&%&'&%$%""'&%&'(&%&'(%$%&'&%&""'&%&'(&%&'(%$%&'&%&""&%$%&'(&'(%$#$%&%&'""&%$%&'(&'(%$#$%&%&'""'&%$%&'(%&'%$%&'&'(""'&%$%&'(%&'%$%&'&'(""('&%%%&%$%&&&')(&&&""('&%%%&%$%&&&')(&&&""&&%$%%$#$&'()&&%%""&&%$%%$#$&'()&&%%""%%$%&&%$%%&&&%%$$""%%$%&&%$%%&&&%%$$""$$$%&'(&%$%%%$$##""$$$%&'(&%$%%%$$##""##$%%%%%%%$$$##""""##$%%%%%%%$$$##""""""#$$$$$$$###""!!""""#$$$$$$$###""!!""!!"##"!! ""!!"##"!! "" "" "" !"##"!!""" !"##"!!"""!!!""#####$%$#""#""!!!""#####$%$#""#""""###$$%&%&$%$###""""###$$%&%&$%$###""#$$%&'&%'$#$%%$"""#$$%&'&%'$#$%%$"""&%$%'%$$%&$%&'%""&%$%'%$$%&$%&'%""%$#$%$##$%#$%%$""%$#$%$##$%#$%%$""$#"#$#""#$"#$%&""$#"#$#""#$"#$%&""$#$%$##"#"#$%(""$#$%$##"#"#$%(""%$%$%$$#$#$%&'""%$%$%$$#$#$%&'""&%$#$%&$&$%&$%""&%$#$%&$&$%&$%""%$#"#$%$%&%$#$""%$#"#$%$%&%$#$""%$#$%$#$%$%$%""%$#$%$#$%$%$%""'%$%&%$%$#$%&""'%$%&%$%$#$%&""&%&$%&%&#"#$%""&%&$%&%&#"#$%""%$%%$#$$#"#$""%$%%$#$$#"#$""%&&$"#&$#$&""%&&$"#&$#$&""&$%$#"%&$'(""&$%$#"%&$'(""&%$&$"$%$&'""&%$&$"$%$&'""%$#$&#$&#$&""%$#$&#$&#$&""&%$#'$'#&'(""&%$#'$'#&'(""&%"&'&"$%'""&%"&'&"$%'""%$"%$#"#%&""%$"%$#"#%&""&$#$&$#"$%""&$#$&$#"$%""'%$#%'$#$%""'%$#%'$#$%""'&%$%($%""'&%$%($%""&%$#$%'$""&%$#$%'$""%$#"#$%&""%$#"#$%&""$#"!"#$%""$#"!"#$%""$#"#$%&""$#"#$%&""%$#$%$%""%$#$%$%""&%$%$#$""&%$%$#$""'&%$#"#""'&%$#"#""('&%$#$""('&%$#$""%$#$$""%$#$$""$#"#$""$#"#$""%$#$%""%$#$%""&%$%&""&%$%&""$#$%""$#$%""%$%&""%$%&""%$#$""%$#$""$#"#""$#"#""$#$""$#$""%$%""%$%""$%""$%""%$""%$""%""%""&""&""%""%"""ur ?t Sueend 5q 5a >_ph &r $e to ^rf f n oq U_ ]d rd tB@; :K [G ;8C %F %<G M B N Q A L> \7 nC p8; 7 A <,, ?- V, . d L!!! 2 \L% , _3^                 !" #! "#!#$%#"#%&&$# "!"%"!!$%&%$'('('')*())*'(+(*++)'+*),,-.,/-,0/,,.0/0120.023310-./.-./2/12321 445-5544675--677-86457945:4:;;84<:559<=;:8;=:<>><9?76?=::>?8=@A>9B?6=?B68B8@BB@=C97C?>7?CCA9>AC5!attack1Y{[z]|`WYbizi{_mb}hkd]jYhmTKn|_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dwieh_T{o^WnjcJrbL=jW#cqfblvrT!jRhKylIsfBvOFi$"|{wYuS|~eXx[jZo4@`EWE[>6>i>k>hyB[GBW] az~=or7ib7^WH! zXOb | j0¬@_>ҳBiTU6%ݢattack3]{_zieTddNlkhlgpjmij]ul_>ymek_Utq^ZnmcLubO?pW&rdrhcWmxtV!mRlKzpKuiCyQ4n%|{}Y{S|eX[qZx4@hyE^Ed=6Gi@g@dyEXGFT]T=wP|9je9`XK z]Ohy |p2¨@k=ѩDoUU5(۫attack4]z_zk~fTfdOkkjlhqjplj_wlb>z~pem_Wts^\npcNxbR3vW(esjeWmzwYpToM{sKvlC|U4t(|y{`V|eWZvQY~4@lyDaDi=5LhCaC_yISGJO\J){P8ni8cXP w[Oly }u-ŝlBu*ՙDr_Ģ@5%ۡattack5]z_zi~dTdcNkkhlgpjmij]ul_>x~lek_Utq^YnmcLubN=pW&rdrhcWmxtV!mRlKzoKuiCyQ4n%|{}`{S|eW}ZnYu3?fyD\Db=5EgAdAayFUGFQ\L=sPx8gb8]XH wqOs¤ }|-ǘl_}֏7r^ŝU=ۂattack6[{]ya~`R\bk| k}`lb{ije_jXjlUKr}ac^_P}e^Qp^cGfbF>WW!r`n__ip-gL!`L]FutcHl_@jFFU"|sjt{fWbQ|gf_[bNaO?GBjL:L;L=g:r:oyWW7E<7< yx |mrhOsqĨkn1z s {n*ʝkndUxeڗgDri]ơeTC"{attack7[{\y_~`PZbkzk{^lb|gjc\jXglTKo}^c[_P}b^PpZcGbbE>QW"r^n]_ho-dK!\LYFur`Oj]@fDCO#bcp ~UWQQUfc_fReRCNFjR?R>KC"h9v 9sj9eM9a[{dVLYWEKAEB$$gf [rUNv\V#Z1f _ ~X)ƠUnP`{No՛OfuU]PTC"{attack8[{\y_~`PZbkzk{^lb|gjc\jXglTKo}^c[_P}b^PpZcGbbE>QW"r^n]_ho-dK!\LYFur`Oj]@fDCO#bcp ~UWQQUfc_fReRCNFjR?R>KC"h9v 9sj9eM9a[{dVLYWEKAEB$$gf [rUNv\V#Z1f _ ~X)ƠUnP`{No՛OfuU]PT5!death1Y{[z]|`WYbizi{_mb}hkd]jYhmTKn|_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dSlih_N{`J~Ak::=y"h! +]98zg9y8lR}~)ƑȑCޜC㕙 sm|aPzOsp8k|S5³emGʍ=IѺHOMMdeath3Y[xs]lYii{i_[hZc]VhX,nkK\FdEB\GdI*V5^\gfò ^°~\p#j(gƨ>UoZljkKCgCC)(Z--*V98[98xNv/?Ć̽C zim"U[~6snp]<¯D'ʫH(ѵ(ZmMdeath4csvze~dXgkbsuuhs|e^i[rX_g]rb2xk(eVlUKd`~l`1_lgzxfqynog{fzs,p+_eTykvpajk,PYZY5MTWW1`GCvrhB|jTC}Brmouxk0(ɊK;k^~zilŸWY{kyEibcƞa9̂A#԰X%ۄ#aǃ"3)찑death5ui3Xv|4NxNtdLk3]z3HzKJIxUYO-wb~b,ukv~l:qy\Dw\SZCcBbixDawMcbM\U2Ih0pSA_@Zo2UN\RN2TMa{a9ls{tTm3]Sv5TkDSwG"k)CQ\\M:E]Hc/3ob:y*4x7oyUS#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dSlih_N{`J~Ak::=y"h! +]98zg9y8lR}~)ƑȑCޜC㕙 sm|aPzOsp8k|S5³emGʍ=IѺHOMMdeathb3Y[xs]lYii{i_[hZc]VhX,nkK\FdEB\GdI*V5^\gfò ^°~\p#j(gƨ>UoZljkKCgCC)(Z--*V98[98xNv/?Ć̽C zim"U[~6snp]<¯D'ʫH(ѵ(ZmMdeathb4csvze~dXgkbsuuhs|e^i[rX_g]rb2xk(eVlUKd`~l`1_lgzxfqynog{fzs,p+_eTykvpajk,PYZY5MTWW1`GCvrhB|jTC}Brmouxk0(ɊK;k^~zilŸWY{kyEibcƞa9̂A#԰X%ۄ#aǃ"3)찑deathb5ui3Xv|4NxNtdLk3]z3HzKJIxUYO-wb~b,ukv~l:qy\Dw\SZCcBbixDawMcbM\U2Ih0pSA_@Zo2UN\RN2TMa{a9ls{tTm3]Sv5TkDSwG"k)CQ\\M:E]Hc/3ob:y*4x7oyUS#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dUS#r^n]_ho/eM#]MYHmbHj]BgFDT""|ljn} {_W\Q|_fY[\N[N?ADjE=EVTEMBED'!rp \XNi[jX\US#r^n]_ho-eM#]MYHn_Hj]@gFDT""|lnz {_W\Q|_fY[\N[N?ADjE=EVTEMBED'!pm c\Nkay\`US#r^n]_ho2eM#]MYHm\Hj]JgFDT""|lnw {_W\Q|_fY[\N[N?ADjE=EVTEMBED'!lj \YNk[Y]US#r^n]_ho/eM#]MYHidJj]fgFDT""|ljn~ {_W\Q|_fY[\N[N?ADjE=EVTEMBED'$tr daNjcaeUS#r^n]_ho/eM#]MYHl^Hj]@gFDT""|lny {_W\Q|_fY[\N[N?ADjE=EVTEMBED'$nl \YNl[jY]US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``d9|M89r|q8qwcOgnEYQtXP:N6OF89G8},.U{$v|Inhsqqd^On)w(qy,lCek0fmcp_gmiz`gh .ׇpainb4`~[Nao"ds_hawo~]Gol$e{n}%ctnpptrbsis2ajihd_MdlPcaW{nlNKnN?VfOAcMHwf_ip^WnqIB8Z"MW}{oXVa&s`\ws!sts6qi‘hdX?`O>k?qes>tt ZX@McZdPE{NDG`k?Gh@N{aUluWRv:L:_k_ fI`yHH|kZU{j {8 {oDwGTC}O DmSzCv^{=GAS\RoBJ|@K<)@Y$H5%G~ V[|V&pPUzi`UyÌx PIYo\>}^KjQIȃvFYQ*gaՉRS‚zSS#㥋painb6lM-Xm`.NpeHkHF|N-`|]-HquE{vDIpwO{{uSfI-nYuX+mbvud:lq;:oJrL7=I+QL ݂Y 8O sP9N ,䬡painb7m;6[oN0SqZFl?P}=6\}K0Vsh>|iO*ZgIIDS=f?G_hE75WLHSzL 2_ jH3]:painb8o!tzp*aXsAfn3"rh(c^tFU~ES_sNW~Q[-Bf(s[Gz[FAraOzcO0o^s"vq.}!o{,t,}o53 0%}4)jQʄ6a`'j#maAe"4Ae,RE][M[L5p:TsBtB1?ON#pkN)hYN/yN8nnu)h1023=-k5=4E剹/g^,vm@g3JQY+j7vE6eb.|cJ[91A<}#[P#4$M[3-Npainb9o6̂p1ssDnL6ʈ0it@}>brG}K,EKrFyF~fqOyQ~*nppPsHـrTӕ}Hڋ|i th~qiޙN$V(~m>l9ZD҆4lDTDK>gJJ.MeZThUg*hNYN5ljN4ZNCNBN-}[邬P.d哰f>s|>{ 9i?ŊDO"=qV߄G8mw@t>puEI(J@upBhYEЈINfIJ7zA@38lg@kAk,HJ^RGQBgRS"QMR C|l≰d+sۓuCCᙺ-EmPʆJPa;snS8EVɊC5ge[G@KnJENlM&AApainb11xbzSy|[wradžTl}PvNp{SX(\_{H~vG~eyRzSx+xcWY}w{~x ~{t&KCv"Uhp\ŇZQ|[@DkMM=AehHcHb+JA\X_WXhXiW`R&[~τz+ǓCCǙ%Zlf \PvJhچg:YlS5}doHMKHTN܃O(=Wpainb12z||jǂ~kQy{lɈ]}\n}^aIjf}N}Md{VVLy[c[}2-}G@Cxhk v̆iRj_MSR=?~kExEwL=WgZxYpkZ~YsX(x~>D ½DҜ%o}kƊVyܜ z:l ҁ_.Ⓑd΀VSKJ_SݗS):Ypainb13{}oÁnP{qň`{_`cKnf~O}Nd}WVL{YaY~2#G@Dyzlj| mRNmfOTT=?jEyExL:Yi[~ Zvy[ZwX)>DDӋ,tƁoȎNYyݡ~ƨEʿEn$t̂n͎NXy⡜~ȯEǂwEx],}Ί uЕN_娌ۅM=qy2n#ohu}Hw_fDApj n|WxNo|fPvShRi?;_j@X@WK1:hh g{jhMgzX6ũŕ|>{ͪyEqfEgL,xӆ q}ԑ|N[{j|߁[S#r`n__ip-hN`N]HrdHl_BkHFZ""|sjt{fWbQ|gfZg]Z\[CBPFHFIK7,h;w :ty`W`n__ip-fT^T[NurdHl_@iNCR#}sjt{fWbQ|hfXd[V[X?@LEEEEK6(h]\ETKEK0!zx }jiNikjln`W`n__ip-hR`Q^LurdHl_BkKCS*|ut}gRbNwicYd]VXXFBL|IDDEC8's[R`n__ip-jQcQ`KrdHl_BmKFb,"zvt{iRbNvkcYe]WXYFBM~IEDF>8(s;p;my<_M<[[je h?ZZdTK6KW0$zx }jiNhklnL>0/h;p:my<_M<[[ee h?ZYESIEIW/$zx }jXiNikjlnbDZB[L2Hb=p _G=[X vdkLYXFOEFE,$yw|iXiNfjkn<v t og.joeUe^Kҧf_mbTeT /)run9Yz[y_|`WZaNi|i|bhi|kflaf_lh\Jo{`fcSZ}jS[dXUkVOKe=0ao``jq2gP`O]JrcHn_@jIC\)"{uxzgRfQxifVmZ`Wa?<`AX?XL/Fp=p _G=[X wfk=[[FQH4HX/!yw|iXiNhkjkn;v t qh.âjoeUh]Kҧf_ocTeT )-run10Y}[|_zcWZdNiibhi|kflaf_lh\JozcfcSZ}jS[dXUkVOKe=0`o``jp-eR`S]MqfHm_BiMC]-zuxygRfQwifQlT^Q`?8\;T9UL)Al=p _G=[[ vfk=[[FQH4HX/!|z{lXlOennq<~y wpj)lohUdbUҧi^lfYhT'-run11Y}[|_zcWZdNiibhi|kflaf_lh\JozcfcSZ}jS[dXUkVOKe=0`o``jp-eR`S]MqfHm_BiMC]-zuxygRfQwifQlT^Q`?7Y;Q8Q>'8k;p:my<_M;[Xvhk=]\FSI7I0$|z{lXlOennq<~y wqj)lohUebUҧi^lfYhT7"run12Z{\z`|aW[bNj| j}amc{jkf`jYkmVKp|ac``Q}g_Ro`dHhcG>[S#r`n__ip-hN`N]HrdHl_BkHFZ""|sjt{fWbQ|gfZg]Z\[CBPFHFIK7,h9w 9ty:fM:bX{hh=]\ETKEK0!zx }jiNiljlnUS#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dUS#r^n]_ho1eM#]MYHhWHj]AgFDT""|mnr{`W\Q|`^X][PZPC@EjE>E>K5!i1q 1ny1`M1\Xa `>VTEMBED'!om {_^Nf^^b<~j hnZ3\oYU^L_ɧWUlVYXT4 leap3PoRmTTXOV`n`o_mb}hkd]jYhmTAeRf]`Q}d_Qo\dGdcE>RQ#r^n]_ho;pP#hQeKgTHj]BrIET"|mn oz`R\R{`^ZZ]M\M>?EC>C=K4 i1q 1nj1`M1\Xh`L^\FVLEM1$lj }\[Ng[[__W1jlqs pglej_rznKyt>ta?]7|zYS{fY\r[v3BoFfFiL3Qn>s>qyBcGB_[ j=EՁy6vWb%yXOhj« | p/Ƞ@l=إBnTŤU 3:׉leap5bdfynWaprrhg{|re}gdqrgm@wxlc`Zg|gYgp_^^g]\ASU=uhfuq2iieibcuynHtrJkbCLAz ywYtNyw^WsZfYf=C]GVGUL3:p@{?y@kG?g[ Zx>usencdePJ%~wvuNftjŪuyFNJIJDJ6)i@ >Yy?KG>G[ :^VCSReQ FdHP09~hfwXWOfVjĩW[٣PUlNRŢQT =rleap8cjdifOWbQrjrjhnY|ql[fkPqnK@wNc`aE|g`Fp_e<gd:AS\uhbfSqb-iGeGaAuyPHsPJk@CLbbkUYQNUf^QaD`D=MGQ@Q?K=$p?f>cy?UG>Q[ B]U?RPeO EdFP/<|rpubaOd`j§aeؠZUjXRĠ[T5!leap9Y{[z]|`WYbizi{_mb}hkd]jYhmTKn|_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``dUS#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo |a`Ng``d<l jo\3¤_o[U_NUѨYUmXRZT 4!stand2Zz[x^~_WYajyjz_mb|hkd]jYhmTKn}]c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHq_Hj]@gFDT""{mnz y`W\Qz`fW]ZPYPC>EjC>C>K4!i8{ 8yj8kM8g a `>VTEMBED'!pn ~_X_No^j\cUS#r^n]_ho-eM#]MYHpbHj]_gFDT""{mjn| y`W\Qz`fW]ZPYPC>EjC>C>K4!i9{ 8yj9kM8gXa `>VTEMBED'!rp |baNs^l_e;m k }^/Ü^o\U}PKѝY_zWTYT4!stand4[x]w_|]PZ_kwkx_mb|hkd]jYhmTKp{\c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHr^Hj]@gFDT""{mny y`W\Qz`fW]ZPYPC>EjC>C>K4!i9{ 8xy9jM8fa `>VTEMBED'!nl |^[]NxZl[#a1i g Z/ĖZnYT΃L>ӗT_RTTT4!stand5Z{\z^{`WZbjzj{_mb|hkd]jYhmTKo{_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHqaHj]@gFDT""|mjn| {`W\Q|`fW]ZPYPC>EjC>C>K4!i9{ 8yj9kM8gXa `>VTEMBED'!qo |a`Nv]l^#d1l j ]/ę]n[T΁O>әWf}UTWT4"stand6Y{[z]|`WYbizi{_mb}hkd]jYhmTKn{_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""{nn| yaW\QzafW^ZPYQ?>FC?C>K4"h:{9zxj:jM9yfXa `>VTEMBED'!qo |a[`Nx]m^#d1l j ]/×]n[T̓O>ҘWfUTWT4!|stand7W|Yz[|aWWcg{g|_mb}hkd]jYhmTKl{_f]`Q}d_Qo\dGdcE>US#r^n]_ho/eM#]MYHnbHj]_gFDT""{mjn| y`W\Qz`fW]ZPYPC>EjC>C>K4!i:{9xxj:jM9wfX|a `>VTEMBED'!rp }b[aNt^l^#e;m k ~]/^n\UOLϚX_{VTXT1!{stand8\z]y_{_P[akzkz_mb|hkd]jYhmTKpz^c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHr`Hj]@gFDT""xmjn{ w`W\Qx`fT]WPVPCA>K1!h9{ 8yj9kM8gXza `>VTENDFE) qn |`_Nl]l^cӝW^rUTXT5!~stand9Y{[z]|`WYbizi{_mb}hkd]jYhmTKn{_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjo| z`W^Q{`fW]ZPZPC?EjD>D>K5!i9{ 8xy9jM8fX~b b>XVENDEE)!qo |a`Nl^j`dѥX_sVTYT5!walk1Y{[z]|`WYbizi{_mb}hkd]jYhmTKn|_c]`Q}d_Qo\dGdcE>UQ&r^n]_ho-eM#]MYHpaHj]@gFDU("|mjm| {`W[Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~c_>XVDODEF)$qo }a`Ng`j`dL;!i9{ 8xj9jM8fX~e a>ZYEQGEH,$qo }a`Ng`j`dU>IE!p9{ 8xj9jM8fX~a`KWUeO-EdF*%nl }^]Ng]]a[YeQGdH,$rp |aaNf`ae<l jo\)¤_o\UbNJѨY_mXRZT9#walk5Y|[z]{aPYci{i|]mc|fke[kZfmUJn{_cV]Q|]\RpU`H]`FAKT*u^m\^gn-_N#YNVHupaHj\@aGCL)"uno| raW]QvafVaXTZT>CGF@I?I9#i9{ 8xy9jM8f~f b>[YEQGEH,$rp |aaNf`ae<l jo\)¤_o\U`NUѨY_mXRZT<"walk6Y|[z]{aPYci{i|]mc|fke[kZfmUJn{_cV]Q|]\RpU`H]`FAKR*u^m\^gn-_N#YNVHupaHj\@aGCL)!zno| waW^QzafZa\S]T>FGjJ@K?L<"i9{ 8xy9jM8f~fbL\ZFRHFI-!rp |aaNf`jae<l jo\.¤_o\UdNJѨY_mXRZT>"walk7Y|[z]{aPYci{i|]mc|fke[kZfmUJn{_cV]Q|]\RpU`H]`FAIR)u^m\^gn-_N#YNVHupaHj\@aGCJ("{njo| yaW]Q}af\a^S_T=IGL@N?L>"i9{ 8xj9jM8fX~eaL[YFQGFH,!rp |aaNf`jae<l jo\.¤_o\UdNJѨY_mXRZT5!walk8Y{[z]{`WYbizi{_mb}hkd]jYhmTKnz_c]`Q}d_Qo\dGdcE>UQ&r^n]_ho-eM#]MYHpaHj]@gFDU("|mjm| {`W[Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8f~c_>XVDODEF)$qo |a`Nf``d<l jn\)£_o[U`MAѧYUmXRZT5!huh1Y{[z]|`WYbizi{_mb}hkd]jYhmTKn|_c]`Q}d_Qo\dGdcE>US#r^n]_ho-eM#]MYHpaHj]@gFDT""|mjn| {`W\Q|`fX][PZPC@EjE>E>K5!i9{ 8xj9jM8fX~a `>VTEMBED'!qo }a`Ng``d last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/water.lua0000644000076400001440000020761610540115020014674 0ustar dividuumusers-- Nachdem es einen Votebot gab, welcher nach neuen Levels gebettelt hat... -- Hier ist es :-) function level_size() return 64, 46 end function level_koth_pos() return 56, 22 end -- function level_spawn_point(player) -- return world_tile_center(11, 11) -- end function level_init() world_dig(32, 23, TILE_WATER) world_dig(61, 16, TILE_WATER) world_dig(62, 16, TILE_WATER) world_dig(61, 17, TILE_WATER) world_dig(62, 17, TILE_WATER) world_dig(60, 15, TILE_WATER) world_dig(61, 15, TILE_WATER) world_dig(60, 16, TILE_WATER) world_dig(59, 15, TILE_WATER) world_dig(59, 16, TILE_WATER) world_dig(58, 15, TILE_WATER) world_dig(58, 16, TILE_WATER) world_dig(57, 15, TILE_WATER) world_dig(57, 16, TILE_WATER) world_dig(56, 15, TILE_WATER) world_dig(56, 16, TILE_WATER) world_dig(55, 15, TILE_WATER) world_dig(55, 16, TILE_WATER) world_dig(54, 15, TILE_WATER) world_dig(54, 16, TILE_WATER) world_dig(53, 15, TILE_WATER) world_dig(53, 16, TILE_WATER) world_dig(52, 15, TILE_WATER) world_dig(52, 16, TILE_WATER) world_dig(51, 15, TILE_WATER) world_dig(51, 16, TILE_WATER) world_dig(50, 15, TILE_WATER) world_dig(50, 16, TILE_WATER) world_dig(50, 17, TILE_WATER) world_dig(51, 17, TILE_WATER) world_dig(49, 16, TILE_WATER) world_dig(49, 17, TILE_WATER) world_dig(48, 16, TILE_WATER) world_dig(48, 17, TILE_WATER) world_dig(52, 17, TILE_WATER) world_dig(53, 17, TILE_WATER) world_dig(54, 17, TILE_WATER) world_dig(55, 17, TILE_WATER) world_dig(56, 17, TILE_WATER) world_dig(57, 17, TILE_WATER) world_dig(58, 17, TILE_WATER) world_dig(59, 17, TILE_WATER) world_dig(60, 17, TILE_WATER) world_dig(48, 15, TILE_WATER) world_dig(49, 15, TILE_WATER) world_dig(47, 14, TILE_WATER) world_dig(48, 14, TILE_WATER) world_dig(47, 15, TILE_WATER) world_dig(47, 13, TILE_WATER) world_dig(48, 13, TILE_WATER) world_dig(47, 12, TILE_WATER) world_dig(48, 12, TILE_WATER) world_dig(47, 11, TILE_WATER) world_dig(48, 11, TILE_WATER) world_dig(47, 10, TILE_WATER) world_dig(48, 10, TILE_WATER) world_dig(47, 9, TILE_WATER) world_dig(48, 9, TILE_WATER) world_dig(47, 8, TILE_WATER) world_dig(48, 8, TILE_WATER) world_dig(47, 7, TILE_WATER) world_dig(48, 7, TILE_WATER) world_dig(47, 6, TILE_WATER) world_dig(48, 6, TILE_WATER) world_dig(47, 5, TILE_WATER) world_dig(48, 5, TILE_WATER) world_dig(47, 4, TILE_WATER) world_dig(48, 4, TILE_WATER) world_dig(47, 3, TILE_WATER) world_dig(48, 3, TILE_WATER) world_dig(47, 2, TILE_WATER) world_dig(48, 2, TILE_WATER) world_dig(47, 1, TILE_WATER) world_dig(48, 1, TILE_WATER) world_dig(49, 1, TILE_WATER) world_dig(50, 1, TILE_WATER) world_dig(51, 1, TILE_WATER) world_dig(52, 1, TILE_WATER) world_dig(53, 1, TILE_WATER) world_dig(54, 1, TILE_WATER) world_dig(55, 1, TILE_WATER) world_dig(54, 2, TILE_WATER) world_dig(55, 2, TILE_WATER) world_dig(56, 1, TILE_WATER) world_dig(56, 2, TILE_WATER) world_dig(57, 1, TILE_WATER) world_dig(57, 2, TILE_WATER) world_dig(58, 1, TILE_WATER) world_dig(59, 1, TILE_WATER) world_dig(60, 1, TILE_WATER) world_dig(61, 1, TILE_WATER) world_dig(62, 1, TILE_WATER) world_dig(61, 2, TILE_WATER) world_dig(62, 2, TILE_WATER) world_dig(61, 3, TILE_WATER) world_dig(62, 3, TILE_WATER) world_dig(62, 4, TILE_WATER) world_dig(62, 5, TILE_WATER) world_dig(62, 6, TILE_WATER) world_dig(62, 7, TILE_WATER) world_dig(62, 8, TILE_WATER) world_dig(62, 9, TILE_WATER) world_dig(62, 10, TILE_WATER) world_dig(62, 11, TILE_WATER) world_dig(62, 12, TILE_WATER) world_dig(62, 13, TILE_WATER) world_dig(61, 12, TILE_WATER) world_dig(61, 13, TILE_WATER) world_dig(61, 14, TILE_WATER) world_dig(62, 14, TILE_WATER) world_dig(62, 15, TILE_WATER) world_dig(60, 14, TILE_WATER) world_dig(59, 14, TILE_WATER) world_dig(58, 14, TILE_WATER) world_dig(57, 14, TILE_WATER) world_dig(56, 14, TILE_WATER) world_dig(55, 14, TILE_WATER) world_dig(54, 14, TILE_WATER) world_dig(53, 14, TILE_WATER) world_dig(52, 14, TILE_WATER) world_dig(51, 14, TILE_WATER) world_dig(50, 14, TILE_WATER) world_dig(49, 14, TILE_WATER) world_dig(49, 13, TILE_WATER) world_dig(49, 9, TILE_WATER) world_dig(49, 10, TILE_WATER) world_dig(49, 8, TILE_WATER) world_dig(49, 7, TILE_WATER) world_dig(50, 7, TILE_WATER) world_dig(50, 8, TILE_WATER) world_dig(49, 6, TILE_WATER) world_dig(50, 6, TILE_WATER) world_dig(49, 5, TILE_WATER) world_dig(50, 5, TILE_WATER) world_dig(49, 4, TILE_WATER) world_dig(49, 3, TILE_WATER) world_dig(49, 2, TILE_WATER) world_dig(50, 2, TILE_WATER) world_dig(50, 3, TILE_WATER) world_dig(51, 2, TILE_WATER) world_dig(52, 2, TILE_WATER) world_dig(53, 2, TILE_WATER) world_dig(53, 3, TILE_WATER) world_dig(54, 3, TILE_WATER) world_dig(55, 3, TILE_WATER) world_dig(56, 3, TILE_WATER) world_dig(55, 4, TILE_WATER) world_dig(56, 4, TILE_WATER) world_dig(55, 5, TILE_WATER) world_dig(56, 5, TILE_WATER) world_dig(54, 4, TILE_WATER) world_dig(54, 5, TILE_WATER) world_dig(53, 4, TILE_WATER) world_dig(53, 5, TILE_WATER) world_dig(53, 6, TILE_WATER) world_dig(54, 6, TILE_WATER) world_dig(52, 5, TILE_WATER) world_dig(52, 6, TILE_WATER) world_dig(51, 5, TILE_WATER) world_dig(51, 6, TILE_WATER) world_dig(51, 4, TILE_WATER) world_dig(52, 4, TILE_WATER) world_dig(57, 3, TILE_WATER) world_dig(58, 2, TILE_WATER) world_dig(58, 3, TILE_WATER) world_dig(59, 2, TILE_WATER) world_dig(59, 3, TILE_WATER) world_dig(60, 2, TILE_WATER) world_dig(60, 3, TILE_WATER) world_dig(59, 4, TILE_WATER) world_dig(60, 4, TILE_WATER) world_dig(59, 5, TILE_WATER) world_dig(60, 5, TILE_WATER) world_dig(58, 5, TILE_WATER) world_dig(58, 6, TILE_WATER) world_dig(59, 6, TILE_WATER) world_dig(58, 7, TILE_WATER) world_dig(59, 7, TILE_WATER) world_dig(57, 6, TILE_WATER) world_dig(57, 7, TILE_WATER) world_dig(56, 6, TILE_WATER) world_dig(56, 7, TILE_WATER) world_dig(55, 6, TILE_WATER) world_dig(55, 7, TILE_WATER) world_dig(54, 7, TILE_WATER) world_dig(61, 4, TILE_WATER) world_dig(61, 8, TILE_WATER) world_dig(61, 9, TILE_WATER) world_dig(60, 8, TILE_WATER) world_dig(60, 9, TILE_WATER) world_dig(59, 9, TILE_WATER) world_dig(59, 10, TILE_WATER) world_dig(60, 10, TILE_WATER) world_dig(57, 9, TILE_WATER) world_dig(58, 9, TILE_WATER) world_dig(57, 10, TILE_WATER) world_dig(58, 10, TILE_WATER) world_dig(56, 9, TILE_WATER) world_dig(56, 10, TILE_WATER) world_dig(56, 8, TILE_WATER) world_dig(57, 8, TILE_WATER) world_dig(57, 5, TILE_WATER) world_dig(60, 6, TILE_WATER) world_dig(61, 5, TILE_WATER) world_dig(61, 7, TILE_WATER) world_dig(57, 11, TILE_WATER) world_dig(58, 11, TILE_WATER) world_dig(56, 11, TILE_WATER) world_dig(55, 10, TILE_WATER) world_dig(55, 11, TILE_WATER) world_dig(54, 10, TILE_WATER) world_dig(54, 11, TILE_WATER) world_dig(54, 9, TILE_WATER) world_dig(55, 9, TILE_WATER) world_dig(54, 8, TILE_WATER) world_dig(55, 8, TILE_WATER) world_dig(61, 6, TILE_WATER) world_dig(61, 10, TILE_WATER) world_dig(61, 11, TILE_WATER) world_dig(60, 11, TILE_WATER) world_dig(60, 12, TILE_WATER) world_dig(58, 12, TILE_WATER) world_dig(59, 12, TILE_WATER) world_dig(58, 13, TILE_WATER) world_dig(59, 13, TILE_WATER) world_dig(57, 12, TILE_WATER) world_dig(57, 13, TILE_WATER) world_dig(56, 12, TILE_WATER) world_dig(56, 13, TILE_WATER) world_dig(55, 12, TILE_WATER) world_dig(55, 13, TILE_WATER) world_dig(59, 8, TILE_WATER) world_dig(60, 13, TILE_WATER) world_dig(54, 12, TILE_WATER) world_dig(53, 10, TILE_WATER) world_dig(53, 11, TILE_WATER) world_dig(53, 9, TILE_WATER) world_dig(58, 8, TILE_WATER) world_dig(59, 11, TILE_WATER) world_dig(53, 12, TILE_WATER) world_dig(53, 13, TILE_WATER) world_dig(54, 13, TILE_WATER) world_dig(52, 12, TILE_WATER) world_dig(52, 13, TILE_WATER) world_dig(51, 12, TILE_WATER) world_dig(51, 13, TILE_WATER) world_dig(52, 11, TILE_WATER) world_dig(51, 11, TILE_WATER) world_dig(51, 10, TILE_WATER) world_dig(52, 10, TILE_WATER) world_dig(51, 9, TILE_WATER) world_dig(52, 9, TILE_WATER) world_dig(51, 8, TILE_WATER) world_dig(52, 8, TILE_WATER) world_dig(52, 7, TILE_WATER) world_dig(53, 7, TILE_WATER) world_dig(53, 8, TILE_WATER) world_dig(50, 12, TILE_WATER) world_dig(50, 13, TILE_WATER) world_dig(50, 11, TILE_WATER) world_dig(50, 10, TILE_WATER) world_dig(50, 9, TILE_WATER) world_dig(51, 7, TILE_WATER) world_dig(50, 4, TILE_WATER) world_dig(52, 3, TILE_WATER) world_dig(57, 4, TILE_WATER) world_dig(58, 4, TILE_WATER) world_dig(60, 7, TILE_WATER) world_dig(49, 11, TILE_WATER) world_dig(49, 12, TILE_WATER) world_dig(51, 3, TILE_WATER) world_dig(47, 16, TILE_WATER) world_dig(47, 17, TILE_WATER) world_dig(47, 18, TILE_WATER) world_dig(48, 18, TILE_WATER) world_dig(47, 19, TILE_WATER) world_dig(48, 19, TILE_WATER) world_dig(49, 18, TILE_WATER) world_dig(49, 19, TILE_WATER) world_dig(50, 18, TILE_WATER) world_dig(50, 19, TILE_WATER) world_dig(51, 18, TILE_WATER) world_dig(51, 19, TILE_WATER) world_dig(49, 20, TILE_WATER) world_dig(50, 20, TILE_WATER) world_dig(49, 21, TILE_WATER) world_dig(50, 21, TILE_WATER) world_dig(49, 22, TILE_WATER) world_dig(50, 22, TILE_WATER) world_dig(48, 21, TILE_WATER) world_dig(48, 22, TILE_WATER) world_dig(48, 20, TILE_WATER) world_dig(51, 20, TILE_WATER) world_dig(51, 21, TILE_WATER) world_dig(52, 20, TILE_WATER) world_dig(52, 21, TILE_WATER) world_dig(52, 18, TILE_WATER) world_dig(52, 19, TILE_WATER) world_dig(47, 20, TILE_WATER) world_dig(47, 21, TILE_WATER) world_dig(48, 23, TILE_WATER) world_dig(49, 23, TILE_WATER) world_dig(48, 24, TILE_WATER) world_dig(49, 24, TILE_WATER) world_dig(47, 24, TILE_WATER) world_dig(47, 25, TILE_WATER) world_dig(48, 25, TILE_WATER) world_dig(47, 26, TILE_WATER) world_dig(48, 26, TILE_WATER) world_dig(47, 27, TILE_WATER) world_dig(48, 27, TILE_WATER) world_dig(47, 28, TILE_WATER) world_dig(48, 28, TILE_WATER) world_dig(47, 29, TILE_WATER) world_dig(48, 29, TILE_WATER) world_dig(46, 25, TILE_WATER) world_dig(46, 26, TILE_WATER) world_dig(46, 24, TILE_WATER) world_dig(46, 23, TILE_WATER) world_dig(47, 23, TILE_WATER) world_dig(46, 22, TILE_WATER) world_dig(47, 22, TILE_WATER) world_dig(46, 21, TILE_WATER) world_dig(46, 20, TILE_WATER) world_dig(46, 19, TILE_WATER) world_dig(46, 18, TILE_WATER) world_dig(46, 17, TILE_WATER) world_dig(46, 16, TILE_WATER) world_dig(46, 15, TILE_WATER) world_dig(46, 14, TILE_WATER) world_dig(46, 13, TILE_WATER) world_dig(46, 12, TILE_WATER) world_dig(46, 11, TILE_WATER) world_dig(46, 10, TILE_WATER) world_dig(46, 4, TILE_WATER) world_dig(46, 5, TILE_WATER) world_dig(46, 3, TILE_WATER) world_dig(46, 2, TILE_WATER) world_dig(45, 1, TILE_WATER) world_dig(46, 1, TILE_WATER) world_dig(45, 2, TILE_WATER) world_dig(45, 3, TILE_WATER) world_dig(45, 4, TILE_WATER) world_dig(45, 5, TILE_WATER) world_dig(45, 6, TILE_WATER) world_dig(46, 6, TILE_WATER) world_dig(45, 7, TILE_WATER) world_dig(46, 7, TILE_WATER) world_dig(45, 8, TILE_WATER) world_dig(46, 8, TILE_WATER) world_dig(45, 9, TILE_WATER) world_dig(46, 9, TILE_WATER) world_dig(45, 10, TILE_WATER) world_dig(45, 11, TILE_WATER) world_dig(45, 12, TILE_WATER) world_dig(45, 13, TILE_WATER) world_dig(45, 14, TILE_WATER) world_dig(45, 15, TILE_WATER) world_dig(45, 16, TILE_WATER) world_dig(45, 17, TILE_WATER) world_dig(45, 18, TILE_WATER) world_dig(45, 19, TILE_WATER) world_dig(45, 20, TILE_WATER) world_dig(45, 21, TILE_WATER) world_dig(45, 22, TILE_WATER) world_dig(45, 23, TILE_WATER) world_dig(45, 24, TILE_WATER) world_dig(45, 25, TILE_WATER) world_dig(45, 26, TILE_WATER) world_dig(45, 27, TILE_WATER) world_dig(46, 27, TILE_WATER) world_dig(45, 28, TILE_WATER) world_dig(46, 28, TILE_WATER) world_dig(45, 29, TILE_WATER) world_dig(46, 29, TILE_WATER) world_dig(45, 30, TILE_WATER) world_dig(46, 30, TILE_WATER) world_dig(45, 31, TILE_WATER) world_dig(46, 31, TILE_WATER) world_dig(45, 32, TILE_WATER) world_dig(46, 32, TILE_WATER) world_dig(45, 33, TILE_WATER) world_dig(46, 33, TILE_WATER) world_dig(45, 34, TILE_WATER) world_dig(46, 34, TILE_WATER) world_dig(45, 35, TILE_WATER) world_dig(46, 35, TILE_WATER) world_dig(45, 36, TILE_WATER) world_dig(46, 36, TILE_WATER) world_dig(45, 37, TILE_WATER) world_dig(46, 37, TILE_WATER) world_dig(45, 38, TILE_WATER) world_dig(46, 38, TILE_WATER) world_dig(45, 39, TILE_WATER) world_dig(46, 39, TILE_WATER) world_dig(45, 40, TILE_WATER) world_dig(46, 40, TILE_WATER) world_dig(45, 41, TILE_WATER) world_dig(46, 41, TILE_WATER) world_dig(45, 42, TILE_WATER) world_dig(46, 42, TILE_WATER) world_dig(45, 43, TILE_WATER) world_dig(46, 43, TILE_WATER) world_dig(45, 44, TILE_WATER) world_dig(46, 44, TILE_WATER) world_dig(47, 44, TILE_WATER) world_dig(48, 44, TILE_WATER) world_dig(47, 43, TILE_WATER) world_dig(48, 43, TILE_WATER) world_dig(47, 42, TILE_WATER) world_dig(48, 42, TILE_WATER) world_dig(47, 41, TILE_WATER) world_dig(48, 41, TILE_WATER) world_dig(47, 40, TILE_WATER) world_dig(48, 40, TILE_WATER) world_dig(47, 39, TILE_WATER) world_dig(48, 39, TILE_WATER) world_dig(47, 38, TILE_WATER) world_dig(47, 37, TILE_WATER) world_dig(47, 36, TILE_WATER) world_dig(47, 35, TILE_WATER) world_dig(47, 34, TILE_WATER) world_dig(51, 22, TILE_WATER) world_dig(52, 22, TILE_WATER) world_dig(51, 23, TILE_WATER) world_dig(52, 23, TILE_WATER) world_dig(51, 24, TILE_WATER) world_dig(52, 24, TILE_WATER) world_dig(51, 25, TILE_WATER) world_dig(52, 25, TILE_WATER) world_dig(51, 26, TILE_WATER) world_dig(52, 26, TILE_WATER) world_dig(51, 27, TILE_WATER) world_dig(52, 27, TILE_WATER) world_dig(51, 28, TILE_WATER) world_dig(52, 28, TILE_WATER) world_dig(53, 27, TILE_WATER) world_dig(53, 28, TILE_WATER) world_dig(54, 27, TILE_WATER) world_dig(54, 28, TILE_WATER) world_dig(55, 27, TILE_WATER) world_dig(55, 28, TILE_WATER) world_dig(56, 27, TILE_WATER) world_dig(56, 28, TILE_WATER) world_dig(57, 27, TILE_WATER) world_dig(57, 28, TILE_WATER) world_dig(58, 27, TILE_WATER) world_dig(58, 28, TILE_WATER) world_dig(59, 27, TILE_WATER) world_dig(59, 28, TILE_WATER) world_dig(60, 27, TILE_WATER) world_dig(60, 28, TILE_WATER) world_dig(61, 27, TILE_WATER) world_dig(61, 28, TILE_WATER) world_dig(62, 27, TILE_WATER) world_dig(62, 28, TILE_WATER) world_dig(61, 26, TILE_WATER) world_dig(62, 26, TILE_WATER) world_dig(61, 25, TILE_WATER) world_dig(62, 25, TILE_WATER) world_dig(61, 24, TILE_WATER) world_dig(62, 24, TILE_WATER) world_dig(61, 23, TILE_WATER) world_dig(62, 23, TILE_WATER) world_dig(61, 22, TILE_WATER) world_dig(62, 22, TILE_WATER) world_dig(61, 21, TILE_WATER) world_dig(62, 21, TILE_WATER) world_dig(61, 20, TILE_WATER) world_dig(62, 20, TILE_WATER) world_dig(61, 19, TILE_WATER) world_dig(62, 19, TILE_WATER) world_dig(61, 18, TILE_WATER) world_dig(62, 18, TILE_WATER) world_dig(50, 23, TILE_WATER) world_dig(50, 24, TILE_WATER) world_dig(49, 25, TILE_WATER) world_dig(50, 25, TILE_WATER) world_dig(49, 26, TILE_WATER) world_dig(50, 26, TILE_WATER) world_dig(50, 27, TILE_WATER) world_dig(50, 28, TILE_WATER) world_dig(50, 29, TILE_WATER) world_dig(51, 29, TILE_WATER) world_dig(50, 30, TILE_WATER) world_dig(51, 30, TILE_WATER) world_dig(49, 29, TILE_WATER) world_dig(49, 30, TILE_WATER) world_dig(49, 31, TILE_WATER) world_dig(50, 31, TILE_WATER) world_dig(48, 30, TILE_WATER) world_dig(47, 30, TILE_WATER) world_dig(49, 27, TILE_WATER) world_dig(49, 28, TILE_WATER) world_dig(48, 31, TILE_WATER) world_dig(48, 32, TILE_WATER) world_dig(49, 32, TILE_WATER) world_dig(48, 33, TILE_WATER) world_dig(49, 33, TILE_WATER) world_dig(47, 32, TILE_WATER) world_dig(47, 33, TILE_WATER) world_dig(48, 34, TILE_WATER) world_dig(48, 35, TILE_WATER) world_dig(47, 31, TILE_WATER) world_dig(50, 32, TILE_WATER) world_dig(50, 33, TILE_WATER) world_dig(51, 32, TILE_WATER) world_dig(51, 33, TILE_WATER) world_dig(50, 34, TILE_WATER) world_dig(51, 34, TILE_WATER) world_dig(52, 34, TILE_WATER) world_dig(51, 35, TILE_WATER) world_dig(52, 35, TILE_WATER) world_dig(51, 36, TILE_WATER) world_dig(52, 36, TILE_WATER) world_dig(53, 34, TILE_WATER) world_dig(53, 35, TILE_WATER) world_dig(54, 34, TILE_WATER) world_dig(54, 35, TILE_WATER) world_dig(53, 33, TILE_WATER) world_dig(54, 33, TILE_WATER) world_dig(55, 33, TILE_WATER) world_dig(55, 34, TILE_WATER) world_dig(54, 32, TILE_WATER) world_dig(55, 32, TILE_WATER) world_dig(56, 32, TILE_WATER) world_dig(56, 33, TILE_WATER) world_dig(57, 32, TILE_WATER) world_dig(57, 33, TILE_WATER) world_dig(58, 32, TILE_WATER) world_dig(58, 33, TILE_WATER) world_dig(57, 31, TILE_WATER) world_dig(58, 31, TILE_WATER) world_dig(59, 31, TILE_WATER) world_dig(59, 32, TILE_WATER) world_dig(60, 31, TILE_WATER) world_dig(60, 32, TILE_WATER) world_dig(60, 30, TILE_WATER) world_dig(61, 30, TILE_WATER) world_dig(61, 31, TILE_WATER) world_dig(62, 30, TILE_WATER) world_dig(62, 31, TILE_WATER) world_dig(62, 29, TILE_WATER) world_dig(61, 29, TILE_WATER) world_dig(60, 29, TILE_WATER) world_dig(59, 29, TILE_WATER) world_dig(59, 30, TILE_WATER) world_dig(58, 29, TILE_WATER) world_dig(58, 30, TILE_WATER) world_dig(57, 29, TILE_WATER) world_dig(57, 30, TILE_WATER) world_dig(56, 29, TILE_WATER) world_dig(56, 30, TILE_WATER) world_dig(55, 29, TILE_WATER) world_dig(55, 30, TILE_WATER) world_dig(54, 29, TILE_WATER) world_dig(54, 30, TILE_WATER) world_dig(53, 29, TILE_WATER) world_dig(53, 30, TILE_WATER) world_dig(52, 29, TILE_WATER) world_dig(52, 30, TILE_WATER) world_dig(52, 31, TILE_WATER) world_dig(53, 31, TILE_WATER) world_dig(51, 31, TILE_WATER) world_dig(52, 32, TILE_WATER) world_dig(53, 32, TILE_WATER) world_dig(52, 33, TILE_WATER) world_dig(54, 31, TILE_WATER) world_dig(55, 31, TILE_WATER) world_dig(56, 31, TILE_WATER) world_dig(59, 33, TILE_WATER) world_dig(60, 33, TILE_WATER) world_dig(61, 32, TILE_WATER) world_dig(61, 33, TILE_WATER) world_dig(62, 32, TILE_WATER) world_dig(62, 33, TILE_WATER) world_dig(61, 34, TILE_WATER) world_dig(62, 34, TILE_WATER) world_dig(61, 35, TILE_WATER) world_dig(62, 35, TILE_WATER) world_dig(61, 36, TILE_WATER) world_dig(62, 36, TILE_WATER) world_dig(61, 37, TILE_WATER) world_dig(62, 37, TILE_WATER) world_dig(60, 36, TILE_WATER) world_dig(60, 37, TILE_WATER) world_dig(60, 35, TILE_WATER) world_dig(59, 35, TILE_WATER) world_dig(59, 36, TILE_WATER) world_dig(58, 35, TILE_WATER) world_dig(58, 36, TILE_WATER) world_dig(58, 34, TILE_WATER) world_dig(59, 34, TILE_WATER) world_dig(60, 34, TILE_WATER) world_dig(58, 37, TILE_WATER) world_dig(59, 37, TILE_WATER) world_dig(57, 36, TILE_WATER) world_dig(57, 37, TILE_WATER) world_dig(57, 38, TILE_WATER) world_dig(58, 38, TILE_WATER) world_dig(56, 37, TILE_WATER) world_dig(56, 38, TILE_WATER) world_dig(55, 37, TILE_WATER) world_dig(55, 38, TILE_WATER) world_dig(55, 36, TILE_WATER) world_dig(56, 36, TILE_WATER) world_dig(54, 36, TILE_WATER) world_dig(54, 37, TILE_WATER) world_dig(55, 35, TILE_WATER) world_dig(56, 35, TILE_WATER) world_dig(56, 34, TILE_WATER) world_dig(57, 34, TILE_WATER) world_dig(57, 35, TILE_WATER) world_dig(53, 36, TILE_WATER) world_dig(53, 37, TILE_WATER) world_dig(52, 37, TILE_WATER) world_dig(52, 38, TILE_WATER) world_dig(53, 38, TILE_WATER) world_dig(51, 37, TILE_WATER) world_dig(51, 38, TILE_WATER) world_dig(50, 37, TILE_WATER) world_dig(50, 38, TILE_WATER) world_dig(49, 37, TILE_WATER) world_dig(49, 38, TILE_WATER) world_dig(48, 37, TILE_WATER) world_dig(48, 38, TILE_WATER) world_dig(48, 36, TILE_WATER) world_dig(49, 36, TILE_WATER) world_dig(49, 35, TILE_WATER) world_dig(49, 34, TILE_WATER) world_dig(50, 35, TILE_WATER) world_dig(50, 36, TILE_WATER) world_dig(50, 39, TILE_WATER) world_dig(51, 39, TILE_WATER) world_dig(49, 39, TILE_WATER) world_dig(49, 40, TILE_WATER) world_dig(50, 40, TILE_WATER) world_dig(49, 41, TILE_WATER) world_dig(50, 41, TILE_WATER) world_dig(49, 42, TILE_WATER) world_dig(50, 42, TILE_WATER) world_dig(51, 41, TILE_WATER) world_dig(51, 42, TILE_WATER) world_dig(52, 41, TILE_WATER) world_dig(52, 42, TILE_WATER) world_dig(53, 41, TILE_WATER) world_dig(53, 42, TILE_WATER) world_dig(54, 41, TILE_WATER) world_dig(54, 42, TILE_WATER) world_dig(53, 40, TILE_WATER) world_dig(54, 40, TILE_WATER) world_dig(55, 40, TILE_WATER) world_dig(55, 41, TILE_WATER) world_dig(56, 40, TILE_WATER) world_dig(56, 41, TILE_WATER) world_dig(55, 42, TILE_WATER) world_dig(56, 42, TILE_WATER) world_dig(57, 41, TILE_WATER) world_dig(57, 42, TILE_WATER) world_dig(58, 41, TILE_WATER) world_dig(58, 42, TILE_WATER) world_dig(57, 43, TILE_WATER) world_dig(58, 43, TILE_WATER) world_dig(57, 44, TILE_WATER) world_dig(58, 44, TILE_WATER) world_dig(56, 44, TILE_WATER) world_dig(50, 44, TILE_WATER) world_dig(51, 44, TILE_WATER) world_dig(49, 44, TILE_WATER) world_dig(52, 44, TILE_WATER) world_dig(53, 44, TILE_WATER) world_dig(54, 44, TILE_WATER) world_dig(55, 44, TILE_WATER) world_dig(59, 44, TILE_WATER) world_dig(60, 44, TILE_WATER) world_dig(61, 44, TILE_WATER) world_dig(51, 43, TILE_WATER) world_dig(52, 43, TILE_WATER) world_dig(53, 43, TILE_WATER) world_dig(54, 43, TILE_WATER) world_dig(55, 43, TILE_WATER) world_dig(56, 43, TILE_WATER) world_dig(59, 42, TILE_WATER) world_dig(59, 43, TILE_WATER) world_dig(60, 42, TILE_WATER) world_dig(60, 43, TILE_WATER) world_dig(49, 43, TILE_WATER) world_dig(50, 43, TILE_WATER) world_dig(61, 43, TILE_WATER) world_dig(62, 43, TILE_WATER) world_dig(62, 44, TILE_WATER) world_dig(60, 41, TILE_WATER) world_dig(61, 41, TILE_WATER) world_dig(61, 42, TILE_WATER) world_dig(62, 41, TILE_WATER) world_dig(62, 42, TILE_WATER) world_dig(59, 41, TILE_WATER) world_dig(52, 40, TILE_WATER) world_dig(57, 40, TILE_WATER) world_dig(58, 40, TILE_WATER) world_dig(59, 40, TILE_WATER) world_dig(60, 40, TILE_WATER) world_dig(61, 40, TILE_WATER) world_dig(51, 40, TILE_WATER) world_dig(52, 39, TILE_WATER) world_dig(53, 39, TILE_WATER) world_dig(54, 38, TILE_WATER) world_dig(54, 39, TILE_WATER) world_dig(55, 39, TILE_WATER) world_dig(56, 39, TILE_WATER) world_dig(57, 39, TILE_WATER) world_dig(59, 38, TILE_WATER) world_dig(58, 39, TILE_WATER) world_dig(59, 39, TILE_WATER) world_dig(60, 38, TILE_WATER) world_dig(60, 39, TILE_WATER) world_dig(61, 38, TILE_WATER) world_dig(61, 39, TILE_WATER) world_dig(62, 38, TILE_WATER) world_dig(62, 39, TILE_WATER) world_dig(62, 40, TILE_WATER) world_dig(44, 26, TILE_WATER) world_dig(44, 27, TILE_WATER) world_dig(43, 26, TILE_WATER) world_dig(43, 27, TILE_WATER) world_dig(42, 26, TILE_WATER) world_dig(42, 27, TILE_WATER) world_dig(41, 26, TILE_WATER) world_dig(41, 27, TILE_WATER) world_dig(40, 26, TILE_WATER) world_dig(40, 27, TILE_WATER) world_dig(40, 28, TILE_WATER) world_dig(41, 28, TILE_WATER) world_dig(38, 27, TILE_WATER) world_dig(39, 27, TILE_WATER) world_dig(38, 28, TILE_WATER) world_dig(39, 28, TILE_WATER) world_dig(37, 27, TILE_WATER) world_dig(37, 28, TILE_WATER) world_dig(36, 27, TILE_WATER) world_dig(36, 28, TILE_WATER) world_dig(34, 27, TILE_WATER) world_dig(35, 27, TILE_WATER) world_dig(34, 28, TILE_WATER) world_dig(35, 28, TILE_WATER) world_dig(33, 27, TILE_WATER) world_dig(33, 28, TILE_WATER) world_dig(31, 27, TILE_WATER) world_dig(32, 27, TILE_WATER) world_dig(31, 28, TILE_WATER) world_dig(32, 28, TILE_WATER) world_dig(30, 27, TILE_WATER) world_dig(30, 28, TILE_WATER) world_dig(28, 27, TILE_WATER) world_dig(29, 27, TILE_WATER) world_dig(28, 28, TILE_WATER) world_dig(29, 28, TILE_WATER) world_dig(26, 27, TILE_WATER) world_dig(27, 27, TILE_WATER) world_dig(26, 28, TILE_WATER) world_dig(27, 28, TILE_WATER) world_dig(25, 27, TILE_WATER) world_dig(25, 28, TILE_WATER) world_dig(23, 27, TILE_WATER) world_dig(24, 27, TILE_WATER) world_dig(23, 28, TILE_WATER) world_dig(24, 28, TILE_WATER) world_dig(22, 27, TILE_WATER) world_dig(22, 28, TILE_WATER) world_dig(20, 27, TILE_WATER) world_dig(21, 27, TILE_WATER) world_dig(20, 28, TILE_WATER) world_dig(21, 28, TILE_WATER) world_dig(19, 27, TILE_WATER) world_dig(19, 28, TILE_WATER) world_dig(18, 27, TILE_WATER) world_dig(18, 28, TILE_WATER) world_dig(17, 27, TILE_WATER) world_dig(17, 28, TILE_WATER) world_dig(16, 27, TILE_WATER) world_dig(16, 28, TILE_WATER) world_dig(15, 27, TILE_WATER) world_dig(15, 28, TILE_WATER) world_dig(14, 27, TILE_WATER) world_dig(14, 28, TILE_WATER) world_dig(13, 27, TILE_WATER) world_dig(13, 28, TILE_WATER) world_dig(12, 27, TILE_WATER) world_dig(12, 28, TILE_WATER) world_dig(11, 27, TILE_WATER) world_dig(11, 28, TILE_WATER) world_dig(10, 27, TILE_WATER) world_dig(10, 28, TILE_WATER) world_dig(9, 27, TILE_WATER) world_dig(9, 28, TILE_WATER) world_dig(8, 27, TILE_WATER) world_dig(8, 28, TILE_WATER) world_dig(7, 27, TILE_WATER) world_dig(7, 28, TILE_WATER) world_dig(6, 27, TILE_WATER) world_dig(6, 28, TILE_WATER) world_dig(5, 27, TILE_WATER) world_dig(5, 28, TILE_WATER) world_dig(4, 27, TILE_WATER) world_dig(4, 28, TILE_WATER) world_dig(3, 27, TILE_WATER) world_dig(3, 28, TILE_WATER) world_dig(2, 27, TILE_WATER) world_dig(2, 28, TILE_WATER) world_dig(1, 27, TILE_WATER) world_dig(1, 28, TILE_WATER) world_dig(1, 26, TILE_WATER) world_dig(2, 26, TILE_WATER) world_dig(1, 25, TILE_WATER) world_dig(2, 25, TILE_WATER) world_dig(3, 25, TILE_WATER) world_dig(3, 26, TILE_WATER) world_dig(2, 24, TILE_WATER) world_dig(3, 24, TILE_WATER) world_dig(4, 24, TILE_WATER) world_dig(4, 25, TILE_WATER) world_dig(3, 23, TILE_WATER) world_dig(4, 23, TILE_WATER) world_dig(5, 23, TILE_WATER) world_dig(5, 24, TILE_WATER) world_dig(4, 22, TILE_WATER) world_dig(5, 22, TILE_WATER) world_dig(3, 22, TILE_WATER) world_dig(2, 22, TILE_WATER) world_dig(2, 23, TILE_WATER) world_dig(1, 22, TILE_WATER) world_dig(1, 23, TILE_WATER) world_dig(1, 21, TILE_WATER) world_dig(2, 21, TILE_WATER) world_dig(1, 20, TILE_WATER) world_dig(2, 20, TILE_WATER) world_dig(1, 19, TILE_WATER) world_dig(2, 19, TILE_WATER) world_dig(1, 18, TILE_WATER) world_dig(2, 18, TILE_WATER) world_dig(1, 17, TILE_WATER) world_dig(2, 17, TILE_WATER) world_dig(3, 17, TILE_WATER) world_dig(3, 18, TILE_WATER) world_dig(1, 16, TILE_WATER) world_dig(2, 16, TILE_WATER) world_dig(3, 16, TILE_WATER) world_dig(4, 16, TILE_WATER) world_dig(4, 17, TILE_WATER) world_dig(5, 16, TILE_WATER) world_dig(5, 17, TILE_WATER) world_dig(6, 16, TILE_WATER) world_dig(6, 17, TILE_WATER) world_dig(7, 16, TILE_WATER) world_dig(7, 17, TILE_WATER) world_dig(8, 16, TILE_WATER) world_dig(8, 17, TILE_WATER) world_dig(9, 16, TILE_WATER) world_dig(9, 17, TILE_WATER) world_dig(10, 16, TILE_WATER) world_dig(10, 17, TILE_WATER) world_dig(11, 16, TILE_WATER) world_dig(11, 17, TILE_WATER) world_dig(12, 16, TILE_WATER) world_dig(12, 17, TILE_WATER) world_dig(13, 16, TILE_WATER) world_dig(13, 17, TILE_WATER) world_dig(14, 16, TILE_WATER) world_dig(14, 17, TILE_WATER) world_dig(15, 16, TILE_WATER) world_dig(15, 17, TILE_WATER) world_dig(16, 16, TILE_WATER) world_dig(16, 17, TILE_WATER) world_dig(17, 16, TILE_WATER) world_dig(17, 17, TILE_WATER) world_dig(18, 16, TILE_WATER) world_dig(18, 17, TILE_WATER) world_dig(19, 16, TILE_WATER) world_dig(19, 17, TILE_WATER) world_dig(20, 16, TILE_WATER) world_dig(20, 17, TILE_WATER) world_dig(21, 16, TILE_WATER) world_dig(21, 17, TILE_WATER) world_dig(22, 16, TILE_WATER) world_dig(22, 17, TILE_WATER) world_dig(23, 16, TILE_WATER) world_dig(23, 17, TILE_WATER) world_dig(24, 16, TILE_WATER) world_dig(24, 17, TILE_WATER) world_dig(25, 16, TILE_WATER) world_dig(25, 17, TILE_WATER) world_dig(26, 16, TILE_WATER) world_dig(26, 17, TILE_WATER) world_dig(27, 16, TILE_WATER) world_dig(27, 17, TILE_WATER) world_dig(28, 16, TILE_WATER) world_dig(28, 17, TILE_WATER) world_dig(29, 16, TILE_WATER) world_dig(29, 17, TILE_WATER) world_dig(30, 16, TILE_WATER) world_dig(30, 17, TILE_WATER) world_dig(31, 16, TILE_WATER) world_dig(31, 17, TILE_WATER) world_dig(32, 16, TILE_WATER) world_dig(32, 17, TILE_WATER) world_dig(33, 16, TILE_WATER) world_dig(33, 17, TILE_WATER) world_dig(34, 16, TILE_WATER) world_dig(34, 17, TILE_WATER) world_dig(35, 16, TILE_WATER) world_dig(35, 17, TILE_WATER) world_dig(36, 16, TILE_WATER) world_dig(36, 17, TILE_WATER) world_dig(37, 16, TILE_WATER) world_dig(37, 17, TILE_WATER) world_dig(38, 16, TILE_WATER) world_dig(38, 17, TILE_WATER) world_dig(39, 16, TILE_WATER) world_dig(39, 17, TILE_WATER) world_dig(40, 16, TILE_WATER) world_dig(40, 17, TILE_WATER) world_dig(41, 16, TILE_WATER) world_dig(41, 17, TILE_WATER) world_dig(42, 16, TILE_WATER) world_dig(42, 17, TILE_WATER) world_dig(43, 16, TILE_WATER) world_dig(43, 17, TILE_WATER) world_dig(44, 16, TILE_WATER) world_dig(44, 17, TILE_WATER) world_dig(43, 18, TILE_WATER) world_dig(44, 18, TILE_WATER) world_dig(43, 19, TILE_WATER) world_dig(44, 19, TILE_WATER) world_dig(44, 20, TILE_WATER) world_dig(44, 21, TILE_WATER) world_dig(44, 22, TILE_WATER) world_dig(44, 23, TILE_WATER) world_dig(44, 24, TILE_WATER) world_dig(44, 25, TILE_WATER) world_dig(43, 24, TILE_WATER) world_dig(43, 25, TILE_WATER) world_dig(42, 25, TILE_WATER) world_dig(41, 25, TILE_WATER) world_dig(40, 25, TILE_WATER) world_dig(39, 25, TILE_WATER) world_dig(39, 26, TILE_WATER) world_dig(38, 25, TILE_WATER) world_dig(38, 26, TILE_WATER) world_dig(37, 25, TILE_WATER) world_dig(37, 26, TILE_WATER) world_dig(36, 25, TILE_WATER) world_dig(36, 26, TILE_WATER) world_dig(35, 26, TILE_WATER) world_dig(34, 26, TILE_WATER) world_dig(33, 26, TILE_WATER) world_dig(32, 26, TILE_WATER) world_dig(31, 26, TILE_WATER) world_dig(30, 25, TILE_WATER) world_dig(31, 25, TILE_WATER) world_dig(30, 26, TILE_WATER) world_dig(29, 25, TILE_WATER) world_dig(29, 26, TILE_WATER) world_dig(28, 25, TILE_WATER) world_dig(28, 26, TILE_WATER) world_dig(27, 25, TILE_WATER) world_dig(27, 26, TILE_WATER) world_dig(26, 25, TILE_WATER) world_dig(26, 26, TILE_WATER) world_dig(25, 25, TILE_WATER) world_dig(25, 26, TILE_WATER) world_dig(24, 25, TILE_WATER) world_dig(24, 26, TILE_WATER) world_dig(23, 25, TILE_WATER) world_dig(23, 26, TILE_WATER) world_dig(22, 25, TILE_WATER) world_dig(22, 26, TILE_WATER) world_dig(21, 25, TILE_WATER) world_dig(21, 26, TILE_WATER) world_dig(20, 25, TILE_WATER) world_dig(20, 26, TILE_WATER) world_dig(19, 25, TILE_WATER) world_dig(19, 26, TILE_WATER) world_dig(18, 25, TILE_WATER) world_dig(18, 26, TILE_WATER) world_dig(17, 25, TILE_WATER) world_dig(17, 26, TILE_WATER) world_dig(16, 25, TILE_WATER) world_dig(16, 26, TILE_WATER) world_dig(15, 25, TILE_WATER) world_dig(15, 26, TILE_WATER) world_dig(14, 25, TILE_WATER) world_dig(14, 26, TILE_WATER) world_dig(12, 25, TILE_WATER) world_dig(13, 25, TILE_WATER) world_dig(12, 26, TILE_WATER) world_dig(13, 26, TILE_WATER) world_dig(11, 25, TILE_WATER) world_dig(11, 26, TILE_WATER) world_dig(10, 25, TILE_WATER) world_dig(10, 26, TILE_WATER) world_dig(9, 24, TILE_WATER) world_dig(10, 24, TILE_WATER) world_dig(9, 25, TILE_WATER) world_dig(7, 24, TILE_WATER) world_dig(8, 24, TILE_WATER) world_dig(7, 25, TILE_WATER) world_dig(8, 25, TILE_WATER) world_dig(6, 24, TILE_WATER) world_dig(6, 25, TILE_WATER) world_dig(5, 25, TILE_WATER) world_dig(1, 24, TILE_WATER) world_dig(6, 22, TILE_WATER) world_dig(6, 23, TILE_WATER) world_dig(6, 21, TILE_WATER) world_dig(7, 21, TILE_WATER) world_dig(7, 22, TILE_WATER) world_dig(8, 21, TILE_WATER) world_dig(9, 21, TILE_WATER) world_dig(8, 22, TILE_WATER) world_dig(9, 22, TILE_WATER) world_dig(10, 22, TILE_WATER) world_dig(11, 22, TILE_WATER) world_dig(10, 23, TILE_WATER) world_dig(11, 23, TILE_WATER) world_dig(12, 22, TILE_WATER) world_dig(12, 23, TILE_WATER) world_dig(11, 24, TILE_WATER) world_dig(12, 24, TILE_WATER) world_dig(13, 24, TILE_WATER) world_dig(9, 26, TILE_WATER) world_dig(8, 26, TILE_WATER) world_dig(6, 26, TILE_WATER) world_dig(7, 26, TILE_WATER) world_dig(3, 21, TILE_WATER) world_dig(4, 21, TILE_WATER) world_dig(5, 21, TILE_WATER) world_dig(10, 21, TILE_WATER) world_dig(11, 21, TILE_WATER) world_dig(7, 23, TILE_WATER) world_dig(8, 23, TILE_WATER) world_dig(3, 20, TILE_WATER) world_dig(4, 20, TILE_WATER) world_dig(5, 20, TILE_WATER) world_dig(6, 20, TILE_WATER) world_dig(7, 20, TILE_WATER) world_dig(3, 19, TILE_WATER) world_dig(4, 19, TILE_WATER) world_dig(4, 18, TILE_WATER) world_dig(5, 18, TILE_WATER) world_dig(5, 19, TILE_WATER) world_dig(6, 18, TILE_WATER) world_dig(6, 19, TILE_WATER) world_dig(7, 18, TILE_WATER) world_dig(7, 19, TILE_WATER) world_dig(8, 18, TILE_WATER) world_dig(9, 18, TILE_WATER) world_dig(8, 19, TILE_WATER) world_dig(9, 19, TILE_WATER) world_dig(10, 18, TILE_WATER) world_dig(11, 18, TILE_WATER) world_dig(10, 19, TILE_WATER) world_dig(11, 19, TILE_WATER) world_dig(12, 19, TILE_WATER) world_dig(13, 19, TILE_WATER) world_dig(12, 20, TILE_WATER) world_dig(13, 20, TILE_WATER) world_dig(14, 19, TILE_WATER) world_dig(15, 19, TILE_WATER) world_dig(14, 20, TILE_WATER) world_dig(15, 20, TILE_WATER) world_dig(16, 19, TILE_WATER) world_dig(16, 20, TILE_WATER) world_dig(17, 19, TILE_WATER) world_dig(17, 20, TILE_WATER) world_dig(15, 21, TILE_WATER) world_dig(16, 21, TILE_WATER) world_dig(14, 21, TILE_WATER) world_dig(12, 21, TILE_WATER) world_dig(13, 21, TILE_WATER) world_dig(10, 20, TILE_WATER) world_dig(11, 20, TILE_WATER) world_dig(9, 20, TILE_WATER) world_dig(8, 20, TILE_WATER) world_dig(13, 18, TILE_WATER) world_dig(14, 18, TILE_WATER) world_dig(15, 18, TILE_WATER) world_dig(16, 18, TILE_WATER) world_dig(17, 18, TILE_WATER) world_dig(18, 18, TILE_WATER) world_dig(18, 19, TILE_WATER) world_dig(19, 18, TILE_WATER) world_dig(20, 18, TILE_WATER) world_dig(19, 19, TILE_WATER) world_dig(20, 19, TILE_WATER) world_dig(21, 18, TILE_WATER) world_dig(21, 19, TILE_WATER) world_dig(22, 18, TILE_WATER) world_dig(22, 19, TILE_WATER) world_dig(20, 20, TILE_WATER) world_dig(21, 20, TILE_WATER) world_dig(19, 20, TILE_WATER) world_dig(18, 20, TILE_WATER) world_dig(17, 21, TILE_WATER) world_dig(18, 21, TILE_WATER) world_dig(19, 21, TILE_WATER) world_dig(20, 21, TILE_WATER) world_dig(22, 20, TILE_WATER) world_dig(21, 21, TILE_WATER) world_dig(22, 21, TILE_WATER) world_dig(23, 20, TILE_WATER) world_dig(24, 20, TILE_WATER) world_dig(23, 21, TILE_WATER) world_dig(24, 21, TILE_WATER) world_dig(25, 20, TILE_WATER) world_dig(26, 20, TILE_WATER) world_dig(25, 21, TILE_WATER) world_dig(26, 21, TILE_WATER) world_dig(24, 22, TILE_WATER) world_dig(25, 22, TILE_WATER) world_dig(23, 22, TILE_WATER) world_dig(23, 23, TILE_WATER) world_dig(24, 23, TILE_WATER) world_dig(21, 22, TILE_WATER) world_dig(22, 22, TILE_WATER) world_dig(21, 23, TILE_WATER) world_dig(22, 23, TILE_WATER) world_dig(19, 23, TILE_WATER) world_dig(20, 23, TILE_WATER) world_dig(19, 24, TILE_WATER) world_dig(20, 24, TILE_WATER) world_dig(16, 23, TILE_WATER) world_dig(17, 23, TILE_WATER) world_dig(16, 24, TILE_WATER) world_dig(17, 24, TILE_WATER) world_dig(14, 23, TILE_WATER) world_dig(15, 23, TILE_WATER) world_dig(14, 24, TILE_WATER) world_dig(15, 24, TILE_WATER) world_dig(13, 23, TILE_WATER) world_dig(13, 22, TILE_WATER) world_dig(14, 22, TILE_WATER) world_dig(15, 22, TILE_WATER) world_dig(16, 22, TILE_WATER) world_dig(18, 22, TILE_WATER) world_dig(19, 22, TILE_WATER) world_dig(18, 23, TILE_WATER) world_dig(26, 22, TILE_WATER) world_dig(27, 21, TILE_WATER) world_dig(28, 21, TILE_WATER) world_dig(27, 22, TILE_WATER) world_dig(28, 22, TILE_WATER) world_dig(29, 21, TILE_WATER) world_dig(29, 22, TILE_WATER) world_dig(30, 22, TILE_WATER) world_dig(29, 23, TILE_WATER) world_dig(30, 23, TILE_WATER) world_dig(28, 23, TILE_WATER) world_dig(27, 23, TILE_WATER) world_dig(27, 24, TILE_WATER) world_dig(28, 24, TILE_WATER) world_dig(26, 24, TILE_WATER) world_dig(24, 24, TILE_WATER) world_dig(25, 24, TILE_WATER) world_dig(21, 24, TILE_WATER) world_dig(22, 24, TILE_WATER) world_dig(18, 24, TILE_WATER) world_dig(25, 23, TILE_WATER) world_dig(26, 23, TILE_WATER) world_dig(32, 22, TILE_WATER) world_dig(33, 22, TILE_WATER) world_dig(33, 23, TILE_WATER) world_dig(34, 22, TILE_WATER) world_dig(35, 22, TILE_WATER) world_dig(34, 23, TILE_WATER) world_dig(35, 23, TILE_WATER) world_dig(36, 22, TILE_WATER) world_dig(37, 22, TILE_WATER) world_dig(36, 23, TILE_WATER) world_dig(37, 23, TILE_WATER) world_dig(34, 24, TILE_WATER) world_dig(35, 24, TILE_WATER) world_dig(32, 24, TILE_WATER) world_dig(33, 24, TILE_WATER) world_dig(30, 24, TILE_WATER) world_dig(31, 24, TILE_WATER) world_dig(29, 24, TILE_WATER) world_dig(31, 23, TILE_WATER) world_dig(36, 24, TILE_WATER) world_dig(37, 24, TILE_WATER) world_dig(38, 23, TILE_WATER) world_dig(38, 24, TILE_WATER) world_dig(39, 23, TILE_WATER) world_dig(39, 24, TILE_WATER) world_dig(32, 25, TILE_WATER) world_dig(33, 25, TILE_WATER) world_dig(35, 25, TILE_WATER) world_dig(34, 25, TILE_WATER) world_dig(38, 22, TILE_WATER) world_dig(39, 22, TILE_WATER) world_dig(40, 22, TILE_WATER) world_dig(41, 22, TILE_WATER) world_dig(40, 23, TILE_WATER) world_dig(41, 23, TILE_WATER) world_dig(40, 21, TILE_WATER) world_dig(41, 21, TILE_WATER) world_dig(42, 21, TILE_WATER) world_dig(42, 22, TILE_WATER) world_dig(42, 20, TILE_WATER) world_dig(43, 20, TILE_WATER) world_dig(43, 21, TILE_WATER) world_dig(43, 22, TILE_WATER) world_dig(42, 23, TILE_WATER) world_dig(40, 24, TILE_WATER) world_dig(41, 24, TILE_WATER) world_dig(41, 20, TILE_WATER) world_dig(38, 21, TILE_WATER) world_dig(39, 21, TILE_WATER) world_dig(37, 21, TILE_WATER) world_dig(36, 21, TILE_WATER) world_dig(35, 21, TILE_WATER) world_dig(35, 20, TILE_WATER) world_dig(36, 20, TILE_WATER) world_dig(36, 19, TILE_WATER) world_dig(37, 19, TILE_WATER) world_dig(37, 20, TILE_WATER) world_dig(37, 18, TILE_WATER) world_dig(38, 18, TILE_WATER) world_dig(38, 19, TILE_WATER) world_dig(39, 18, TILE_WATER) world_dig(40, 18, TILE_WATER) world_dig(39, 19, TILE_WATER) world_dig(40, 19, TILE_WATER) world_dig(41, 18, TILE_WATER) world_dig(42, 18, TILE_WATER) world_dig(41, 19, TILE_WATER) world_dig(42, 19, TILE_WATER) world_dig(40, 20, TILE_WATER) world_dig(39, 20, TILE_WATER) world_dig(34, 21, TILE_WATER) world_dig(33, 20, TILE_WATER) world_dig(34, 20, TILE_WATER) world_dig(33, 21, TILE_WATER) world_dig(32, 20, TILE_WATER) world_dig(32, 21, TILE_WATER) world_dig(32, 19, TILE_WATER) world_dig(33, 19, TILE_WATER) world_dig(34, 19, TILE_WATER) world_dig(34, 18, TILE_WATER) world_dig(35, 18, TILE_WATER) world_dig(35, 19, TILE_WATER) world_dig(36, 18, TILE_WATER) world_dig(38, 20, TILE_WATER) world_dig(31, 21, TILE_WATER) world_dig(31, 22, TILE_WATER) world_dig(30, 21, TILE_WATER) world_dig(27, 20, TILE_WATER) world_dig(28, 20, TILE_WATER) world_dig(27, 19, TILE_WATER) world_dig(28, 19, TILE_WATER) world_dig(29, 19, TILE_WATER) world_dig(29, 20, TILE_WATER) world_dig(30, 19, TILE_WATER) world_dig(30, 20, TILE_WATER) world_dig(31, 18, TILE_WATER) world_dig(32, 18, TILE_WATER) world_dig(31, 19, TILE_WATER) world_dig(33, 18, TILE_WATER) world_dig(31, 20, TILE_WATER) world_dig(25, 19, TILE_WATER) world_dig(26, 19, TILE_WATER) world_dig(27, 18, TILE_WATER) world_dig(28, 18, TILE_WATER) world_dig(29, 18, TILE_WATER) world_dig(30, 18, TILE_WATER) world_dig(24, 19, TILE_WATER) world_dig(23, 19, TILE_WATER) world_dig(24, 18, TILE_WATER) world_dig(25, 18, TILE_WATER) world_dig(26, 18, TILE_WATER) world_dig(23, 18, TILE_WATER) world_dig(12, 18, TILE_WATER) world_dig(9, 23, TILE_WATER) world_dig(5, 26, TILE_WATER) world_dig(4, 26, TILE_WATER) world_dig(20, 22, TILE_WATER) world_dig(17, 22, TILE_WATER) world_dig(23, 24, TILE_WATER) world_dig(42, 24, TILE_WATER) world_dig(43, 23, TILE_WATER) world_dig(42, 28, TILE_WATER) world_dig(43, 28, TILE_WATER) world_dig(44, 28, TILE_WATER) world_dig(1, 1, TILE_PLAIN) world_dig(1, 2, TILE_PLAIN) world_dig(1, 3, TILE_PLAIN) world_dig(1, 6, TILE_PLAIN) world_dig(1, 7, TILE_PLAIN) world_dig(1, 8, TILE_PLAIN) world_dig(1, 5, TILE_PLAIN) world_dig(1, 4, TILE_PLAIN) world_dig(1, 9, TILE_PLAIN) world_dig(1, 10, TILE_PLAIN) world_dig(1, 11, TILE_PLAIN) world_dig(1, 12, TILE_PLAIN) world_dig(1, 13, TILE_PLAIN) world_dig(2, 13, TILE_PLAIN) world_dig(3, 13, TILE_PLAIN) world_dig(3, 12, TILE_PLAIN) world_dig(3, 11, TILE_PLAIN) world_dig(3, 10, TILE_PLAIN) world_dig(2, 9, TILE_PLAIN) world_dig(2, 8, TILE_PLAIN) world_dig(3, 8, TILE_PLAIN) world_dig(3, 7, TILE_PLAIN) world_dig(2, 7, TILE_PLAIN) world_dig(2, 6, TILE_PLAIN) world_dig(2, 5, TILE_PLAIN) world_dig(2, 4, TILE_PLAIN) world_dig(3, 4, TILE_PLAIN) world_dig(4, 4, TILE_PLAIN) world_dig(4, 5, TILE_PLAIN) world_dig(5, 5, TILE_PLAIN) world_dig(5, 6, TILE_PLAIN) world_dig(6, 6, TILE_PLAIN) world_dig(6, 5, TILE_PLAIN) world_dig(7, 5, TILE_PLAIN) world_dig(7, 4, TILE_PLAIN) world_dig(6, 4, TILE_PLAIN) world_dig(5, 4, TILE_PLAIN) world_dig(4, 3, TILE_PLAIN) world_dig(5, 3, TILE_PLAIN) world_dig(8, 6, TILE_PLAIN) world_dig(8, 7, TILE_PLAIN) world_dig(8, 8, TILE_PLAIN) world_dig(9, 8, TILE_PLAIN) world_dig(7, 7, TILE_PLAIN) world_dig(7, 6, TILE_PLAIN) world_dig(9, 9, TILE_PLAIN) world_dig(9, 10, TILE_PLAIN) world_dig(8, 10, TILE_PLAIN) world_dig(7, 10, TILE_PLAIN) world_dig(7, 11, TILE_PLAIN) world_dig(6, 11, TILE_PLAIN) world_dig(5, 11, TILE_PLAIN) world_dig(4, 11, TILE_PLAIN) world_dig(4, 12, TILE_PLAIN) world_dig(5, 12, TILE_PLAIN) world_dig(6, 12, TILE_PLAIN) world_dig(8, 11, TILE_PLAIN) world_dig(10, 10, TILE_PLAIN) world_dig(8, 5, TILE_PLAIN) world_dig(9, 5, TILE_PLAIN) world_dig(9, 6, TILE_PLAIN) world_dig(8, 4, TILE_PLAIN) world_dig(9, 4, TILE_PLAIN) world_dig(10, 4, TILE_PLAIN) world_dig(10, 5, TILE_PLAIN) world_dig(9, 3, TILE_PLAIN) world_dig(10, 3, TILE_PLAIN) world_dig(11, 3, TILE_PLAIN) world_dig(11, 4, TILE_PLAIN) world_dig(12, 3, TILE_PLAIN) world_dig(12, 4, TILE_PLAIN) world_dig(13, 3, TILE_PLAIN) world_dig(13, 4, TILE_PLAIN) world_dig(14, 3, TILE_PLAIN) world_dig(14, 4, TILE_PLAIN) world_dig(15, 3, TILE_PLAIN) world_dig(15, 4, TILE_PLAIN) world_dig(16, 4, TILE_PLAIN) world_dig(15, 5, TILE_PLAIN) world_dig(16, 5, TILE_PLAIN) world_dig(15, 6, TILE_PLAIN) world_dig(16, 6, TILE_PLAIN) world_dig(17, 5, TILE_PLAIN) world_dig(17, 6, TILE_PLAIN) world_dig(16, 7, TILE_PLAIN) world_dig(17, 7, TILE_PLAIN) world_dig(16, 8, TILE_PLAIN) world_dig(17, 8, TILE_PLAIN) world_dig(11, 11, TILE_PLAIN) world_dig(12, 11, TILE_PLAIN) world_dig(11, 12, TILE_PLAIN) world_dig(12, 12, TILE_PLAIN) world_dig(10, 11, TILE_PLAIN) world_dig(10, 12, TILE_PLAIN) world_dig(13, 12, TILE_PLAIN) world_dig(12, 13, TILE_PLAIN) world_dig(13, 13, TILE_PLAIN) world_dig(14, 12, TILE_PLAIN) world_dig(14, 13, TILE_PLAIN) world_dig(13, 14, TILE_PLAIN) world_dig(14, 14, TILE_PLAIN) world_dig(15, 13, TILE_PLAIN) world_dig(15, 14, TILE_PLAIN) world_dig(16, 13, TILE_PLAIN) world_dig(17, 13, TILE_PLAIN) world_dig(16, 14, TILE_PLAIN) world_dig(17, 14, TILE_PLAIN) world_dig(16, 12, TILE_PLAIN) world_dig(17, 12, TILE_PLAIN) world_dig(18, 12, TILE_PLAIN) world_dig(18, 13, TILE_PLAIN) world_dig(17, 11, TILE_PLAIN) world_dig(18, 11, TILE_PLAIN) world_dig(17, 10, TILE_PLAIN) world_dig(18, 10, TILE_PLAIN) world_dig(19, 10, TILE_PLAIN) world_dig(19, 11, TILE_PLAIN) world_dig(18, 9, TILE_PLAIN) world_dig(19, 9, TILE_PLAIN) world_dig(20, 9, TILE_PLAIN) world_dig(20, 10, TILE_PLAIN) world_dig(21, 9, TILE_PLAIN) world_dig(21, 10, TILE_PLAIN) world_dig(17, 4, TILE_PLAIN) world_dig(18, 4, TILE_PLAIN) world_dig(18, 5, TILE_PLAIN) world_dig(19, 4, TILE_PLAIN) world_dig(19, 5, TILE_PLAIN) world_dig(20, 4, TILE_PLAIN) world_dig(20, 5, TILE_PLAIN) world_dig(21, 4, TILE_PLAIN) world_dig(21, 5, TILE_PLAIN) world_dig(22, 4, TILE_PLAIN) world_dig(22, 5, TILE_PLAIN) world_dig(23, 4, TILE_PLAIN) world_dig(23, 5, TILE_PLAIN) world_dig(22, 3, TILE_PLAIN) world_dig(23, 3, TILE_PLAIN) world_dig(22, 2, TILE_PLAIN) world_dig(23, 2, TILE_PLAIN) world_dig(24, 2, TILE_PLAIN) world_dig(24, 3, TILE_PLAIN) world_dig(23, 1, TILE_PLAIN) world_dig(24, 1, TILE_PLAIN) world_dig(25, 1, TILE_PLAIN) world_dig(26, 1, TILE_PLAIN) world_dig(25, 2, TILE_PLAIN) world_dig(26, 2, TILE_PLAIN) world_dig(27, 2, TILE_PLAIN) world_dig(26, 3, TILE_PLAIN) world_dig(27, 3, TILE_PLAIN) world_dig(28, 2, TILE_PLAIN) world_dig(28, 3, TILE_PLAIN) world_dig(27, 4, TILE_PLAIN) world_dig(28, 4, TILE_PLAIN) world_dig(29, 4, TILE_PLAIN) world_dig(28, 5, TILE_PLAIN) world_dig(29, 5, TILE_PLAIN) world_dig(28, 6, TILE_PLAIN) world_dig(29, 6, TILE_PLAIN) world_dig(30, 5, TILE_PLAIN) world_dig(30, 6, TILE_PLAIN) world_dig(29, 7, TILE_PLAIN) world_dig(30, 7, TILE_PLAIN) world_dig(29, 8, TILE_PLAIN) world_dig(30, 8, TILE_PLAIN) world_dig(21, 11, TILE_PLAIN) world_dig(22, 11, TILE_PLAIN) world_dig(21, 12, TILE_PLAIN) world_dig(22, 12, TILE_PLAIN) world_dig(23, 11, TILE_PLAIN) world_dig(23, 12, TILE_PLAIN) world_dig(24, 11, TILE_PLAIN) world_dig(24, 12, TILE_PLAIN) world_dig(25, 11, TILE_PLAIN) world_dig(25, 12, TILE_PLAIN) world_dig(24, 13, TILE_PLAIN) world_dig(25, 13, TILE_PLAIN) world_dig(26, 12, TILE_PLAIN) world_dig(26, 13, TILE_PLAIN) world_dig(29, 12, TILE_PLAIN) world_dig(30, 12, TILE_PLAIN) world_dig(29, 13, TILE_PLAIN) world_dig(30, 13, TILE_PLAIN) world_dig(31, 12, TILE_PLAIN) world_dig(31, 13, TILE_PLAIN) world_dig(30, 11, TILE_PLAIN) world_dig(31, 11, TILE_PLAIN) world_dig(31, 10, TILE_PLAIN) world_dig(32, 10, TILE_PLAIN) world_dig(32, 11, TILE_PLAIN) world_dig(31, 9, TILE_PLAIN) world_dig(32, 9, TILE_PLAIN) world_dig(33, 9, TILE_PLAIN) world_dig(33, 10, TILE_PLAIN) world_dig(32, 8, TILE_PLAIN) world_dig(33, 8, TILE_PLAIN) world_dig(32, 7, TILE_PLAIN) world_dig(33, 7, TILE_PLAIN) world_dig(31, 7, TILE_PLAIN) world_dig(31, 8, TILE_PLAIN) world_dig(31, 6, TILE_PLAIN) world_dig(32, 6, TILE_PLAIN) world_dig(33, 6, TILE_PLAIN) world_dig(32, 5, TILE_PLAIN) world_dig(33, 5, TILE_PLAIN) world_dig(32, 4, TILE_PLAIN) world_dig(33, 4, TILE_PLAIN) world_dig(34, 4, TILE_PLAIN) world_dig(34, 5, TILE_PLAIN) world_dig(35, 4, TILE_PLAIN) world_dig(35, 5, TILE_PLAIN) world_dig(36, 4, TILE_PLAIN) world_dig(36, 5, TILE_PLAIN) world_dig(37, 4, TILE_PLAIN) world_dig(37, 5, TILE_PLAIN) world_dig(36, 6, TILE_PLAIN) world_dig(37, 6, TILE_PLAIN) world_dig(38, 5, TILE_PLAIN) world_dig(38, 6, TILE_PLAIN) world_dig(37, 7, TILE_PLAIN) world_dig(38, 7, TILE_PLAIN) world_dig(39, 6, TILE_PLAIN) world_dig(39, 7, TILE_PLAIN) world_dig(38, 8, TILE_PLAIN) world_dig(39, 8, TILE_PLAIN) world_dig(38, 9, TILE_PLAIN) world_dig(39, 9, TILE_PLAIN) world_dig(40, 8, TILE_PLAIN) world_dig(40, 9, TILE_PLAIN) world_dig(39, 10, TILE_PLAIN) world_dig(40, 10, TILE_PLAIN) world_dig(39, 11, TILE_PLAIN) world_dig(40, 11, TILE_PLAIN) world_dig(38, 14, TILE_PLAIN) world_dig(39, 14, TILE_PLAIN) world_dig(38, 15, TILE_PLAIN) world_dig(39, 15, TILE_PLAIN) world_dig(37, 13, TILE_PLAIN) world_dig(38, 13, TILE_PLAIN) world_dig(37, 14, TILE_PLAIN) world_dig(36, 13, TILE_PLAIN) world_dig(36, 14, TILE_PLAIN) world_dig(36, 12, TILE_PLAIN) world_dig(37, 12, TILE_PLAIN) world_dig(35, 12, TILE_PLAIN) world_dig(35, 13, TILE_PLAIN) world_dig(35, 11, TILE_PLAIN) world_dig(36, 11, TILE_PLAIN) world_dig(34, 11, TILE_PLAIN) world_dig(34, 12, TILE_PLAIN) world_dig(34, 10, TILE_PLAIN) world_dig(35, 10, TILE_PLAIN) world_dig(40, 13, TILE_PLAIN) world_dig(41, 13, TILE_PLAIN) world_dig(40, 14, TILE_PLAIN) world_dig(41, 14, TILE_PLAIN) world_dig(42, 13, TILE_PLAIN) world_dig(42, 14, TILE_PLAIN) world_dig(43, 13, TILE_PLAIN) world_dig(43, 14, TILE_PLAIN) world_dig(42, 12, TILE_PLAIN) world_dig(43, 12, TILE_PLAIN) world_dig(42, 11, TILE_PLAIN) world_dig(43, 11, TILE_PLAIN) world_dig(39, 5, TILE_PLAIN) world_dig(40, 5, TILE_PLAIN) world_dig(40, 6, TILE_PLAIN) world_dig(41, 5, TILE_PLAIN) world_dig(41, 6, TILE_PLAIN) world_dig(40, 4, TILE_PLAIN) world_dig(41, 4, TILE_PLAIN) world_dig(42, 4, TILE_PLAIN) world_dig(42, 5, TILE_PLAIN) world_dig(41, 3, TILE_PLAIN) world_dig(42, 3, TILE_PLAIN) world_dig(43, 3, TILE_PLAIN) world_dig(43, 4, TILE_PLAIN) world_dig(29, 11, TILE_PLAIN) world_dig(28, 11, TILE_PLAIN) world_dig(28, 10, TILE_PLAIN) world_dig(28, 9, TILE_PLAIN) world_dig(27, 9, TILE_PLAIN) world_dig(26, 9, TILE_PLAIN) world_dig(25, 9, TILE_PLAIN) world_dig(25, 10, TILE_PLAIN) world_dig(19, 8, TILE_PLAIN) world_dig(19, 7, TILE_PLAIN) world_dig(18, 7, TILE_PLAIN) world_dig(2, 44, TILE_PLAIN) world_dig(3, 44, TILE_PLAIN) world_dig(2, 43, TILE_PLAIN) world_dig(3, 43, TILE_PLAIN) world_dig(4, 43, TILE_PLAIN) world_dig(4, 44, TILE_PLAIN) world_dig(4, 42, TILE_PLAIN) world_dig(5, 42, TILE_PLAIN) world_dig(5, 43, TILE_PLAIN) world_dig(6, 42, TILE_PLAIN) world_dig(6, 43, TILE_PLAIN) world_dig(5, 41, TILE_PLAIN) world_dig(6, 41, TILE_PLAIN) world_dig(5, 40, TILE_PLAIN) world_dig(6, 40, TILE_PLAIN) world_dig(5, 39, TILE_PLAIN) world_dig(6, 39, TILE_PLAIN) world_dig(4, 39, TILE_PLAIN) world_dig(4, 40, TILE_PLAIN) world_dig(4, 38, TILE_PLAIN) world_dig(5, 38, TILE_PLAIN) world_dig(3, 37, TILE_PLAIN) world_dig(4, 37, TILE_PLAIN) world_dig(3, 38, TILE_PLAIN) world_dig(3, 36, TILE_PLAIN) world_dig(4, 36, TILE_PLAIN) world_dig(2, 36, TILE_PLAIN) world_dig(2, 37, TILE_PLAIN) world_dig(1, 36, TILE_PLAIN) world_dig(1, 37, TILE_PLAIN) world_dig(1, 35, TILE_PLAIN) world_dig(2, 35, TILE_PLAIN) world_dig(1, 34, TILE_PLAIN) world_dig(2, 34, TILE_PLAIN) world_dig(1, 33, TILE_PLAIN) world_dig(2, 33, TILE_PLAIN) world_dig(3, 33, TILE_PLAIN) world_dig(3, 34, TILE_PLAIN) world_dig(2, 32, TILE_PLAIN) world_dig(3, 32, TILE_PLAIN) world_dig(2, 31, TILE_PLAIN) world_dig(3, 31, TILE_PLAIN) world_dig(4, 31, TILE_PLAIN) world_dig(4, 32, TILE_PLAIN) world_dig(5, 31, TILE_PLAIN) world_dig(6, 31, TILE_PLAIN) world_dig(5, 32, TILE_PLAIN) world_dig(6, 32, TILE_PLAIN) world_dig(7, 31, TILE_PLAIN) world_dig(7, 32, TILE_PLAIN) world_dig(8, 31, TILE_PLAIN) world_dig(8, 32, TILE_PLAIN) world_dig(9, 31, TILE_PLAIN) world_dig(9, 32, TILE_PLAIN) world_dig(8, 33, TILE_PLAIN) world_dig(9, 33, TILE_PLAIN) world_dig(10, 32, TILE_PLAIN) world_dig(10, 33, TILE_PLAIN) world_dig(11, 32, TILE_PLAIN) world_dig(11, 33, TILE_PLAIN) world_dig(10, 34, TILE_PLAIN) world_dig(11, 34, TILE_PLAIN) world_dig(10, 35, TILE_PLAIN) world_dig(11, 35, TILE_PLAIN) world_dig(12, 34, TILE_PLAIN) world_dig(12, 35, TILE_PLAIN) world_dig(11, 36, TILE_PLAIN) world_dig(12, 36, TILE_PLAIN) world_dig(11, 37, TILE_PLAIN) world_dig(12, 37, TILE_PLAIN) world_dig(11, 38, TILE_PLAIN) world_dig(12, 38, TILE_PLAIN) world_dig(9, 38, TILE_PLAIN) world_dig(10, 38, TILE_PLAIN) world_dig(9, 39, TILE_PLAIN) world_dig(10, 39, TILE_PLAIN) world_dig(8, 38, TILE_PLAIN) world_dig(8, 39, TILE_PLAIN) world_dig(7, 39, TILE_PLAIN) world_dig(7, 40, TILE_PLAIN) world_dig(8, 40, TILE_PLAIN) world_dig(7, 38, TILE_PLAIN) world_dig(7, 37, TILE_PLAIN) world_dig(8, 37, TILE_PLAIN) world_dig(7, 36, TILE_PLAIN) world_dig(8, 36, TILE_PLAIN) world_dig(9, 36, TILE_PLAIN) world_dig(9, 37, TILE_PLAIN) world_dig(10, 36, TILE_PLAIN) world_dig(10, 37, TILE_PLAIN) world_dig(14, 41, TILE_PLAIN) world_dig(15, 41, TILE_PLAIN) world_dig(14, 42, TILE_PLAIN) world_dig(15, 42, TILE_PLAIN) world_dig(14, 43, TILE_PLAIN) world_dig(15, 43, TILE_PLAIN) world_dig(16, 43, TILE_PLAIN) world_dig(15, 44, TILE_PLAIN) world_dig(16, 44, TILE_PLAIN) world_dig(16, 42, TILE_PLAIN) world_dig(13, 41, TILE_PLAIN) world_dig(13, 42, TILE_PLAIN) world_dig(13, 40, TILE_PLAIN) world_dig(14, 40, TILE_PLAIN) world_dig(12, 40, TILE_PLAIN) world_dig(12, 41, TILE_PLAIN) world_dig(12, 39, TILE_PLAIN) world_dig(13, 39, TILE_PLAIN) world_dig(11, 41, TILE_PLAIN) world_dig(11, 42, TILE_PLAIN) world_dig(12, 42, TILE_PLAIN) world_dig(11, 43, TILE_PLAIN) world_dig(12, 43, TILE_PLAIN) world_dig(13, 43, TILE_PLAIN) world_dig(15, 37, TILE_PLAIN) world_dig(16, 37, TILE_PLAIN) world_dig(15, 38, TILE_PLAIN) world_dig(16, 38, TILE_PLAIN) world_dig(16, 36, TILE_PLAIN) world_dig(17, 36, TILE_PLAIN) world_dig(17, 37, TILE_PLAIN) world_dig(16, 35, TILE_PLAIN) world_dig(17, 35, TILE_PLAIN) world_dig(18, 35, TILE_PLAIN) world_dig(18, 36, TILE_PLAIN) world_dig(17, 34, TILE_PLAIN) world_dig(18, 34, TILE_PLAIN) world_dig(19, 34, TILE_PLAIN) world_dig(19, 35, TILE_PLAIN) world_dig(20, 34, TILE_PLAIN) world_dig(20, 35, TILE_PLAIN) world_dig(21, 34, TILE_PLAIN) world_dig(21, 35, TILE_PLAIN) world_dig(22, 34, TILE_PLAIN) world_dig(22, 35, TILE_PLAIN) world_dig(12, 33, TILE_PLAIN) world_dig(13, 33, TILE_PLAIN) world_dig(13, 34, TILE_PLAIN) world_dig(12, 32, TILE_PLAIN) world_dig(13, 32, TILE_PLAIN) world_dig(14, 32, TILE_PLAIN) world_dig(14, 33, TILE_PLAIN) world_dig(15, 33, TILE_PLAIN) world_dig(14, 34, TILE_PLAIN) world_dig(15, 34, TILE_PLAIN) world_dig(16, 33, TILE_PLAIN) world_dig(16, 34, TILE_PLAIN) world_dig(17, 33, TILE_PLAIN) world_dig(18, 33, TILE_PLAIN) world_dig(19, 33, TILE_PLAIN) world_dig(23, 33, TILE_PLAIN) world_dig(24, 33, TILE_PLAIN) world_dig(23, 34, TILE_PLAIN) world_dig(24, 34, TILE_PLAIN) world_dig(25, 33, TILE_PLAIN) world_dig(25, 34, TILE_PLAIN) world_dig(24, 35, TILE_PLAIN) world_dig(25, 35, TILE_PLAIN) world_dig(26, 34, TILE_PLAIN) world_dig(26, 35, TILE_PLAIN) world_dig(27, 35, TILE_PLAIN) world_dig(26, 36, TILE_PLAIN) world_dig(27, 36, TILE_PLAIN) world_dig(28, 36, TILE_PLAIN) world_dig(27, 37, TILE_PLAIN) world_dig(28, 37, TILE_PLAIN) world_dig(27, 38, TILE_PLAIN) world_dig(28, 38, TILE_PLAIN) world_dig(29, 37, TILE_PLAIN) world_dig(29, 38, TILE_PLAIN) world_dig(28, 39, TILE_PLAIN) world_dig(29, 39, TILE_PLAIN) world_dig(30, 38, TILE_PLAIN) world_dig(30, 39, TILE_PLAIN) world_dig(29, 40, TILE_PLAIN) world_dig(30, 40, TILE_PLAIN) world_dig(27, 39, TILE_PLAIN) world_dig(26, 38, TILE_PLAIN) world_dig(26, 39, TILE_PLAIN) world_dig(25, 38, TILE_PLAIN) world_dig(25, 39, TILE_PLAIN) world_dig(24, 39, TILE_PLAIN) world_dig(24, 40, TILE_PLAIN) world_dig(25, 40, TILE_PLAIN) world_dig(23, 39, TILE_PLAIN) world_dig(23, 40, TILE_PLAIN) world_dig(22, 39, TILE_PLAIN) world_dig(22, 40, TILE_PLAIN) world_dig(21, 40, TILE_PLAIN) world_dig(21, 41, TILE_PLAIN) world_dig(22, 41, TILE_PLAIN) world_dig(20, 40, TILE_PLAIN) world_dig(20, 41, TILE_PLAIN) world_dig(18, 37, TILE_PLAIN) world_dig(17, 38, TILE_PLAIN) world_dig(18, 38, TILE_PLAIN) world_dig(17, 39, TILE_PLAIN) world_dig(18, 39, TILE_PLAIN) world_dig(19, 39, TILE_PLAIN) world_dig(18, 40, TILE_PLAIN) world_dig(19, 40, TILE_PLAIN) world_dig(18, 41, TILE_PLAIN) world_dig(19, 41, TILE_PLAIN) world_dig(19, 42, TILE_PLAIN) world_dig(20, 42, TILE_PLAIN) world_dig(21, 42, TILE_PLAIN) world_dig(20, 43, TILE_PLAIN) world_dig(21, 43, TILE_PLAIN) world_dig(22, 42, TILE_PLAIN) world_dig(22, 43, TILE_PLAIN) world_dig(27, 43, TILE_PLAIN) world_dig(28, 43, TILE_PLAIN) world_dig(27, 44, TILE_PLAIN) world_dig(28, 44, TILE_PLAIN) world_dig(29, 44, TILE_PLAIN) world_dig(30, 44, TILE_PLAIN) world_dig(31, 44, TILE_PLAIN) world_dig(32, 44, TILE_PLAIN) world_dig(33, 44, TILE_PLAIN) world_dig(34, 44, TILE_PLAIN) world_dig(33, 43, TILE_PLAIN) world_dig(34, 43, TILE_PLAIN) world_dig(33, 42, TILE_PLAIN) world_dig(34, 42, TILE_PLAIN) world_dig(33, 41, TILE_PLAIN) world_dig(34, 41, TILE_PLAIN) world_dig(32, 41, TILE_PLAIN) world_dig(32, 42, TILE_PLAIN) world_dig(32, 40, TILE_PLAIN) world_dig(33, 40, TILE_PLAIN) world_dig(31, 40, TILE_PLAIN) world_dig(31, 41, TILE_PLAIN) world_dig(31, 39, TILE_PLAIN) world_dig(32, 39, TILE_PLAIN) world_dig(31, 38, TILE_PLAIN) world_dig(31, 36, TILE_PLAIN) world_dig(32, 36, TILE_PLAIN) world_dig(31, 37, TILE_PLAIN) world_dig(32, 37, TILE_PLAIN) world_dig(31, 35, TILE_PLAIN) world_dig(32, 35, TILE_PLAIN) world_dig(33, 35, TILE_PLAIN) world_dig(33, 36, TILE_PLAIN) world_dig(33, 34, TILE_PLAIN) world_dig(34, 34, TILE_PLAIN) world_dig(34, 35, TILE_PLAIN) world_dig(35, 34, TILE_PLAIN) world_dig(35, 35, TILE_PLAIN) world_dig(35, 33, TILE_PLAIN) world_dig(36, 33, TILE_PLAIN) world_dig(36, 34, TILE_PLAIN) world_dig(35, 32, TILE_PLAIN) world_dig(36, 32, TILE_PLAIN) world_dig(34, 32, TILE_PLAIN) world_dig(34, 33, TILE_PLAIN) world_dig(33, 32, TILE_PLAIN) world_dig(33, 33, TILE_PLAIN) world_dig(32, 31, TILE_PLAIN) world_dig(33, 31, TILE_PLAIN) world_dig(32, 32, TILE_PLAIN) world_dig(31, 31, TILE_PLAIN) world_dig(31, 32, TILE_PLAIN) world_dig(30, 31, TILE_PLAIN) world_dig(30, 32, TILE_PLAIN) world_dig(30, 30, TILE_PLAIN) world_dig(31, 30, TILE_PLAIN) world_dig(36, 30, TILE_PLAIN) world_dig(37, 30, TILE_PLAIN) world_dig(36, 31, TILE_PLAIN) world_dig(37, 31, TILE_PLAIN) world_dig(38, 30, TILE_PLAIN) world_dig(38, 31, TILE_PLAIN) world_dig(39, 30, TILE_PLAIN) world_dig(39, 31, TILE_PLAIN) world_dig(40, 30, TILE_PLAIN) world_dig(40, 31, TILE_PLAIN) world_dig(39, 29, TILE_PLAIN) world_dig(40, 29, TILE_PLAIN) world_dig(40, 15, TILE_PLAIN) world_dig(41, 15, TILE_PLAIN) world_dig(42, 15, TILE_PLAIN) world_dig(43, 15, TILE_PLAIN) world_dig(44, 14, TILE_PLAIN) world_dig(44, 15, TILE_PLAIN) world_dig(44, 13, TILE_PLAIN) world_dig(44, 12, TILE_PLAIN) world_dig(44, 11, TILE_PLAIN) world_dig(41, 31, TILE_PLAIN) world_dig(40, 32, TILE_PLAIN) world_dig(41, 32, TILE_PLAIN) world_dig(42, 32, TILE_PLAIN) world_dig(41, 33, TILE_PLAIN) world_dig(42, 33, TILE_PLAIN) world_dig(43, 32, TILE_PLAIN) world_dig(43, 33, TILE_PLAIN) world_dig(42, 31, TILE_PLAIN) world_dig(43, 31, TILE_PLAIN) world_dig(42, 30, TILE_PLAIN) world_dig(43, 30, TILE_PLAIN) world_dig(41, 30, TILE_PLAIN) world_dig(41, 29, TILE_PLAIN) world_dig(42, 29, TILE_PLAIN) world_dig(43, 29, TILE_PLAIN) world_dig(44, 29, TILE_PLAIN) world_dig(44, 30, TILE_PLAIN) world_dig(44, 31, TILE_PLAIN) world_dig(44, 32, TILE_PLAIN) world_dig(44, 33, TILE_PLAIN) world_dig(37, 36, TILE_PLAIN) world_dig(38, 36, TILE_PLAIN) world_dig(37, 37, TILE_PLAIN) world_dig(38, 37, TILE_PLAIN) world_dig(37, 35, TILE_PLAIN) world_dig(38, 35, TILE_PLAIN) world_dig(39, 35, TILE_PLAIN) world_dig(39, 36, TILE_PLAIN) world_dig(40, 35, TILE_PLAIN) world_dig(40, 36, TILE_PLAIN) world_dig(39, 37, TILE_PLAIN) world_dig(40, 37, TILE_PLAIN) world_dig(41, 36, TILE_PLAIN) world_dig(41, 37, TILE_PLAIN) world_dig(40, 38, TILE_PLAIN) world_dig(41, 38, TILE_PLAIN) world_dig(40, 39, TILE_PLAIN) world_dig(41, 39, TILE_PLAIN) world_dig(40, 40, TILE_PLAIN) world_dig(41, 40, TILE_PLAIN) world_dig(40, 41, TILE_PLAIN) world_dig(41, 41, TILE_PLAIN) world_dig(42, 40, TILE_PLAIN) world_dig(42, 41, TILE_PLAIN) world_dig(41, 42, TILE_PLAIN) world_dig(42, 42, TILE_PLAIN) world_dig(43, 41, TILE_PLAIN) world_dig(43, 42, TILE_PLAIN) world_dig(42, 43, TILE_PLAIN) world_dig(43, 43, TILE_PLAIN) world_dig(41, 43, TILE_PLAIN) world_dig(41, 44, TILE_PLAIN) world_dig(42, 44, TILE_PLAIN) world_dig(40, 44, TILE_PLAIN) world_dig(40, 43, TILE_PLAIN) world_dig(39, 43, TILE_PLAIN) world_dig(39, 44, TILE_PLAIN) world_dig(39, 42, TILE_PLAIN) world_dig(40, 42, TILE_PLAIN) world_dig(39, 41, TILE_PLAIN) world_dig(39, 40, TILE_PLAIN) world_dig(38, 40, TILE_PLAIN) world_dig(38, 41, TILE_PLAIN) world_dig(38, 39, TILE_PLAIN) world_dig(39, 39, TILE_PLAIN) world_dig(37, 39, TILE_PLAIN) world_dig(37, 40, TILE_PLAIN) world_dig(36, 39, TILE_PLAIN) world_dig(36, 40, TILE_PLAIN) world_dig(35, 39, TILE_PLAIN) world_dig(35, 40, TILE_PLAIN) world_dig(34, 39, TILE_PLAIN) world_dig(34, 40, TILE_PLAIN) world_dig(33, 39, TILE_PLAIN) world_dig(33, 37, TILE_PLAIN) world_dig(34, 37, TILE_PLAIN) world_dig(33, 38, TILE_PLAIN) world_dig(34, 38, TILE_PLAIN) world_dig(35, 37, TILE_PLAIN) world_dig(35, 38, TILE_PLAIN) world_dig(36, 38, TILE_PLAIN) world_dig(29, 31, TILE_PLAIN) world_dig(28, 31, TILE_PLAIN) world_dig(27, 31, TILE_PLAIN) world_dig(27, 30, TILE_PLAIN) world_dig(26, 30, TILE_PLAIN) world_dig(25, 30, TILE_PLAIN) world_dig(25, 31, TILE_PLAIN) world_dig(25, 32, TILE_PLAIN) world_dig(53, 18, TILE_PLAIN) world_dig(54, 18, TILE_PLAIN) world_dig(53, 19, TILE_PLAIN) world_dig(54, 19, TILE_PLAIN) world_dig(55, 18, TILE_PLAIN) world_dig(55, 19, TILE_PLAIN) world_dig(56, 18, TILE_PLAIN) world_dig(56, 19, TILE_PLAIN) world_dig(57, 18, TILE_PLAIN) world_dig(57, 19, TILE_PLAIN) world_dig(58, 18, TILE_PLAIN) world_dig(58, 19, TILE_PLAIN) world_dig(59, 18, TILE_PLAIN) world_dig(59, 19, TILE_PLAIN) world_dig(58, 20, TILE_PLAIN) world_dig(59, 20, TILE_PLAIN) world_dig(60, 19, TILE_PLAIN) world_dig(60, 20, TILE_PLAIN) world_dig(60, 18, TILE_PLAIN) world_dig(57, 20, TILE_PLAIN) world_dig(56, 20, TILE_PLAIN) world_dig(55, 20, TILE_PLAIN) world_dig(54, 20, TILE_PLAIN) world_dig(53, 20, TILE_PLAIN) world_dig(53, 21, TILE_PLAIN) world_dig(54, 21, TILE_PLAIN) world_dig(55, 21, TILE_PLAIN) world_dig(56, 21, TILE_PLAIN) world_dig(57, 21, TILE_PLAIN) world_dig(58, 21, TILE_PLAIN) world_dig(57, 22, TILE_PLAIN) world_dig(58, 22, TILE_PLAIN) world_dig(59, 21, TILE_PLAIN) world_dig(59, 22, TILE_PLAIN) world_dig(60, 21, TILE_PLAIN) world_dig(60, 22, TILE_PLAIN) world_dig(60, 23, TILE_PLAIN) world_dig(59, 23, TILE_PLAIN) world_dig(58, 23, TILE_PLAIN) world_dig(58, 24, TILE_PLAIN) world_dig(59, 24, TILE_PLAIN) world_dig(57, 23, TILE_PLAIN) world_dig(57, 24, TILE_PLAIN) world_dig(56, 23, TILE_PLAIN) world_dig(56, 24, TILE_PLAIN) world_dig(55, 22, TILE_PLAIN) world_dig(56, 22, TILE_PLAIN) world_dig(55, 23, TILE_PLAIN) world_dig(54, 22, TILE_PLAIN) world_dig(54, 23, TILE_PLAIN) world_dig(53, 22, TILE_PLAIN) world_dig(53, 23, TILE_PLAIN) world_dig(60, 24, TILE_PLAIN) world_dig(60, 25, TILE_PLAIN) world_dig(60, 26, TILE_PLAIN) world_dig(59, 25, TILE_PLAIN) world_dig(59, 26, TILE_PLAIN) world_dig(58, 25, TILE_PLAIN) world_dig(58, 26, TILE_PLAIN) world_dig(57, 25, TILE_PLAIN) world_dig(57, 26, TILE_PLAIN) world_dig(56, 25, TILE_PLAIN) world_dig(55, 24, TILE_PLAIN) world_dig(55, 25, TILE_PLAIN) world_dig(54, 24, TILE_PLAIN) world_dig(54, 25, TILE_PLAIN) world_dig(53, 24, TILE_PLAIN) world_dig(53, 25, TILE_PLAIN) world_dig(53, 26, TILE_PLAIN) world_dig(54, 26, TILE_PLAIN) world_dig(55, 26, TILE_PLAIN) world_dig(56, 26, TILE_PLAIN) world_make_border(TILE_GFX_BORDER) food_spawner = { { x = 5, y = 5, r = 5, a = 300, i = 200, n = 0, }, { x = 5, y = 40, r = 5, a = 300, i = 200, n = 0, } } last_food = game_time() end function level_tick() for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end infon/level/foo.lua0000644000076400001440000011734010540115020014327 0ustar dividuumusers-- Nachdem es einen Votebot gab, welcher nach neuen Levels gebettelt hat... -- Hier ist es :-) function level_size() return 64, 46 end function level_koth_pos() return 32, 23 end function level_init() world_dig(32, 23, TILE_PLAIN) world_dig(18, 21, TILE_PLAIN) world_dig(19, 21, TILE_PLAIN) world_dig(18, 22, TILE_PLAIN) world_dig(19, 22, TILE_PLAIN) world_dig(20, 21, TILE_PLAIN) world_dig(20, 22, TILE_PLAIN) world_dig(21, 21, TILE_PLAIN) world_dig(21, 22, TILE_PLAIN) world_dig(22, 21, TILE_PLAIN) world_dig(22, 22, TILE_PLAIN) world_dig(21, 23, TILE_PLAIN) world_dig(22, 23, TILE_PLAIN) world_dig(23, 22, TILE_PLAIN) world_dig(23, 23, TILE_PLAIN) world_dig(24, 22, TILE_PLAIN) world_dig(24, 23, TILE_PLAIN) world_dig(25, 22, TILE_PLAIN) world_dig(25, 23, TILE_PLAIN) world_dig(26, 22, TILE_PLAIN) world_dig(26, 23, TILE_PLAIN) world_dig(27, 22, TILE_PLAIN) world_dig(27, 23, TILE_PLAIN) world_dig(28, 22, TILE_PLAIN) world_dig(28, 23, TILE_PLAIN) world_dig(29, 22, TILE_PLAIN) world_dig(29, 23, TILE_PLAIN) world_dig(30, 22, TILE_PLAIN) world_dig(30, 23, TILE_PLAIN) world_dig(31, 22, TILE_PLAIN) world_dig(31, 23, TILE_PLAIN) world_dig(32, 22, TILE_PLAIN) world_dig(33, 22, TILE_PLAIN) world_dig(33, 23, TILE_PLAIN) world_dig(34, 22, TILE_PLAIN) world_dig(34, 23, TILE_PLAIN) world_dig(35, 22, TILE_PLAIN) world_dig(35, 23, TILE_PLAIN) world_dig(36, 22, TILE_PLAIN) world_dig(36, 23, TILE_PLAIN) world_dig(35, 24, TILE_PLAIN) world_dig(36, 24, TILE_PLAIN) world_dig(37, 23, TILE_PLAIN) world_dig(37, 24, TILE_PLAIN) world_dig(38, 23, TILE_PLAIN) world_dig(38, 24, TILE_PLAIN) world_dig(39, 23, TILE_PLAIN) world_dig(39, 24, TILE_PLAIN) world_dig(40, 23, TILE_PLAIN) world_dig(40, 24, TILE_PLAIN) world_dig(41, 23, TILE_PLAIN) world_dig(41, 24, TILE_PLAIN) world_dig(42, 23, TILE_PLAIN) world_dig(42, 24, TILE_PLAIN) world_dig(43, 23, TILE_PLAIN) world_dig(43, 24, TILE_PLAIN) world_dig(44, 23, TILE_PLAIN) world_dig(44, 24, TILE_PLAIN) world_dig(45, 23, TILE_PLAIN) world_dig(45, 24, TILE_PLAIN) world_dig(46, 23, TILE_PLAIN) world_dig(46, 24, TILE_PLAIN) world_dig(45, 22, TILE_PLAIN) world_dig(46, 22, TILE_PLAIN) world_dig(47, 22, TILE_PLAIN) world_dig(47, 23, TILE_PLAIN) world_dig(46, 21, TILE_PLAIN) world_dig(47, 21, TILE_PLAIN) world_dig(48, 21, TILE_PLAIN) world_dig(48, 22, TILE_PLAIN) world_dig(47, 20, TILE_PLAIN) world_dig(48, 20, TILE_PLAIN) world_dig(49, 20, TILE_PLAIN) world_dig(49, 21, TILE_PLAIN) world_dig(48, 19, TILE_PLAIN) world_dig(49, 19, TILE_PLAIN) world_dig(50, 19, TILE_PLAIN) world_dig(50, 20, TILE_PLAIN) world_dig(49, 18, TILE_PLAIN) world_dig(50, 18, TILE_PLAIN) world_dig(51, 18, TILE_PLAIN) world_dig(51, 19, TILE_PLAIN) world_dig(51, 17, TILE_PLAIN) world_dig(52, 17, TILE_PLAIN) world_dig(52, 18, TILE_PLAIN) world_dig(53, 17, TILE_PLAIN) world_dig(53, 18, TILE_PLAIN) world_dig(52, 16, TILE_PLAIN) world_dig(53, 16, TILE_PLAIN) world_dig(54, 16, TILE_PLAIN) world_dig(54, 17, TILE_PLAIN) world_dig(53, 15, TILE_PLAIN) world_dig(54, 15, TILE_PLAIN) world_dig(53, 14, TILE_PLAIN) world_dig(54, 14, TILE_PLAIN) world_dig(55, 14, TILE_PLAIN) world_dig(55, 15, TILE_PLAIN) world_dig(54, 13, TILE_PLAIN) world_dig(55, 13, TILE_PLAIN) world_dig(54, 12, TILE_PLAIN) world_dig(55, 12, TILE_PLAIN) world_dig(54, 11, TILE_PLAIN) world_dig(55, 11, TILE_PLAIN) world_dig(54, 10, TILE_PLAIN) world_dig(55, 10, TILE_PLAIN) world_dig(53, 10, TILE_PLAIN) world_dig(53, 11, TILE_PLAIN) world_dig(53, 9, TILE_PLAIN) world_dig(54, 9, TILE_PLAIN) world_dig(52, 9, TILE_PLAIN) world_dig(52, 10, TILE_PLAIN) world_dig(52, 8, TILE_PLAIN) world_dig(53, 8, TILE_PLAIN) world_dig(51, 8, TILE_PLAIN) world_dig(51, 9, TILE_PLAIN) world_dig(51, 7, TILE_PLAIN) world_dig(52, 7, TILE_PLAIN) world_dig(50, 7, TILE_PLAIN) world_dig(50, 8, TILE_PLAIN) world_dig(50, 6, TILE_PLAIN) world_dig(51, 6, TILE_PLAIN) world_dig(49, 6, TILE_PLAIN) world_dig(49, 7, TILE_PLAIN) world_dig(49, 5, TILE_PLAIN) world_dig(50, 5, TILE_PLAIN) world_dig(48, 5, TILE_PLAIN) world_dig(48, 6, TILE_PLAIN) world_dig(47, 5, TILE_PLAIN) world_dig(47, 6, TILE_PLAIN) world_dig(46, 5, TILE_PLAIN) world_dig(46, 6, TILE_PLAIN) world_dig(45, 5, TILE_PLAIN) world_dig(45, 6, TILE_PLAIN) world_dig(44, 5, TILE_PLAIN) world_dig(44, 6, TILE_PLAIN) world_dig(44, 7, TILE_PLAIN) world_dig(45, 7, TILE_PLAIN) world_dig(43, 6, TILE_PLAIN) world_dig(43, 7, TILE_PLAIN) world_dig(42, 6, TILE_PLAIN) world_dig(42, 7, TILE_PLAIN) world_dig(42, 8, TILE_PLAIN) world_dig(43, 8, TILE_PLAIN) world_dig(41, 7, TILE_PLAIN) world_dig(41, 8, TILE_PLAIN) world_dig(41, 9, TILE_PLAIN) world_dig(42, 9, TILE_PLAIN) world_dig(40, 8, TILE_PLAIN) world_dig(40, 9, TILE_PLAIN) world_dig(40, 10, TILE_PLAIN) world_dig(41, 10, TILE_PLAIN) world_dig(39, 9, TILE_PLAIN) world_dig(39, 10, TILE_PLAIN) world_dig(39, 11, TILE_PLAIN) world_dig(40, 11, TILE_PLAIN) world_dig(38, 10, TILE_PLAIN) world_dig(38, 11, TILE_PLAIN) world_dig(38, 12, TILE_PLAIN) world_dig(39, 12, TILE_PLAIN) world_dig(37, 11, TILE_PLAIN) world_dig(37, 12, TILE_PLAIN) world_dig(37, 13, TILE_PLAIN) world_dig(38, 13, TILE_PLAIN) world_dig(47, 19, TILE_PLAIN) world_dig(47, 18, TILE_PLAIN) world_dig(48, 18, TILE_PLAIN) world_dig(46, 18, TILE_PLAIN) world_dig(46, 19, TILE_PLAIN) world_dig(46, 17, TILE_PLAIN) world_dig(47, 17, TILE_PLAIN) world_dig(45, 17, TILE_PLAIN) world_dig(45, 18, TILE_PLAIN) world_dig(45, 16, TILE_PLAIN) world_dig(46, 16, TILE_PLAIN) world_dig(44, 16, TILE_PLAIN) world_dig(44, 17, TILE_PLAIN) world_dig(44, 15, TILE_PLAIN) world_dig(45, 15, TILE_PLAIN) world_dig(43, 15, TILE_PLAIN) world_dig(43, 16, TILE_PLAIN) world_dig(43, 14, TILE_PLAIN) world_dig(44, 14, TILE_PLAIN) world_dig(42, 14, TILE_PLAIN) world_dig(42, 15, TILE_PLAIN) world_dig(42, 13, TILE_PLAIN) world_dig(43, 13, TILE_PLAIN) world_dig(41, 13, TILE_PLAIN) world_dig(41, 14, TILE_PLAIN) world_dig(40, 12, TILE_PLAIN) world_dig(41, 12, TILE_PLAIN) world_dig(40, 13, TILE_PLAIN) world_dig(39, 13, TILE_PLAIN) world_dig(36, 11, TILE_PLAIN) world_dig(36, 12, TILE_PLAIN) world_dig(36, 10, TILE_PLAIN) world_dig(37, 10, TILE_PLAIN) world_dig(35, 10, TILE_PLAIN) world_dig(35, 11, TILE_PLAIN) world_dig(35, 9, TILE_PLAIN) world_dig(36, 9, TILE_PLAIN) world_dig(34, 9, TILE_PLAIN) world_dig(34, 10, TILE_PLAIN) world_dig(34, 8, TILE_PLAIN) world_dig(35, 8, TILE_PLAIN) world_dig(34, 7, TILE_PLAIN) world_dig(35, 7, TILE_PLAIN) world_dig(33, 7, TILE_PLAIN) world_dig(33, 8, TILE_PLAIN) world_dig(32, 6, TILE_PLAIN) world_dig(33, 6, TILE_PLAIN) world_dig(32, 7, TILE_PLAIN) world_dig(31, 5, TILE_PLAIN) world_dig(32, 5, TILE_PLAIN) world_dig(31, 6, TILE_PLAIN) world_dig(30, 4, TILE_PLAIN) world_dig(31, 4, TILE_PLAIN) world_dig(30, 5, TILE_PLAIN) world_dig(29, 3, TILE_PLAIN) world_dig(30, 3, TILE_PLAIN) world_dig(29, 4, TILE_PLAIN) world_dig(28, 3, TILE_PLAIN) world_dig(28, 4, TILE_PLAIN) world_dig(27, 3, TILE_PLAIN) world_dig(27, 4, TILE_PLAIN) world_dig(26, 3, TILE_PLAIN) world_dig(26, 4, TILE_PLAIN) world_dig(26, 5, TILE_PLAIN) world_dig(27, 5, TILE_PLAIN) world_dig(25, 4, TILE_PLAIN) world_dig(25, 5, TILE_PLAIN) world_dig(25, 6, TILE_PLAIN) world_dig(26, 6, TILE_PLAIN) world_dig(24, 5, TILE_PLAIN) world_dig(24, 6, TILE_PLAIN) world_dig(24, 7, TILE_PLAIN) world_dig(25, 7, TILE_PLAIN) world_dig(26, 7, TILE_PLAIN) world_dig(25, 8, TILE_PLAIN) world_dig(26, 8, TILE_PLAIN) world_dig(25, 9, TILE_PLAIN) world_dig(26, 9, TILE_PLAIN) world_dig(25, 10, TILE_PLAIN) world_dig(26, 10, TILE_PLAIN) world_dig(25, 11, TILE_PLAIN) world_dig(26, 11, TILE_PLAIN) world_dig(25, 12, TILE_PLAIN) world_dig(26, 12, TILE_PLAIN) world_dig(25, 13, TILE_PLAIN) world_dig(26, 13, TILE_PLAIN) world_dig(33, 9, TILE_PLAIN) world_dig(33, 10, TILE_PLAIN) world_dig(32, 10, TILE_PLAIN) world_dig(32, 11, TILE_PLAIN) world_dig(33, 11, TILE_PLAIN) world_dig(31, 11, TILE_PLAIN) world_dig(31, 12, TILE_PLAIN) world_dig(32, 12, TILE_PLAIN) world_dig(30, 12, TILE_PLAIN) world_dig(30, 13, TILE_PLAIN) world_dig(31, 13, TILE_PLAIN) world_dig(29, 12, TILE_PLAIN) world_dig(29, 13, TILE_PLAIN) world_dig(29, 14, TILE_PLAIN) world_dig(30, 14, TILE_PLAIN) world_dig(28, 13, TILE_PLAIN) world_dig(28, 14, TILE_PLAIN) world_dig(27, 13, TILE_PLAIN) world_dig(27, 14, TILE_PLAIN) world_dig(27, 15, TILE_PLAIN) world_dig(28, 15, TILE_PLAIN) world_dig(26, 14, TILE_PLAIN) world_dig(26, 15, TILE_PLAIN) world_dig(25, 14, TILE_PLAIN) world_dig(24, 13, TILE_PLAIN) world_dig(24, 14, TILE_PLAIN) world_dig(23, 13, TILE_PLAIN) world_dig(23, 14, TILE_PLAIN) world_dig(22, 12, TILE_PLAIN) world_dig(23, 12, TILE_PLAIN) world_dig(22, 13, TILE_PLAIN) world_dig(21, 12, TILE_PLAIN) world_dig(21, 13, TILE_PLAIN) world_dig(21, 11, TILE_PLAIN) world_dig(22, 11, TILE_PLAIN) world_dig(20, 11, TILE_PLAIN) world_dig(20, 12, TILE_PLAIN) world_dig(19, 11, TILE_PLAIN) world_dig(19, 12, TILE_PLAIN) world_dig(19, 10, TILE_PLAIN) world_dig(20, 10, TILE_PLAIN) world_dig(18, 10, TILE_PLAIN) world_dig(18, 11, TILE_PLAIN) world_dig(18, 9, TILE_PLAIN) world_dig(19, 9, TILE_PLAIN) world_dig(17, 8, TILE_PLAIN) world_dig(18, 8, TILE_PLAIN) world_dig(17, 9, TILE_PLAIN) world_dig(16, 7, TILE_PLAIN) world_dig(17, 7, TILE_PLAIN) world_dig(16, 8, TILE_PLAIN) world_dig(15, 6, TILE_PLAIN) world_dig(16, 6, TILE_PLAIN) world_dig(15, 7, TILE_PLAIN) world_dig(15, 5, TILE_PLAIN) world_dig(16, 5, TILE_PLAIN) world_dig(14, 4, TILE_PLAIN) world_dig(15, 4, TILE_PLAIN) world_dig(14, 5, TILE_PLAIN) world_dig(14, 3, TILE_PLAIN) world_dig(15, 3, TILE_PLAIN) world_dig(16, 3, TILE_PLAIN) world_dig(16, 4, TILE_PLAIN) world_dig(17, 3, TILE_PLAIN) world_dig(17, 4, TILE_PLAIN) world_dig(18, 3, TILE_PLAIN) world_dig(18, 4, TILE_PLAIN) world_dig(19, 3, TILE_PLAIN) world_dig(19, 4, TILE_PLAIN) world_dig(20, 3, TILE_PLAIN) world_dig(20, 4, TILE_PLAIN) world_dig(21, 3, TILE_PLAIN) world_dig(21, 4, TILE_PLAIN) world_dig(20, 5, TILE_PLAIN) world_dig(21, 5, TILE_PLAIN) world_dig(22, 4, TILE_PLAIN) world_dig(22, 5, TILE_PLAIN) world_dig(21, 6, TILE_PLAIN) world_dig(22, 6, TILE_PLAIN) world_dig(21, 7, TILE_PLAIN) world_dig(22, 7, TILE_PLAIN) world_dig(21, 8, TILE_PLAIN) world_dig(22, 8, TILE_PLAIN) world_dig(20, 7, TILE_PLAIN) world_dig(20, 8, TILE_PLAIN) world_dig(20, 9, TILE_PLAIN) world_dig(21, 9, TILE_PLAIN) world_dig(21, 10, TILE_PLAIN) world_dig(17, 10, TILE_PLAIN) world_dig(17, 11, TILE_PLAIN) world_dig(16, 10, TILE_PLAIN) world_dig(16, 11, TILE_PLAIN) world_dig(16, 12, TILE_PLAIN) world_dig(17, 12, TILE_PLAIN) world_dig(15, 11, TILE_PLAIN) world_dig(15, 12, TILE_PLAIN) world_dig(14, 11, TILE_PLAIN) world_dig(14, 12, TILE_PLAIN) world_dig(13, 11, TILE_PLAIN) world_dig(13, 12, TILE_PLAIN) world_dig(13, 13, TILE_PLAIN) world_dig(14, 13, TILE_PLAIN) world_dig(12, 12, TILE_PLAIN) world_dig(12, 13, TILE_PLAIN) world_dig(11, 12, TILE_PLAIN) world_dig(11, 13, TILE_PLAIN) world_dig(11, 14, TILE_PLAIN) world_dig(12, 14, TILE_PLAIN) world_dig(10, 13, TILE_PLAIN) world_dig(10, 14, TILE_PLAIN) world_dig(9, 13, TILE_PLAIN) world_dig(9, 14, TILE_PLAIN) world_dig(8, 13, TILE_PLAIN) world_dig(8, 14, TILE_PLAIN) world_dig(7, 13, TILE_PLAIN) world_dig(7, 14, TILE_PLAIN) world_dig(7, 12, TILE_PLAIN) world_dig(8, 12, TILE_PLAIN) world_dig(6, 12, TILE_PLAIN) world_dig(6, 13, TILE_PLAIN) world_dig(6, 11, TILE_PLAIN) world_dig(7, 11, TILE_PLAIN) world_dig(5, 11, TILE_PLAIN) world_dig(5, 12, TILE_PLAIN) world_dig(4, 10, TILE_PLAIN) world_dig(5, 10, TILE_PLAIN) world_dig(4, 11, TILE_PLAIN) world_dig(4, 9, TILE_PLAIN) world_dig(5, 9, TILE_PLAIN) world_dig(3, 9, TILE_PLAIN) world_dig(3, 10, TILE_PLAIN) world_dig(3, 8, TILE_PLAIN) world_dig(4, 8, TILE_PLAIN) world_dig(3, 7, TILE_PLAIN) world_dig(4, 7, TILE_PLAIN) world_dig(3, 6, TILE_PLAIN) world_dig(4, 6, TILE_PLAIN) world_dig(3, 5, TILE_PLAIN) world_dig(4, 5, TILE_PLAIN) world_dig(5, 5, TILE_PLAIN) world_dig(5, 6, TILE_PLAIN) world_dig(4, 4, TILE_PLAIN) world_dig(5, 4, TILE_PLAIN) world_dig(6, 4, TILE_PLAIN) world_dig(6, 5, TILE_PLAIN) world_dig(5, 3, TILE_PLAIN) world_dig(6, 3, TILE_PLAIN) world_dig(7, 3, TILE_PLAIN) world_dig(7, 4, TILE_PLAIN) world_dig(7, 5, TILE_PLAIN) world_dig(8, 4, TILE_PLAIN) world_dig(8, 5, TILE_PLAIN) world_dig(9, 5, TILE_PLAIN) world_dig(8, 6, TILE_PLAIN) world_dig(9, 6, TILE_PLAIN) world_dig(10, 5, TILE_PLAIN) world_dig(10, 6, TILE_PLAIN) world_dig(9, 7, TILE_PLAIN) world_dig(10, 7, TILE_PLAIN) world_dig(11, 6, TILE_PLAIN) world_dig(11, 7, TILE_PLAIN) world_dig(10, 8, TILE_PLAIN) world_dig(11, 8, TILE_PLAIN) world_dig(12, 7, TILE_PLAIN) world_dig(12, 8, TILE_PLAIN) world_dig(11, 9, TILE_PLAIN) world_dig(12, 9, TILE_PLAIN) world_dig(13, 9, TILE_PLAIN) world_dig(12, 10, TILE_PLAIN) world_dig(13, 10, TILE_PLAIN) world_dig(12, 11, TILE_PLAIN) world_dig(13, 14, TILE_PLAIN) world_dig(14, 14, TILE_PLAIN) world_dig(13, 15, TILE_PLAIN) world_dig(14, 15, TILE_PLAIN) world_dig(13, 16, TILE_PLAIN) world_dig(14, 16, TILE_PLAIN) world_dig(13, 17, TILE_PLAIN) world_dig(14, 17, TILE_PLAIN) world_dig(12, 16, TILE_PLAIN) world_dig(12, 17, TILE_PLAIN) world_dig(12, 18, TILE_PLAIN) world_dig(13, 18, TILE_PLAIN) world_dig(12, 19, TILE_PLAIN) world_dig(13, 19, TILE_PLAIN) world_dig(12, 20, TILE_PLAIN) world_dig(13, 20, TILE_PLAIN) world_dig(12, 21, TILE_PLAIN) world_dig(13, 21, TILE_PLAIN) world_dig(12, 22, TILE_PLAIN) world_dig(13, 22, TILE_PLAIN) world_dig(3, 19, TILE_PLAIN) world_dig(4, 19, TILE_PLAIN) world_dig(3, 20, TILE_PLAIN) world_dig(4, 20, TILE_PLAIN) world_dig(5, 19, TILE_PLAIN) world_dig(5, 20, TILE_PLAIN) world_dig(4, 21, TILE_PLAIN) world_dig(5, 21, TILE_PLAIN) world_dig(6, 20, TILE_PLAIN) world_dig(6, 21, TILE_PLAIN) world_dig(7, 20, TILE_PLAIN) world_dig(7, 21, TILE_PLAIN) world_dig(8, 20, TILE_PLAIN) world_dig(8, 21, TILE_PLAIN) world_dig(9, 20, TILE_PLAIN) world_dig(9, 21, TILE_PLAIN) world_dig(10, 20, TILE_PLAIN) world_dig(10, 21, TILE_PLAIN) world_dig(11, 20, TILE_PLAIN) world_dig(11, 21, TILE_PLAIN) world_dig(11, 22, TILE_PLAIN) world_dig(14, 21, TILE_PLAIN) world_dig(14, 22, TILE_PLAIN) world_dig(15, 21, TILE_PLAIN) world_dig(15, 22, TILE_PLAIN) world_dig(16, 21, TILE_PLAIN) world_dig(16, 22, TILE_PLAIN) world_dig(17, 22, TILE_PLAIN) world_dig(16, 23, TILE_PLAIN) world_dig(17, 23, TILE_PLAIN) world_dig(18, 23, TILE_PLAIN) world_dig(19, 23, TILE_PLAIN) world_dig(20, 23, TILE_PLAIN) world_dig(3, 21, TILE_PLAIN) world_dig(4, 22, TILE_PLAIN) world_dig(5, 22, TILE_PLAIN) world_dig(4, 23, TILE_PLAIN) world_dig(5, 23, TILE_PLAIN) world_dig(6, 22, TILE_PLAIN) world_dig(6, 23, TILE_PLAIN) world_dig(5, 24, TILE_PLAIN) world_dig(6, 24, TILE_PLAIN) world_dig(7, 24, TILE_PLAIN) world_dig(6, 25, TILE_PLAIN) world_dig(7, 25, TILE_PLAIN) world_dig(6, 26, TILE_PLAIN) world_dig(7, 26, TILE_PLAIN) world_dig(6, 27, TILE_PLAIN) world_dig(7, 27, TILE_PLAIN) world_dig(8, 26, TILE_PLAIN) world_dig(8, 27, TILE_PLAIN) world_dig(7, 28, TILE_PLAIN) world_dig(8, 28, TILE_PLAIN) world_dig(9, 28, TILE_PLAIN) world_dig(8, 29, TILE_PLAIN) world_dig(9, 29, TILE_PLAIN) world_dig(8, 30, TILE_PLAIN) world_dig(9, 30, TILE_PLAIN) world_dig(8, 31, TILE_PLAIN) world_dig(9, 31, TILE_PLAIN) world_dig(10, 30, TILE_PLAIN) world_dig(10, 31, TILE_PLAIN) world_dig(11, 30, TILE_PLAIN) world_dig(11, 31, TILE_PLAIN) world_dig(12, 30, TILE_PLAIN) world_dig(12, 31, TILE_PLAIN) world_dig(13, 30, TILE_PLAIN) world_dig(13, 31, TILE_PLAIN) world_dig(14, 30, TILE_PLAIN) world_dig(14, 31, TILE_PLAIN) world_dig(15, 30, TILE_PLAIN) world_dig(15, 31, TILE_PLAIN) world_dig(15, 29, TILE_PLAIN) world_dig(16, 29, TILE_PLAIN) world_dig(16, 30, TILE_PLAIN) world_dig(15, 28, TILE_PLAIN) world_dig(16, 28, TILE_PLAIN) world_dig(17, 28, TILE_PLAIN) world_dig(17, 29, TILE_PLAIN) world_dig(16, 27, TILE_PLAIN) world_dig(17, 27, TILE_PLAIN) world_dig(18, 27, TILE_PLAIN) world_dig(18, 28, TILE_PLAIN) world_dig(17, 26, TILE_PLAIN) world_dig(18, 26, TILE_PLAIN) world_dig(19, 26, TILE_PLAIN) world_dig(19, 27, TILE_PLAIN) world_dig(18, 25, TILE_PLAIN) world_dig(19, 25, TILE_PLAIN) world_dig(19, 24, TILE_PLAIN) world_dig(20, 24, TILE_PLAIN) world_dig(20, 25, TILE_PLAIN) world_dig(21, 24, TILE_PLAIN) world_dig(21, 25, TILE_PLAIN) world_dig(26, 24, TILE_PLAIN) world_dig(27, 24, TILE_PLAIN) world_dig(28, 24, TILE_PLAIN) world_dig(27, 25, TILE_PLAIN) world_dig(28, 25, TILE_PLAIN) world_dig(27, 26, TILE_PLAIN) world_dig(28, 26, TILE_PLAIN) world_dig(29, 25, TILE_PLAIN) world_dig(29, 26, TILE_PLAIN) world_dig(28, 27, TILE_PLAIN) world_dig(29, 27, TILE_PLAIN) world_dig(28, 28, TILE_PLAIN) world_dig(29, 28, TILE_PLAIN) world_dig(28, 29, TILE_PLAIN) world_dig(29, 29, TILE_PLAIN) world_dig(30, 28, TILE_PLAIN) world_dig(30, 29, TILE_PLAIN) world_dig(29, 30, TILE_PLAIN) world_dig(30, 30, TILE_PLAIN) world_dig(29, 31, TILE_PLAIN) world_dig(30, 31, TILE_PLAIN) world_dig(29, 32, TILE_PLAIN) world_dig(30, 32, TILE_PLAIN) world_dig(31, 32, TILE_PLAIN) world_dig(30, 33, TILE_PLAIN) world_dig(31, 33, TILE_PLAIN) world_dig(30, 34, TILE_PLAIN) world_dig(31, 34, TILE_PLAIN) world_dig(30, 35, TILE_PLAIN) world_dig(31, 35, TILE_PLAIN) world_dig(30, 36, TILE_PLAIN) world_dig(31, 36, TILE_PLAIN) world_dig(32, 36, TILE_PLAIN) world_dig(31, 37, TILE_PLAIN) world_dig(32, 37, TILE_PLAIN) world_dig(31, 38, TILE_PLAIN) world_dig(32, 38, TILE_PLAIN) world_dig(13, 32, TILE_PLAIN) world_dig(14, 32, TILE_PLAIN) world_dig(15, 32, TILE_PLAIN) world_dig(16, 31, TILE_PLAIN) world_dig(16, 32, TILE_PLAIN) world_dig(15, 33, TILE_PLAIN) world_dig(16, 33, TILE_PLAIN) world_dig(17, 32, TILE_PLAIN) world_dig(17, 33, TILE_PLAIN) world_dig(18, 32, TILE_PLAIN) world_dig(18, 33, TILE_PLAIN) world_dig(19, 33, TILE_PLAIN) world_dig(18, 34, TILE_PLAIN) world_dig(19, 34, TILE_PLAIN) world_dig(20, 33, TILE_PLAIN) world_dig(20, 34, TILE_PLAIN) world_dig(21, 33, TILE_PLAIN) world_dig(21, 34, TILE_PLAIN) world_dig(20, 35, TILE_PLAIN) world_dig(21, 35, TILE_PLAIN) world_dig(22, 34, TILE_PLAIN) world_dig(22, 35, TILE_PLAIN) world_dig(23, 34, TILE_PLAIN) world_dig(23, 35, TILE_PLAIN) world_dig(24, 34, TILE_PLAIN) world_dig(24, 35, TILE_PLAIN) world_dig(23, 36, TILE_PLAIN) world_dig(24, 36, TILE_PLAIN) world_dig(25, 35, TILE_PLAIN) world_dig(25, 36, TILE_PLAIN) world_dig(26, 35, TILE_PLAIN) world_dig(26, 36, TILE_PLAIN) world_dig(27, 35, TILE_PLAIN) world_dig(27, 36, TILE_PLAIN) world_dig(28, 35, TILE_PLAIN) world_dig(28, 36, TILE_PLAIN) world_dig(29, 35, TILE_PLAIN) world_dig(29, 36, TILE_PLAIN) world_dig(28, 34, TILE_PLAIN) world_dig(29, 34, TILE_PLAIN) world_dig(17, 34, TILE_PLAIN) world_dig(17, 35, TILE_PLAIN) world_dig(18, 35, TILE_PLAIN) world_dig(19, 35, TILE_PLAIN) world_dig(18, 36, TILE_PLAIN) world_dig(19, 36, TILE_PLAIN) world_dig(18, 37, TILE_PLAIN) world_dig(19, 37, TILE_PLAIN) world_dig(17, 36, TILE_PLAIN) world_dig(17, 37, TILE_PLAIN) world_dig(16, 37, TILE_PLAIN) world_dig(16, 38, TILE_PLAIN) world_dig(17, 38, TILE_PLAIN) world_dig(15, 37, TILE_PLAIN) world_dig(15, 38, TILE_PLAIN) world_dig(15, 39, TILE_PLAIN) world_dig(16, 39, TILE_PLAIN) world_dig(14, 38, TILE_PLAIN) world_dig(14, 39, TILE_PLAIN) world_dig(13, 38, TILE_PLAIN) world_dig(13, 39, TILE_PLAIN) world_dig(12, 38, TILE_PLAIN) world_dig(12, 39, TILE_PLAIN) world_dig(11, 38, TILE_PLAIN) world_dig(11, 39, TILE_PLAIN) world_dig(10, 38, TILE_PLAIN) world_dig(10, 39, TILE_PLAIN) world_dig(9, 38, TILE_PLAIN) world_dig(9, 39, TILE_PLAIN) world_dig(8, 38, TILE_PLAIN) world_dig(8, 39, TILE_PLAIN) world_dig(7, 37, TILE_PLAIN) world_dig(8, 37, TILE_PLAIN) world_dig(7, 38, TILE_PLAIN) world_dig(6, 37, TILE_PLAIN) world_dig(6, 38, TILE_PLAIN) world_dig(6, 36, TILE_PLAIN) world_dig(7, 36, TILE_PLAIN) world_dig(5, 35, TILE_PLAIN) world_dig(6, 35, TILE_PLAIN) world_dig(5, 36, TILE_PLAIN) world_dig(5, 34, TILE_PLAIN) world_dig(6, 34, TILE_PLAIN) world_dig(5, 33, TILE_PLAIN) world_dig(6, 33, TILE_PLAIN) world_dig(4, 33, TILE_PLAIN) world_dig(4, 34, TILE_PLAIN) world_dig(4, 32, TILE_PLAIN) world_dig(5, 32, TILE_PLAIN) world_dig(4, 31, TILE_PLAIN) world_dig(5, 31, TILE_PLAIN) world_dig(4, 30, TILE_PLAIN) world_dig(5, 30, TILE_PLAIN) world_dig(4, 29, TILE_PLAIN) world_dig(5, 29, TILE_PLAIN) world_dig(6, 29, TILE_PLAIN) world_dig(6, 30, TILE_PLAIN) world_dig(5, 28, TILE_PLAIN) world_dig(6, 28, TILE_PLAIN) world_dig(7, 29, TILE_PLAIN) world_dig(33, 38, TILE_PLAIN) world_dig(32, 39, TILE_PLAIN) world_dig(33, 39, TILE_PLAIN) world_dig(34, 38, TILE_PLAIN) world_dig(34, 39, TILE_PLAIN) world_dig(35, 38, TILE_PLAIN) world_dig(35, 39, TILE_PLAIN) world_dig(36, 38, TILE_PLAIN) world_dig(36, 39, TILE_PLAIN) world_dig(35, 37, TILE_PLAIN) world_dig(36, 37, TILE_PLAIN) world_dig(37, 37, TILE_PLAIN) world_dig(37, 38, TILE_PLAIN) world_dig(36, 36, TILE_PLAIN) world_dig(37, 36, TILE_PLAIN) world_dig(38, 36, TILE_PLAIN) world_dig(38, 37, TILE_PLAIN) world_dig(37, 35, TILE_PLAIN) world_dig(38, 35, TILE_PLAIN) world_dig(37, 34, TILE_PLAIN) world_dig(38, 34, TILE_PLAIN) world_dig(37, 33, TILE_PLAIN) world_dig(38, 33, TILE_PLAIN) world_dig(39, 33, TILE_PLAIN) world_dig(39, 34, TILE_PLAIN) world_dig(38, 32, TILE_PLAIN) world_dig(39, 32, TILE_PLAIN) world_dig(38, 31, TILE_PLAIN) world_dig(39, 31, TILE_PLAIN) world_dig(40, 31, TILE_PLAIN) world_dig(40, 32, TILE_PLAIN) world_dig(39, 30, TILE_PLAIN) world_dig(40, 30, TILE_PLAIN) world_dig(39, 29, TILE_PLAIN) world_dig(40, 29, TILE_PLAIN) world_dig(41, 29, TILE_PLAIN) world_dig(41, 30, TILE_PLAIN) world_dig(40, 28, TILE_PLAIN) world_dig(41, 28, TILE_PLAIN) world_dig(40, 27, TILE_PLAIN) world_dig(41, 27, TILE_PLAIN) world_dig(42, 27, TILE_PLAIN) world_dig(42, 28, TILE_PLAIN) world_dig(41, 26, TILE_PLAIN) world_dig(42, 26, TILE_PLAIN) world_dig(41, 25, TILE_PLAIN) world_dig(42, 25, TILE_PLAIN) world_dig(43, 25, TILE_PLAIN) world_dig(43, 26, TILE_PLAIN) world_dig(40, 34, TILE_PLAIN) world_dig(39, 35, TILE_PLAIN) world_dig(40, 35, TILE_PLAIN) world_dig(39, 36, TILE_PLAIN) world_dig(40, 36, TILE_PLAIN) world_dig(41, 35, TILE_PLAIN) world_dig(41, 36, TILE_PLAIN) world_dig(40, 37, TILE_PLAIN) world_dig(41, 37, TILE_PLAIN) world_dig(42, 36, TILE_PLAIN) world_dig(42, 37, TILE_PLAIN) world_dig(41, 38, TILE_PLAIN) world_dig(42, 38, TILE_PLAIN) world_dig(43, 37, TILE_PLAIN) world_dig(43, 38, TILE_PLAIN) world_dig(44, 38, TILE_PLAIN) world_dig(43, 39, TILE_PLAIN) world_dig(44, 39, TILE_PLAIN) world_dig(45, 38, TILE_PLAIN) world_dig(45, 39, TILE_PLAIN) world_dig(44, 40, TILE_PLAIN) world_dig(45, 40, TILE_PLAIN) world_dig(46, 39, TILE_PLAIN) world_dig(46, 40, TILE_PLAIN) world_dig(47, 39, TILE_PLAIN) world_dig(47, 40, TILE_PLAIN) world_dig(46, 41, TILE_PLAIN) world_dig(47, 41, TILE_PLAIN) world_dig(48, 40, TILE_PLAIN) world_dig(48, 41, TILE_PLAIN) world_dig(49, 40, TILE_PLAIN) world_dig(49, 41, TILE_PLAIN) world_dig(49, 39, TILE_PLAIN) world_dig(50, 39, TILE_PLAIN) world_dig(50, 40, TILE_PLAIN) world_dig(51, 39, TILE_PLAIN) world_dig(51, 40, TILE_PLAIN) world_dig(50, 38, TILE_PLAIN) world_dig(51, 38, TILE_PLAIN) world_dig(52, 38, TILE_PLAIN) world_dig(52, 39, TILE_PLAIN) world_dig(51, 37, TILE_PLAIN) world_dig(52, 37, TILE_PLAIN) world_dig(53, 37, TILE_PLAIN) world_dig(53, 38, TILE_PLAIN) world_dig(52, 36, TILE_PLAIN) world_dig(53, 36, TILE_PLAIN) world_dig(52, 35, TILE_PLAIN) world_dig(53, 35, TILE_PLAIN) world_dig(52, 34, TILE_PLAIN) world_dig(53, 34, TILE_PLAIN) world_dig(52, 33, TILE_PLAIN) world_dig(53, 33, TILE_PLAIN) world_dig(51, 33, TILE_PLAIN) world_dig(51, 34, TILE_PLAIN) world_dig(51, 32, TILE_PLAIN) world_dig(52, 32, TILE_PLAIN) world_dig(50, 31, TILE_PLAIN) world_dig(51, 31, TILE_PLAIN) world_dig(50, 32, TILE_PLAIN) world_dig(50, 30, TILE_PLAIN) world_dig(51, 30, TILE_PLAIN) world_dig(49, 30, TILE_PLAIN) world_dig(49, 31, TILE_PLAIN) world_dig(49, 29, TILE_PLAIN) world_dig(50, 29, TILE_PLAIN) world_dig(48, 29, TILE_PLAIN) world_dig(48, 30, TILE_PLAIN) world_dig(48, 28, TILE_PLAIN) world_dig(49, 28, TILE_PLAIN) world_dig(48, 27, TILE_PLAIN) world_dig(49, 27, TILE_PLAIN) world_dig(47, 27, TILE_PLAIN) world_dig(47, 28, TILE_PLAIN) world_dig(47, 26, TILE_PLAIN) world_dig(48, 26, TILE_PLAIN) world_dig(46, 26, TILE_PLAIN) world_dig(46, 27, TILE_PLAIN) world_dig(46, 25, TILE_PLAIN) world_dig(47, 25, TILE_PLAIN) world_dig(45, 25, TILE_PLAIN) world_dig(45, 26, TILE_PLAIN) world_dig(53, 32, TILE_PLAIN) world_dig(54, 32, TILE_PLAIN) world_dig(54, 33, TILE_PLAIN) world_dig(53, 31, TILE_PLAIN) world_dig(54, 31, TILE_PLAIN) world_dig(55, 31, TILE_PLAIN) world_dig(55, 32, TILE_PLAIN) world_dig(56, 31, TILE_PLAIN) world_dig(56, 32, TILE_PLAIN) world_dig(56, 30, TILE_PLAIN) world_dig(57, 30, TILE_PLAIN) world_dig(57, 31, TILE_PLAIN) world_dig(58, 30, TILE_PLAIN) world_dig(58, 31, TILE_PLAIN) world_dig(57, 29, TILE_PLAIN) world_dig(58, 29, TILE_PLAIN) world_dig(59, 29, TILE_PLAIN) world_dig(59, 30, TILE_PLAIN) world_dig(58, 28, TILE_PLAIN) world_dig(59, 28, TILE_PLAIN) world_dig(59, 27, TILE_PLAIN) world_dig(60, 27, TILE_PLAIN) world_dig(60, 28, TILE_PLAIN) world_dig(59, 26, TILE_PLAIN) world_dig(60, 26, TILE_PLAIN) world_dig(59, 25, TILE_PLAIN) world_dig(60, 25, TILE_PLAIN) world_dig(61, 25, TILE_PLAIN) world_dig(61, 26, TILE_PLAIN) world_dig(60, 24, TILE_PLAIN) world_dig(61, 24, TILE_PLAIN) world_dig(59, 23, TILE_PLAIN) world_dig(60, 23, TILE_PLAIN) world_dig(59, 24, TILE_PLAIN) world_dig(59, 22, TILE_PLAIN) world_dig(60, 22, TILE_PLAIN) world_dig(58, 21, TILE_PLAIN) world_dig(59, 21, TILE_PLAIN) world_dig(58, 22, TILE_PLAIN) world_dig(58, 20, TILE_PLAIN) world_dig(59, 20, TILE_PLAIN) world_dig(57, 20, TILE_PLAIN) world_dig(57, 21, TILE_PLAIN) world_dig(57, 19, TILE_PLAIN) world_dig(58, 19, TILE_PLAIN) world_dig(56, 19, TILE_PLAIN) world_dig(56, 20, TILE_PLAIN) world_dig(55, 18, TILE_PLAIN) world_dig(56, 18, TILE_PLAIN) world_dig(55, 19, TILE_PLAIN) world_dig(54, 18, TILE_PLAIN) world_dig(54, 19, TILE_PLAIN) world_dig(55, 17, TILE_PLAIN) world_dig(17, 39, TILE_PLAIN) world_dig(16, 40, TILE_PLAIN) world_dig(17, 40, TILE_PLAIN) world_dig(18, 39, TILE_PLAIN) world_dig(18, 40, TILE_PLAIN) world_dig(17, 41, TILE_PLAIN) world_dig(18, 41, TILE_PLAIN) world_dig(19, 40, TILE_PLAIN) world_dig(19, 41, TILE_PLAIN) world_dig(18, 42, TILE_PLAIN) world_dig(19, 42, TILE_PLAIN) world_dig(20, 41, TILE_PLAIN) world_dig(20, 42, TILE_PLAIN) world_dig(21, 41, TILE_PLAIN) world_dig(21, 42, TILE_PLAIN) world_dig(22, 42, TILE_PLAIN) world_dig(21, 43, TILE_PLAIN) world_dig(22, 43, TILE_PLAIN) world_dig(23, 42, TILE_PLAIN) world_dig(23, 43, TILE_PLAIN) world_dig(24, 42, TILE_PLAIN) world_dig(24, 43, TILE_PLAIN) world_dig(25, 42, TILE_PLAIN) world_dig(25, 43, TILE_PLAIN) world_dig(26, 42, TILE_PLAIN) world_dig(26, 43, TILE_PLAIN) world_dig(27, 42, TILE_PLAIN) world_dig(27, 43, TILE_PLAIN) world_dig(28, 42, TILE_PLAIN) world_dig(28, 43, TILE_PLAIN) world_dig(29, 42, TILE_PLAIN) world_dig(29, 43, TILE_PLAIN) world_dig(30, 42, TILE_PLAIN) world_dig(30, 43, TILE_PLAIN) world_dig(30, 41, TILE_PLAIN) world_dig(31, 41, TILE_PLAIN) world_dig(31, 42, TILE_PLAIN) world_dig(32, 41, TILE_PLAIN) world_dig(32, 42, TILE_PLAIN) world_dig(31, 40, TILE_PLAIN) world_dig(32, 40, TILE_PLAIN) world_dig(33, 40, TILE_PLAIN) world_dig(33, 41, TILE_PLAIN) world_dig(34, 40, TILE_PLAIN) world_dig(34, 41, TILE_PLAIN) world_dig(35, 40, TILE_PLAIN) world_dig(37, 39, TILE_PLAIN) world_dig(52, 40, TILE_PLAIN) world_dig(51, 41, TILE_PLAIN) world_dig(52, 41, TILE_PLAIN) world_dig(53, 41, TILE_PLAIN) world_dig(52, 42, TILE_PLAIN) world_dig(53, 42, TILE_PLAIN) world_dig(54, 41, TILE_PLAIN) world_dig(54, 42, TILE_PLAIN) world_dig(55, 41, TILE_PLAIN) world_dig(55, 42, TILE_PLAIN) world_dig(56, 41, TILE_PLAIN) world_dig(56, 42, TILE_PLAIN) world_dig(57, 41, TILE_PLAIN) world_dig(57, 42, TILE_PLAIN) world_dig(58, 41, TILE_PLAIN) world_dig(58, 42, TILE_PLAIN) world_dig(58, 40, TILE_PLAIN) world_dig(59, 40, TILE_PLAIN) world_dig(59, 41, TILE_PLAIN) world_dig(60, 40, TILE_PLAIN) world_dig(60, 41, TILE_PLAIN) world_dig(59, 39, TILE_PLAIN) world_dig(60, 39, TILE_PLAIN) world_dig(61, 39, TILE_PLAIN) world_dig(61, 40, TILE_PLAIN) world_dig(60, 38, TILE_PLAIN) world_dig(61, 38, TILE_PLAIN) world_dig(61, 37, TILE_PLAIN) world_dig(61, 36, TILE_PLAIN) world_dig(61, 34, TILE_PLAIN) world_dig(61, 35, TILE_PLAIN) world_dig(61, 33, TILE_PLAIN) world_dig(61, 32, TILE_PLAIN) world_dig(61, 31, TILE_PLAIN) world_dig(60, 31, TILE_PLAIN) world_dig(60, 32, TILE_PLAIN) world_dig(60, 30, TILE_PLAIN) world_dig(61, 30, TILE_PLAIN) world_dig(59, 31, TILE_PLAIN) world_dig(3, 18, TILE_PLAIN) world_dig(4, 18, TILE_PLAIN) world_dig(3, 17, TILE_PLAIN) world_dig(4, 17, TILE_PLAIN) world_dig(4, 16, TILE_PLAIN) world_dig(5, 16, TILE_PLAIN) world_dig(5, 17, TILE_PLAIN) world_dig(4, 15, TILE_PLAIN) world_dig(5, 15, TILE_PLAIN) world_dig(5, 14, TILE_PLAIN) world_dig(6, 14, TILE_PLAIN) world_dig(6, 15, TILE_PLAIN) world_dig(5, 13, TILE_PLAIN) world_dig(52, 6, TILE_PLAIN) world_dig(51, 5, TILE_PLAIN) world_dig(52, 5, TILE_PLAIN) world_dig(52, 4, TILE_PLAIN) world_dig(53, 4, TILE_PLAIN) world_dig(53, 5, TILE_PLAIN) world_dig(53, 3, TILE_PLAIN) world_dig(54, 3, TILE_PLAIN) world_dig(54, 4, TILE_PLAIN) world_dig(55, 3, TILE_PLAIN) world_dig(55, 4, TILE_PLAIN) world_dig(56, 3, TILE_PLAIN) world_dig(56, 4, TILE_PLAIN) world_dig(55, 2, TILE_PLAIN) world_dig(56, 2, TILE_PLAIN) world_dig(57, 2, TILE_PLAIN) world_dig(57, 3, TILE_PLAIN) world_dig(58, 2, TILE_PLAIN) world_dig(58, 3, TILE_PLAIN) world_dig(59, 2, TILE_PLAIN) world_dig(59, 3, TILE_PLAIN) world_dig(58, 4, TILE_PLAIN) world_dig(59, 4, TILE_PLAIN) world_dig(60, 3, TILE_PLAIN) world_dig(60, 4, TILE_PLAIN) world_dig(61, 4, TILE_PLAIN) world_dig(60, 5, TILE_PLAIN) world_dig(61, 5, TILE_PLAIN) world_dig(60, 6, TILE_PLAIN) world_dig(61, 6, TILE_PLAIN) world_dig(61, 7, TILE_PLAIN) world_dig(61, 8, TILE_PLAIN) world_dig(61, 9, TILE_PLAIN) world_dig(61, 10, TILE_PLAIN) world_dig(60, 10, TILE_PLAIN) world_dig(60, 11, TILE_PLAIN) world_dig(61, 11, TILE_PLAIN) world_dig(60, 12, TILE_PLAIN) world_dig(61, 12, TILE_PLAIN) world_dig(59, 11, TILE_PLAIN) world_dig(59, 12, TILE_PLAIN) world_dig(59, 13, TILE_PLAIN) world_dig(60, 13, TILE_PLAIN) world_dig(58, 12, TILE_PLAIN) world_dig(58, 13, TILE_PLAIN) world_dig(58, 14, TILE_PLAIN) world_dig(59, 14, TILE_PLAIN) world_dig(57, 13, TILE_PLAIN) world_dig(57, 14, TILE_PLAIN) world_dig(57, 15, TILE_PLAIN) world_dig(58, 15, TILE_PLAIN) world_dig(56, 14, TILE_PLAIN) world_dig(56, 15, TILE_PLAIN) world_dig(33, 5, TILE_PLAIN) world_dig(33, 4, TILE_PLAIN) world_dig(34, 4, TILE_PLAIN) world_dig(34, 5, TILE_PLAIN) world_dig(33, 3, TILE_PLAIN) world_dig(34, 3, TILE_PLAIN) world_dig(35, 3, TILE_PLAIN) world_dig(35, 4, TILE_PLAIN) world_dig(36, 3, TILE_PLAIN) world_dig(36, 4, TILE_PLAIN) world_dig(35, 2, TILE_PLAIN) world_dig(36, 2, TILE_PLAIN) world_dig(37, 2, TILE_PLAIN) world_dig(37, 3, TILE_PLAIN) world_dig(38, 2, TILE_PLAIN) world_dig(38, 3, TILE_PLAIN) world_dig(39, 2, TILE_PLAIN) world_dig(39, 3, TILE_PLAIN) world_dig(40, 2, TILE_PLAIN) world_dig(40, 3, TILE_PLAIN) world_dig(41, 2, TILE_PLAIN) world_dig(41, 3, TILE_PLAIN) world_dig(42, 2, TILE_PLAIN) world_dig(42, 3, TILE_PLAIN) world_dig(41, 4, TILE_PLAIN) world_dig(42, 4, TILE_PLAIN) world_dig(43, 3, TILE_PLAIN) world_dig(43, 4, TILE_PLAIN) world_dig(42, 5, TILE_PLAIN) world_dig(43, 5, TILE_PLAIN) world_dig(36, 40, TILE_PLAIN) world_dig(35, 41, TILE_PLAIN) world_dig(36, 41, TILE_PLAIN) world_dig(35, 42, TILE_PLAIN) world_dig(36, 42, TILE_PLAIN) world_dig(37, 41, TILE_PLAIN) world_dig(37, 42, TILE_PLAIN) world_dig(36, 43, TILE_PLAIN) world_dig(37, 43, TILE_PLAIN) world_dig(38, 42, TILE_PLAIN) world_dig(38, 43, TILE_PLAIN) world_dig(39, 42, TILE_PLAIN) world_dig(39, 43, TILE_PLAIN) world_dig(40, 42, TILE_PLAIN) world_dig(40, 43, TILE_PLAIN) world_dig(41, 42, TILE_PLAIN) world_dig(41, 43, TILE_PLAIN) world_dig(42, 42, TILE_PLAIN) world_dig(42, 43, TILE_PLAIN) world_dig(43, 42, TILE_PLAIN) world_dig(43, 43, TILE_PLAIN) world_dig(44, 42, TILE_PLAIN) world_dig(44, 43, TILE_PLAIN) world_dig(43, 41, TILE_PLAIN) world_dig(44, 41, TILE_PLAIN) world_dig(45, 41, TILE_PLAIN) world_dig(5, 37, TILE_PLAIN) world_dig(5, 38, TILE_PLAIN) world_dig(5, 39, TILE_PLAIN) world_dig(6, 39, TILE_PLAIN) world_dig(4, 38, TILE_PLAIN) world_dig(4, 39, TILE_PLAIN) world_dig(4, 40, TILE_PLAIN) world_dig(5, 40, TILE_PLAIN) world_dig(3, 39, TILE_PLAIN) world_dig(3, 40, TILE_PLAIN) world_dig(3, 41, TILE_PLAIN) world_dig(4, 41, TILE_PLAIN) world_dig(5, 41, TILE_PLAIN) world_dig(4, 42, TILE_PLAIN) world_dig(5, 42, TILE_PLAIN) world_dig(6, 42, TILE_PLAIN) world_dig(5, 43, TILE_PLAIN) world_dig(6, 43, TILE_PLAIN) world_dig(7, 42, TILE_PLAIN) world_dig(7, 43, TILE_PLAIN) world_dig(8, 43, TILE_PLAIN) world_dig(9, 43, TILE_PLAIN) world_dig(10, 43, TILE_PLAIN) world_dig(11, 43, TILE_PLAIN) world_dig(12, 43, TILE_PLAIN) world_dig(11, 42, TILE_PLAIN) world_dig(12, 42, TILE_PLAIN) world_dig(11, 41, TILE_PLAIN) world_dig(12, 41, TILE_PLAIN) world_dig(11, 40, TILE_PLAIN) world_dig(12, 40, TILE_PLAIN) world_dig(13, 40, TILE_PLAIN) world_dig(13, 41, TILE_PLAIN) world_dig(31, 21, TILE_PLAIN) world_dig(32, 21, TILE_PLAIN) world_dig(31, 20, TILE_PLAIN) world_dig(32, 20, TILE_PLAIN) world_dig(33, 20, TILE_PLAIN) world_dig(33, 21, TILE_PLAIN) world_dig(34, 20, TILE_PLAIN) world_dig(34, 21, TILE_PLAIN) world_dig(30, 21, TILE_PLAIN) world_dig(30, 20, TILE_PLAIN) world_dig(30, 24, TILE_PLAIN) world_dig(31, 24, TILE_PLAIN) world_dig(32, 24, TILE_PLAIN) world_dig(31, 25, TILE_PLAIN) world_dig(32, 25, TILE_PLAIN) world_dig(31, 26, TILE_PLAIN) world_dig(32, 26, TILE_PLAIN) world_dig(33, 25, TILE_PLAIN) world_dig(33, 26, TILE_PLAIN) world_dig(34, 25, TILE_PLAIN) world_dig(34, 26, TILE_PLAIN) world_dig(33, 24, TILE_PLAIN) world_dig(34, 24, TILE_PLAIN) world_dig(35, 21, TILE_PLAIN) world_dig(36, 21, TILE_PLAIN) world_dig(35, 20, TILE_PLAIN) world_dig(36, 20, TILE_PLAIN) world_dig(35, 25, TILE_PLAIN) world_dig(36, 25, TILE_PLAIN) world_dig(35, 26, TILE_PLAIN) world_dig(36, 26, TILE_PLAIN) world_dig(31, 19, TILE_PLAIN) world_dig(32, 19, TILE_PLAIN) world_dig(33, 19, TILE_PLAIN) world_dig(34, 19, TILE_PLAIN) world_dig(35, 19, TILE_PLAIN) world_dig(26, 16, TILE_PLAIN) world_dig(27, 16, TILE_PLAIN) world_dig(26, 17, TILE_PLAIN) world_dig(27, 17, TILE_PLAIN) world_dig(25, 16, TILE_PLAIN) world_dig(25, 17, TILE_PLAIN) world_dig(25, 18, TILE_PLAIN) world_dig(26, 18, TILE_PLAIN) world_dig(24, 17, TILE_PLAIN) world_dig(24, 18, TILE_PLAIN) world_dig(24, 19, TILE_PLAIN) world_dig(25, 19, TILE_PLAIN) world_dig(23, 18, TILE_PLAIN) world_dig(23, 19, TILE_PLAIN) world_dig(23, 20, TILE_PLAIN) world_dig(24, 20, TILE_PLAIN) world_dig(22, 19, TILE_PLAIN) world_dig(22, 20, TILE_PLAIN) world_dig(23, 21, TILE_PLAIN) local w, h = level_size() local offsets = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { -1, 0 }, { 1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 } } for x = 1, w-2 do for y = 1, h-2 do local change = true for n, offset in pairs(offsets) do local xx, yy = unpack(offset) if world_get_type(x + xx, y + yy) ~= TILE_SOLID then change = false break end end if change then world_set_gfx(x, y, TILE_GFX_LAVA) end end end world_make_border(TILE_GFX_LAVA) food_spawner = {} for s = 0, 15 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, r = math.random(3), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time() } world_add_food(food_spawner[s].x, food_spawner[s].y, 10000) end last_food = game_time() end function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/gpn.lua0000644000076400001440000002575710540115020014342 0ustar dividuumusers-- GPN Level function level_size() return 40, 28 end function level_koth_pos() return 20, 14 end function level_init() world_dig(20, 14, TILE_PLAIN) world_dig(12, 4, TILE_PLAIN) world_dig(11, 4, TILE_PLAIN) world_dig(10, 4, TILE_PLAIN) world_dig(9, 4, TILE_PLAIN) world_dig(8, 4, TILE_PLAIN) world_dig(7, 5, TILE_PLAIN) world_dig(8, 5, TILE_PLAIN) world_dig(9, 5, TILE_PLAIN) world_dig(10, 5, TILE_PLAIN) world_dig(11, 5, TILE_PLAIN) world_dig(6, 6, TILE_PLAIN) world_dig(7, 6, TILE_PLAIN) world_dig(8, 6, TILE_PLAIN) world_dig(9, 6, TILE_PLAIN) world_dig(5, 7, TILE_PLAIN) world_dig(6, 7, TILE_PLAIN) world_dig(7, 7, TILE_PLAIN) world_dig(8, 7, TILE_PLAIN) world_dig(4, 8, TILE_PLAIN) world_dig(5, 8, TILE_PLAIN) world_dig(6, 8, TILE_PLAIN) world_dig(4, 9, TILE_PLAIN) world_dig(5, 9, TILE_PLAIN) world_dig(6, 10, TILE_PLAIN) world_dig(7, 10, TILE_PLAIN) world_dig(5, 10, TILE_PLAIN) world_dig(5, 11, TILE_PLAIN) world_dig(6, 11, TILE_PLAIN) world_dig(6, 12, TILE_PLAIN) world_dig(5, 12, TILE_PLAIN) world_dig(6, 13, TILE_PLAIN) world_dig(6, 14, TILE_PLAIN) world_dig(5, 14, TILE_PLAIN) world_dig(5, 13, TILE_PLAIN) world_dig(6, 15, TILE_PLAIN) world_dig(5, 15, TILE_PLAIN) world_dig(6, 16, TILE_PLAIN) world_dig(5, 16, TILE_PLAIN) world_dig(6, 17, TILE_PLAIN) world_dig(6, 18, TILE_PLAIN) world_dig(7, 18, TILE_PLAIN) world_dig(7, 19, TILE_PLAIN) world_dig(6, 19, TILE_PLAIN) world_dig(7, 20, TILE_PLAIN) world_dig(6, 20, TILE_PLAIN) world_dig(8, 21, TILE_PLAIN) world_dig(7, 21, TILE_PLAIN) world_dig(8, 20, TILE_PLAIN) world_dig(9, 20, TILE_PLAIN) world_dig(9, 21, TILE_PLAIN) world_dig(9, 22, TILE_PLAIN) world_dig(8, 22, TILE_PLAIN) world_dig(10, 22, TILE_PLAIN) world_dig(10, 23, TILE_PLAIN) world_dig(10, 21, TILE_PLAIN) world_dig(11, 21, TILE_PLAIN) world_dig(11, 22, TILE_PLAIN) world_dig(12, 20, TILE_PLAIN) world_dig(12, 21, TILE_PLAIN) world_dig(13, 20, TILE_PLAIN) world_dig(13, 19, TILE_PLAIN) world_dig(14, 19, TILE_PLAIN) world_dig(14, 20, TILE_PLAIN) world_dig(14, 21, TILE_PLAIN) world_dig(13, 21, TILE_PLAIN) world_dig(13, 18, TILE_PLAIN) world_dig(14, 18, TILE_PLAIN) world_dig(13, 17, TILE_PLAIN) world_dig(13, 16, TILE_PLAIN) world_dig(14, 16, TILE_PLAIN) world_dig(14, 17, TILE_PLAIN) world_dig(13, 15, TILE_PLAIN) world_dig(13, 14, TILE_PLAIN) world_dig(14, 14, TILE_PLAIN) world_dig(14, 15, TILE_PLAIN) world_dig(12, 15, TILE_PLAIN) world_dig(12, 14, TILE_PLAIN) world_dig(11, 15, TILE_PLAIN) world_dig(11, 14, TILE_PLAIN) world_dig(12, 5, TILE_PLAIN) world_dig(13, 4, TILE_PLAIN) world_dig(13, 5, TILE_PLAIN) world_dig(13, 6, TILE_PLAIN) world_dig(14, 5, TILE_PLAIN) world_dig(14, 6, TILE_PLAIN) world_dig(15, 7, TILE_PLAIN) world_dig(17, 4, TILE_PLAIN) world_dig(18, 4, TILE_PLAIN) world_dig(18, 5, TILE_PLAIN) world_dig(17, 5, TILE_PLAIN) world_dig(18, 6, TILE_PLAIN) world_dig(18, 7, TILE_PLAIN) world_dig(19, 7, TILE_PLAIN) world_dig(19, 8, TILE_PLAIN) world_dig(19, 9, TILE_PLAIN) world_dig(18, 9, TILE_PLAIN) world_dig(18, 8, TILE_PLAIN) world_dig(18, 10, TILE_PLAIN) world_dig(17, 9, TILE_PLAIN) world_dig(17, 8, TILE_PLAIN) world_dig(19, 10, TILE_PLAIN) world_dig(19, 11, TILE_PLAIN) world_dig(18, 11, TILE_PLAIN) world_dig(19, 12, TILE_PLAIN) world_dig(19, 13, TILE_PLAIN) world_dig(19, 14, TILE_PLAIN) world_dig(18, 14, TILE_PLAIN) world_dig(18, 13, TILE_PLAIN) world_dig(19, 15, TILE_PLAIN) world_dig(19, 16, TILE_PLAIN) world_dig(20, 15, TILE_PLAIN) world_dig(20, 16, TILE_PLAIN) world_dig(20, 17, TILE_PLAIN) world_dig(20, 18, TILE_PLAIN) world_dig(19, 18, TILE_PLAIN) world_dig(19, 17, TILE_PLAIN) world_dig(21, 17, TILE_PLAIN) world_dig(21, 18, TILE_PLAIN) world_dig(21, 19, TILE_PLAIN) world_dig(20, 19, TILE_PLAIN) world_dig(20, 20, TILE_PLAIN) world_dig(19, 20, TILE_PLAIN) world_dig(19, 19, TILE_PLAIN) world_dig(20, 21, TILE_PLAIN) world_dig(19, 21, TILE_PLAIN) world_dig(20, 22, TILE_PLAIN) world_dig(19, 4, TILE_PLAIN) world_dig(20, 4, TILE_PLAIN) world_dig(21, 4, TILE_PLAIN) world_dig(22, 4, TILE_PLAIN) world_dig(22, 5, TILE_PLAIN) world_dig(23, 5, TILE_PLAIN) world_dig(24, 5, TILE_PLAIN) world_dig(24, 6, TILE_PLAIN) world_dig(25, 6, TILE_PLAIN) world_dig(25, 7, TILE_PLAIN) world_dig(25, 8, TILE_PLAIN) world_dig(25, 9, TILE_PLAIN) world_dig(25, 10, TILE_PLAIN) world_dig(25, 11, TILE_PLAIN) world_dig(25, 12, TILE_PLAIN) world_dig(24, 12, TILE_PLAIN) world_dig(23, 12, TILE_PLAIN) world_dig(22, 12, TILE_PLAIN) world_dig(21, 12, TILE_PLAIN) world_dig(20, 12, TILE_PLAIN) world_dig(20, 13, TILE_PLAIN) world_dig(21, 13, TILE_PLAIN) world_dig(24, 11, TILE_PLAIN) world_dig(24, 10, TILE_PLAIN) world_dig(24, 9, TILE_PLAIN) world_dig(24, 8, TILE_PLAIN) world_dig(24, 7, TILE_PLAIN) world_dig(23, 6, TILE_PLAIN) world_dig(21, 5, TILE_PLAIN) world_dig(20, 5, TILE_PLAIN) world_dig(19, 5, TILE_PLAIN) world_dig(25, 22, TILE_PLAIN) world_dig(25, 21, TILE_PLAIN) world_dig(25, 20, TILE_PLAIN) world_dig(26, 19, TILE_PLAIN) world_dig(26, 18, TILE_PLAIN) world_dig(26, 17, TILE_PLAIN) world_dig(26, 16, TILE_PLAIN) world_dig(27, 16, TILE_PLAIN) world_dig(27, 15, TILE_PLAIN) world_dig(27, 14, TILE_PLAIN) world_dig(27, 13, TILE_PLAIN) world_dig(27, 12, TILE_PLAIN) world_dig(27, 11, TILE_PLAIN) world_dig(27, 10, TILE_PLAIN) world_dig(27, 9, TILE_PLAIN) world_dig(27, 8, TILE_PLAIN) world_dig(28, 8, TILE_PLAIN) world_dig(28, 7, TILE_PLAIN) world_dig(28, 6, TILE_PLAIN) world_dig(28, 5, TILE_PLAIN) world_dig(29, 6, TILE_PLAIN) world_dig(29, 7, TILE_PLAIN) world_dig(29, 8, TILE_PLAIN) world_dig(29, 9, TILE_PLAIN) world_dig(30, 10, TILE_PLAIN) world_dig(30, 11, TILE_PLAIN) world_dig(30, 12, TILE_PLAIN) world_dig(30, 13, TILE_PLAIN) world_dig(30, 14, TILE_PLAIN) world_dig(31, 15, TILE_PLAIN) world_dig(31, 16, TILE_PLAIN) world_dig(31, 17, TILE_PLAIN) world_dig(31, 18, TILE_PLAIN) world_dig(32, 18, TILE_PLAIN) world_dig(32, 19, TILE_PLAIN) world_dig(32, 20, TILE_PLAIN) world_dig(32, 21, TILE_PLAIN) world_dig(33, 21, TILE_PLAIN) world_dig(33, 22, TILE_PLAIN) world_dig(31, 14, TILE_PLAIN) world_dig(31, 13, TILE_PLAIN) world_dig(31, 12, TILE_PLAIN) world_dig(30, 9, TILE_PLAIN) world_dig(30, 8, TILE_PLAIN) world_dig(28, 9, TILE_PLAIN) world_dig(27, 17, TILE_PLAIN) world_dig(27, 18, TILE_PLAIN) world_dig(26, 20, TILE_PLAIN) world_dig(26, 21, TILE_PLAIN) world_dig(28, 10, TILE_PLAIN) world_dig(28, 11, TILE_PLAIN) world_dig(34, 21, TILE_PLAIN) world_dig(34, 20, TILE_PLAIN) world_dig(35, 19, TILE_PLAIN) world_dig(35, 18, TILE_PLAIN) world_dig(35, 17, TILE_PLAIN) world_dig(35, 16, TILE_PLAIN) world_dig(35, 15, TILE_PLAIN) world_dig(35, 14, TILE_PLAIN) world_dig(36, 14, TILE_PLAIN) world_dig(36, 13, TILE_PLAIN) world_dig(36, 12, TILE_PLAIN) world_dig(36, 11, TILE_PLAIN) world_dig(36, 10, TILE_PLAIN) world_dig(36, 9, TILE_PLAIN) world_dig(36, 8, TILE_PLAIN) world_dig(36, 7, TILE_PLAIN) world_dig(36, 6, TILE_PLAIN) world_dig(36, 5, TILE_PLAIN) world_dig(35, 7, TILE_PLAIN) world_dig(35, 8, TILE_PLAIN) world_dig(35, 9, TILE_PLAIN) world_dig(35, 10, TILE_PLAIN) world_dig(35, 11, TILE_PLAIN) world_dig(36, 15, TILE_PLAIN) world_dig(34, 19, TILE_PLAIN) world_dig(5, 23, TILE_PLAIN) world_dig(6, 23, TILE_PLAIN) world_dig(7, 23, TILE_PLAIN) world_dig(8, 23, TILE_PLAIN) world_dig(9, 23, TILE_PLAIN) world_dig(11, 23, TILE_PLAIN) world_dig(12, 23, TILE_PLAIN) world_dig(13, 23, TILE_PLAIN) world_dig(14, 23, TILE_PLAIN) world_dig(15, 23, TILE_PLAIN) world_dig(16, 23, TILE_PLAIN) world_dig(17, 23, TILE_PLAIN) world_dig(18, 23, TILE_PLAIN) world_dig(19, 23, TILE_PLAIN) world_dig(20, 23, TILE_PLAIN) world_dig(21, 23, TILE_PLAIN) world_dig(22, 23, TILE_PLAIN) world_dig(23, 23, TILE_PLAIN) world_dig(24, 23, TILE_PLAIN) world_dig(25, 23, TILE_PLAIN) world_dig(26, 23, TILE_PLAIN) world_dig(27, 23, TILE_PLAIN) world_dig(28, 23, TILE_PLAIN) world_dig(29, 23, TILE_PLAIN) world_dig(30, 23, TILE_PLAIN) world_dig(31, 23, TILE_PLAIN) world_dig(32, 23, TILE_PLAIN) world_dig(33, 23, TILE_PLAIN) world_dig(34, 23, TILE_PLAIN) world_dig(35, 23, TILE_PLAIN) world_dig(37, 4, TILE_PLAIN) world_dig(36, 4, TILE_PLAIN) world_dig(35, 4, TILE_PLAIN) world_dig(34, 4, TILE_PLAIN) world_dig(33, 4, TILE_PLAIN) world_dig(32, 4, TILE_PLAIN) world_dig(32, 5, TILE_PLAIN) world_dig(31, 5, TILE_PLAIN) world_dig(30, 5, TILE_PLAIN) world_dig(29, 5, TILE_PLAIN) world_dig(27, 5, TILE_PLAIN) world_dig(26, 5, TILE_PLAIN) world_dig(25, 5, TILE_PLAIN) world_dig(25, 4, TILE_PLAIN) world_dig(24, 4, TILE_PLAIN) world_dig(23, 4, TILE_PLAIN) world_dig(16, 4, TILE_PLAIN) world_dig(15, 4, TILE_PLAIN) world_dig(14, 4, TILE_PLAIN) world_dig(7, 4, TILE_PLAIN) world_dig(6, 4, TILE_PLAIN) world_dig(5, 4, TILE_PLAIN) world_dig(4, 4, TILE_PLAIN) world_dig(4, 3, TILE_PLAIN) world_dig(3, 3, TILE_PLAIN) world_dig(3, 4, TILE_PLAIN) world_dig(2, 4, TILE_PLAIN) world_dig(1, 4, TILE_PLAIN) world_dig(38, 4, TILE_PLAIN) world_dig(36, 23, TILE_PLAIN) world_dig(37, 23, TILE_PLAIN) world_dig(38, 23, TILE_PLAIN) world_dig(4, 23, TILE_PLAIN) world_dig(3, 23, TILE_PLAIN) world_dig(2, 23, TILE_PLAIN) world_dig(1, 23, TILE_PLAIN) world_dig(15, 6, TILE_PLAIN) world_make_border(TILE_GFX_BORDER) food_spawner = {} for s = 0, 10 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, r = math.random(3), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time() } world_add_food(food_spawner[s].x, food_spawner[s].y, 10000) end last_food = game_time() end function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/cn.lua0000644000076400001440000004614010540115020014143 0ustar dividuumusers-- Computernight Level function level_size() return 40, 28 end function level_koth_pos() return 20, 14 end function level_init() world_fill_all(TILE_GFX_SNOW_SOLID) world_dig(20, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(20, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(20, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(20, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(37, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(38, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(38, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(37, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(37, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 7, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 5, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(29, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(30, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(31, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(32, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 25, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(4, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(4, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(5, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(6, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(8, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 22, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(9, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(10, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(11, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(12, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(38, 8, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(37, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(36, 4, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 3, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(34, 3, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(33, 3, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(20, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(26, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(27, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(28, 24, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 23, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(7, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(13, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(14, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(15, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(16, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(17, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(18, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(19, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(20, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(21, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(22, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(23, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(24, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(25, 6, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 9, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 10, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 11, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 12, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 13, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 14, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 15, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 16, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 17, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 18, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 19, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 20, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_dig(35, 21, TILE_PLAIN, TILE_GFX_SNOW_PLAIN) world_make_border(TILE_GFX_SNOW_BORDER) food_spawner = {} for s = 0, 10 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, r = math.random(3), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time() } world_add_food(food_spawner[s].x, food_spawner[s].y, 10000) end last_food = game_time() end function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/stripeslice.lua0000644000076400001440000001040510545233544016105 0ustar dividuumusers-- Mapname: Stripe Slice -- Author: Dunedan -- Version: 0.3 function maplayout() tile = {} tile["S"] = TILE_GFX_SOLID; tile["P"] = TILE_GFX_PLAIN; tile["B"] = TILE_GFX_BORDER; tile["T"] = TILE_GFX_SNOW_SOLID; tile["U"] = TILE_GFX_SNOW_PLAIN; tile["V"] = TILE_GFX_SNOW_BORDER; tile["W"] = TILE_GFX_WATER; tile["L"] = TILE_GFX_LAVA; tile["N"] = TILE_GFX_NONE; tile["K"] = TILE_GFX_KOTH; tile["D"] = TILE_GFX_DESERT; m = {} m[1] = "WWWWWWWWWWWWWWWWWWWWUUTTTUUUUUUTTUUUUUWWWWWWWWWWWWWWWWWWWW"; m[2] = "WWWWWWWWWWWWWWWWWUUUUUTTUUUUUUUTTUUUUUUUUWWWWWWWWWWWWWWWWW"; m[3] = "WWWWWWWWWWWWWWUUUUUUUUUUUUUUUUTTTUUUUSSSSSSSWWWWWWWWWWWWWW"; m[4] = "WWWWWWWWWWWUUUUUUUUUUUUUUTTUUUUTUUUUSSSUUUSSSUUWWWWWWWWWWW"; m[5] = "WWWWWWWWTTTTUUUUUUUUUTTTTTUUUUUUUUUUSSSUUUUUUUUUUUWWWWWWWW"; m[6] = "WWWWWWUUTTUUUUUUUUUUPTTTTTUUUUUUUUUUUUUUUUUUSSUUUUUUWWWWWW"; m[7] = "WWWWUUUUUUUUUUTTTUPPPTTTTTTTUUUUUSSSSUUUUPPSSSPPUUUTTTWWWW"; m[8] = "WWUUUUUPPPUUPPTTTPPPPPTTPPPPPPPPPSSSSSPPPPPPPPPPPPPTTTTPWW"; m[9] = "WSSPPPPPPPPPPPPPTPPPPPPSSPPPPPPPPPPPPPPPPPPPPPPPPPPTTTPPPW"; m[10] = "SSSPPPPPPPPPPPPPPPPPPPPSSSPPPPPPPPPPSSSSSPPPPPPPPPPPPPPPPP"; m[11] = "PPSSPPPPPPSSSPPPPPPPPPPSSPPPPPPPPPPPPPSSPPPPPPPPPSSPPPPPPP"; m[12] = "PPSSPPPPPSSSSDDDDPPPPPSSPPPPPPPPPPPPPPSSSSPPDDDPPPSPPPPPPP"; m[13] = "DPSSDDDDSSDDDDDDDDDDDDDDDPSSSSSSDDDDDDSSSDDDDDDDDDSSDDDDDD"; m[14] = "DDDSDDDDSSSDDDDSSSSDDSSDDSSSSDDDDDDDDDDSSDDDSSDDDSSSSSDDDD"; m[15] = "DDDSDDDDDSSSSSSSSSSSDSSDDDDDDKDDDDDSSDDDDDDDSSDDDDDSSDDDDD"; m[16] = "DDDDDDDDDSSDDDDSSSDDDDSSDDDDDDDDDDDDSSDDDDDDSSDDDDDDDDDDSS"; m[17] = "DDDDDDDDDSSDDDDDDDDDDDDDDDDSSSSSDPPPSSSSDDDDDDDDDDDDDSSSSS"; m[18] = "PPPLLDDSSSDDPPPPPPPPPPPPPSSSSSSDDPPPPSSPPPPPPPPPPPPPPPSSSS"; m[19] = "PPLLLPPPPSSSPPPPPPPPPPPPPPPSSPPPPPPPPSSPPPTTPPPPPPSSSSSSSS"; m[20] = "PPLLLPPPPSSSSPPPPPPPPPPPPPPPPPPPPPPPPSPPPTTTPPPPSSSSSSSPPP"; m[21] = "WPPPPPPPPPSSSPPPPPTTTTTPPPPPPPPPTTPPPSSPPTTTPPPPPSSSPPPPPW"; m[22] = "WWPPPPPPPPTTPPPPPPPTTTTPPPPPPPTTTTPPPPPPPPTTPPPPUUSSPPPPWW"; m[23] = "WWWWUUUUUUTTTUUUPPPTTTUUUUUUUUUTUUUUUPPPUUTTUUUUUUUUUUWWWW"; m[24] = "WWWWWWUUUUUUUUUUUUUTTTUUUUUUUUUTUUUUUUUUUUTTUUUUUUUUWWWWWW"; m[25] = "WWWWWWWWUUUUUUUUUUUTTUUUUUUUUUTTUUUUUUUUUUTTUUUUUUWWWWWWWW"; m[26] = "WWWWWWWWWWWTTUUUUUUUUUUUUUUTTTTTTTUUUUUUUUUUUUUWWWWWWWWWWW"; m[27] = "WWWWWWWWWWWWWWUUUUUUUUUTTTTTTTTTUUUUUTTTUUUUWWWWWWWWWWWWWW"; m[28] = "WWWWWWWWWWWWWWWWWUUUUUUUUUUUUUUUUUUUUUTTUWWWWWWWWWWWWWWWWW"; m[29] = "WWWWWWWWWWWWWWWWWWWWTTUUUUUUUUUUUUUUUUWWWWWWWWWWWWWWWWWWWW"; end function level_size() local mapsizeX = 1 local mapsizeY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do if string.len(m[i]) > mapsizeX then mapsizeX = string.len(m[i]) end end mapsizeY = arraySize return mapsizeX+2, mapsizeY+2 end function level_koth_pos() local kothX = 1 local kothY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "K" then kothX = j kothY = i end end end return kothX, kothY end -- wird aufgerufen wenn ein Bot joint -- player ist, uh wie erstaunlich, die Spielernummer --function level_spawn_point(player) -- availSpawnpoints = {{2,2},{15,15}} -- return world_tile_center(15, 15) --end function level_init() maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "P" or k == "U" or k == "D" or k == "K" then world_set_type(j,i, TILE_PLAIN) end world_set_gfx(j,i, tile[k]) end end world_make_border(TILE_GFX_WATER) food_spawner = {} for s = 0, 15 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, r = math.random(2), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time() } world_add_food(food_spawner[s].x, food_spawner[s].y, 10000) end last_food = game_time() end -- wird, wie der Name schon sagt, jede Runde ausgefuehrt function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/infon.lua0000644000076400001440000001256410603240401014661 0ustar dividuumusers-- Mapname: infon -- Author: g, copied a lot of code from Dunedan -- Version: 0.1 function maplayout() tile = {} tile["S"] = TILE_GFX_SOLID; tile["P"] = TILE_GFX_PLAIN; tile["B"] = TILE_GFX_BORDER; tile["T"] = TILE_GFX_SNOW_SOLID; tile["U"] = TILE_GFX_SNOW_PLAIN; tile["V"] = TILE_GFX_SNOW_BORDER; tile["W"] = TILE_GFX_WATER; tile["L"] = TILE_GFX_LAVA; tile["N"] = TILE_GFX_NONE; tile["K"] = TILE_GFX_KOTH; tile["D"] = TILE_GFX_DESERT; m = {} m[ 1] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 2] = "PPPPPSPPPPPPPPPPPPPPPPPPPPPPPSSSSSSSPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 3] = "PPPPSSSPPPPPPPPPPPPPPPPPPPPPSSSPPSSSPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 4] = "PPPPSSSPPPPPPPPPPPPPPPPPPPPSSSPPPSSSPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 5] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPSSSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 6] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPSSSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 7] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPSSSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[ 8] = "PSSSSSSPPPSSSSPPSSSSSPPPPPSSSSSSSPPPSSSSSSPPPPSSSSSPSSSSSSPPPP"; m[ 9] = "PPPPSSSPPPPSSSSSPPPSSSPPPPPSSSPPPPPSSWWWWSSSPPPPSSSSPPPSSSSPPP"; m[10] = "PPPPSSSPPPPSSSSPPPPPSSPPPPPSSSPPPPSSSWWWWWSSPPPPSSSSPPPPSSSPPP"; m[11] = "PPPPSSSPPPPSSSSPPPPPSSSPPPPSSSPPPPSSSWWWWWSSSPPPSSSPPPPPSSSPPP"; m[12] = "PPPPSSSPPPPSSSPPPPPPSSSPPPPSSSPPPPSSWWWWWWSSSPPPSSSPPPPPSSSPPP"; m[13] = "PPPPSSSPPPPSSSPPPPPPSSSPPPPSSSPPPPSSWWWKWWSSSPPPSSSPPPPPSSSPPP"; m[14] = "PPPPSSSPPPPSSSPPPPPPSSSPPPPSSSPPPPSSWWWWWWSSSPPPSSSPPPPPSSSPPP"; m[15] = "PPPPSSSPPPPSSSPPPPPPSSSPPPPSSSPPPPSSSWWWWWSSPPPPSSSPPPPPSSSPPP"; m[16] = "PPPPSSSPPPPSSSPPPPPPSSSPPPPSSSPPPPPSSWWWWWSSPPPPSSSPPPPPSSSPPP"; m[17] = "PPPPSSSPPPPSSSSPPPPPSSSPPPPSSSPPPPPSSSWWWSSPPPPPSSSPPPPPSSSPPP"; m[18] = "PPSSSSSSSPSSSSSSSPSSSSSSSPSSSSSSSPPPPSSSSSPPPPSSSSSSSPSSSSSSSP"; m[19] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; m[20] = "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"; end function level_size() local mapsizeX = 1 local mapsizeY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do if string.len(m[i]) > mapsizeX then mapsizeX = string.len(m[i]) end end mapsizeY = arraySize return mapsizeX+2, mapsizeY+2 end function level_koth_pos() local kothX = 1 local kothY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "K" then kothX = j kothY = i end end end return kothX, kothY end -- wird aufgerufen wenn ein Bot joint -- player ist, uh wie erstaunlich, die Spielernummer --function level_spawn_point(player) -- availSpawnpoints = {{2,2},{15,15}} -- return world_tile_center(15, 15) --end function level_init() maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "P" or k == "U" or k == "D" or k == "K" then world_set_type(j,i, TILE_PLAIN) end world_set_gfx(j,i, tile[k]) end end -- world_make_border(TILE_GFX_WATER) food_spawner = {} food_spawner[0] = { x = 17, y = 12, r = 4, a = 300, i = 200, n = 0, } food_spawner[1] = { x = 54, y = 12, r = 4, a = 300, i = 200, n = 0, } for s = 2, 12 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, r = math.random(2), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time(), } world_add_food(food_spawner[s].x, food_spawner[s].y, 9000) end last_food = game_time() end -- wird, wie der Name schon sagt, jede Runde ausgefuehrt function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.r * 2 + 1 ) - spawner.r, spawner.y + math.random(spawner.r * 2 + 1 ) - spawner.r, spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/level/castle.lua0000644000076400001440000002003010603240401015006 0ustar dividuumusers-- Mapname: castle -- Author: g, copied lot of code from Dunedan -- Version: 0.1 function maplayout() tile = {} tile["S"] = TILE_GFX_SOLID; tile["P"] = TILE_GFX_PLAIN; tile["B"] = TILE_GFX_BORDER; tile["T"] = TILE_GFX_SNOW_SOLID; tile["U"] = TILE_GFX_SNOW_PLAIN; tile["V"] = TILE_GFX_SNOW_BORDER; tile["W"] = TILE_GFX_WATER; tile["L"] = TILE_GFX_LAVA; tile["N"] = TILE_GFX_NONE; tile["K"] = TILE_GFX_KOTH; tile["D"] = TILE_GFX_DESERT; m = {} m[ 1] = "SSSSSSWWWWWWWWWWWWWWWWWWWWWWWSSSSSWWWWWWWWWWWWWWWWWWWWWWWSSSSSS"; m[ 2] = "SPPPPSWSSSSSWSSSSSWSSSSSWSSSSSPPPSSSSSWSSSSSWSSSSSWSSSSSWSPPPPS"; m[ 3] = "SPPPPSSSPPPSSSPPPSSSPPPSSSPPPPPPPPPPPSSSPPPSSSPPPSSSPPPSSSPPPPS"; m[ 4] = "SPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPS"; m[ 5] = "SPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPS"; m[ 6] = "SSSPPSSPPPPPPPPPPPPPPPPPPPPSSPPPPPSSPPPPPPPPPPPPPPPPPPPPSSPPSSS"; m[ 7] = "WWSPPSSSSPPPPSPPSSSPPPPPPSSSSSPPPSSSSSPPPPPPSSSPPSPPPPSSSSPPSWW"; m[ 8] = "WSSPPPSSSSSPPSSPPSSSSPPSSSSSSSPPPSSSSSSSPPSSSSPPSSPPSSSSSPPPSSW"; m[ 9] = "WSPPPPSSSSSSPPSSPPSSSSSSSSSSSPPPPPSSSSSSSSSSSPPSSPPSSSSSSPPPPSW"; m[10] = "WSPPPPPSSSSSSSSSSPPSSSSSSSSSPPPSPPPSSSSSSSSSPPSSSSSSSSSSPPPPPSW"; m[11] = "WSPPPPPSSSSSSSSSSSPPSSSSSSSPPPSSSPPPSSSSSSSPPSSSSSSSSSSSPPPPPSW"; m[12] = "WSSPPPPPSSSSSSSSSSSPPSSSSSPPPSSSSSPPPSSSSSPPSSSSSSSSSSSPPPPPSSW"; m[13] = "WWSPPPPPSSSSSSSSSSSSPPSPSPPPPSSSSSPPPPSPSPPSSSSSSSSSSSSPPPPPSWW"; m[14] = "WSSPPPPPPSPPPSPPPSPPPPPPPPPPPPSSSPPPPPPPPPPPPSPPPSPPPSPPPPPPSSW"; m[15] = "WSPPPPPPPPPSPPPSPPPSPPPPPPSSSPPSPPSSSPPPPPPSPPPSPPPSPPPPPPPPPSW"; m[16] = "WSPPPPPPSSSSSSSSSSSSSSPPPSSSSSPPPSSSSSPPPSSSSSSSSSSSSSSPPPPPPSW"; m[17] = "WSPPPPPPSSSSSSSSSSSSSPPPSSSSSSSPSSSSSSSPPPSSSSSSSSSSSSSPPPPPPSW"; m[18] = "WSSPPPPSSSSSSSSSSSSSPPPSSSSSSSPPPSSSSSSSPPPSSSSSSSSSSSSSPPPPSSW"; m[19] = "WWSPPPPSSSSSSSSSSSSPPPSSSSSSSPPPPPSSSSSSSPPPSSSSSSSSSSSSPPPPSWW"; m[20] = "WSSPPPSSSSSSSSSSSSPPPSSSSSSSPPPSPPPSSSSSSSPPPSSSSSSSSSSSSPPPSSW"; m[21] = "WSPPPPSSSSSSSSSSSPPPSSSSSSSSPSSSSSPSSSSSSSSPPPSSSSSSSSSSSPPPPSW"; m[22] = "SSPPPSSPPSSPPSSPPPPPPSSPPSSPPSPPPSPPSSPPSSPPPPPPSSPPSSPPSSPPPSS"; m[23] = "SPPPPPPPPPPPPPPPPPPPPPPPPPPPSSPKPSSPPPPPPPPPPPPPPPPPPPPPPPPPPPS"; m[24] = "SSPPPSSPPSSPPSSPPPPPPSSPPSSPPSPPPSPPSSPPSSPPPPPPSSPPSSPPSSPPPSS"; m[25] = "WSPPPPSSSSSSSSSSSPPPSSSSSSSSPSSSSSPSSSSSSSSPPPSSSSSSSSSSSPPPPSW"; m[26] = "WSSPPPSSSSSSSSSSSSPPPSSSSSSSPPPSPPPSSSSSSSPPPSSSSSSSSSSSSPPPSSW"; m[27] = "WWSPPPPSSSSSSSSSSSSPPPSSSSSSSPPPPPSSSSSSSPPPSSSSSSSSSSSSPPPPSWW"; m[28] = "WSSPPPPSSSSSSSSSSSSSPPPSSSSSSSPPPSSSSSSSPPPSSSSSSSSSSSSSPPPPSSW"; m[29] = "WSPPPPPPSSSSSSSSSSSSSPPPSSSSSSSPSSSSSSSPPPSSSSSSSSSSSSSPPPPPPSW"; m[30] = "WSPPPPPPSSSSSSSSSSSSSSPPPSSSSSPPPSSSSSPPPSSSSSSSSSSSSSSPPPPPPSW"; m[31] = "WSPPPPPPPPPSPPPSPPPSPPPPPPSSSPPSPPSSSPPPPPPSPPPSPPPSPPPPPPPPPSW"; m[32] = "WSSPPPPPPSPPPSPPPSPPPPPPPPPPPPSSSPPPPPPPPPPPPSPPPSPPPSPPPPPPSSW"; m[33] = "WWSPPPPPSSSSSSSSSSSSPPSPSPPPPSSSSSPPPPSPSPPSSSSSSSSSSSSPPPPPSWW"; m[34] = "WSSPPPPPSSSSSSSSSSSPPSSSSSPPPSSSSSPPPSSSSSPPSSSSSSSSSSSPPPPPSSW"; m[35] = "WSPPPPPSSSSSSSSSSSPPSSSSSSSPPPSSSPPPSSSSSSSPPSSSSSSSSSSSPPPPPSW"; m[36] = "WSPPPPPSSSSSSSSSSPPSSSSSSSSSPPPSPPPSSSSSSSSSPPSSSSSSSSSSPPPPPSW"; m[37] = "WSPPPPSSSSSSPPSSPPSSSSSSSSSSSPPPPPSSSSSSSSSSSPPSSPPSSSSSSPPPPSW"; m[38] = "WSSPPPSSSSSPPSSPPSSSSPPSSSSSSSPPPSSSSSSSPPSSSSPPSSPPSSSSSPPPSSW"; m[39] = "WWSPPSSSSPPPPSPPSSSPPPPPPSSSSSPPPSSSSSPPPPPPSSSPPSPPPPSSSSPPSWW"; m[40] = "SSSPPSSPPPPPPPPPPPPPPPPPPPPSSPPPPPSSPPPPPPPPPPPPPPPPPPPPSSPPSSS"; m[41] = "SPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPS"; m[42] = "SPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPS"; m[43] = "SPPPPSSSPPPSSSPPPSSSPPPSSSPPPPPPPPPPPSSSPPPSSSPPPSSSPPPSSSPPPPS"; m[44] = "SPPPPSWSSSSSWSSSSSWSSSSSWSSSSSPPPSSSSSWSSSSSWSSSSSWSSSSSWSPPPPS"; m[45] = "SSSSSSWWWWWWWWWWWWWWWWWWWWWWWSSSSSWWWWWWWWWWWWWWWWWWWWWWWSSSSSS"; end function level_size() local mapsizeX = 1 local mapsizeY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do if string.len(m[i]) > mapsizeX then mapsizeX = string.len(m[i]) end end mapsizeY = arraySize return mapsizeX+2, mapsizeY+2 end function level_koth_pos() local kothX = 1 local kothY = 1 maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "K" then kothX = j kothY = i end end end return kothX, kothY end -- wird aufgerufen wenn ein Bot joint -- player ist, uh wie erstaunlich, die Spielernummer --function level_spawn_point(player) -- availSpawnpoints = {{2,2},{15,15}} -- return world_tile_center(15, 15) --end function level_init() maplayout() arraySize = table.getn(m); for i=1, arraySize, 1 do for j=1, string.len(m[i]), 1 do k = string.upper(string.sub(m[i],j,j)) if k == "P" or k == "U" or k == "D" or k == "K" then world_set_type(j,i, TILE_PLAIN) end world_set_gfx(j,i, tile[k]) end end world_make_border(TILE_GFX_WATER) food_spawner = {} food_spawner[0] = { x = 1, y = 1, rx = 61, ry = 2, a = 200, i = 200, n = game_time() } food_spawner[1] = { x = 1, y = 42, rx = 61, ry = 2, a = 200, i = 200, n = game_time() } food_spawner[2] = { x = 1, y = 3, rx = 2, ry = 39, a = 200, i = 200, n = game_time() } food_spawner[3] = { x = 60, y = 3, rx = 2, ry = 39, a = 200, i = 200, n = game_time() } for s = 4, 20 do local dx, dy = world_find_digged() food_spawner[s] = { x = dx, y = dy, rx = math.random(5), ry = math.random(5), a = math.random(100) + 30, i = math.random(1000) + 1000, n = game_time() } world_add_food(food_spawner[s].x, food_spawner[s].y, 10000) end last_food = game_time() end -- wird, wie der Name schon sagt, jede Runde ausgefuehrt function level_tick() if game_time() > last_food + 10000 then for n, spawner in pairs(food_spawner) do if game_time() > spawner.n then world_add_food(spawner.x + math.random(spawner.rx) , spawner.y + math.random(spawner.ry) , spawner.a) spawner.n = spawner.n + spawner.i end end end end infon/contrib/0000755000076400001440000000000010603314645013402 5ustar dividuumusersinfon/contrib/debian/0000755000076400001440000000000010540115021014607 5ustar dividuumusersinfon/contrib/debian/patches/0000755000076400001440000000000010540115021016236 5ustar dividuumusersinfon/contrib/debian/patches/10-config.lua.dpatch0000755000076400001440000000171210540115021021672 0ustar dividuumusers#! /bin/sh /usr/share/dpatch/dpatch-run ## 10-config.lua.dpatch by Joachim Breitner ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: No description. @DPATCH@ diff -urNad infon-0~r139~/config.lua infon-0~r139/config.lua --- infon-0~r139~/config.lua 2006-12-22 15:51:04.000000000 +0000 +++ infon-0~r139/config.lua 2006-12-22 15:54:21.884025875 +0000 @@ -1,12 +1,15 @@ -- ip and port to bind listen socket -listenaddr = "0.0.0.0" +listenaddr = "127.0.0.1" listenport = 1234 +-- uncomment the following line to enable other players +-- to connect over the network +-- listenaddr = "0.0.0.0" -- password for the 'shell' command. disabled if empty or missing. debugpass = "" -- message displayed every 10 seconds -join_info = "this message can be changed in config.lua" +join_info = "this message can be changed in /etc/infond/config.lua" -- maps to rotate maps = {"foo", "gpn", "water", "cn", "owl" } infon/contrib/debian/patches/00list0000644000076400001440000000001610540115021017271 0ustar dividuumusers10-config.lua infon/contrib/debian/addfiles/0000755000076400001440000000000010532602710016371 5ustar dividuumusersinfon/contrib/debian/addfiles/infon-wrapper0000644000076400001440000000035210532602710021103 0ustar dividuumusers#!/bin/bash . /usr/bin/ssft.sh [ -n "$SSFT_FRONTEND" ] || SSFT_FRONTEND="$( ssft_choose_frontend )" SSFT_DEFAULT="infon.dividuum.de:1234" if ssft_read_string "Infon" "Connect to server:" then infon $SSFT_RESULT else exit 1 fi infon/contrib/debian/addfiles/daemonize.h0000644000076400001440000000505410532602710020521 0ustar dividuumusers/* Copyright (c) 2006 Joachim Breitner . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #define PIDFILE "/var/run/infond.pid" void undaemonize() { int ret; ret = unlink(PIDFILE); if (ret == -1) { perror("Could not delete " PIDFILE); // exit(1); } } void daemonize(int argc, char *argv[]) { int ret; if ( ! (argc > 1 && strcmp(argv[1], "-d") == 0) ) { return; } /* init script has to change directory */ /* ret = chdir("/usr/share/infon-server/"); if (ret == -1) { perror("Could not change to data directory"); exit(1); } */ int pid = fork(); if (pid == -1) { // error perror("Could not fork"); exit(1); } if (pid) { // parent process FILE *pidfile = fopen(PIDFILE,"w"); if (pidfile == NULL) { perror("Could not open pidfile"); exit(1); } ret = fprintf(pidfile,"%d\n",pid); if (ret < 0) { perror("Could not write to pidfile"); } ret = fclose(pidfile); if (ret != 0) { perror("Could not close pidfile"); } exit(EXIT_SUCCESS); } else { struct passwd *pwinfo = getpwnam("nobody"); if (pwinfo == NULL) { perror("Could not find user nobody"); exit (1); } if (setuid(pwinfo->pw_uid) == -1) { perror("Could not change userid"); exit(1); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } atexit(undaemonize); } infon/contrib/debian/infon-viewer.manpages0000644000076400001440000000001710532602710020741 0ustar dividuumusersdebian/infon.6 infon/contrib/debian/infon-server.init0000644000076400001440000000226210532602710020122 0ustar dividuumusers#! /bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/bin/infond DAEMON_OPTS=-d NAME=infond DESC=infond test -x $DAEMON || exit 0 # Include infon defaults if available if [ -f /etc/default/infon-server ] ; then . /etc/default/infon-server fi test "$START_INFOND" = "1" || exit 0 set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --pidfile /var/run/$NAME.pid \ --chdir /usr/share/infon-server/ \ --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; force-reload) start-stop-daemon --stop --test --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON \ && $0 restart \ || exit 0 ;; restart) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON sleep 1 start-stop-daemon --start --pidfile /var/run/$NAME.pid \ --chdir /usr/share/infon-server/ \ --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 infon/contrib/debian/control0000644000076400001440000000335110540115021016214 0ustar dividuumusersSource: infon Section: games Priority: extra Maintainer: Joachim Breitner Build-Depends: debhelper (>= 5), libevent-dev, zlib1g-dev, libreadline5-dev, libsdl1.2-dev, libsdl-gfx1.2-dev, libsdl-sge-dev, dpatch Standards-Version: 3.7.2 XS-Vcs-Svn: http://infon.dividuum.de/svn/infon/trunk/contrib/debian Package: infon-server Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Program bugs to compete for food and survival - Server Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their “intelligence” in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. . This package contains the infon server which hosts the game. To upload code to it, you only need a telnet client. To be able to view the game, see the infon-viewer package. . Homepage: http://infon.dividuum.de/ Package: infon-viewer Architecture: any Recommends: infon-devel Suggests: infon-server Depends: ${shlibs:Depends}, ${misc:Depends}, ssft, zenity | kdebase Description: Program bugs to compete for food and survival - GUI Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their “intelligence” in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. . This package contains the graphical client to view the game in progress. To host a game, see the infon-server package. . Homepage: http://infon.dividuum.de/ infon/contrib/debian/infon-server.install0000644000076400001440000000027310540115021020616 0ustar dividuumusersinfond usr/bin level/ usr/share/infon-server/ infond.lua player.lua player-default.lua player-highlevel.lua server.lua usr/share/infon-server/ rules/ etc/infond/ config.lua etc/infond/ infon/contrib/debian/infond.80000644000076400001440000000353110532602710016166 0ustar dividuumusers.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH INFOND 8 "November 21, 2006" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME infond \- Program bugs to compete for food and survival .SH SYNOPSIS .B infond .RI [ -d ] .SH DESCRIPTION This manual page documents briefly the .B infond command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBinfond\fP is the server for the infon game. Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their "intelligence" in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. The server will be accessible on port 1234 for telnet clients as well as for graphical clients, such as .BR infon (6). It can be configured by editing the file .BR /etc/infond.lua . .SH OPTIONS .TP .B \-d Runs the program daemonized. Requires root. .SH SEE ALSO .BR infon (6) .SH AUTHOR infon was written by Florian Wesch .PP This manual page was written by Joachim Breitner , for the Debian project (but may be used by others). infon/contrib/debian/compat0000644000076400001440000000000210532602710016014 0ustar dividuumusers5 infon/contrib/debian/changelog0000644000076400001440000000176010540115021016465 0ustar dividuumusersinfon (0~r139-1) unstable; urgency=low * New upstream release * Dropping patches/20-quieten-infond.dpatch, upstream supports a flag for that * Upload to unstable, since etch is frozen. * Sponsored by http://www.aiti-kace.com.gh/ -- Joachim Breitner Fri, 22 Dec 2006 16:35:26 +0000 infon (0~r99-2) experimental; urgency=low * missing build-dep on dpatch (Closes: #402608) (I thought I had checked it in pbuilder. I thought wrongly) -- Joachim Breitner Mon, 11 Dec 2006 18:02:29 +0000 infon (0~r99-1) experimental; urgency=low * New upstream version * Added XS-Vcs-Svn header * Sponsored by AITI-KACE, Accra, Ghana -- Joachim Breitner Mon, 27 Nov 2006 13:29:51 +0000 infon (0~r89-1) experimental; urgency=low * Initial release * Upload to experimental as per release manager’s wish * Sponsored by AITI-KACE, Accra, Ghana -- Joachim Breitner Tue, 21 Nov 2006 09:26:56 +0000 infon/contrib/debian/rules0000755000076400001440000000522210540115021015670 0ustar dividuumusers#!/usr/bin/make -f # -*- makefile -*- # # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 include /usr/share/dpatch/dpatch.make # This has to be exported to make some magic below work. export DH_OPTIONS export CFLAGS = -Wall -g -DDAEMONIZING -DNO_CONSOLE_CLIENT -DRENDERER_PATH=\"/usr/lib/infon-viewer/\" ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. touch configure-stamp addfiles_in: cp debian/addfiles/* . chmod +x infon-wrapper addfiles_out: for file in debian/addfiles/*; do rm -f $$(basename $$file); done #Architecture build: patch addfiles_in build-arch build-indep build-arch: build-arch-stamp build-arch-stamp: configure-stamp # Add here commands to compile the arch part of the package. $(MAKE) infond PREFIX=/usr/share/infon-server/ $(MAKE) infon sdl_gui.so null_gui.so PREFIX=/usr/share/infon-viewer/ touch $@ build-indep: build-indep-stamp build-indep-stamp: configure-stamp # Add here commands to compile the indep part of the package. #$(MAKE) doc touch $@ clean: clean-patched addfiles_out unpatch clean-patched: dh_testdir dh_testroot rm -f build-arch-stamp build-indep-stamp # Add here commands to clean up after the build process. -$(MAKE) clean -$(MAKE) -C lua-5.1.1 clean dh_clean install: install-indep install-arch install-indep: dh_testdir dh_testroot dh_clean -k -i dh_installdirs -i dh_install -i install-arch: dh_testdir dh_testroot dh_clean -k -s dh_installdirs -s #(MAKE) DESTDIR=$(CURDIR)/debian/infon install ln -s ../../../etc/infond/config.lua debian/infon-server/usr/share/infon-server/config.lua ln -s ../../../etc/infond/rules debian/infon-server/usr/share/infon-server/rules dh_install -s # Must not depend on anything. This is to be called by # binary-arch/binary-indep # in another 'make' thread. binary-common: dh_testdir dh_testroot dh_installchangelogs dh_installdocs # dh_installexamples dh_installmenu dh_installinit dh_installman dh_link dh_strip dh_compress dh_fixperms dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb # Build architecture independant packages using the common target. binary-indep: build-indep install-indep $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common # Build architecture dependant packages using the common target. binary-arch: build-arch install-arch $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common #binary: binary-arch binary-indep binary: binary-arch .PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure infon/contrib/debian/infon-server.default0000644000076400001440000000024610532602710020603 0ustar dividuumusers# If you want the infon server to run, switch this to 1. # You might also want to enable access from your network # by editing /etc/infond/config.lua START_INFOND=0 infon/contrib/debian/infon.60000644000076400001440000000314710532602710016023 0ustar dividuumusers.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH INFON 6 "November 21, 2006" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME infon \- Program bugs to compete for food and survival .SH SYNOPSIS .B infon .RI server[:port] .SH DESCRIPTION This manual page documents briefly the .B infon command. .PP \fBinfonx\fP is the graphical viewers for the infon game. Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their "intelligence" in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. You have to specify the hostname of the server to connect to on the command line. .SH OPTIONS .TP .B server[:port] The server (and port) to connect to. .SH SEE ALSO .BR infond (8) .SH AUTHOR infon was written by Florian Wesch .PP This manual page was written by Joachim Breitner , for the Debian project (but may be used by others). infon/contrib/debian/infon-server.manpages0000644000076400001440000000002010532602710020740 0ustar dividuumusersdebian/infond.8 infon/contrib/debian/copyright0000644000076400001440000000657310532602710016564 0ustar dividuumusersThis package was debianized by Joachim Breitner on Tue, 21 Nov 2006 09:26:56 +0000. It was downloaded from http://infon.dividuum.de/ Upstream Author: Florian Wesch # # infon game: # Copyright: 2006 Florian Wesch License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. On Debian systems, the complete text of the GNU General Public License, version 2 can be found in '/usr/share/common-licenses/GPL-2'. # # gfx/5x7.fnt is taken from the SDL_glx project: # Copyright: Andreas Schiffler This file is available under the GNU Library General Public License. On Debian GNU/Linux systems, the complete text of the GNU Library General Public License is found in `/usr/share/common-licenses/LGPL-2'. # # gfx/font.png is taken from the SDL_sge project: # Copyright: Anders Lindström This file is available under the GNU Library General Public License. On Debian GNU/Linux systems, the complete text of the GNU Library General Public License is found in `/usr/share/common-licenses/LGPL'. # # included lua source: # Lua is licensed under the terms of the MIT license reproduced below. This means that Lua is free software and can be used for both academic and commercial purposes at absolutely no cost. For details and rationale, see http://www.lua.org/license.html . =============================================================================== Copyright (C) 1994-2006 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================================================== # # Debian packaging, including daemonize.h # The Debian packaging is (C) 2006, Joachim Breitner and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. infon/contrib/debian/infon-viewer.menu0000644000076400001440000000020610532602710020112 0ustar dividuumusers?package(infon-viewer):needs="X11" section="Games/Simulation"\ title="Infon viewer" command="/usr/share/infon-viewer/infon-wrapper" infon/contrib/debian/infon-viewer.install0000644000076400001440000000031210540115021020603 0ustar dividuumusersinfon usr/bin infon-wrapper usr/share/infon-viewer gfx/theme.png usr/share/infon-viewer/gfx gfx/5x7.fnt usr/share/infon-viewer/gfx gfx/font.png usr/share/infon-viewer/gfx *_gui.so usr/lib/infon-viewer infon/contrib/debian/infon-server.dirs0000644000076400001440000000002710532602710020115 0ustar dividuumusersusr/share/infon-server infon/contrib/infon-devel/0000755000076400001440000000000010540115022015574 5ustar dividuumusersinfon/contrib/infon-devel/infon-devel.py0000755000076400001440000004465510540115022020375 0ustar dividuumusers#!/usr/bin/python # encoding:utf8 # Infon-Devel # Copyright (C) 2006 Joachim Breitner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software PREFIX = './' import pygtk pygtk.require('2.0') import gtk import gobject import gtksourceview import os import sys if not PREFIX in sys.path: sys.path.insert(0, PREFIX) import connview import infonconn class ConnDialog(gtk.Dialog): def __init__(self,window): gtk.Dialog.__init__(self, "Connect to Infon Server", window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK, ) ) self.e_hostname = gtk.Entry() self.e_port = gtk.Entry() self.e_username = gtk.Entry() self.e_password = gtk.Entry() self.vbox.add(gtk.Label("Server")) self.vbox.add(self.e_hostname) self.vbox.add(gtk.Label("Port")) self.vbox.add(self.e_port) self.vbox.add(gtk.Label("Username")) self.vbox.add(self.e_username) self.vbox.add(gtk.Label("Password")) self.vbox.add(self.e_password) self.vbox.show_all() hostname = property( lambda self: self.e_hostname.get_text(), lambda self,v: self.e_hostname.set_text(v)) port = property( lambda self: self.e_port.get_text(), lambda self,v: self.e_port.set_text(v)) username = property( lambda self: self.e_username.get_text(), lambda self,v: self.e_username.set_text(v)) password = property( lambda self: self.e_password.get_text(), lambda self,v: self.e_password.set_text(v)) def run(self): response = gtk.Dialog.run(self) self.hide() return response def run_name_only(self): self.e_hostname.set_sensitive(False) self.e_port.set_sensitive(False) self.e_password.set_sensitive(False) response = gtk.Dialog.run(self) self.hide() self.e_hostname.set_sensitive(True) self.e_port.set_sensitive(True) self.e_password.set_sensitive(True) return response class InfonDevel: def new(self,action): # Check for possible changes! self.bugbuf.begin_not_undoable_action() self.bugbuf.set_text("") self.filename = None self.bugbuf.end_not_undoable_action() self.bugbuf.set_modified(False) self.bugbuf.place_cursor(self.bugbuf.get_start_iter()) def open(self, action): chooser = gtk.FileChooserDialog('Open bug...', None, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) response = chooser.run() if response == gtk.RESPONSE_OK: filename = chooser.get_filename() if filename: self.open_file(filename) chooser.destroy() def open_file(self,filename): if os.path.isabs(filename): path = filename else: path = os.path.abspath(filename) try: txt = open(path).read() except: return False self.bugbuf.begin_not_undoable_action() self.bugbuf.set_text(txt) self.bugbuf.end_not_undoable_action() self.filename = path self.bugbuf.set_modified(False) self.bugbuf.place_cursor(self.bugbuf.get_start_iter()) def save(self,action): if not self.filename: self.save_as(action) else: if os.path.isabs(self.filename): path = self.filename else: path = os.path.abspath(self.filename) start = self.bugbuf.get_start_iter() end = self.bugbuf.get_end_iter() open(path,"w").write(self.bugbuf.get_text(start,end)) self.bugbuf.set_modified(False) def save_as(self,action): chooser = gtk.FileChooserDialog('Save bug as...', None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) if self.filename: chooser.set_current_name(self.filename) response = chooser.run() if response == gtk.RESPONSE_OK: filename = chooser.get_filename() if filename: self.filename = filename self.save(action) chooser.destroy() def server_settings(self,action): self.conndialog.hostname = self.conn.hostname self.conndialog.port = self.conn.port self.conndialog.username = self.conn.username self.conndialog.password = self.conn.password if self.conndialog.run() == gtk.RESPONSE_OK: self.conn.hostname = self.conndialog.hostname self.conn.port = self.conndialog.port self.conn.username = self.conndialog.username self.conn.password = self.conndialog.password def change_name(self,action): self.conndialog.hostname = self.conn.hostname self.conndialog.port = self.conn.port self.conndialog.username = self.conn.username self.conndialog.password = self.conn.password if self.conndialog.run_name_only() == gtk.RESPONSE_OK: self.conn.username = self.conndialog.username def commit_code(self, action): start = self.bugbuf.get_start_iter() end = self.bugbuf.get_end_iter() self.conn.upload(self.bugbuf.get_text(start,end)) def connect(self, action): self.conn.open_connection() def disconnect(self, action): self.conn.close_connection() def info(self,action): dialog = gtk.AboutDialog() dialog.set_authors(["Joachim Breitner "]) dialog.set_license("GPL") dialog.set_name("Infon Devel") dialog.set_website("http://infon.dividuum.de/") dialog.set_website_label("http://infon.dividuum.de/") # dialog.set_version("0.0") dialog.run() dialog.destroy() def delete_event(self, widget, event, data=None): # Change FALSE to TRUE and the main window will not be destroyed # with a "delete_event". return False def setup_menu(self): actions = gtk.ActionGroup("menu") actions.add_actions([ ('FileMenu', None, '_File'), ('new', gtk.STOCK_NEW, '_New', None, 'New Bug', self.new), ('openbug', gtk.STOCK_OPEN, '_Open Bug...', None, 'Open a new bug', self.open), ('savebug', gtk.STOCK_SAVE, '_Save Bug', None, 'Save the current bug',self.save), ('savebugas', gtk.STOCK_SAVE_AS, 'S_ave Bug As...', None, 'Save the current bug',self.save_as), ('quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the program', self.destroy), ('GameMenu', None, '_Game'), ('ViewMenu', None, '_View'), ('ChooseServer', gtk.STOCK_NETWORK, 'Choose _Server', None, 'Choose an Infon Server', self.server_settings), ('ChangeName', gtk.STOCK_EDIT, 'Change _Name', None, 'Change your Player Name', self.change_name), ('ChangeColor', gtk.STOCK_SELECT_COLOR, 'Change C_olor', None, 'Change your Player’s Color', lambda a: None), ('CommitBug', gtk.STOCK_APPLY, 'Commit _Bug', None, 'Commit your code to the server', self.commit_code), ('RestartBug', gtk.STOCK_REFRESH, '_Restart Bug', None, 'Restart the your bug’s main loops', lambda a: self.conn.reload()), ('Connect', gtk.STOCK_CONNECT, '_Connect to Server', None, 'Connect to Server', self.connect), ('Disconnect', gtk.STOCK_DISCONNECT, '_Disconnect from Server', None, 'Disconnect from Server', self.disconnect), ('HelpMenu', None, '_Help'), ('info', gtk.STOCK_INFO, '_Info', None, 'Information about this program', self.info), ]) actions.add_toggle_actions([ ('ShowNumbers', None, 'Show _Line Numbers', None, 'Toggle visibility of line numbers in the left margin', lambda a, s: s.set_show_line_numbers(a.get_active())), ('ShowMarkers', None, 'Show _Markers', None, 'Toggle visibility of markers in the left margin', lambda a, s: s.set_show_line_markers(a.get_active())), ('AutoIndent', None, 'Enable _Auto Indent', None, 'Toggle automatic auto indentation of text', lambda a, s: s.set_auto_indent(a.get_active())), #('InsertSpaces', None, 'Insert _Spaces Instead of Tabs', None, 'Whether to insert space characters when inserting tabulations', # lambda a, s: s.set_insert_spaces_instead_of_tabs(a.get_active())), ],self.bugview) self.ui = gtk.UIManager() self.ui.add_ui_from_string(''' ''') action = actions.get_action('ShowNumbers') action.set_active(self.bugview.get_show_line_numbers()) action = actions.get_action('ShowMarkers') action.set_active(self.bugview.get_show_line_markers()) action = actions.get_action('AutoIndent') action.set_active(self.bugview.get_auto_indent()) #action = actions.get_action('InsertSpaces') #action.set_active(self.bugview.get_insert_spaces_instead_of_tabs()) #action = actions.get_action('TabsWidth%d' % self.bugview.get_tabs_width()) #if action: # action.set_active(True) self.ui.insert_action_group(actions,0) def setup_bugview(self): self.bugbuf = gtksourceview.SourceBuffer() lm = gtksourceview.SourceLanguagesManager() lang = lm.get_language_from_mime_type("text/x-lua") self.bugbuf.set_highlight(True) self.bugbuf.set_language(lang) def set_bt_markers(blubb): begin, end = self.bugbuf.get_bounds() markers = self.bugbuf.get_markers_in_region(begin, end) map(self.bugbuf.delete_marker, markers) for creature, line in self.conn.bt: if line: pos = self.bugbuf.get_iter_at_line(line) self.bugbuf.create_marker(None, "bt", pos) self.conn.connect("new_bt",set_bt_markers) self.bugview = gtksourceview.SourceView(self.bugbuf) self.bugview.props.show_line_numbers = True self.bugview.props.show_line_markers = True self.bugview.props.auto_indent = True #self.bugview.props.insert_spaces_instead_of_tabs = True icon = gtk.gdk.pixbuf_new_from_file(PREFIX + 'marker.png') self.bugview.set_marker_pixbuf("bt",icon) def setup_connview(self): self.connview = connview.ConnView() self.connview.append_system('Welcome to InfonDevel\n') def new_message(conn,type,msg): if type == infonconn.DIR_NONE: self.connview.append_system(msg) if type == infonconn.DIR_INCOMING: self.connview.append_incoming(msg) if type == infonconn.DIR_OUTGOING: self.connview.append_outgoing(msg) self.conn.connect("new_message",new_message) #self.connview.append_incoming('Incoming\n') #self.connview.append_outgoing('Outgoing\n') #self.connview.append_outgoing('Outgoing\n') #self.connview.append_outgoing('Outgoing\n') def setup_statusbar(self): self.status = gtk.Statusbar() def setup_conn(self): self.conn = infonconn.InfonConn() def setup_title(self): def set_title(): title = '' title += "Infon Devel" if self.bugbuf.get_modified(): title += " ⋆ " else: title += " – " if self.filename: title += self.filename else: title += "[unnamed]" if self.bugbuf.get_modified(): title += " ⋆ " else: title += " – " state = self.conn.props.state if state == infonconn.STATE_PRESETUP: title += "[no server specified]" elif state == infonconn.STATE_OFFLINE: title += "[offline]" elif state == infonconn.STATE_CONNECTING: title += "%s@%s:%s [connecting]" % (self.conn.username, self.conn.hostname, self.conn.port) elif state == infonconn.STATE_CONNECTED: title += "%s@%s:%s" % (self.conn.username, self.conn.hostname, self.conn.port) elif state == infonconn.STATE_DISCONNECTING: title += "%s@%s:%s [disconnecting]" % (self.conn.username, self.conn.hostname, self.conn.port) self.window.props.title = title self.bugbuf.connect("modified-changed", lambda b: set_title()) self.conn.connect("notify::state", lambda c,p: set_title()) set_title() def setup_toolbarstates(self): actions = self.ui.get_action_groups()[0] def statebased(): state = self.conn.props.state online = state == infonconn.STATE_CONNECTED actions.get_action('ChangeName').set_sensitive(online) actions.get_action('ChangeColor').set_sensitive(online) actions.get_action('CommitBug').set_sensitive(online) actions.get_action('RestartBug').set_sensitive(online) actions.get_action('Connect').set_sensitive(not online) actions.get_action('Disconnect').set_sensitive(online) actions.get_action('ChooseServer').set_sensitive( state == infonconn.STATE_OFFLINE or state == infonconn.STATE_PRESETUP ) self.conn.connect("notify::state", lambda c,p: statebased()) statebased() def __init__(self): self.filename = None self.setup_conn() self.setup_bugview() self.setup_connview() self.setup_menu() self.setup_statusbar() pane = gtk.VPaned() frame = gtk.ScrolledWindow() frame.add(self.bugview) frame.props.shadow_type = gtk.SHADOW_IN frame.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) pane.pack1(frame, True) frame = gtk.ScrolledWindow() frame.add(self.connview) frame.props.shadow_type = gtk.SHADOW_IN frame.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) pane.pack2(frame, False) pane.props.position = 300 vbox1 = gtk.VBox() vbox1.pack_start(self.ui.get_widget('/MenuBar'), expand=False) vbox1.pack_start(self.ui.get_widget('/ToolBar'), expand=False) vbox1.pack_start(pane) vbox1.pack_start(self.status, expand=False) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_default_size(700,432) # Golden Ratio :-) self.window.props.border_width = 0 self.window.add_accel_group(self.ui.get_accel_group()) #self.window.set_icon(gtk.gdk.pixbuf_new_from_file('icon.png')) self.window.connect("delete_event", self.delete_event) self.window.connect("destroy", self.destroy) self.window.add(vbox1) self.conndialog = ConnDialog(self.window) self.setup_title() self.setup_toolbarstates() self.bugview.grab_focus() self.window.show_all() def main(self): gtk.main() def destroy(self, widget, data=None): gtk.main_quit() if __name__ == "__main__": InfonDevel().main() # vim:ts=4:sw=4:sts=4:et infon/contrib/infon-devel/connview.py0000644000076400001440000000300710532613762020015 0ustar dividuumusers import gtk import pango class ConnView(gtk.TextView): def __init__(self,*args): gtk.TextView.__init__(self,*args) font_desc = pango.FontDescription('monospace 10') if font_desc: self.modify_font(font_desc) self.props.editable = False self.props.cursor_visible = False self.props.buffer.create_tag("system", foreground="#555") self.props.buffer.create_tag("incoming", foreground="blue") self.props.buffer.create_tag("outgoing", foreground="red") self.connect_after("realize",ConnView.realized) def realized(self): end = self.props.buffer.get_end_iter() self.scroll_to_iter(end,0.1) def append_system(self, text): buffer = self.props.buffer end = buffer.get_end_iter() buffer.insert_with_tags_by_name(end, text, "system") if self.flags() & gtk.REALIZED: self.scroll_mark_onscreen(buffer.get_insert()) def append_incoming(self, text): buffer = self.props.buffer end = buffer.get_end_iter() buffer.insert_with_tags_by_name(end, text, "incoming") if self.flags() & gtk.REALIZED: self.scroll_mark_onscreen(buffer.get_insert()) def append_outgoing(self, text): buffer = self.props.buffer end = buffer.get_end_iter() buffer.insert_with_tags_by_name(end, text, "outgoing") if self.flags() & gtk.REALIZED: self.scroll_mark_onscreen(buffer.get_insert()) # vim:ts=4:sw=4:sts=4:et infon/contrib/infon-devel/marker.png0000644000076400001440000000073110532613762017603 0ustar dividuumusersPNG  IHDR&N:bKGD pHYs  ~tIME  +xJyfIDAT(ROKp~:KB9" 1)VDAtԮ~>`>@ FCKɡ?5]ui4Dsx> L6vE\j2Gbǚ5E5~CY3.,|><"fi$q|0,z2»wxn{a(I@aԪ(O_;"ul|@b3(|  ^hC%xz`"o{>!o.Gnv,)z0l4-Blc(a]xQt=*iP%u$f=o$gMk}(Bz@N!H8uqG_o0\۾#7]0pP&IENDB`infon/contrib/infon-devel/debian/0000755000076400001440000000000010540115022017016 5ustar dividuumusersinfon/contrib/infon-devel/debian/changelog0000644000076400001440000000027410540115022020673 0ustar dividuumusersinfon-devel (0~r144-1) unstable; urgency=low * Initial Release * Sponsored by http://www.aiti-kace.com.gh/ -- Joachim Breitner Fri, 22 Dec 2006 16:53:10 +0000 infon/contrib/infon-devel/debian/control0000644000076400001440000000211710540115022020422 0ustar dividuumusersSource: infon-devel Section: games Priority: extra Maintainer: Joachim Breitner Build-Depends: debhelper (>= 5.0.38), python-all-dev (>= 2.3.5-11), python-central (>= 0.5.6) XS-Python-Version: all Standards-Version: 3.7.2 XS-Vcs-Svn: http://infon.dividuum.de/svn/infon/trunk/contrib/infon-devel Package: infon-devel Architecture: all Suggests: infon-server Recommends: infon-viewer Depends: ${python:Depends}, python-gnome2-desktop XB-Python-Version: ${python:Versions} Description: Develop bots for the infon game Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their “intelligence” in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. . This package contains a graphical lua editor with integration into the infon server and allows easy uploading of the code. It also marks the currently executed line of code. . Homepage: http://infon.dividuum.de/ infon/contrib/infon-devel/debian/dirs0000644000076400001440000000003610533001514017703 0ustar dividuumusersusr/bin usr/share/infon-devel infon/contrib/infon-devel/debian/compat0000644000076400001440000000000210533001514020216 0ustar dividuumusers5 infon/contrib/infon-devel/debian/copyright0000644000076400001440000000230110533001514020747 0ustar dividuumusersThis package was debianized by Joachim Breitner on Mon, 27 Nov 2006 18:17:14 +0000 It was downloaded from http://infon.dividuum.de/ Copyright Holder: Copyright: 2006 Joachim Breitner License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. On Debian systems, the complete text of the GNU General Public License, version 2 can be found in '/usr/share/common-licenses/GPL-2'. The Debian packaging is (C) 2006, Joachim Breitner and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. infon/contrib/infon-devel/debian/rules0000755000076400001440000000153710533001514020106 0ustar dividuumusers#!/usr/bin/make -f build: clean: dh_testdir dh_clean rm -f *.pyc install: build dh_testdir dh_testroot dh_clean -k dh_installdirs install -m 0755 $(CURDIR)/infon-devel.py $(CURDIR)/debian/infon-devel/usr/bin/infon-devel sed -i -e 's!^PREFIX.*$$!PREFIX = "/usr/share/infon-devel/"!' $(CURDIR)/debian/infon-devel/usr/bin/infon-devel install -m 0644 $(CURDIR)/connview.py \ $(CURDIR)/infonconn.py \ $(CURDIR)/marker.png \ $(CURDIR)/debian/infon-devel/usr/share/infon-devel binary-indep: build install binary-arch: build install dh_testdir dh_testroot dh_installchangelogs dh_installdocs dh_installman infon-devel.1 dh_compress dh_fixperms dh_pycentral dh_installdeb dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install infon/contrib/infon-devel/infonconn.py0000644000076400001440000002175310540115022020145 0ustar dividuumusersimport gobject import random import os import pwd import asyncore import socket import errno import re STATE_PRESETUP = 0 # Nothing configured. Maybe not used. STATE_OFFLINE = 1 STATE_CONNECTING = 2 STATE_CONNECTED = 3 STATE_DISCONNECTING = 4 DIR_NONE = 0 DIR_INCOMING = 1 DIR_OUTGOING = 2 class InfonConn(gobject.GObject): __gproperties__ = { 'state' : ( gobject.TYPE_INT, 'state of the connection', '', STATE_PRESETUP, STATE_DISCONNECTING, STATE_OFFLINE, gobject.PARAM_READWRITE ), } __gsignals__ = { 'new_message' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING,) ), 'new_bt' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (), ), } def __init__(self): gobject.GObject.__init__(self) self.state = STATE_OFFLINE #self.hostname = "infon.dividuum.de" self.hostname = "localhost" self.port = "1234" self._username = pwd.getpwuid(os.getuid())[0] self.password = "pw%04d" % random.randrange(0,10000) self.playerid = None self.socket = None self.outbuffer = "" self.codebuffer = "" self.btbuffer = "" self.waiting_code = None def do_get_property(self, property): if property.name == 'state': return self.state else: raise AttributeError, 'unknown property %s' % property.name def do_set_property(self, property, value): if property.name == 'state': self.state = value else: raise AttributeError, 'unknown property %s' % property.name def open_connection(self): assert not self.socket self.props.state = STATE_CONNECTING self.emit("new_message", DIR_NONE, "Connecting to %s:%s..." % (self.hostname,self.port)) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setblocking(False) try: self.socket.connect( (self.hostname, int(self.port)) ) except socket.error, (x,s): if x != errno.EINPROGRESS: self.emit("new_message", DIR_NONE, "failed: %s!" % s) self.props.state = STATE_OFFLINE gobject.io_add_watch(self.socket, gobject.IO_OUT, self.connected) def start_writing(self): def outgoing(socket, condition): if len(self.codebuffer) > 0: sent = socket.send(self.codebuffer) self.emit("new_message", DIR_OUTGOING, "[your code...]\n") self.codebuffer = self.codebuffer[sent:] elif len(self.outbuffer) > 0: sent = socket.send(self.outbuffer) self.emit("new_message", DIR_OUTGOING, self.outbuffer[:sent]) self.outbuffer = self.outbuffer[sent:] return len(self.codebuffer) > 0 or len(self.outbuffer) > 0 gobject.io_add_watch(self.socket, gobject.IO_OUT, outgoing) def connected(self,s,condition): self.emit("new_message", DIR_NONE, "Connected!") gobject.io_add_watch(s, gobject.IO_IN | gobject.IO_PRI, self.incoming) player_re = re.compile("joined. player (\d+) ") def incoming(self, s, condition): data = "" try: data = s.recv(8192) except socket.error, (x,s): self.emit("new_message", DIR_NONE, "\nConnection Closed: %s!\n" % s) self.props.state = STATE_OFFLINE return False if data: self.emit("new_message", DIR_INCOMING, data) if self.state == STATE_CONNECTING: if data.find("Press ") != -1: self.send("\n") elif data.find("enter '?' for help") != -1: self.send("j\n") elif data.find("press enter for new player") != -1: self.send("\n") elif data.find("password for new player") != -1: self.send("%s\n" % self.password) elif data.find("joined. player") != -1: m = self.player_re.search(data) assert m self.playerid = int(m.group(1)) self.start_bting() assert data.find("> ") != -1 self.send ("n\n") if self.state == STATE_CONNECTING or self.state == STATE_CONNECTED: if data.find("Player Name:") != -1: self.send("%s\n" % self.username) self.props.state = STATE_CONNECTED if self.state == STATE_CONNECTED: if data.find("enter your lua code") != -1: assert self.waiting_code self.codebuffer = self.waiting_code self.waiting_code = None self.start_writing() elif data.find("traceback:") != -1: self.parse_backtrace(data) if data.find("> ") != -1: self.start_writing() return True def upload(self, code): assert self.props.state == STATE_CONNECTED self.waiting_code = "%s\n.\n" % code self.send("b\n") def reload(self): assert self.props.state == STATE_CONNECTED self.send("r\n") def send(self, txt): self.outbuffer += txt self.start_writing() def set_username(self,username): changed = self._username != username self._username = username if changed and self.props.state == STATE_CONNECTED: self.send("n\n") def close_connection(self): assert self.props.state == STATE_CONNECTED self.send("q\n") self.props.state = STATE_DISCONNECTING ### BT Getting ### def start_bting(self): #self.emit("new_message", DIR_NONE,"Connecting to %s:%s..." % (self.hostname,self.port)) self.btsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.btsocket.setblocking(False) try: self.btsocket.connect( (self.hostname, int(self.port)) ) except socket.error, (x,s): if x != errno.EINPROGRESS: self.emit("new_message", DIR_NONE, "BT socket failed: %s!" % s) gobject.io_add_watch(self.btsocket, gobject.IO_OUT, self.btconnected) def btconnected(self,s,condition): #self.emit("new_message", DIR_NONE, "Connected Backtrace-Getter") gobject.io_add_watch(s, gobject.IO_IN | gobject.IO_PRI, self.btincoming) def btincoming(self, s, condition): try: data = s.recv(8192) except socket.error, (x,s): self.btconnected = False return False if data: if data.find("Press ") != -1: self.btsend("\n") elif data.find("enter '?' for help") != -1: self.btsend("j\n") elif data.find("press enter for new player") != -1: self.btsend("%d\n" % self.playerid) elif data.find("password for player") != -1: self.btsend("%s\n" % self.password) elif data.find("joined. player ") != -1: gobject.timeout_add(200, self.get_backtrace); self.btconnected = True elif data.find("traceback:") != -1: self.parse_backtrace(data) return True creature_re = re.compile("^ 0: sent = socket.send(self.btbuffer) self.btbuffer = self.btbuffer[sent:] return len(self.btbuffer) gobject.io_add_watch(self.btsocket, gobject.IO_OUT, btoutgoing) ## Properties username = property( lambda s: s._username, set_username) gobject.type_register(InfonConn) # vim:ts=4:sw=4:sts=4:et infon/contrib/infon-devel/infon-devel.10000644000076400001440000000125210533001514020066 0ustar dividuumusers.TH INFON-DEVEL "1" "November 2006" "infon-devel" "User Commands" .SH NAME infon-devel \- write bots for the game infon .SH DESCRIPTION Infon is a game which simulates the live of simple bugs who eat, propagate, eat each other and evolve. The players can not control the bugs directly but write their "intelligence" in the simple script language lua and upload it to the game using a plain telnet connection. The code can then be modified even while the game is running. Infon Devel is a graphical lua editor with integration into the infon server and allows easy uploading of the code. It also marks the currently executed line of code. .SH SEE ALSO .BR infon (6) .BR infond (6) infon/contrib/bots/0000755000076400001440000000000010603314645014351 5ustar dividuumusersinfon/contrib/bots/BlueloopV00.lua0000644000076400001440000000621410603314645017126 0ustar dividuumusers-------------------------------------------------------------------------- -- Blueloop V00 -- -- Fuer jedes gespawnte Vieh wird eine eigene Creature Klasse instanziiert -------------------------------------------------------------------------- function Creature:onSpawned() print("Creature " .. self.id .. " spawned") end function Creature:onAttacked(attacker) print("Help! Creature " .. self.id .. " is attacked by Creature " .. attacker) end function Creature:onKilled(killer) if killer == self.id then print("Creature " .. self.id .. " suicided") elseif killer then print("Creature " .. self.id .. " killed by Creature " .. killer) else print("Creature " .. self.id .. " died") end end function Wait() while (get_state(self.id) ~= CREATURE_IDLE) do self:wait_for_next_round() end; end function Creature:main() if self.dx == nil then self.dx = 256 end if self.dy == nil then self.dy = 0 end if victim == nil then victim = -1 end ---------------------------------------------- Wenn ein globaler Angriff aktiv ist: if (victim ~= -1) and (get_type(self.id) == 1) then if exists(victim) then local x,y = get_pos(victim) -- Wo ist der angegriffene? self:moveto(x,y) -- hinlaufen self:attack(victim) -- angreifen! else victim = -1 -- Tot -> Angriff beenden print"Angriff beendet!" end end ---------------------------------------------- Warten bis Creatur IDLE if get_state(self.id) ~= CREATURE_IDLE then self:wait_for_next_round() return end ---------------------------------------------- Wo ist der nchste Feind? local feind_id, feind_x, feind_y, feind_playernum, feind_dist = nearest_enemy(self.id) ---------------------------------------------- Wenn er nah genug ist und wir gesund sind -> angreifen if (feind_id ~= nil) and (victim == -1) then if (feind_dist < 8000) and (self:health() > 50) and (victim == -1) then print("Starte Angriff auf " .. feind_id ) victim = feind_id end end ---------------------------------------------- Fressen! if get_tile_food(self.id) > 0 then set_state(self.id, CREATURE_EAT) else local x, y = self:pos() if not self:moveto(x+self.dx,y+self.dy) then self.dx = math.random(512)-256 self.dy = math.random(512)-256 end end if self:health() < 90 then set_state(self.id, CREATURE_HEAL) end; if get_food(self.id) > 8000 then if get_type(self.id) == 0 then set_convert(self.id, 1) set_state(self.id,CREATURE_CONVERT) else set_state(self.id,CREATURE_SPAWN) end end if get_state(self.id) == CREATURE_IDLE then self:moveto(get_koth_pos()) end self:wait_for_next_round() end --------------------------------------------------------------------------------- infon/contrib/bots/unbug.lua0000644000076400001440000002055510603314645016203 0ustar dividuumusers--[[ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ]] -- author g² -- version 0.7 --some defines ATTACK_RANGE = 512 FLIGHT_RANGE = 2 * ATTACK_RANGE groupWeHaveAKing = false groupWeHaveAFlyer = false kothIsWalkable = false function Creature:onSpawned(parent) if parent then print("Creature " .. self.id .. " spawned by " .. parent) else print("Creature " .. self.id .. " spawned") end -- test if koth is walkable local kingx, kingy = get_koth_pos() if set_path(self.id, kingx, kingy) then self.iCanWalkToKoth = true if not kothIsWalkable then kothIsWalkable = self.id end -- set a new path local x1, y1, x2, y2 = world_size() while not set_path(self.id,math.random(x1, x2),math.random(y1, y2)) do end end end function Creature:eat () set_state(self.id,CREATURE_EAT) while get_food(self.id) < get_max_food(self.id) and get_tile_food(self.id) > 0 and (not self:enemyInRange()) and get_health(self.id) > 2 do self:wait_for_next_round() end end function Creature:detstinationReached () self.currentx, self.currenty = get_pos(self.id) -- test if the x and y postition is near the destination if self.destx == self.currentx and self.desty == self.currenty then return true else return false end end function Creature:go () -- test if already going if get_state(self.id) ~= CREATURE_WALK then -- if no valid path is set or reached destination if (not self.validPath) or self:detstinationReached() then local x1, y1, x2, y2 = world_size() self.destx = math.random(x1, x2) self.desty = math.random(y1, y2) while not set_path(self.id, self.destx, self.desty) do self.destx = math.random(x1, x2) self.desty = math.random(y1, y2) end -- the path has set and have to be gone self.validPath=true end if not set_state(self.id, CREATURE_WALK) then self:screen_message("stateErr") print("cannot set sate CREATURE_WALK in Creature:go() ID "..self.id) end end end -- returns the type of an enemy function Creature:enemyInRange () local enemy_id, ex, ey, eplayernum, edist = get_nearest_enemy(self.id) if get_type(self.id) == 1 then if edist and edist <= ATTACK_RANGE then return get_type(enemy_id) else return false end else if edist and edist <= FLIGHT_RANGE then return get_type(enemy_id) else return false end end end function attackNearestEnemy () local creature_id, x, y, playernum, dist = get_nearest_enemy(self.id) if (not creature_id) or dist > ATTACK_RANGE then return false else set_target(self.id, creature_id) set_state(self.id, CREATURE_ATTACK) end end function Creature:becomeKing () -- set lock, there can be only one king ;-) groupWeHaveAKing = self.id self:screen_message("King!") local kingx, kingy = get_koth_pos() if set_path(self.id, kingx, kingy) then set_state(self.id, CREATURE_WALK) while get_state(self.id) == CREATURE_WALK do self:wait_for_next_round() end set_state(self.id, CREATURE_IDLE) while self:enemyInRange() ~= 1 and get_health(self.id) > 30 do if get_health(self.id) < 70 and get_food(self.id) > 0 then set_state(self.id, CREATURE_HEAL) while get_health(self.id) < 100 and get_food(self.id) > 0 and not (self:enemyInRange() == 1) do self:wait_for_next_round() end set_state(self.id, CREATURE_IDLE) end self:wait_for_next_round() end end self:screen_message("ID "..self.id) self.validPath = false --release lock groupWeHaveAKing = false end function Creature:mainWorker () self:screen_message("ID "..self.id) if get_health(self.id) > 80 and kothIsWalkable and not groupWeHaveAKing and self:enemyInRange() ~= 1 then self:becomeKing() end if get_food(self.id) > 9000 and get_health(self.id) > 90 and not (self:enemyInRange() == 1) then if not groupWeHaveAFlyer and not kothIsWalkable then set_convert(self.id,2) groupWeHaveAFlyer = self.id else set_convert(self.id,1) end set_state(self.id, CREATURE_CONVERT) while get_state(self.id) == CREATURE_CONVERT do self:wait_for_next_round() end end if get_health(self.id) < 91 and get_food(self.id) > 0 and not (self:enemyInRange() == 1) then if not set_state(self.id, CREATURE_HEAL) then print("setStateErr CREATURE_HEAL") end while get_health(self.id) < 100 and get_food(self.id) > 0 and self:enemyInRange() ~= 1 do self:wait_for_next_round() end end if get_tile_food(self.id) > 0 and get_food(self.id) < get_max_food(self.id) and not (self:enemyInRange() == 1) then self:eat() elseif get_tile_food(self.id) == 0 or self:enemyInRange() == 1 then self:go() end end function Creature:mainBreeder () if get_health(self.id) > 90 and kothIsWalkable and not groupWeHaveAKing then self:becomeKing() end self:screen_message("ID "..self.id) local enemy_id, ex, ey, eplayernum, edist = get_nearest_enemy(self.id) if edist and edist <= ATTACK_RANGE then set_target(self.id, enemy_id) set_state(self.id, CREATURE_ATTACK) else if get_food(self.id) > 14000 and get_health(self.id) > 80 then set_convert(self.id,1); set_state(self.id, CREATURE_SPAWN) while get_state(self.id) == CREATURE_SPAWN and (not self:enemyInRange()) do self:wait_for_next_round() end end if get_health(self.id) < 85 and get_food(self.id) > 0 then set_state(self.id, CREATURE_HEAL) while get_health(self.id) < 100 and get_food(self.id) > 0 and (not self:enemyInRange()) do self:wait_for_next_round() end end if get_tile_food(self.id) > 0 and get_food(self.id) < get_max_food(self.id) then self:eat() elseif get_tile_food(self.id) == 0 then self:go() end end -- self:screen_message(self.id.."_"..get_cpu_usage()) end ------------------------------------------------------------------------------- function Creature:mainFlyer () self:screen_message("ID "..self.id) if get_health(self.id) > 80 and not groupWeHaveAKing then self:becomeKing() end if get_health(self.id) < 85 and get_food(self.id) > 0 and not (self:enemyInRange() == 1) then if not set_state(self.id, CREATURE_HEAL) then print("setStateErr CREATURE_HEAL") end while get_health(self.id) < 100 and get_food(self.id) > 0 and not (self:enemyInRange() == 1) do self:wait_for_next_round() end end -- choose a new destination befor go() -- good luck ;-) if self:enemyInRange() == 1 and get_state(self.id) ~= CREATURE_WALK then self.validPath=false end if get_tile_food(self.id) > 0 and get_food(self.id) < get_max_food(self.id) and not (self:enemyInRange() == 1) then self:eat() elseif get_tile_food(self.id) == 0 then self:go() end end function Creature:main () -- check for invalid kothIsWalkable lock if kothIsWalkable and not creature_exists(kothIsWalkable) then kothIsWalkable = false end -- maybe kothIsWalkable is false but another creature can walk to koth if not kothIsWalkable and self.iCanWalkToKoth then local kingx, kingy = get_koth_pos() if set_path(self.id, kingx, kingy) then kothIsWalkable = self.id else self.iCanWalkToKoth = false end -- set a new path local x1, y1, x2, y2 = world_size() while not set_path(self.id,math.random(x1, x2),math.random(y1, y2)) do end end -- check for invalid kinglock (maybe creature was killed) if groupWeHaveAKing then if not creature_exists(groupWeHaveAKing) then groupWeHaveAKing = false end end if groupWeHaveAKing == self.id then groupWeHaveAKing = false end -- check for invalid flyerlock if groupWeHaveAFlyer then if not creature_exists(groupWeHaveAFlyer) then groupWeHaveAFlyer = false end end if groupWeHaveAFlyer == self.id and get_type(self.id) ~= 2 then groupWeHaveAFlyer = false end -- jump to type specific code if get_type(self.id) == 0 then self:mainWorker() elseif get_type(self.id) == 1 then self:mainBreeder() elseif get_type(self.id) == 2 then self:mainFlyer() end end infon/contrib/bots/queener.lua0000644000076400001440000002141310603314645016521 0ustar dividuumusers-------------------------------------------------------------------------- -- Default Code -------------------------------------------------------------------------- -- Called after the Creature was created. You cannot -- call long-running methods (like moveto) here. function Creature:onSpawned() print("Creature " .. self.id .. " spawned") end -- Called each round for every attacker on this -- creature. No long-running methods here! function Creature:onAttacked(attacker) -- print("Help! Creature " .. self.id .. " is attacked by Creature " .. attacker) end -- Called by typing 'r' in the console, after creation (after -- onSpawned) or by calling self:restart(). No long-running -- methods calls here! function Creature:onRestart() end -- Called after beeing killed. Since the creature is already -- dead, self.id cannot be used to call the Lowlevel API. function Creature:onKilled(killer) if killer == self.id then print("Creature " .. self.id .. " suicided") elseif killer then print("Creature " .. self.id .. " killed by Creature " .. killer) else print("Creature " .. self.id .. " died") end end function Creature:start(fun) if self.fun ~= self[fun] then self:screen_message(fun) self.fun = self[fun] self.logic = coroutine.create(self[fun]) end end function Creature:handle() if self.logic then local ok, msg = coroutine.resume(self.logic, self) if not ok then print("creature logic " .. self.id .. " aborted: " .. msg) self.logic = nil end end end function Creature:queen_idle() if self:health() < 70 and self:food() > 0 then self:begin_healing() while self:is_healing() do self:wait_for_next_round() end queen_stop = false end if self:health() > 30 and self:food() > 8000 then self:begin_spawning() while self:is_spawning() do self:wait_for_next_round() end queen_stop = false end end function Creature:be_queen() queen_id = self.id if self:type() == 0 then while true do local x1, y1, x2, y2 = world_size() while not self:set_path(math.random(x2 - x1) + x1, math.random(y2 - y1) + y1) do end self:begin_walk_path() while self:is_walking() and self:food() < 8000 do if self:tile_food() > 0 then self:begin_eating() while self:is_eating() and self:food() < 8000 do self:wait_for_next_round() end self:begin_walk_path() end self:wait_for_next_round() end if self:food() >= 8000 then self:convert(1) break end end end self:screen_message("Queen") while true do if queen_stop then self:begin_idling() self:queen_idle() self:wait_for_next_round() else local x1, y1, x2, y2 = world_size() while not self:set_path(math.random(x2 - x1) + x1, math.random(y2 - y1) + y1) do end self:begin_walk_path() local time = game_time() while self:is_walking() do if numcreatures < 4 then if self:tile_food() > 0 then self:begin_eating() while self:is_eating() and self:food() < 15000 do self:wait_for_next_round() end self:begin_walk_path() end end self:queen_idle() self:begin_walk_path() self:wait_for_next_round() if queen_stop then break end end end end end function dist(x1, y1, x2, y2) return math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) end function Creature:dist_to_queen() if not queen_id then return 1000000 else local kx, ky = get_pos(queen_id) local cx, cy = self:pos() return dist(kx, ky, cx, cy) end end queen_stop = false function Creature:bring_queen() while true do if self:food() == 0 then return end if self:dist_to_queen() < 500 then queen_stop = true end if self:dist_to_queen() > 100 then if not queen_id then return end local kx, ky = get_pos(queen_id) local time = game_time() self:set_path(kx, ky) self:begin_walk_path() while self:is_walking() do if self:health() < 70 then return end self:wait_for_next_round() if time + 500 < game_time() then kx, ky = get_pos(queen_id) self:set_path(kx, ky) end self:wait_for_next_round() end else self:set_target(queen_id) self:begin_feeding() while self:is_feeding() do self:wait_for_next_round() end end self:wait_for_next_round() end end function Creature:be_slave() if self:type() == 0 then while true do local x1, y1, x2, y2 = world_size() while not self:set_path(math.random(x2 - x1) + x1, math.random(y2 - y1) + y1) do end self:begin_walk_path() while self:is_walking() and self:food() < 5000 do if self:tile_food() > 0 then self:begin_eating() while self:is_eating() and self:food() < 5000 do self:wait_for_next_round() end self:begin_walk_path() end self:wait_for_next_round() end if self:food() >= 5000 then self:convert(2) break end end end local lastx, lasty self.last_food = game_time() while true do local x1, y1, x2, y2 if lastx and lasty then self:screen_message("old") x1, y1, x2, y2 = lastx - 512, lasty - 512, lastx + 512, lasty + 512 lastx, lasty = nil, nil elseif queen_id and numcreatures < 5 then self:screen_message("area") local kx, ky = get_pos(queen_id) x1 = kx - 2048 x2 = kx + 2048 y1 = ky - 2048 y2 = ky + 2048 else self:screen_message("world") x1, y1, x2, y2 = world_size() end while not self:set_path(math.random(x2 - x1) + x1, math.random(y2 - y1) + y1) do end self:begin_walk_path() while self:is_walking() do local x, y = self:pos() if last_food_x and last_food_y and dist(x, y, last_food_x, last_food_y) < 3000 and self.last_food + 10000 < game_time() then self:screen_message("called") self:set_path(last_food_x, last_food_y) end if self:tile_food() > 0 then self.last_food = game_time() last_food_x, last_food_y = self:pos() self:begin_eating() while self:is_eating() do self:wait_for_next_round() end self:begin_healing() while self:is_healing() do self:wait_for_next_round() end lastx, lasty = self:pos() end if self:type() == 1 then if self:food() > 9600 and self:health() > 70 then self:screen_message("bring") self:bring_queen() end else if self:food() > 4600 and self:health() > 30 then self:screen_message("bring") self:bring_queen() end end self:wait_for_next_round() end end end function onRoundStart() numcreatures = 0 for n, creature in pairs(creatures) do if numcreatures == 0 then creature:start('be_queen') else creature:start('be_slave') end numcreatures = numcreatures + 1 end end -- Your Creature Logic here :-) function Creature:main() self:handle() end infon/contrib/bots/easybot.lua0000644000076400001440000000112210603314645016516 0ustar dividuumusers-- Example for the state API. needs_api "state" function bot() function onKilled() print(id .. " died") end function onIdle() return and_start_state "find_food" end function find_food() random_move() end function onTileFood() if can_eat() then return and_be_in_state "eat_food" end end function eat_food() eat() return and_start_state "find_food" end function onLowHealth() return and_be_in_state "healing" end function healing() heal() end end infon/contrib/bots/gravity-bot-working.lua0000644000076400001440000003712210603314645021006 0ustar dividuumusers--------------kbot version 0.5----------------- -- this bot is GPL -- questions & stuff -> kazamatzuri@informatik.uni-wuerzburg.de -- author kazamatzuri ----------------------------------------------- --global communication COUNT=0 HUNTRANGE=6*256 NOHUNTTHRESHOLD=3 DECAYFACTOR=2 --FOODWEIGHT_A=FOODWEIGHT FOODWEIGHT=20 FOODWAIT=60*1000 --food above threshold -> into map FOODTHRESHOLD=50 ENEMYWEIGHT=3 ENEMYWEIGHTAT=100 EATWEIGHT=110 GROWBARRIER=6 -- below this we just grow, no war MIN_GROUNDFOOD=400 -- minimum availabe food before relocating swarm SWARMTARGET={} --count BOTAVERAGE last steps in speedkeep BOTAVERAGE=4 GRAVWEIGHT=10 --bots not bound by swarm law ROGUEBOTSMOD=10 --RANDOMWALK max step size STEPSIZE=1*256 -- CLUMBMODE=1 CLUMBSIZE=1.5*256 -- EMERGENCYRANGE=6*256 INNERRADIUS=3*256 FEEDMODE=false FEEDMODETHRESHOLD=0.5 KOTHBOTLIMIT=12 KOTHBOT=-1 gravupdate=0 x1, y1, x2, y2 = world_size() gridx=math.floor(x2/256) gridy=math.floor(y2/256) foodmap={} timemap={} foodlist={} grid={} enemys={} a_enemys={} -- first gravity center gx,gy=get_koth_pos() g={gx,gy} function Creature:kpos() local rx,ry=self:pos() return {rx,ry} end -- initialization function Creature:onSpawned() print("new bot enters the world ") COUNT=COUNT+1 self.wt=self:getrandomstep() self.steps={} local i = 0 for i=1,BOTAVERAGE do self.steps[i]={} end self.cstep=0 end -- overwriting global info (keypress i in telnetserver) -- to be a bit more talkative function info() local chkd=0 for id, creature in pairs(creatures) do posx,posy=get_pos(id) print(id .. ":" ..get_type(id) .. " on "..posx..":"..posy .. "==> hp:"..get_health(id)..". food:"..get_food(id) .." state:" .. get_state(id).." punkte: "..player_score(player_number)) chkd=chkd+1 end print("colony state: "..COUNT.." gravitycenter: "..g[1]..":"..g[2]) COUNT=chkd end function suicideall() for id,creature in pairs(creatures) do suicide(id) end end function Creature:onAttacked(attacker) local ex,ey = get_pos(attacker) enemys[attacker]={ex,ey} end function Creature:onKilled(killer) if killer == self.id then print("kbot " .. self.id .. " suicided") elseif killer then print("kbot " .. self.id .. " killed by Creature " .. killer) else print("kbot " .. self.id .. " starved") end if KOTHBOT==self.id then KOTHBOT=-1 end --foodmap[killer]=nil end function Creature:checkcount_hardcore() -- sometimes the own counting isn't right, so we have to check hardcore style local scnum=0 for i,id in pairs(creatures) do scnum=scnum+1 end return scnum end function Creature:printloc() -- talkative debug self.mx,self.my=self:pos() return ( self.id..":"..get_type(self.id).." on "..self.mx .. ":"..self.my.." ") end function Creature:checkdata() -- per round data self.loc=self:kpos() self.t=self:type() self.hp = self:health() end function Creature:dist(x0,y0,x1,y1) return (math.sqrt((x0-x1)^2+(y0-y1)^2)) end function Creature:reactattack() --p("------under attack-----") -- i am attacked local enemy_id, enemy_x, enemy_y, enemy_playernum, enemy_dist = nearest_enemy(self.id) a_enemys[enemy_id]=true enemys[enemy_id]={enemy_x,enemy_y} --todo: need attacked bool?? end function Creature:expand() -- spawn/evolve if (self:food() > 8020 and get_type(self.id)==0 and not FEEDMODE) then set_convert(self.id,1) set_state(self.id,CREATURE_CONVERT) --p("evolving <<<<<<<<<<<<<<") return true end if (self:food() > 8020 and get_type(self.id)==1 and get_health(self.id)>40)then set_state(self.id,CREATURE_SPAWN) return true end return false end function Creature:hunt() if get_type(self.id)==0 then return false end local enemy_id, enemy_x, enemy_y, enemy_playernum, enemy_dist = nearest_enemy(self.id) if enemy_id==nil then --p("no enemy") return false end local enemy_type = get_type(enemy_id) local enemy_health=get_health(enemy_id) enemys[enemy_id]={enemy_x,enemy_y} -- enemy to near? not my fault *G if enemy_dist < 512 then self:set_target(enemy_id) set_state(self.id,CREATURE_ATTACK) --self:kattack(enemy_id,enemy_dist,enemy_x,enemy_y) self.huntmode=true return true end -- easy prey anywhere? if enemy_dist < HUNTRANGE and enemy_type==0 and self.t==1 and self.hp>20 and COUNT>NOHUNTTHRESHOLD then --p("gone hunting------------") self.wt={enemy_x,enemy_y} set_path(self.id,enemy_x,enemy_y) self.huntmode=true return false end return false end function Creature:meal() --p(self:printloc() .. "feeding with from " .. self.actfood .. " food, now have: " .. self:food() .."f, " .. self:health() .."h") -- have a nice meal self.actfood = get_tile_food(self.id) -- trigger circle search around it local x,y=7 if self.actfood>50 then --self.wt=self:kpos() self:set_path(self.wt[1],self.wt[2]) end if self.actfood>0 then set_state(self.id,CREATURE_EAT) return true else return false end end function Creature:rndcircle(c,r) local dx=math.random(r*2+1)-r local dy=math.random(r*2+1)-r return {c[1]+dx,c[2]+dy} end -- run forest run, but whereto? function Creature:escaperoute() -- todo update to new format local enemy_id, enemy_x, enemy_y, enemy_playernum, enemy_dist = nearest_enemy(self.id) local ex,ey=self:pos() nx,ny=self:getvalidtarget(math.floor(ex/256),math.floor(ey/256)) return nx,ny end function Creature:updategravitycenter() --p("updategrav") local ng={} local lcount=1 local realcount=0 local warriorcount=0 ng[1]=0 ng[2]=0 local blubid=0 local avfood=0 for id, creature in pairs(creatures) do blubid=id realcount=realcount+1 if COUNT>KOTHBOTLIMIT and get_type(id)==1 and KOTHBOT==-1 and get_health(id)>50 then KOTHBOT=id end if get_type(id)==1 then warriorcount=warriorcount+1 avfood=avfood+get_tile_food(id) end local x,y=get_pos(id) if get_state(id)==CREATURE_EAT and get_type(id)==0 then ng[1],ng[2]=ng[1]+x*EATWEIGHT,ng[2]+y*EATWEIGHT lcount=lcount+EATWEIGHT-1 if get_tile_food(id)> 1000 then ng[1],ng[2]=ng[1]+x*EATWEIGHT,ng[2]+y*EATWEIGHT lcount=lcount+EATWEIGHT-1 end else ng[1],ng[2]=ng[1]+x,ng[2]+y lcount=lcount+1 end end if lcount==1 then ng[1],ng[2]=get_pos(blubid) end COUNT=realcount WCOUNT=warriorcount INNERCIRCLE=1*256+(1.011^WCOUNT)*256 --todo move gravity in clumbmode better --if COUNTGROWBARRIER then for i,c in pairs(enemys) do if creature_exists(i) then local x,y =get_pos(i) ng[1]=(ng[1]+ENEMYWEIGHT*x) ng[2]=(ng[2]+ENEMYWEIGHT*y) else enemys[i]=nil end --p(ng[1]..":"..ng[2]) lcount=lcount+ENEMYWEIGHT end end for i,c in pairs(foodmap) do if foodmap[i]>FOODTHRESHOLD then local y= math.mod(i,gridx) local x= math.floor((i-y)/gridx) --print(i.."=>"..x..":"..y.." food: "..foodmap[i]) ng[1]=(ng[1]+(c/100)*(x*256+128)) ng[2]=(ng[2]+(c/100)*(y*256+128)) lcount=lcount+(c/100) end end g[1],g[2]=ng[1]/lcount,ng[2]/lcount if COUNT10 and COUNT<20 then STEPSIZE=5*256 ROGUEBOTSMOD=6 elseif COUNT>20 and COUNT<40 then STEPSIZE=7*256 ROGUEBOTSMOD=8 else STEPSIZE=5*256 ROGUEBOTSMOD=7 end if foodcounter== nil then foodcounter=1 end foodcounter=0 local blub=game_time() for u=1,gridx do for v=1,gridy do if foodmap[u*gridx+v]~= nil then if foodmap[u*gridx+v]>FOODTHRESHOLD and math.abs(blub-timemap[u*gridx+v])> FOODWAIT then foodlist[foodcounter]={u,v} foodcounter=foodcounter+1 end end end end --p((foodcounter).." places with food mapped") avfood=avfood/warriorcount --print(avfood/warriorcount.." "..MIN_GROUNDFOOD) if not swarmonthemove then SWARMTARGET=g end local kx,ky=get_koth_pos() local nwfood = self:getnearestfood_swarm(kx,ky,1000) --print (nwfood[1].." "..nwfood[2]) if avfoodFEEDMODETHRESHOLD and COUNT>3 then -- p("feedmode on") FEEDMODE=true else -- p("feedmode off") FEEDMODE=FALSE end end function Creature:getrandomstep() local x,y=self:pos() if self.v==nil then self.v={} end if self.v[1]==nil then self.v[1]=0 self.v[2]=0 end if self.id==KOTHBOT then return get_koth_pos() end local pivot={} pivot[1]=self.v[1]*2 + (x+GRAVWEIGHT*g[1])/(GRAVWEIGHT+1) pivot[2]=self.v[2]*2 + (y+GRAVWEIGHT*g[2])/(GRAVWEIGHT+1) local s = STEPSIZE local n = {} local sc=1 repeat if get_type(self.id)==1 then n = self:rndcircle(g,INNERCIRCLE+sc) sc=sc+16 else n = self:rndcircle(pivot,s) s=s+32 end --p("calc "..pivot[1]..":"..pivot[2].."__"..s) until set_path(self.id,math.floor(n[1]),math.floor(n[2])) local delta={} delta[1]=math.floor(-n[1]+x) delta[2]=math.floor(-n[2]+y) n[1]=math.floor(n[1]) n[2]=math.floor(n[2]) self.v[1]=(self.v[1]*BOTAVERAGE+delta[1])/(BOTAVERAGE+1) self.v[2]=(self.v[2]*BOTAVERAGE+delta[2])/(BOTAVERAGE+1) return n end function Creature:getnearestfood_swarm(x,y,thold) local max =0 local actmax = -1 local blub=game_time() for i=1,foodcounter-1 do if math.abs(blub-timemap[foodlist[i][1]*gridx+foodlist[i][2]])max then actmax=i max = foodmap[foodlist[i][1]*256+foodlist[i][2]] end end if actmax==-1 then return {math.random(x2),math.random(y2)} end if {foodlist[actmax][1]*256+128,foodlist[actmax][2]*256+128}==nil then p("inner nil") return {math.random(x2),math.random(y2)} end return {foodlist[actmax][1]*256+128,foodlist[actmax][2]*256+128} end function Creature:getnearestfood() local min =gridx*256 local actmin = -1 local minx,miny=0,0 local blub=game_time() --for i=1,foodcounter-1 do -- local d = self:dist(foodlist[i][1],foodlist[i][2],self.gridloc[1],self.gridloc[2]) --if d < min and math.abs(blub-timemap[foodlist[i][1]*gridx+foodlist[i][2]])FOODTHRESHOLD then -- actmin=i -- min = d --end --end for id,creature in pairs(creatures) do local d = get_distance(self.id,id) if d2000 and get_health(self.id)< 65 then set_state(self.id,CREATURE_HEAL) return true else return false end end function Creature:updatefood() local t = self.gridloc[1]*gridx+self.gridloc[2] local blub=game_time() if foodmap[t] == nil then foodmap[t] = self.actfood timemap[t]=blub else if foodmap[t]< self.actfood then foodmap[t]=self.actfood timemap[t]=blub end end end function Creature:updategrid() local x,y=self:pos() local t=math.floor(x/256)*gridx+math.floor(y/256) if grid[t]==nil then grid[t]={true,0} else end end function Creature:getnearestmaster() local actmin=-1 local min=gridx*256 for id,creature in pairs(creatures) do if get_type(id)==1 then local d=get_distance(self.id,id) if d < min then actmin=id min=d end end end if actmin==-1 then return nil else local x,y=get_pos(actmin) return {x,y,actmin} end end function Creature:go_feed() if self:food()>5000 and self:health()>60 and get_type(self.id)==0 then local m=self:getnearestmaster() if m==nil then return false end if self:dist(m[1],m[2],self.loc[1],self.loc[2]) < 256 then set_target(self.id,m[3]) set_state(self.id,CREATURE_FEED) return true else self.wt=m self:set_path(self.wt[1],self.wt[2]) set_state(self.id,CREATURE_WALK) end end end function Creature:main() -- local x,y=get_koth_pos() -- set_path(self.id,x,y) -- set_state(self.id,CREATURE_WALK) -- self:wait_for_next_round() --set_message(self.id,self.id.."OF"..player_number) if self.wt==nil then self.wt=self:kpos() end self.loc=self:kpos() self.gridloc={math.floor(self.loc[1]/256),math.floor(self.loc[2]/256)} if self.foodstepping==nil then self.foodstepping=1 end self.huntmode=false self.t=self:type() self.hp = self:health() if math.abs(gravupdate-game_time())>1000 then self:updategravitycenter() gravupdate=game_time() end while self:is_converting() or self:is_spawning() or self:is_healing() do self:wait_for_next_round() end while self:is_feeding() and self:food()>1000 do self:wait_for_next_round() end self.actfood=get_tile_food(self.id) self:updategrid() self:updatefood() --p("blub") if self:hunt() then -- p(self.id .. "is hunting ") elseif FEEDMODE and self:go_feed() then set_message(self.id,"feeding") elseif self:expand() then set_message(self.id,"evolving") elseif self:heal() then set_message(self.id,"healing") elseif self:meal() then set_message(self.id,"eating") elseif self:move() then if KOTHBOT==self.id then set_message(self.id,"KINGBOT") else set_message(self.id,"moving") end else set_message(self.id,"else ") end self:wait_for_next_round() end infon/contrib/bots/BlueloopV01.lua0000644000076400001440000000721610603314645017132 0ustar dividuumusers-------------------------------------------------------------------------- -- Default Logik -- -- Fuer jedes gespawnte Vieh wird eine eigene Creature Klasse instanziiert -------------------------------------------------------------------------- function Creature:onSpawned() print("Creature " .. self.id .. " spawned") end function Creature:onAttacked(attacker) print("Help! Creature " .. self.id .. " is attacked by Creature " .. attacker) -- Ich bin noch zu klein zum kmpfen if (get_type(self.id) == 0) or (self:health() > 20) then local x,y = self:pos() -- weglaufen self:set_path(x-16000+math.random(8000),y-1600+math.random(8000)) self:begin_walk_path() else -- Smack my Bit up! self:set_target(attacker) self:begin_attacking() end end function Creature:onKilled(killer) if killer == self.id then print("Creature " .. self.id .. " suicided") elseif killer then print("Creature " .. self.id .. " killed by Creature " .. killer) else print("Creature " .. self.id .. " died") end end function Creature:Wait() while (get_state(self.id) ~= CREATURE_IDLE) do self:wait_for_next_round() end; end function Creature:Fressen() if get_tile_food(self.id) > 0 then set_state(self.id, CREATURE_EAT) self:Wait() else local x, y = self:pos() if not self:moveto(x+self.dx,y+self.dy) then self.dx = math.random(256)-128 self.dy = math.random(256)-128 end end if self:health() < 90 then set_state(self.id, CREATURE_HEAL) self:Wait() end end function Creature:Angreifen() -- Wo ist der nchste Feind? local feind_id, feind_x, feind_y, feind_playernum, feind_dist = nearest_enemy(self.id) -- Wenn er nah genug ist und wir gesund sind -> angreifen if (feind_id ~= nil) and (feind_dist < 500) and (self:health() > 60) then print("Starte Angriff auf " .. feind_id .. " Abstand: " .. feind_dist) while (exists(feind_id)) do local x,y = get_pos(feind_id) -- Wo ist der angegriffene? self:moveto(x,y) -- hinlaufen self:attack(feind_id) -- angreifen! self:Wait() end end end function Creature:main() if self.dx == nil then self.dx = 256 end if self.dy == nil then self.dy = 0 end if victim == nil then victim = -1 end if get_type(self.id) == 0 then print("Creature " .. self.id .. " soll fressen") while get_food(self.id) < 8000 do self:Fressen() end print("Creature " .. self.id .. " soll sich verwandeln") set_convert(self.id, 1) set_state(self.id,CREATURE_CONVERT) self:Wait() else print("Creature " .. self.id .. " soll fressen") while get_food(self.id) < 8000 do self:Fressen() self:Angreifen() end print("Creature " .. self.id .. " vermehrt sich") set_state(self.id,CREATURE_SPAWN) self:Wait() --print("Creature " .. self.id .. " soll zu King of the Hill") --self:moveto(get_koth_pos()) --self:Wait() --print("Creature " .. self.id .. " ist King of the Hill") --while self:health() > 30 do -- local feind_id, feind_x, feind_y, feind_playernum, feind_dist = nearest_enemy(self.id) -- self:attack(feind_id) --end end end infon/contrib/bots/GuardBot.lua0000644000076400001440000004570010603314645016571 0ustar dividuumusers-- By Chromix -- !!! unfinished !!! -- max tilefood = 9999 --local gtMap; --gtMap = nil; gtCreatures = gtCreatures or {}; unexploredfields = unexploredfields or 0; local currTick = 0; local function asserttype( _var, _type ) if type( _var ) ~= _type then assert( false, "type " .. type( _var ) .. " matches " .. _type ); end end --[[ local function heap_pop( _heap ) local retNode = table.remove( _heap, 1 ); if _heap[1] then table.insert( _heap, 1, table.remove(_heap, table.getn(_heap)) ); local oldPosition = 1; local currValue = _heap[oldPosition]; while true do local newPosition = oldPosition * 2; local node = _heap[newPosition]; if node and node.totalCosts < currValue.totalCosts then _heap[oldPosition] = node; _heap[newPosition] = currValue; oldPosition = newPosition; else newPosition = newPosition + 1; node = _heap[newPosition]; if node and node.totalCosts < currValue.totalCosts then _heap[oldPosition] = node; _heap[newPosition] = currValue; else break; end end end end asserttype( retNode, "table" ); return retNode; end -- Node: -- totalCosts function heap_push( _heap, _what ) asserttype(_heap, "table"); asserttype(_what, "table"); local newSize = table.getn( _heap ) + 1; table.insert( _heap, _what ); if newSize == 1 then return; end local oldSize = newSize; newSize = math.floor( oldSize / 2 ); local nextNode = _heap[newSize]; while newSize >= 1 and nextNode.totalCosts > _what.totalCosts do _heap[oldSize] = nextNode; _heap[newSize] = _what; oldSize, newSize = newSize, math.floor( newSize / 2 ); nextNode = _heap[newSize]; end end ]] function scanMap( _creature ) local tMap = {}; local minx, miny, maxx, maxy = world_size(); local crX, crY = _creature:pos(); local totalfields = 0; for x = math.floor(minx/256), math.floor(maxx/256) do tMap[x] = {}; for y = math.floor(miny/256), math.floor(maxy/256) do local walkable = ( _creature:set_path( x * 256 + 128, y * 256 + 128 ) or ( x == crX and y == crY ) ) and { food = 0, seenfood = false, lastvisit = 0, nearunexplored = 0, nearfood = 0 } or nil; if walkable then if tMap[x][y-1] then tMap[x][y-1].nearunexplored = tMap[x][y-1].nearunexplored + 1; walkable.nearunexplored = walkable.nearunexplored + 1; end if tMap[x-1] and tMap[x-1][y] then tMap[x-1][y].nearunexplored = tMap[x-1][y].nearunexplored + 1; walkable.nearunexplored = walkable.nearunexplored + 1; end tMap[x][y] = walkable totalfields = totalfields + 1; end if get_cpu_usage() > 80 then _creature:wait_for_next_round(); end end end unexploredfields = totalfields; return tMap; end function onGameStart() gtMap = nil; gtCreatures = {}; end Creature.ROLE_EXPLORER = 1; Creature.ROLE_ASPIRING_GUARDIAN = Creature.ROLE_EXPLORER + 1; Creature.ROLE_GUARDIAN = Creature.ROLE_ASPIRING_GUARDIAN + 1; function Creature:hasNoRole() return self.currRole == nil; end function Creature:hasRoleExplorer() return self.currRole == self.ROLE_EXPLORER; end function Creature:takeRoleExplorer() self.currRole = self.ROLE_EXPLORER; end function Creature:hasRoleAspiringGuardian() return self.currRole == self.ROLE_ASPIRING_GUARDIAN; end function Creature:takeRoleAspiringGuardian() self.currRole = self.ROLE_ASPIRING_GUARDIAN; end function Creature:hasRoleGuardian() return self.currRole == self.ROLE_GUARDIAN; end function Creature:takeRoleGuardian() self.currRole = self.ROLE_GUARDIAN; end function Creature:hasGuardField() return self.guardPatch ~= nil; end function Creature:estimateNearbyFood() local myX, myY = self.currX, self.currY; local estimate = 0; for x = myX - 2, myX + 2 do local xRow = gtMap[x]; if xRow then for y = myY - 2, myY + 2 do local tile = xRow[y]; if tile and tile.seenfood then estimate = estimate + tile.food + (currTick - tile.lastvisit) * 0.001 end end end end return math.floor(estimate); end function Creature:findNearbyFood() local myX, myY = self.currX, self.currY; local maxfood = 0; local foodX, foodY; for x = myX - 2, myX + 2 do local xRow = gtMap[x]; if xRow then for y = myY - 2, myY + 2 do local tile = gtMap[x][y]; if tile and tile.seenfood then local estimate = tile.food + (currTick - tile.lastvisit) * 0.001 if maxfood < estimate then foodX, foodY = x, y; maxfood = estimate; end end end end end return foodX, foodY; end function Creature:checkForNewField() local myX, myY = self.currX, self.currY; assert( gtMap[myX][myY].nearunexplored >= 0 ); assert( gtMap[myX][myY].nearfood >= 0 ); if gtMap[myX][myY].lastvisit == 0 then unexploredfields = unexploredfields - 1; if gtMap[myX][myY-1] then gtMap[myX][myY-1].nearunexplored = gtMap[myX][myY-1].nearunexplored - 1; end if gtMap[myX][myY+1] then gtMap[myX][myY+1].nearunexplored = gtMap[myX][myY+1].nearunexplored - 1; end if gtMap[myX-1] and gtMap[myX-1][myY] then gtMap[myX-1][myY].nearunexplored = gtMap[myX-1][myY].nearunexplored - 1; end if gtMap[myX+1] and gtMap[myX+1][myY] then gtMap[myX+1][myY].nearunexplored = gtMap[myX+1][myY].nearunexplored - 1; end return true; else return false; end end function Creature:checkForFoodOnField() local myX, myY = self.currX, self.currY; local food = self:tile_food(); gtMap[myX][myY].food = food; gtMap[myX][myY].lastvisit = currTick; if food > 0 and not gtMap[myX][myY].seenfood then gtMap[myX][myY].seenfood = true; if gtMap[myX][myY-1] then gtMap[myX][myY-1].nearfood = gtMap[myX][myY-1].nearfood + 1; end if gtMap[myX][myY+1] then gtMap[myX][myY+1].nearfood = gtMap[myX][myY+1].nearfood + 1; end if gtMap[myX-1] and gtMap[myX-1][myY] then gtMap[myX-1][myY].nearfood = gtMap[myX-1][myY].nearfood + 1; end if gtMap[myX+1] and gtMap[myX+1][myY] then gtMap[myX+1][myY].nearfood = gtMap[myX+1][myY].nearfood + 1; end return food, true; else return food, false; end end -- Called after the Creature was created. You cannot -- call long-running methods (like moveto) here. function Creature:onSpawned(parent) if parent then print("Creature " .. self.id .. " spawned by " .. parent) else print("Creature " .. self.id .. " spawned") end gtCreatures[self] = true; -- self:takeRoleExplorer(); end function Creature:findInterestingUnexploredField() local tInteresting = {}; local myX, myY = self.currX, self.currY; local bestscore; for x, yEntry in pairs( gtMap ) do for y, entry in pairs( yEntry ) do local score = 0; -- unexplored fields are interesting if entry.lastvisit == 0 and x ~= myX and y ~= myY then -- they're even more interesting, if there are more unexplored fields next to them -- fields that contain food might have other food fields next to them score = 1 + entry.nearunexplored + (6 * entry.nearfood); score = score - math.sqrt( math.pow( myX - x, 2 ) + math.pow( myY - y, 2 ) ) / 10; if not bestscore or score > bestscore then bestscore = score; table.insert( tInteresting, { score = score, x = x, y = y } ); end end end end table.sort( tInteresting, function( _e1, _e2 ) return _e1.score > _e2.score end ); local bestentry = tInteresting[1]; if bestentry then return bestentry.x, bestentry.y; else return false, false; end end function Creature:findNextFoodField() local myX, myY = self.currX, self.currY; local bestDist, foodX, foodY; for x, yEntry in pairs( gtMap ) do for y, entry in pairs( yEntry ) do local dist = math.sqrt( math.exp( myX - x, 2 ) + math.exp( myY - y, 2 ) ); if not bestDist or dist < bestDist then bestDist = dist; foodX, foodY = x, y; end end end return foodX, foodY; end function Creature:goTo( _x, _y ) if self:set_path( _x * 256 + 128, _y * 256 + 128 ) then self.targetX = _x; self.targetY = _y; self:begin_walk_path(); return true; else return false; end end function Creature:stopMoving() if self:is_walking() then self:begin_idling(); self.targetX = self.currX; self.targetY = self.currY; end end function Creature:checkForArrival() -- if self:is_walking() and self.currX == self.targetX and self.currY == self.targetY then -- self:begin_idling(); -- self:screen_message( "Arrived" ); -- return true; -- else -- return false; -- end end function Creature:createGuardField() local tTiles = {}; local tStack = {}; local tKnown = {}; local myX, myY = self.currX, self.currY; local totalX, totalY, tilecount = 0, 0, 0; local currTile = gtMap[myX][myY]; assert( currTile.seenfood or self.guardPatch ); if not currTile.seenfood and self.guardPatch then currTile = next( self.guardPatch.tTiles ); -- recreate else currTile.X, currTile.Y = myX, myY; -- create new end tKnown[currTile] = true; while currTile do tTiles[currTile] = true; tilecount = tilecount + 1; for _, nextOffset in pairs( { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } } ) do local nextTile = gtMap[currTile.X + nextOffset[1]] and gtMap[currTile.X + nextOffset[1]][currTile.Y + nextOffset[2]]; if nextTile and nextTile.seenfood and not tKnown[nextTile] then tKnown[nextTile] = true; nextTile.X = currTile.X + nextOffset[1]; nextTile.Y = currTile.Y + nextOffset[2]; table.insert( tStack, nextTile ); totalX = totalX + nextTile.X; totalY = totalY + nextTile.Y; end end currTile = table.remove( tStack ); end assert( next( tTiles ) ); local centerX, centerY = math.floor( totalX / tilecount ), math.floor( totalY / tilecount ); while not gtMap[centerX] or not gtMap[centerX][centerY] do centerX = centerX - 1 + math.random( 2 ); centerY = centerY - 1 + math.random( 2 ); -- TODO: improve this end self.guardPatch = { centerX = centerX, centerY = centerY, tTiles = tTiles, lastscan = 0, scanInProgress = false }; end function Creature:needsToCheckGuardField() return self.guardPatch and not self.guardPatch.scanInProgress and self.guardPatch.lastscan < currTick - 10 * 1000; end function Creature:isCheckingGuardField() return self.guardPatch and self.guardPatch.scanInProgress; end function Creature:beginCheckGuardField() self.guardPatch.scanInProgress = true; local plan = self.guardPatch.tScanplan; if not plan then plan = {}; local tKnown = {}; self.guardPatch.tScanplan = plan; -- plan: check all fields + the border fields that don't belong to the guardTiles for tile in pairs( self.guardPatch.tTiles ) do table.insert( plan, { X = tile.X, Y = tile.Y } ); for _, nextOffset in pairs( { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } } ) do local adjTile = gtMap[tile.X + nextOffset[1]] and gtMap[tile.X + nextOffset[1]][tile.Y + nextOffset[2]]; if adjTile and not self.guardPatch.tTiles[adjTile] and not tKnown[adjTile] then tKnown[adjTile] = true; table.insert( plan, { X = tile.X + nextOffset[1], Y = tile.Y + nextOffset[2] } ); end end end end self.guardPatch.scanstep = 1; self:goTo( plan[self.guardPatch.scanstep].X, plan[self.guardPatch.scanstep].Y ); end function Creature:continueCheckGuardField() local myX, myY = self.currX, self.currY; -- did we reach the target field, or stopped before that? if myX ~= self.guardPatch.tScanplan[self.guardPatch.scanstep].X or myY ~= self.guardPatch.tScanplan[self.guardPatch.scanstep].Y then for i = 1, table.getn( self.guardPatch.tScanplan ) do if myX == self.guardPatch.tScanplan[i].X and myY == self.guardPatch.tScanplan[i].Y then table.remove( self.guardPatch.tScanplan, i ); break; end end else --self.guardPatch.scanstep = self.guardPatch.scanstep + 1; table.remove( self.guardPatch.tScanplan, 1 ); end if self.guardPatch.scanstep > table.getn( self.guardPatch.tScanplan ) then self.guardPatch.lastscan = currTick; self.guardPatch.scanInProgress = false; self:screen_message( "Return" ); -- recreate it self:createGuardField(); self:goTo( self.guardPatch.centerX, self.guardPatch.centerY ); else self:goTo( self.guardPatch.tScanplan[self.guardPatch.scanstep].X, self.guardPatch.tScanplan[self.guardPatch.scanstep].Y ); end end -- Called each round for every attacker on this -- creature. No long-running methods here! function Creature:onAttacked(attacker) if self:hasRoleExplorer() then self:screen_message( "*squeek*" ); elseif self:hasRoleAspiringGuardian() then self:screen_message( "mean :-(" ); elseif self:hasRoleGuardian() then self:screen_message( "*ouch*" ); end end -- Called by typing 'r' in the console, after creation (after -- onSpawned) or by calling self:restart(). No long-running -- methods calls here! function Creature:onRestart() print("Creature " .. self.id .. " restarting") local myX, myY = self:pos(); self.targetX, self.targetX = math.floor(myX/256), math.floor(myY/256); self:takeRoleExplorer(); end -- Called after beeing killed. Since the creature is already -- dead, self.id cannot be used to call the Lowlevel API. function Creature:onKilled(killer) if killer == self.id then print("Creature " .. self.id .. " suicided") elseif killer then print("Creature " .. self.id .. " killed by Creature " .. killer) else print("Creature " .. self.id .. " died") end gtCreatures[self] = nil; end -- Your Creature Logic here :-) function Creature:main() -- self:screen_message( self.id.." of "..player_number ); if not gtMap then gtMap = true; gtMap = scanMap( self ); end -- wait for map creation while gtMap == true do self:wait_for_next_round(); end -- update vars local myX, myY = self:pos(); myX, myY = math.floor( myX / 256 ), math.floor( myY / 256 ); self.currX, self.currY = myX, myY; currTick = game_time(); -- check fields & update map local isNewField = self:checkForNewField(); local foodOnField, foundNewFoodSource = self:checkForFoodOnField(); if get_cpu_usage() > 95 then return; -- avoid getting killed by the cpu limit end if self:hasNoRole() then self:takeRoleExplorer(); end self:checkForArrival(); if self:hasRoleExplorer() then -- emergency heal if self:health() < 20 and self:food() > 0 and not self:is_healing() then self:screen_message( "Emergncy" ); self:begin_healing(); return; end if foundNewFoodSource then self:stopMoving(); if self:hasGuardField() then self:screen_message( "Yay :-)" ); self:createGuardField(); self:takeRoleGuardian(); end self:begin_eating(); local thefood = self:estimateNearbyFood(); self:screen_message( "Yummy!" ); if thefood + self:food() > 8100 and self:health() > 80 then self:begin_idling(); self:takeRoleAspiringGuardian(); self:screen_message( "AGuard" ); assert( self:hasRoleAspiringGuardian() ); return; end end if self:food() > 8100 and self:health() > 80 then self:begin_idling(); self:takeRoleAspiringGuardian(); self:screen_message( "AGuard" ); assert( self:hasRoleAspiringGuardian() ); return; end if self:is_idle() then if self:health() < 95 and self:food() > 0 then self:begin_healing(); return; end -- find an interesting field to visit local cannotMove = true; local intX, intY; if get_cpu_usage() < 80 then intX, intY = self:findInterestingUnexploredField(); if intX then if self:goTo( intX, intY ) then cannotMove = false; self:screen_message( "Explore" ); end else -- no unexplored fields left -- TODO: Switch to another role end end -- can't move? There *must* be a field we can move to while cannotMove do self:screen_message( "AuxMove" ); intX = myX - 2 + math.random(4); intY = myY - 2 + math.random(4); cannotMove = not self:goTo( intX, intY ); end else self:wait_for_next_round(); end elseif self:hasRoleAspiringGuardian() then if self:health() < 90 and self:food() > 0 and not self:is_healing() and not self:is_converting() then if not self:is_eating() or ( self:is_eating() and self:health() < 20 ) then self:begin_healing(); end end if self:is_idle() then if self:food() > 8000 and self:health() >= 80 then self:screen_message( "Evolving" ); self:convert( 1 ); self:screen_message( "Guard" ); self:takeRoleGuardian(); return; elseif self:estimateNearbyFood() + self:food() > 8100 then if foodOnField > 0 then self:begin_eating(); else local intX, intY = self:findNearbyFood(); if intX then if not self:goTo( intX, intY ) then self:takeRoleExplorer(); end else self:takeRoleExplorer(); end end else self:takeRoleExplorer(); end end elseif self:hasRoleGuardian() then if self:is_walking() and self:isCheckingGuardField() and foodOnField > 0 and self:food() < self:max_food() then self:stopMoving(); end if self:is_idle() then self:screen_message( "Guard :)" ); if self:health() < 40 and self:food() < 200 then local thefood = self:estimateNearbyFood(); print( "EstFood: " .. thefood ); if thefood < 1000 then self:takeRoleExplorer(); -- become explorer before starving return; end end if self:health() < 20 and self:food() > 0 then self:screen_message( "Emergncy" ); self:begin_healing(); elseif not self:hasGuardField() then if gtMap[myX][myY].seenfood then self:createGuardField(); else local intX, intY = self:findNearbyFood(); if not intX then intX, intY = self:findNextFoodField(); end self:screen_message( "GoFood" ); self:goTo( intX, intY ); end elseif self:health() < 98 and self:food() > 0 then self:screen_message( "StayFit" ); self:begin_healing(); elseif self:health() > 95 and self:food() > 9000 then self:screen_message( "Multiply" ); self:begin_spawning(); elseif self:needsToCheckGuardField() or ( self:food() == 0 and not self:isCheckingGuardField() ) then self:screen_message( "ChkFood" ); self:beginCheckGuardField(); elseif foodOnField > 0 and self:food() < self:max_food() then self:screen_message( "AllMine" ); self:begin_eating(); elseif self:isCheckingGuardField() then self:screen_message( "ChkFood" ); self:continueCheckGuardField(); end end end --local kohx, kohy = get_koth_pos(); --print( string.format( "Tick:%d, ID:%d, X:%d, Y:%d, Food: %d, type:%d, tilefood:%d", game_time(), self.id, myX/256, myY/256, self:food(), self:type(), self:tile_food() ) ); --print( "CPU usage: " .. get_cpu_usage() ); -- print( currTick ) end infon/contrib/bots/stupibot2.lua0000644000076400001440000000326410603314645017014 0ustar dividuumusers function Creature:onAttacked ( attacker ) if get_type( self.id ) == 1 then set_target( self.id, attacker ); set_state( self.id, CREATURE_ATTACK ) end end function Creature:walkAndKill () victim, self.vX, self.vY, p, d = get_nearest_enemy( self.id ) if victim then if get_distance( self.id, victim ) <= 512 then set_target( self.id, victim ) set_state( self.id, CREATURE_ATTACK ) else if not set_path( self.id, self.vX, self.vY ) and get_state( self.id ) ~= CREATURE_WALK then self.destX, self.destY = getRandomCoords() set_path( self.id, self.destX, self.destY ) end set_state( self.id, CREATURE_WALK ) end end end function getRandomCoords () local x1, y1, x2, y2 = world_size() return math.random(x1,x2), math.random(y1,y2) end function Creature:eatAndGrow () x,y = get_pos( self.id ) if get_state( self.id ) == CREATURE_CONVERT then return elseif get_food(self.id) >= 8000 and get_state(self.id) == CREATURE_IDLE then set_convert( self.id, 1 ); set_state( self.id, CREATURE_CONVERT ) elseif get_tile_food( self.id ) > 0 then set_state( self.id, CREATURE_EAT ) elseif get_state( self.id ) ~= CREATURE_WALK then self.destX, self.destY = getRandomCoords() set_path( self.id, self.destX, self.destY ) set_state( self.id, CREATURE_WALK ) end end function Creature:main () if get_type( self.id ) == 0 then self:eatAndGrow(); set_message( self.id, 'LittleBot' ) else self:walkAndKill(); set_message( self.id, 'StupiBot' ) end end infon/contrib/bots/stupibot.lua0000644000076400001440000000306610603314645016732 0ustar dividuumusersfunction Creature:onSpawned( ) kx, ky = get_koth_pos() if not set_path( self.id, kx, ky ) then suicide( self.id ); print( 'Killed myself: ' .. self.id) end -- it's a trap self.status = CREATURE_IDLE end function Creature:onKilled( killer ) print( self.id .. ' killed by ' .. killer ) end function Creature:onAttacked( attacker ) if get_type( self.id ) == 1 then set_target( self.id, attacker ); set_state( self.id, CREATURE_ATTACK ) end end function Creature:walkAndKill() victim, self.vX, self.vY, p, d = nearest_enemy( self.id ) if get_distance( self.id, victim ) <= 256 then set_target( self.id, victim ) set_state( self.id, CREATURE_ATTACK ) else set_path( self.id, self.vX, self.vY ) set_state( self.id, CREATURE_WALK ) end end function getRandomCoords() return math.random( 256,12544 ), math.random( 256,8448 ) end function Creature:eatAndGrow() x,y = get_pos( self.id ) if get_state( self.id ) == CREATURE_CONVERT then return elseif get_food(self.id) >= 8000 and get_state(self.id) == CREATURE_IDLE then set_convert( self.id, 1 ); set_state( self.id, CREATURE_CONVERT ) elseif get_tile_food( self.id ) > 0 then set_state( self.id, CREATURE_EAT ) elseif get_state( self.id ) ~= CREATURE_WALK then self.destX, self.destY = getRandomCoords() set_path( self.id, self.destX, self.destY ) set_state( self.id, CREATURE_WALK ) end end function Creature:main() if get_type( self.id ) == 0 then self:eatAndGrow(); set_message( self.id, 'LittleBot' ) else self:walkAndKill(); set_message( self.id, 'StupiBot' ) end end infon/contrib/bots/README.txt0000644000076400001440000000006010603314645016043 0ustar dividuumusersVarious bug source codes, contributed by users. infon/contrib/bots/sissy-bot-menu.lua0000644000076400001440000000622710603314645017761 0ustar dividuumusers-- This source creates menu for the sissy-bot. -- To use it, append it to sissy-bot.lua source -- and type '0' in the prompt. dofile("menu") menu "Sissybot" .sub "Health Goals" .sub "Type 0" .add("30%", function () w_health_type0 = 30 end) .add("50%", function () w_health_type0 = 50 end) .add("80%", function () w_health_type0 = 80 end) .super .sub "Type 1" .add("30%", function () w_health_type1 = 30 end) .add("50%", function () w_health_type1 = 50 end) .add("80%", function () w_health_type1 = 80 end) .super .sub "Type 2" .add("30%", function () w_health_type2 = 30 end) .add("50%", function () w_health_type2 = 50 end) .add("80%", function () w_health_type2 = 80 end) .super .super .sub "Food Goals" .sub "Type 0" .add(" 2000", function () w_fed_type0 = 2000 end) .add(" 5000", function () w_fed_type0 = 5000 end) .add("10000", function () w_fed_type0 = 10000 end) .super .sub "Type 1" .add(" 5000", function () w_fed_type1 = 5000 end) .add("10000", function () w_fed_type1 = 10000 end) .add("20000", function () w_fed_type1 = 20000 end) .super .sub "Type 2" .add(" 1000", function () w_fed_type2 = 1000 end) .add(" 2000", function () w_fed_type2 = 2000 end) .add(" 5000", function () w_fed_type2 = 5000 end) .super .super .sub "Type Distribution" .add("65%, 25%, 10%", function () w_type1_total, w_type2_total = .25, .10 end) .add("34%, 33%, 33%", function () w_type1_total, w_type2_total = .33, .33 end) .add("20%, 30%, 50%", function () w_type1_total, w_type2_total = .30, .50 end) .super .sub "Strategies" .add("Aggressive", function () zero_convert1 = 7 zero_convert2 = 6 zero_heal = 5 zero_distribute = 2 zero_runaway = 4 zero_koth = 3 zero_fight = 1 one_fight = 4 one_heal = 2 one_breed = 3 one_king = 1 two_heal = 2 two_distribute = 1 two_runaway = 4 two_koth = 3 end) .add("Default", function () zero_convert1 = 4 zero_convert2 = 3 zero_heal = 6 zero_distribute = 2 zero_runaway = 7 zero_koth = 5 zero_fight = 1 one_fight = 1 one_heal = 4 one_breed = 2 one_king = 3 two_heal = 3 two_distribute = 1 two_runaway = 4 two_koth = 2 end) .super .sep .sub "Debugging" .add("Show Decisions", function () ANN_DECISION_TYPE0 = true ANN_DECISION_TYPE1 = true ANN_DECISION_TYPE2 = true end) .add("Hide Decisions", function () ANN_DECISION_TYPE0 = false ANN_DECISION_TYPE1 = false ANN_DECISION_TYPE2 = false end) .super .sep .add("About", function () print("role-priority neural network based bot by mike mcmanus and nick irvine") end) infon/contrib/bots/sissy-bot.lua0000644000076400001440000006267610603314645017031 0ustar dividuumusers-- This bot uses a role-priority neural network to make decisions about -- its actions each turn. The weights labelled zero_xxxxx, one_xxxxx and -- two_xxxxx represent the role bias for each type of creature (type0, type1 -- and type2). Changing those weights will change the behaviour of the -- creature and is a really simple way of making different bots. There are -- a total of 2903040 different combinations for this network, so experiment -- a try to find a useful bot for yourself! For example, for a type0 creature, -- setting the weights to: -- zero_convert1 = 1 -- zero_convert2 = 2 -- zero_heal = 3 -- zero_distribute = 4 -- zero_runaway = 5 -- zero_koth = 6 -- zero_fight = 7 -- means that the creature would fight before becoming king, become king before running, -- run before distributing, distribute before healing, etc. So if the fight node is 'on' -- then the creature will ALWAYS fight. -- Once a decision is made, the appropriate role is called. These roles are -- by no means optimized, and we are still working on them. Gather, for example -- is still fairly primitive and we will (hopefully!) be updating it soon. -- If you are interested, a short paper on the results of this bot is available -- at www.uoguelph.ca/~mmcmanus -- If you have any question regarding the code or the algorithms used feel free -- to contact us at: -- mike mcmanus -> mmcmanus@uoguelph.ca -- nick irvine -> nirvine@uoguelph.ca --WEIGHTS w_health_type0 = 80 -- 0 - 100 w_health_type1 = 35 -- 0 - 100 w_health_type2 = 50 -- 0 - 100 w_distribute_amount = 5000 -- 0 - 5000 w_fed_type0 = 5000 -- 0 - 10000 w_fed_type1 = 10000 -- 0 - 20000 w_fed_type2 = 4000 -- 0 - 5000 w_type1_total = .25 -- 0 - 1 w_type2_total = .10 -- 0 - 1 w_need_amount = 5000 -- 0 - 20000 zero_convert1 = 4 zero_convert2 = 3 zero_heal = 6 zero_distribute = 2 zero_runaway = 7 zero_koth = 5 zero_fight = 1 one_fight = 1 one_heal = 4 one_breed = 2 one_king = 3 two_heal = 3 two_distribute = 1 two_runaway = 4 two_koth = 2 -- CREATURE DEFAULT VALUES TYPE0_HEALTH = 100 TYPE0_STORAGE = 10000 -- ENERGY COSTS CONVERT_FOOD_COST = 8000 SPAWN_FOOD_COST = 8000 COVERT_HEALTH_COST = 20 SPAWN_HEALTH_COST = 20 -- ROLE STATES CREATURE_BREEDER = 0 CREATURE_FIGHTER = 1 CREATURE_PATIENT = 2 CREATURE_DISTRIBUTOR = 3 CREATURE_KING = 4 CREATURE_RUNNER = 5 CREATURE_CONVERTER = 6 CREATURE_NOROLE = 100 RUNNER_DISTANCE = 30 --SPECIAL STATES -- see self.special_state CREATURE_WAIT = 10 CREATURE_GO = 13 GATHER_FOOD_THRESHOLD = 1 BOUNTIFUL = 1 UNEXPLORED = 0 BARREN = -1 -- DEBUGGING FLAGS ANN_DECISION_TYPE0 = false ANN_DECISION_TYPE1 = false ANN_DECISION_TYPE2 = true cell_width = 0 cell_height = 0 gather_circuit = {} grid = {} distribution = {} need = {} dlen = 0 creaturelist = {} rlen = 0 init = 0 winning = false ------------------------------------------------------------- -- INITIALIZING ------------------------------------------------------------- function game_init( self ) distribution_init( self ) food_init( self ) end function food_init( self ) gather_circuit = { { ["viable"] = UNEXPLORED, ["i"] = 0, ["j"] = 0}, { ["viable"] = UNEXPLORED, ["i"] = 1, ["j"] = 0}, { ["viable"] = UNEXPLORED, ["i"] = 2, ["j"] = 0}, { ["viable"] = UNEXPLORED, ["i"] = 3, ["j"] = 0}, { ["viable"] = UNEXPLORED, ["i"] = 3, ["j"] = 1}, { ["viable"] = UNEXPLORED, ["i"] = 2, ["j"] = 1}, { ["viable"] = UNEXPLORED, ["i"] = 1, ["j"] = 1}, { ["viable"] = UNEXPLORED, ["i"] = 1, ["j"] = 2}, { ["viable"] = UNEXPLORED, ["i"] = 2, ["j"] = 2}, { ["viable"] = UNEXPLORED, ["i"] = 3, ["j"] = 2}, { ["viable"] = UNEXPLORED, ["i"] = 3, ["j"] = 3}, { ["viable"] = UNEXPLORED, ["i"] = 2, ["j"] = 3}, { ["viable"] = UNEXPLORED, ["i"] = 1, ["j"] = 3}, { ["viable"] = UNEXPLORED, ["i"] = 0, ["j"] = 3}, { ["viable"] = UNEXPLORED, ["i"] = 0, ["j"] = 2}, { ["viable"] = UNEXPLORED, ["i"] = 0, ["j"] = 1}, } x1,y1,x2,y2 = world_size() cell_width = math.floor((x2-x1)/4) cell_height = math.floor((y2-y1)/4) end function grid_init( self ) local x1, y1, x2, y2 = world_size() truex = (x2-x1)/xweight truey = (y2-y1)/yweight truex = math.floor(truex) truey = math.floor(truey) for i=0,truex do grid[i] = {} for j=0,truey do if self:set_path(math.floor(i*xweight), math.floor(j*yweight)) then grid[i][j] = -1 else grid[i][j] = nil end end end end function distribution_init( self ) for i=0,1024 do distribution[i] = nil need[i] = nil end end function roles_init( self ) for i=0,1024 do creaturelist[i] = -1 end end function creature_init( self ) if not self.init then self.find = 0 self.init = true self.special_state = CREATURE_GO add_creature( self ) self.giving = false self.giveto = -1 self.giveamount = -1 self.givestart = -1 self.role = CREATURE_NOROLE pick_gather_dest( self ) print("creature" .. self.id .. " initialized" ) end end ------------------------------------------------------------- -- LIBRARY ------------------------------------------------------------- --converts the coordinates to indices in the grid function convert_to_index( x, y ) return math.floor(x/xweight), math.floor(y/yweight) end --converts the indices of the grid to coordinates on the map function convert_to_coords( x, y) return math.floor(x*xweight), math.floor(y*yweight) end --adds a creature to the global creature list function add_creature( self ) creaturelist[rlen] = self rlen = rlen + 1 end --returns the amount of a given creature type function type_amount( type ) amount = 0 for i=0, rlen-1 do if get_type( creaturelist[i].id ) == type then amount = amount + 1 end end return amount end --returns the amount of creatures that are a given role function role_amount( creature_role ) amount = 0 for i=0, rlen-1 do if creaturelist[i].role == creature_role then amount = amount + 1 end end return amount end --sets the special state of the creature function set_special_state( self, state ) self.special_state = state end function get_total_food( ) food = 0 for i=0, dlen-1 do food = food + get_food( distribution[i] ) end return food end function get_total_need( ) total_need = 0 for i=0, dlen-1 do total_need = total_need + need[i] end return total_need end --checks to see if any creatures have died since the last turn function creature_check( ) tempd = {} tempa = {} tlen = 0 for i=0,dlen-1 do if creature_exists( distribution[i] ) then tempd[tlen] = distribution[i] tempa[tlen] = need[i] tlen = tlen+1 end end for i=0,tlen-1 do distribution[i] = tempd[i] need[i] = tempa[i] end dlen = tlen tempc = {} tlen = 0 for i=0,rlen-1 do if creature_exists( creaturelist[i].id ) then tempc[tlen] = creaturelist[i] tlen = tlen+1 else print("A CREATURE DIED") end end for i=0,tlen-1 do tempc[i] = creaturelist[i] end rlen = tlen end function set_special_state( id, state ) for i=0,rlen-1 do if creaturelist[i].id == id then creaturelist[i].special_state = state end end end function enemy_info( self ) enemy_creature_id, x, y, playernum, dist = nearest_enemy( self.id ) if enemy_creature_id ~= nil then closest_enemy_health = get_health( enemy_creature_id ) closest_enemy_food = get_food( enemy_creature_id ) else closest_enemy_health = 0 closest_enemy_food = 0 end return closest_enemy_health, enemy_creature_id end function decision_max( decision, len ) best_choice = decision[0] best_role = 0 for i=1,len do if decision[i] > best_choice then best_choice = decision[i] best_role = i end end return best_role end function cell_to_bounds( self, c ) i,j = gather_circuit[c].i, gather_circuit[c].j x1,y1,x2,y2 = world_size() return i * cell_width+x1, j * cell_height+y1, (i+1) * cell_width + x1, (j+1) * cell_height + y1 end function coords_to_cell( self, x, y ) x1,y1,x2,y2 = world_size() i,j = math.floor((x-x1)*1.0/cell_width), math.floor((y-x1)*1.0/cell_height) for c = 1, 16 do if gather_circuit[c].i == i and gather_circuit[c].j == j then return c end end end function say( self , msg) print(self.id..": "..msg) end ------------------------------------------------------------- -- DISTRIBUTION ------------------------------------------------------------- function request_food( id, amount ) --dont let a creature add itself twice! for i=0,dlen-1 do if distribution[i] == id then need[i] = amount return end end print("added " .. id .. " to distro") distribution[dlen] = id need[dlen] = amount dlen = dlen + 1 end --decides who needs food the most! function pop( ) if dlen <= 0 then dlen = 0 return -1, -1 end creature = distribution[dlen-1] amount = need[dlen-1] dlen = dlen - 1 return creature, amount end function request_remove( id ) for i=0,dlen-1 do if distribution[i] == id then distribution[i] = -1 need[i] = -1 end end end ------------------------------------------------------------- -- GATHERING ------------------------------------------------------------- function pick_gather_dest( self ) x,y = get_pos( self.id ) mycell = coords_to_cell(self, x,y ) dest_cell = math.fmod(mycell + 1 ,16)+1 v = gather_circuit[dest_cell].viable while v == BARREN do dest_cell = math.fmod(dest_cell , 16)+1 v = gather_circuit[dest_cell].viable end x1,y1,x2,y2 = cell_to_bounds( self, dest_cell) x = math.floor(math.random()*(x2-x1)+x1) y = math.floor(math.random()*(y2-y1)+y1) -- should have something in here in case all the points in a cell are -- unreachable (water, etc.) Meh while not set_path(self.id, x, y) do x = math.floor(math.random()*(x2-x1)+x1) y = math.floor(math.random()*(y2-y1)+y1) end self.gather_dest = {["x"]= x, ["y"]= y} end function gather( self ) x, y = get_pos( self.id ) c = coords_to_cell( self, x, y ) if food_here( self ) then update_gather_circuit(self, c, BOUNTIFUL ) set_state( self.id, CREATURE_EAT ) else if x == self.gather_dest.x and y == self.gather_dest.y then pick_gather_dest( self ) else set_path( self.id, self.gather_dest.x, self.gather_dest.y ) set_state( self.id, CREATURE_WALK ) end end end function food_here( self ) return get_tile_food( self.id ) > GATHER_FOOD_THRESHOLD end function update_gather_circuit(self, cell, viable ) gather_circuit[cell].viable = viable end function search_for_food( self, amount ) request_food( self.id, amount ) gather( self ) end ------------------------------------------------------------- -- BREED ------------------------------------------------------------- function breed( self ) if get_food( self.id ) >= SPAWN_FOOD_COST then set_state( self.id, CREATURE_SPAWN ) else search_for_food( self, SPAWN_FOOD_COST - get_food( self.id ) ) end end ------------------------------------------------------------- -- CONVERT ------------------------------------------------------------- function convert( self, type ) if get_food( self.id ) >= CONVERT_FOOD_COST and set_convert( self.id, type )then set_state( self.id, CREATURE_CONVERT ) else search_for_food( self, CONVERT_FOOD_COST - get_food( self.id ) ) end end ------------------------------------------------------------- -- HEAL ------------------------------------------------------------- function heal( self ) if get_food( self.id ) >= w_need_amount then set_state( self.id, CREATURE_HEAL ) else search_for_food( self, w_need_amount ) end end ------------------------------------------------------------- -- FIGHT ------------------------------------------------------------- function fight( self ) enemy_id, e_x, e_y, playernum, dist = nearest_enemy( self.id ) if enemy_id ~= nil then set_target( self.id, enemy_id ) if get_distance( self.id, enemy_id ) < 256 then set_state( self.id, CREATURE_ATTACK) elseif set_path( self.id, e_x, e_y ) then set_state( self.id, CREATURE_WALK ) end end end function fight_king( self ) x, y = get_pos( self.id ) kx, ky = get_koth_pos( ) if x ~= kx and y ~= ky then if math.abs(x - kx) < 128 and math.abs(y - ky) < 128 then enemy_id, e_x, e_y, playernum, dist = nearest_enemy( self.id ) set_target( self.id, enemy_id ) set_state( self.id, CREATURE_ATTACK) elseif set_path( self.id, kx, ky ) then set_state( self.id, CREATURE_WALK ) end end end function check_enemy_type( enemy_type, self_type ) if self_type == 0 and enemy_type ~= 2 then return false elseif self_type == 2 then return false else return true end end ------------------------------------------------------------- -- RUNNER! ------------------------------------------------------------- function run( self ) bx1,by1,bx2,by2 = world_size() x = math.floor(math.random()*(bx2-bx1)+bx1) y = math.floor(math.random()*(by2-by1)+by1) if get_state( self.id ) ~= CREATURE_WALK then while not set_path(self.id, x, y) do x = math.floor(math.random()*(bx2-bx1)+bx1) y = math.floor(math.random()*(by2-by1)+by1) end end set_state( self.id, CREATURE_WALK ) end ------------------------------------------------------------- -- DISTRIBUTE ------------------------------------------------------------- function distribute( self ) request_remove( self.id ) if self.giving == true then print("giving food to" .. self.giveto) if get_distance( self.id, self.giveto ) < 256 then set_target( self.id, self.giveto ) set_state( self.id, CREATURE_FEED ) elseif set_path( self.id, get_pos( self.giveto ) ) then set_special_state( self.giveto, CREATURE_WAIT ) set_state( self.id, CREATURE_WALK ) end disfood = get_food( self.id ) if disfood == 0 or self.givestart - disfood > self.giveamount then set_special_state( self.giveto, CREATURE_GO ) self.giving = false self.giveto = -1 self.giveamount = -1 self.givestart = -1 end elseif dlen == 0 or get_food( self.id ) < self.giveamount and get_food( self.id ) ~= get_max_food( self.id ) then print("gathering") gather( self ) else self.giving = true self.giveto, self.giveamount= pop( ) self.givestart = get_food( self.id ) print("id:" .. self.id .." got " .. self.giveto) for i=0,4 do if self.giveto == -1 or self.giveto == self.id then self.giving = true self.giveto, self.giveamount= pop( ) self.givestart = get_food( self.id )self.giving = false break end end if self.giveto == self.id or self.giveto == -1 then self.giving = false self.giveto, self.giveamount= -1, -1 self.givestart = -1 end end end ------------------------------------------------------------- -- KING OF THE HILL! ------------------------------------------------------------- function king( self ) if get_pos( self.id ) ~= get_koth_pos( ) then set_path( self.id, get_koth_pos( ) ) set_state( self.id, CREATURE_WALK ) else set_state( self.id, CREATURE_IDLE ) end end ------------------------------------------------------------- -- DECIDER ------------------------------------------------------------- function decide( self ) decision = 0 if get_type( self.id ) == 0 then decision = type0_task( self ) elseif get_type( self.id ) == 1 then decision = type1_task( self ) elseif get_type( self.id ) == 2 then decision = type2_task( self ) end if decision == CREATURE_BREEDER then self.role = decision set_message( self.id, "BREED") breed( self ) elseif decision == CREATURE_GATHERER then self.role = decision set_message( self.id, "GATHER") gather( self ) elseif decision == CREATURE_FIGHTER then self.role = decision set_message( self.id, "FIGHT") fight( self ) elseif decision == CREATURE_PATIENT then self.role = decision set_message( self.id, "HEAL") heal( self ) elseif decision == CREATURE_DISTRIBUTOR then self.role = decision set_message( self.id, "DISTRO") distribute( self ) elseif decision == CREATURE_KING then self.role = decision set_message( self.id, "KING") if get_type( self.id ) == 1 then fight_king( self ) else king( self ) end elseif decision == CREATURE_RUNNER then self.role = decision set_message( self.id, "RUN") run( self ) elseif decision == CREATURE_CONVERTER then self.role = decision set_message( self.id, "CONVERT") convert( self, self.convert ) end end function type0_task( self ) total_type1 = type_amount( 1 ) total_type2 = type_amount( 2 ) creature_food = get_food( self.id ) creature_health = get_health( self.id ) creature_type = get_type( self.id ) total_need = get_total_need( ) total_food = get_total_food( ) total_creatures = rlen closest_enemy_health, enemy_id = enemy_info( self ) well_fed_node = well_fed( creature_type, creature_food ) type1_overpop_node = type1_overpopulated( total_creatures, total_type1 ) type2_overpop_node = type2_overpopulated( total_creatures, total_type2 ) starved_node = population_starved( total_need, total_food ) decision = {} for i=0,6 do decision[i] = 0 end decision[0] = zero_convert1 * type0_convert_type1( type1_overpop_node ) decision[1] = zero_convert2 * type0_convert_type2( type2_overpop_node ) decision[2] = zero_heal * not_healthy( creature_type, creature_health ) decision[3] = zero_distribute * distribute_node( starved_node, well_fed_node ) decision[4] = zero_runaway * type0_runaway( self, enemy_id ) decision[5] = zero_koth * type0_king_of_the_hill( self ) decision[6] = zero_fight * type0_fight( enemy_id ) choice = decision_max( decision, 6 ) if ANN_DECISION_TYPE0 then print("convert1? " .. decision[0]) print("convert2? " .. decision[1]) print("patient? " .. decision[2]) print("distri? " .. decision[3]) print("run? " .. decision[4]) print("koth? " .. decision[5]) print("fight? " .. decision[6]) end if choice == 0 then self.convert = 1 return CREATURE_CONVERTER elseif choice == 1 then self.convert = 2 return CREATURE_CONVERTER elseif choice == 2 then return CREATURE_PATIENT elseif choice == 3 then return CREATURE_DISTRIBUTOR elseif choice == 4 then return CREATURE_RUNNER elseif choice == 5 then return CREATURE_KING else return CREATURE_FIGHTER end end function type1_task( self ) total_type1 = type_amount( 1 ) total_type2 = type_amount( 2 ) creature_food = get_food( self.id ) creature_health = get_health( self.id ) creature_type = get_type( self.id ) total_need = get_total_need( ) total_food = get_total_food( ) total_creatures = rlen closest_enemy_health, enemy_id = enemy_info( self ) well_fed_node = well_fed( creature_type, creature_food ) type1_overpop_node = type1_overpopulated( total_creatures, total_type1 ) type2_overpop_node = type2_overpopulated( total_creatures, total_type2 ) starved_node = population_starved( total_need, total_food ) decision = {} for i=0,3 do decision[i] = 0 end health_node = not_healthy( creature_type, creature_health ) if health_node == 0 then health_node = 1 else health_node = 0 end decision[0] = one_fight * type1_fight( enemy_id ) decision[1] = one_heal * not_healthy( creature_type, creature_health ) decision[2] = one_breed * health_node decision[3] = one_king * type1_king_of_the_hill( self ) choice = decision_max( decision, 3 ) if ANN_DECISION_TYPE1 then print("fight? " .. decision[0]) print("heal? " .. decision[1]) print("breed? " .. decision[2]) print("koth? " .. decision[3]) end if choice == 0 then return CREATURE_FIGHTER elseif choice == 1 then return CREATURE_PATIENT elseif choice == 2 then return CREATURE_BREEDER else return CREATURE_KING end end function type2_task( self ) creature_food = get_food( self.id ) creature_health = get_health( self.id ) creature_type = get_type( self.id ) total_need = get_total_need( ) total_food = get_total_food( ) closest_enemy_health, enemy_id = enemy_info( self ) well_fed_node = well_fed( creature_type, creature_food ) starved_node = population_starved( total_need, total_food ) decision = {} for i=0,3 do decision[i] = 0 end health_node = not_healthy( creature_type, creature_health ) if health_node == 0 then health_node = 1 else health_node = 0 end decision[0] = two_heal * not_healthy( creature_type, creature_health ) decision[1] = two_distribute * distribute_node( starved_node, well_fed_node ) decision[2] = two_runaway * type2_runaway( self, enemy_id ) decision[3] = two_koth * type2_king_of_the_hill( self ) choice = decision_max( decision, 3 ) if ANN_DECISION_TYPE2 then print("heal? " .. decision[0]) print("distro? " .. decision[1]) print("run? " .. decision[2]) print("koth? " .. decision[3]) end if choice == 0 then return CREATURE_PATIENT elseif choice == 1 then return CREATURE_DISTRIBUTOR elseif choice == 2 then return CREATURE_RUNNER else return CREATURE_KING end end ------------------------------------------------------------- -- ARTIFICIAL NEURAL NETWORK ------------------------------------------------------------- function type1_fight( enemy_id ) if enemy_id == nil then return 0 else return 1 end end function type0_fight( enemy_id ) if enemy_id == nil then return 0 elseif get_type( enemy_id ) == 2 then return 1 else return 0 end end function type2_runaway( self, enemy_id ) if enemy_id == nil then return 0 elseif get_type( enemy_id ) == 1 or get_type( enemy_id ) == 2 and get_distance( self.id, enemy_id ) < 1024 then return 1 else return 0 end end function type0_runaway( self, enemy_id ) if enemy_id == nil then return 0 elseif get_type( enemy_id ) == 1 and get_distance( self.id, enemy_id ) < 1024 then return 1 else return 0 end end function distribute_node( starved, well_fed ) if starved == 1 or well_fed == 1 then return 1 else return 0 end end function type0_convert_type2( type2_population ) if type2_population == 1 then return 0 else return 1 end end function type0_convert_type1( type1_population ) if type1_population == 1 then return 0 else return 1 end end function not_healthy( creature_type, creature_health ) if creature_type == 0 and creature_health >= w_health_type0 then return 0 elseif creature_type == 1 and creature_health >= w_health_type1 then return 0 elseif creature_type == 2 and creature_health >= w_health_type2 then return 0 else return 1 end end function well_fed( creature_type, creature_food ) if creature_type == 0 and creature_food >= w_fed_type0 then return 1 elseif creature_type == 1 and creature_food >= w_fed_type1 then return 1 elseif creature_type == 2 and creature_food >= w_fed_type2 then return 1 else return 0 end end function type1_overpopulated( total_creatures, total_breeders ) if total_breeders / total_creatures >= w_type1_total then return 1 else return 0 end end function type2_overpopulated( total_creatures, total_flyers ) if total_flyers / total_creatures >= w_type2_total then return 1 else return 0 end end function type0_king_of_the_hill( self ) k = king_player( ) if k == nil or (k == player_number and get_pos( self.id ) == get_koth_pos( )) then return 1 else return 0 end end function type1_king_of_the_hill( self ) k = king_player( ) if k ~= nil and k ~= player_number then return 1 else return 0 end end function type2_king_of_the_hill( self ) k = king_player( ) if k == nil or (k == player_number and get_pos( self.id ) == get_koth_pos( )) then return 1 else return 0 end end function gatherer_overpopulated( total_creatures, total_gatherers ) percentage = total_gatherers / total_creatures if percentage >= w_gather_total then return 1 else return 0 end end function fighter_overpopulated( total_creatures, total_fighters ) percentage = total_fighters / total_creatures if percentage >= w_fight_total then return 1 else return 0 end end function population_starved( total_need, total_food ) if total_need < total_food then return 1 else return 0 end end function potential_target( enemy_id, enemy_food, enemy_health ) if enemy_id == nil then return 0 elseif get_type( enemy_id ) == 0 or get_type( enemy_id ) == 2 then return 1 elseif enemy_health < w_enemy_health then return 1 else return 0 end end function enemy_doing_well( enemy_score, my_score ) if enemy_score > my_score then return 1 else return 0 end end ------------------------------------------------------------- -- GENERAL TASK CHECKER! ------------------------------------------------------------- -- checks to see if someone is coming to give the agent food. function creature_is_busy( self ) if not non_critical_state( self ) then return true elseif self.special_state == CREATURE_WAIT and non_critical_state( self ) then set_state( self.id, CREATURE_IDLE ) return true elseif self.special_state == CREATURE_WAIT then return true else return false end end function non_critical_state( self ) state = get_state( self.id ) if state == CREATURE_SPAWN or state == CREATURE_FEED or state == CREATURE_HEAL or state == CREATURE_CONVERT or state == CREATURE_FIGHT then return false else return true end end function distro_check( self ) if (self.role ~= CREATURE_DISTRIBUTOR and self.giving == true) or (not creature_exists( self.giveto )) then set_special_state( self.giveto, CREATURE_GO ) self.giving = false self.giveto = -1 self.giveamount = -1 self.givestart = -1 end end ------------------------------------------------------------- -- MAIN ------------------------------------------------------------- function Creature:main () if init == 0 then print("game initialized") game_init( self ) init = 1 end creature_init( self ) creature_check( ) distro_check( self ) if not creature_is_busy( self ) then decide( self ) end self:wait_for_next_round() end infon/rules/0000700000076400001440000000000010540115021013045 5ustar dividuumusersinfon/rules/default.lua0000644000076400001440000001070010540115021015204 0ustar dividuumusersfunction onNewGame() round_end_text = nil round_end_time = nil king_player = nil king_time = 0 end function onRound() local time_limit = get_time_limit() if not round_end_text and time_limit and game_time() > time_limit then local maxscore = -1000000 local winner = nil local num_winner = 0 for n in each_player() do local score = player_score(n) if score > maxscore then winner = n maxscore = score num_winner = 1 elseif score == maxscore then num_winner = num_winner + 1 end end if not winner then round_end_text = "Timelimit hit" elseif num_winner == 1 then round_end_text = "Timelimit hit. " .. player_get_name(winner) .. " wins the game!" else round_end_text = "Timelimit hit. The game is a draw." end end if round_end_text then if not round_end_time then round_end_time = game_time() scroller_add(round_end_text) set_intermission(round_end_text) elseif round_end_time + 10000 < game_time() then set_intermission("") world_rotate_map() reset() end end end function onCreatureSpawned(creature, parent) if parent then local parent_player = creature_get_player(parent) player_change_score(parent_player, 10, "Spawned a creature") creature_set_food(creature, 1000) end end function onCreatureKilled(victim, killer) local victim_food = creature_get_food(victim) local victim_x, victim_y = creature_get_pos(victim) -- Suiciding returns less food if not killer then victim_food = victim_food / 3 end world_add_food_by_worldcoord(victim_x, victim_y, victim_food) local victim_player = creature_get_player(victim) if killer == victim then player_change_score(victim_player, -40, "Creature suicides") elseif not killer then player_change_score(victim_player, -3, "Creature died") else local victim_type = creature_get_type(victim) local killer_type = creature_get_type(killer) local killer_player = creature_get_player(killer) if victim_type == 0 and killer_type == 1 then player_change_score(victim_player, -3, "Runner was killed") player_change_score(killer_player, 10, "Killed a runner") elseif victim_type == 1 and killer_type == 1 then player_change_score(victim_player, -8, "Fatty was killed") player_change_score(killer_player, 15, "Crushed a fatty") elseif victim_type == 2 and killer_type == 0 then player_change_score(victim_player, -4, "Flyer was killed") player_change_score(killer_player, 12, "Smashed a flyer") elseif victim_type == 2 and killer_type == 1 then player_change_score(victim_player, -4, "Flyer was killed") player_change_score(killer_player, 12, "Smashed a flyer") else print("BUG: Impossible killer/victim combo") print("victim = " .. victim_type .. " killer = " .. killer_type) end end end function onPlayerCreated(player) local x, y = world_get_spawn_point(player) if x and y then creature_spawn(player, nil, x, y, CREATURE_SMALL) end local x, y = world_get_spawn_point(player) if x and y then creature_spawn(player, nil, x, y, CREATURE_SMALL) end end function onPlayerAllCreaturesDead(player, time) if time < 2000 then return end local x, y = world_get_spawn_point(player) if x and y then creature_spawn(player, nil, x, y, CREATURE_SMALL) end local x, y = world_get_spawn_point(player) if x and y then creature_spawn(player, nil, x, y, CREATURE_SMALL) end end function onPlayerScoreChange(player, score, reason) local score_limit = get_score_limit() if not round_end_text and score_limit and score >= score_limit then round_end_text = "player " .. player_get_name(player) .. " wins the game!" end end function onKingPlayer(player, delta) if player ~= king_player then king_player = player king_time = 0 end king_time = king_time + delta if king_time > 10000 then player_change_score(player, 30, "King of the Hill!") king_time = king_time - 10000 end end function onNoKing() king_player = nil king_time = 0 end infon/rules.h0000644000076400001440000000214410540115023013233 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef RULES_H #define RULES_H #define RESTRICTIVE 0 #define NO_CLIENT_KICK_TIME (120 * 1000) #define PLAYER_KICK_SCORE (-500) #define LUA_MAX_MEM (4 * 1024) #define LUA_MAX_CPU 450000 #define LUA_MAX_REAL_CPU_SECONDS 1 #endif infon/common_world.h0000644000076400001440000000247310536637517014633 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef COMMON_WORLD_H #define COMMON_WORLD_H // Begrenzt durch die Anzahl vorhandener Food Sprites #define MAX_TILE_FOOD 9999 typedef enum { TILE_SOLID = 0, TILE_PLAIN, TILE_LAST_DEFINED, } maptype_e; typedef enum { TILE_GFX_SOLID = 0, TILE_GFX_PLAIN, TILE_GFX_BORDER, TILE_GFX_SNOW_SOLID, TILE_GFX_SNOW_PLAIN, TILE_GFX_SNOW_BORDER, TILE_GFX_WATER, TILE_GFX_LAVA, TILE_GFX_NONE, TILE_GFX_KOTH, TILE_GFX_DESERT, TILE_GFX_LAST_DEFINED } mapgfx_e; #endif infon/misc.h0000644000076400001440000000352210540115023013035 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef MISC_H #define MISC_H void die(const char *fmt, ...); int yesno(const char *fmt, ...); void infomsg(const char *fmt, ...); #ifdef WIN32 const char *ErrorString(int error); #endif #ifndef abs #define abs(a) ((a)<0?-(a):(a)) #endif #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif #ifndef max #define max(a,b) ((a)>(b)?(a):(b)) #endif #define limit(v,a,b) ((v)<(a)?(a):((v)>(b)?(b):(v))) #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define lua_register_constant(L, name) \ do { lua_pushnumber(L, name); lua_setglobal(L, #name); } while (0) #define lua_register_string_constant(L, name) \ do { lua_pushliteral(L, name); lua_setglobal(L, #name); } while (0) #define save_lua_stack(L, diff) \ lua_State *check_L = L; \ int lua_stack = lua_gettop(check_L) - diff;\ fprintf(stderr, "%s> %d\n", __FUNCTION__, lua_stack); #define check_lua_stack() \ fprintf(stderr, "%s< %d\n", __FUNCTION__, lua_gettop(check_L)); \ assert(lua_gettop(check_L) == lua_stack); #endif infon/infon.ico0000600000076400001440000001307610505727453013554 0ustar dividuumusers@@((@!#"&(&#5*,+,/-',5 /8/10%*B&-@131$.G22<58616=15A77A9;:+5O-7R=@>9XGIG 9C_CGT4BdIHR $,DJQ?D_=Eg>Hd9GjE38EMa4>/6O~@?"]d%+CNj>Lp%2")%$3@NrAJz>HVYW/6VX\QVbBPtMTj@UnHSpIQt?aq6>OToERwEO2>;GlbFTyS\_]LUxLWuq_DPHV{xSAHKX]j^_dC]rIW|ISvZNS[q#TJX}OZxFP^PY|VKY#@GWLV9er?iiM[FJMYX]y^S^|&>N\1XrUegfYaw_doT]O]Jp`[Ab76P_Q\Clr=`n~R^vs=tg#.nySas|#rzNi}>|__g}ZeZcUc0EknlQXUffjxIRVdggj~(|rl6Ynot8F[8J:kZjdl_kc*rrus'IDL2n5R9[^o#p|oS%+1eqks>\sxy|z[^J8 'ou{|pxkv+)c Kz#J/v~v|q|Kwjo{:B|'30hљpZ[rx[M=.MMLQGGdGjZ[Zp}rWMpL&I^f=M{c&QC(7_7˙mBI^MMWW=^JGEǟc}}^fmIR<MZpxZ{gD4O֬V¶˔UC=MWRppZQcddܟ^MIlS.I<& r{G8;XO¶q;D==^mjGdآIZZWWMM.M*&  L[p{dQsi\¶i;]M,BW^EMSIZZBBM=#  =BW{dysA|(DB.==RpYB=IZlWzW=, RMMpjEɸӳտqʥKRRIMBWmJG}mWMfmmMMI<&WMIf[H鸹aAaʺeZpxMZLGmR^lpWZ^=IL) p}L鮞s5/AoʏNKBfڛxp[mWMMpmlp=IQ&  pƠԣ55"5qѧFnp^fٲm͜flrprlfIZ{)  Ý}P5555|ѻRIpڋכZIMRm&  x}pr}}prP5"55s|wZZrmÜpMWm[) Mr^plZprZfpP@@55/?ՒW^p}xx߲fZ^m{& =WlrZIWprrfr]`;5";`eZWMlZp$&&$$$2MZpp^MZ}mMZzP;>PzppZlrMMWfĚ岛}r<&MI[Z,MmlIBflSWrpIztDSm^WWmZ.I2[j-22#22*L{*22*#*222<*2ٜ- flW^[rZ+++++++++++>כ#Jϲ-Lj*MZZZmm[~bbbbbbbbbbb1*ϛ2Jj2J. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PATHFINDING_PATH_H #define PATHFINDING_PATH_H #ifdef __cplusplus extern "C" { #endif #include "map.h" #define DEST_WEIGHT 1 typedef struct pathnode_s pathnode_t; typedef struct open_s open_t; typedef struct pathfinder_s { int path_id; int numopen; int maxopen; open_t *openset; int randcnt; int random[256]; } pathfinder_t; struct open_s { portal_t *portal; int fromside; int cost; }; struct pathnode_s { int x; int y; pathnode_t *next; }; pathnode_t *finder_find(pathfinder_t *finder, map_t *map, int sx, int sy, int ex, int ey); pathnode_t *pathnode_new(int x, int y); void path_delete(pathnode_t *path); void finder_init (pathfinder_t *finder); void finder_shutdown(pathfinder_t *finder); #ifdef __cplusplus } #endif #endif infon/common_player.h0000600000076400001440000000221510505727453014755 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef COMMON_PLAYER_H #define COMMON_PLAYER_H #define MAXPLAYERS 32 #define PLAYER_DIRTY_ALIVE (1 << 0) #define PLAYER_DIRTY_NAME (1 << 1) #define PLAYER_DIRTY_COLOR (1 << 2) #define PLAYER_DIRTY_CPU (1 << 3) #define PLAYER_DIRTY_SCORE (1 << 4) #define PLAYER_DIRTY_ALL 0x1F #define PLAYER_DIRTY_NONE 0x00 #endif infon/config.lua0000644000076400001440000000640410603314646013717 0ustar dividuumusers-- ip and port to bind listen socket listenaddr = "0.0.0.0" listenport = 1234 -- password for the 'shell' command. disabled if empty or missing. debugpass = "" -- password to disable no-client kicking. by default, a player is -- kicked, once no client is connected for 120 seconds. using this -- password, players can disable this limit. disabled if empty or -- missing. nokickpass = "" -- message displayed every 10 seconds join_info = "this message can be changed in config.lua" -- maps to rotate maps = {"foo", "gpn", "water", "cn", "owl", "stripeslice", "castle", "infon" } -- rules file to use. rules = "default" -- filename prefix for demo files. disabled if unset. -- demo = "infond" -- time limit for each map time_limit = nil -- score limit for each map score_limit = 500 -- access control list. default is to allow connections -- from all clients. acl = {{ pattern = "^ip:127\.0\..*" }, { pattern = "^special:.*" }, { pattern = ".*" }, { pattern = ".*", deny = "access denied" }} -- available highlevel apis highlevel = { 'oo', 'state' } -- disable joining? -- disable_joining = "no joining!" -- show banner? banner = [[ .--..-. / / \ \'-. _ / / _( o)_ ; \ O O / ' -.\ \___;_/-__ ;) __/ \ //-. ; / // \ ' (INFON ) ) \( ) ) ' / / '.__.- -' _ \\ // _ (_'_/ \_'_) ]] -- allowed files for dofile dofile_allowed = { menu = "Botcode Menu System"; } -- Disable Linehook Function. -- This function offers some advanced debugging features, -- but has not been tested enough. Do not enable, unless -- you know what you're doing. linehook = false -- DO NOT ENABLE THE DEBUGGER IF OTHER PLAYERS CAN CONNECT -- TO YOUR SERVER. The debugger is not yet secured against -- malicious users. debugger = false -- competition = { -- log = "competition.log"; -- bots = { -- { source = "bot1.lua" }, -- { source = "bot2.lua", -- log = "bot2.log", -- name = "2ndbot" } -- } -- } -- -- maps = { "foo", "foo", "foo" } -- time_limit = 10 * 60 * 1000 -- score_limit = nil -- listenaddr = nil -- Things to do once after the first game started -- -- function autoexec() -- start_bot{ source = "contrib/bots/easybot.lua", -- name = "foo", -- password = "secret", -- api = "state" } -- end -- function checking user/password combinations. -- if pass is nil, return a boolean to indicate -- if the username requires a password. If password -- is set, return true if the password is correct. -- -- function check_name_password(user, pass) -- end -- Uncomment the following lines to announce your -- server to the Master Server at infon.dividuum.de. -- This will send a tiny UDP packet every minute. -- -- master_ip = '217.28.96.154' -- infon.dividuum.de -- servername = 'An Infon Server' infon/packet.c0000600000076400001440000000642010531066100013335 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef WIN32 #include #else #include #endif #include #include #include #include "packet.h" void packet_rewind(packet_t *packet) { packet->offset = 0; } void packet_init(packet_t *packet, int type) { packet->type = type; packet_rewind(packet); } int packet_read08(packet_t *packet, uint8_t *data) { if (packet->len - packet->offset < 1) { fprintf(stderr, "reading beyond end\n"); return 0; } *data = packet->data[packet->offset]; packet->offset += 1; return 1; } int packet_read16(packet_t *packet, uint16_t *data) { uint8_t byte; if (!packet_read08(packet, &byte)) return 0; *data = byte & 0x7F; if (byte & 0x80) { if (!packet_read08(packet, &byte)) return 0; *data |= byte << 7; } return 1; } int packet_read32(packet_t *packet, uint32_t *data) { if (packet->len - packet->offset < 4) { fprintf(stderr, "reading beyond end\n"); return 0; } *data = ntohl(*(uint32_t*)&packet->data[packet->offset]); packet->offset += 4; return 1; } int packet_readXX(packet_t *packet, void *data, int len) { if (packet->len - packet->offset < len) { fprintf(stderr, "reading beyond end\n"); return 0; } memcpy(data, &packet->data[packet->offset], len); packet->offset += len; return 1; } int packet_write08(packet_t *packet, uint8_t data) { if (sizeof(packet->data) - packet->offset <= 1) { fprintf(stderr, "packet too full\n"); return 0; } *((uint8_t*)&packet->data[packet->offset]) = data; packet->offset += 1; return 1; } int packet_write16(packet_t *packet, uint16_t data) { assert(data <= 0x7FFF); if (data <= 0x7F) return packet_write08(packet, data); else return packet_write08(packet, (data & 0x7F) | 0x80) && packet_write08(packet, data >> 7); } int packet_write32(packet_t *packet, uint32_t data) { if (sizeof(packet->data) - packet->offset <= 4) { fprintf(stderr, "packet too full\n"); return 0; } *((uint32_t*)&packet->data[packet->offset]) = htonl(data); packet->offset += 4; return 1; } int packet_writeXX(packet_t *packet, const void *data, int len) { if (sizeof(packet->data) - packet->offset <= len) { fprintf(stderr, "packet too full\n"); return 0; } memcpy(&packet->data[packet->offset], data, len); packet->offset += len; return 1; } infon/infon.c0000644000076400001440000001417610603314646013231 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef WIN32 #include #endif #include #include #include #include #include #include #include "global.h" #include "client.h" #include "misc.h" #include "renderer.h" #include "client_game.h" int game_time = 0; static int signal_received = 0; static struct timeval start; static int get_tick() { static struct timeval now; gettimeofday(&now , NULL); return (now.tv_sec - start.tv_sec) * 1000 + (now.tv_usec - start.tv_usec) / 1000; } #ifndef WIN32 static void sighandler(int sig) { signal_received = 1; } #endif static void info() { fprintf(stdout, "%s built %s %s\n", GAME_NAME, __TIME__, __DATE__); #ifdef NO_EXTERNAL_RENDERER fprintf(stdout, "Cannot load external renderers"); #else fprintf(stdout, "External renderers supported"); #endif #ifdef BUILTIN_RENDERER fprintf(stdout, ", builtin renderer '%s'", TOSTRING(BUILTIN_RENDERER)); #endif #ifdef DEFAULT_RENDERER fprintf(stdout, ", default renderer '%s'", TOSTRING(DEFAULT_RENDERER)); #endif fprintf(stdout, "\n"); } int main(int argc, char *argv[]) { char *host = NULL; char *renderer = NULL; int width = 800; int height = 600; int fullscreen = 0; #ifdef EVENT_HOST host = EVENT_HOST; #endif #ifdef DEFAULT_RENDERER renderer = TOSTRING(DEFAULT_RENDERER); #endif // GUI Environment setzt default Renderer um. if (getenv("GUI")) renderer = getenv("GUI"); #ifdef WIN32 char *sep = strrchr(argv[0], '\\'); if (sep) { *sep = '\0'; chdir(argv[0]); } // Spezialfaelle fuer Windows Screensaver Aufrufe if (argc == 2 && stricmp(argv[1], "/s") == 0) { host = "infon.dividuum.de"; width = 1024, height = 768, fullscreen = 1; goto screen_saver_start; } else if (argc == 3 && stricmp(argv[1], "/p") == 0) { exit(EXIT_SUCCESS); } else if (argc == 2 && strstr(argv[1], "/c:") == argv[1]) { die("There are no settings"); } #endif // Keine Fehler auf stderr opterr = 0; int opt; while ((opt = getopt(argc, argv, ":fvx:y:r:h")) != -1) { switch (opt) { case '?': die("you specified an unknown option -%c.", optopt); case ':': die("missing argument to option -%c.", optopt); case 'r': renderer = optarg; break; case 'f': fullscreen = 1; break; case 'x': width = atoi(optarg); break; case 'y': height = atoi(optarg); break; case 'h': die("usage: %s [-r ] [-f] [-x ] [-y ] [-v] [-h] \n" "\n" " -r - renderer to use (sdl_gui, gl_gui, ...)\n" " -x - initial screen width.\n" " -y - initial screen height.\n" " -f - start in fullscreen mode.\n" " -v - display version information.\n" " -h - this help.\n" "\n" " - ip/hostname of an infon game server.\n" " if not port is given, 1234 is used.\n", argv[0]); case 'v': info(); exit(EXIT_SUCCESS); } } switch (argc - optind) { case 0: break; case 1: host = argv[optind]; break; default: die("you specified more than one game server hostname"); } if (!renderer) die("no renderer specified. use the '-r ' option"); #ifdef WIN32 if (!host) { if (yesno("You did not specify a game server.\nConnect to 'infon.dividuum.de:1234'?")) host = "infon.dividuum.de"; else die("You must supply the game servers hostname\n" "as a command line parameter.\n\n" "Example: 'infon.exe infon.dividuum.de'\n\n" "Visit http://infon.dividuum.de/ for help."); } #else if (!host) die("usage: %s [options] \n" "see %s -h for a full list of options", argv[0], argv[0]); #endif #ifndef WIN32 signal(SIGTERM, sighandler); signal(SIGINT, sighandler); signal(SIGPIPE, SIG_IGN); #else screen_saver_start: #endif srand(time(NULL)); gettimeofday(&start, NULL); if (!renderer_init(renderer)) die("cannot initialize the renderer '%s'", renderer); if (!renderer_open(width, height, fullscreen)) die("cannot start the renderer '%s'. sorry", renderer); client_init(host); client_game_init(); int lastticks = get_tick(); while (!signal_received && !renderer_wants_shutdown() && client_is_connected()) { int nowticks = get_tick(); int delta = nowticks - lastticks; if (nowticks < lastticks || nowticks > lastticks + 1000) { // Timewarp? lastticks = nowticks; continue; } lastticks = nowticks; // IO Lesen/Schreiben client_tick(delta); client_creature_move(delta); renderer_tick(game_time, delta); game_time += delta; } client_game_shutdown(); client_shutdown(); renderer_close(); renderer_shutdown(); return EXIT_SUCCESS; } infon/packet.h0000644000076400001440000000467110603314646013373 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PACKET_H #define PACKET_H #include #pragma pack (push, 1) typedef struct #ifndef WIN32 __attribute__((packed)) #endif { #define PACKET_HEADER_SIZE 2 // Wire Data uint8_t len; uint8_t type; #define PACKET_PLAYER_UPDATE 0 #define PACKET_WORLD_UPDATE 1 #define PACKET_SCROLLER_MSG 2 #define PACKET_CREATURE_UPDATE 3 #define PACKET_QUIT_MSG 4 #define PACKET_KOTH_UPDATE 5 #define PACKET_WORLD_INFO 6 #define PACKET_CREATURE_SMILE 7 #define PACKET_GAME_INFO 8 #define PACKET_ROUND 9 #define PACKET_INTERMISSION 10 #define PACKET_WELCOME_MSG 32 #define PACKET_MASTER_PING 253 #define PACKET_START_COMPRESS 254 #define PACKET_HANDSHAKE 255 uint8_t data[256]; // Mgmt Data uint8_t offset; } packet_t; #pragma pack (pop) #define PROTOCOL_ERROR() \ do { \ fprintf(stderr, "Packet Error: %s:%d\n",__FILE__, __LINE__);\ return; \ } while (0) void packet_rewind(packet_t *packet); void packet_init (packet_t *packet, int type); int packet_read08(packet_t *packet, uint8_t *data); int packet_read16(packet_t *packet, uint16_t *data); int packet_read32(packet_t *packet, uint32_t *data); int packet_readXX(packet_t *packet, void *data, int len); int packet_write08(packet_t *packet, uint8_t data); int packet_write16(packet_t *packet, uint16_t data); int packet_write32(packet_t *packet, uint32_t data); int packet_writeXX(packet_t *packet, const void *data, int len); #endif infon/REVISION0000644000076400001440000000001510603315310013105 0ustar dividuumusersREVISION=198 infon/pinger.c0000644000076400001440000000363110603314646013376 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include "packet.h" void ping_master(const char *master_addr, int port, const char *servername, int clients, int players, int creatures) { struct sockaddr_in master; socklen_t addrlen = sizeof(struct sockaddr_in); size_t namelen = strlen(servername); if (namelen > 32) namelen = 32; memset(&master, 0, sizeof(struct sockaddr_in)); master.sin_family = AF_INET; master.sin_addr.s_addr = inet_addr(master_addr); master.sin_port = htons(port); int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) return; packet_t packet; packet_init(&packet, PACKET_MASTER_PING); packet_write08(&packet, clients); packet_write08(&packet, players); packet_write08(&packet, creatures); packet_writeXX(&packet, servername, namelen); packet.len = packet.offset; sendto(sock, &packet, PACKET_HEADER_SIZE + packet.len, 0, (struct sockaddr *)&master, addrlen); close(sock); } infon/libs/0000755000076400001440000000000010603240401012657 5ustar dividuumusersinfon/libs/menu.lua0000644000076400001440000001173510552756356014365 0ustar dividuumusers--[[ Menu system written by Rici Lake in order to demonstrate some interesting syntactic possibilities in Lua This program is released into the public domain. But if you find it useful, you could certainly buy me a coffee sometime. Modified by Florian Wesch to fit into infon. ]]-- ------------------------------------------------------------------ -- menu.lua ------------------------------------------------------------------ do local curriedMethod, method, meta = {}, {}, {} -- __index either executes a method from method or curries a method from -- curriedMethod with its self argument. This allows all calls to be with -- "." rather than ":" and also allows you to write obj.foo instead of -- obj.foo() for methods which don't require arguments. It might -- not be great design, but it is interesting. :) function meta:__index(key) local func = method[key] if func then return func(self) else func = curriedMethod[key] if func then local rv = function(a, b) return func(self, a, b) end self[key] = rv return rv end end end -- quick and dirty display routine. local DASHES = string.rep('-', 80) local DOUBLES = string.rep('=', 80) local function drawmenu(self) local maxsize = string.len(self.name) + 2 local item = 0 for i = 1, self.n do local sz = 6 + string.len(self[1][i]) if maxsize < sz then maxsize = sz end end if maxsize > 75 then maxsize = 75 end local sepformat = " +%-"..maxsize.."."..maxsize.."s+" local nameformat = " | %-"..(maxsize - 2).."."..(maxsize-2).."s |" local itemformat = " | %2i. %-"..(maxsize - 6).."."..(maxsize-6).."s |" local sepline = string.format(sepformat, DASHES) print(string.format(sepformat, DOUBLES)) print(string.format(nameformat, self.name)) print(string.format(sepformat, DOUBLES)) for i = 1, self.n do if self[2][i] then item = item + 1 print(string.format(itemformat, item, self[1][i])) else print(sepline) end end print(sepline) end -- Equally quick and dirty menu execution. Tail calls the function -- associated with the selected menu item. local function domenu(self) while true do print() drawmenu(self) print() local choice = coroutine.yield() if choice == nil then return false end local _, _, item = string.find(choice, "^%s*(%d+)%s*$") if item then item = item + 0 -- force numeric conversion for i = 1, self.n do if self[2][i] then if item == 1 then return self[2][i]() end item = item - 1 end end end print("Selection '" .. choice .. "' not valid.") end end -- Create a new menu with given name and back reference. local function newmenu(name, back) return setmetatable({ {}, {}, -- [1] is the menu label, [2] is the associated function name = name, back = back, n = 0 }, meta) end -- insert a label and a function at the end of a menu local function put(self, name, action) local n = self.n + 1 self.n = n self[1][n] = name self[2][n] = action return self end -- Now the actual menu methods. -- add(label, id) function curriedMethod:add(name, id) return put(self, name, type(id) == "function" and id or function() return id end) end -- create and open a submenu with the given name function curriedMethod:sub(name) local submenu = newmenu(self.name .. " / " .. name, self) put(self, name.." -->", function() return domenu(submenu) end) return submenu end -- create a new, unrelated menu. You cannot use super afterwards function curriedMethod:new(name) return newmenu(name) end -- go back to the previous level, after introducing the automatic Back label -- unless this is a top-level menu function method:super() local mom = self.back if mom then put(self, "-") put(self, "<-- Back", function() return domenu(self.back) end) return self.back else return self end end -- insert a separator line function method:sep() return put(self, "-") end -- and a function to actually execute the thing curriedMethod.run = domenu function menu(name) local coro, input local menu = newmenu("").new(name) function input(key) if not key or not coro or coroutine.status(coro) == "dead" then coro = coroutine.create(menu.run) end local ok, msg = coroutine.resume(coro, key) if not ok then error(_TRACEBACK(coro, msg)) end end function onInput0() input() end function onInput1() input(1) end function onInput2() input(2) end function onInput3() input(3) end function onInput4() input(4) end function onInput5() input(5) end function onInput6() input(6) end function onInput7() input(7) end function onInput8() input(8) end function onInput9() input(9) end return menu end end infon/libs/ldb-break.lua0000644000076400001440000004456210603240401015220 0ustar dividuumusers-- Breakpoint support. -- Most ldb modules will start like this (although they may -- not require ldb itself). The setfenv gives us access to -- all of the ldb configs and hooks, including the splain -- system. local ldb = require"ldb" setfenv(1, require"ldb-config") splain.breakpoints = [[- Some issues with breakpoints The breakpoint code has not been exhaustively debugged, and it has a few glitches and inconveniences. I'll try to fix these (or work around them) before the beta release. * ldb does not check that the file or line specified in the `break` command are correct. Furthermore, the file must be typed exactly as it was specified in the dofile() function (or equivalent). This is particularly awkward for files loaded through require(). It's usually easiest to use the `ldb` command-line script, which will trigger ldb at the beginning of a lua file (or you can use the `debugf` function exported by `require"ldb-break"`). If you omit the filename in the `break` command, then ldb will use the filename from the current callframe. This is almost always the most convenient. You can move up and down in the callframe to find a callframe with the correct filename. You can now use the `next`, `step` and `finish` commands even if you're not in an ldb call initiated by a breakpoint. However, there are a couple of issues: * `finish` will act as though it were `next`, so you'll need to do a second `finish` to actually finish the callframe which called ldb directly. However, I believe that `continue ` will work correctly. * If ldb is being used as an error function (either by assigning `debug.traceback = ldb` or by using something like `xpcall(myfunc, ldb)` then `next` and `step` will be relative to the frame where Lua will throw the error. ldb does not know where that is, so `continue ` will most likely produce an error telling you that the line is not correct. Also, `finish` will, as above, be treated as though it were `next`. If the error is not in the scope of an `xpcall`, then Lua will simply terminate as usual; ldb can't do anything about that. It would be really nice if there were a way to restart a Lua program at the place where the error was thrown, having fixed a variable or something, but there isn't and ldb can't invent mechanisms which don't exist in the Lua debug interface. Any suggestions for overcoming these issues are more than welcome, of course. ]] local getinfo, sethook = debug.getinfo, debug.sethook -- To enable sethook tracing, you need to change the 2 to 3 -- in leave, and change the above from sethook to _sethook. -- local function sethook(_, f) print("sethook", f) _sethook(_, f) end -- -- Also: %s/--\[\[ DEBUG/--[[ DEBUG/ -- A table of tables. -- breaklines[lno][source] is true if there is a breakpoint at -- source:lno. It would be better if we could get -- at the proto, really. local breaklines -- If we're tracking call levels to do 'next' or 'finish', this is -- the current virtual level. When it hits 0, we need to break on -- the next line (or the line in breaknextline). If we're not -- doing 'next' or 'finish', this will be nil. local breaklevel -- True if a 'next' should be restored when breaklevel reaches 0. local breaknext -- If 'next' has a target line, this is the line number. If it's -- set, breaknext must also be set. local breaknextline -- breakcalls and breakrets are independent, but they work the same -- way: each is a table of functions we want to break at call -- or return (not tail return) respectively, with a command table -- (or true) as value. local breakcalls, breakrets -- There are times when stray breaknexts are still around when -- we're on our way out, or when an error is raised. This table -- contains internal functions whose execution indicates that -- a breaknext ought to be ignored. (Usually a 'step' command.) -- The value is a function to execute when the stray hook fires. -- In the case of ldb itself, we just kill the hook; it will get -- re-enabled if necessary on exit. local breakignores = {[ldb] = sethook} -- There's only one leave entry point, so it needs to be chained -- by tail-calling the old one. Unfortunately, we can't get away -- with this here (see long comment below) so we require that -- this be the *first* plugin loaded. do --local _leave = leave function leave(self, ...) --[[ DEBUG print("leave", self.in_hook, breaklevel, breaknext) --]] if not self.in_hook and (breaknext or breaklevel) then -- Boy, would it be handy to have an error hook :) -- Also, this is why I hate the tailcall faking behaviour. -- -- At this point, we're on our way out from an error -- or a direct call. Since we're not in a hook, we -- have to adjust breaklevel to not go off until we -- get back to the caller. Everything from here on -- out is a tailcall except maybe for the trampoline -- inserted by the standalone interpreter, which we -- can ignore because it's a C frame. The problem is -- that we don't know how many tail call frames are -- going to be added by the chained calls to leave. -- -- We also don't really know how far back to go up -- the call chain, but that's less important. What's left -- here is tailcalls and C-frames (hopefully), and behind -- that there will be either the frame which directly called -- ldb, or a luaD_throw back to a pcall or xpcall, which is -- also a C-frame. The only issue with not knowing where to -- go back to is that it makes the semantics of `finish` a -- bit odd: you can't `finish` a frame entered with a direct -- call to ldb. -- -- Undoubtedly, there is a clever way of solving this -- problem, but since I'm pressed for time, I'm going for -- the simple solution, which is to ignore the value of -- breaklevel and just set it to something which will work, -- and to insist that this be the first module loaded. -- -- So we need to ignore the return from sethook() and then our -- own (pseudo)return. We'll just set breaklevel to 2, -- kill breaknext, and hope for the best. breaklevel = 2 breaknext = nil end local c = breaklevel or breakcalls local r = breaklevel or breakrets local l = breaklines or breaknext --[[ DEBUG print("leave-post adjust", self.in_hook, breaklevel, breaknext, c, r, l) --]] if c or r or l then sethook(ldb, (c and "c" or "")..(r and "r" or "")..(l and "l" or "")) else sethook() end return ... --return _leave(self, ...) end end local function setbreakpoint(source, lno, cmds) breaklines = breaklines or {} local sources = breaklines[lno] or {} sources[source] = cmds or true breaklines[lno] = sources end local function setcallbreak(f, cmds) breakcalls = breakcalls or {} breakcalls[f] = cmds or true end local function setretbreak(f, cmds) breakrets = breakrets or {} breakrets[f] = cmds or true end local function clearbreakcall(f) if not f then breakcalls = nil elseif breakcalls then oldcalls = breakcalls[f] breakcalls[f] = nil if not next(breakcalls) then breakcalls = nil end return oldcalls end end local function clearbreakret(f) if not f then breakrets = nil elseif breakrets then oldrets = breakrets[f] breakrets[f] = nil if not next(breakrets) then breakrets = nil end return oldrets end end local function clearbreakpoint(source, lno) if not source then breaklines = nil elseif breaklines then local sources = breaklines[lno] local oldcmds = sources and sources[source] if oldcmds then sources[source] = nil if not next(sources) then breaklines[lno] = nil end if not next(breaklines) then breaklines = nil end end return oldcmds end end function prehandler.line(lno) --[[ DEBUG print("line hook", breaklines, breaklevel, breaknext, breaknextline) --]] local sources = breaklines and breaklines[lno] local info if sources then -- There's no sentinel yet so we have to count levels, -- which should just be ldb and us. info = getinfo(3) local cmds = sources[info.source] if cmds then return "ldb_dohook", cmds end end if breaknext then if not breaknextline or breaknextline == lno then if not info then info = getinfo(3) end if breakignores[info.func] then return breakignores[info.func]() end return "ldb_dohook" end end end function prehandler.call() --[[ DEBUG do local info = getinfo(3) print("call hook", breakcalls, breaklevel, breaknext, breaknextline, info.what, info.name) end --]] if breakcalls then local func = getinfo(3, "f").func local cmds = breakcalls[func] if cmds then return "ldb_dohook", cmds end end breaknext = false if breaklevel == 0 then breaklevel = 1 sethook(ldb, breaklines and "crl" or "cr") elseif breaklevel then breaklevel = breaklevel + 1 end end prehandler["return"] = function() --[[ DEBUG do local info = getinfo(3) print("return hook", breakrets, breaklevel, breaknext, breaknextline, info.what, info.name) end --]] if breakrets then local func = getinfo(3, "f").func local cmds = breakrets[func] if cmds then return "ldb_dohook", cmds end end if breaklevel then breaklevel = breaklevel - 1 if breaklevel <= 0 then sethook(ldb, "crl") breaknext = true end end end prehandler["tail return"] = function() --[[ DEBUG print("tail return hook", breakrets, breaklevel, breaknext) --]] if breaklevel then breaklevel = breaklevel - 1 if breaklevel <= 0 then sethook(ldb, "crl") breaknext = true end end end -- Do a command or a table of commands, and then fall into -- interactive mode unless the command(s) include continue -- The test is for `nil` specifically because self:error() -- returns `false` if there is an error (unless self.ignore_error -- is set, which happens if the command starts with a `!`) function handler:ldb_dohook(token, cmds) breaknext = nil breaknextline = nil breaklevel = nil self.in_hook = true local t = type(cmds) if t == "string" then return self:do_a_command(cmds) elseif t == "table" then for _, cmd in ipairs(cmds) do local flag, val = self:do_a_command(cmd) if flag ~= nil then return flag, val end end end end -- Breakpoint commands splain.breakpoint = [=[[FILE] LINE - Set a breakpoint at FILE:LINE If only a line number is specified, the breakpoint is set in the file of the current context. Note: ldb compares filenames for strict equality; it does not know that ./foo.lua, /usr/home/rici/foo.lua and foo.lua are all the same file. (It just uses the source string from debug.getinfo and compares for equality.) ]=] alias.breakpoint = 'b' function command:breakpoint(args) local file, lno = self.here.source, tonumber(args) if lno then lno = tonumber(args) elseif not args:match"%S" then lno = self.here.currentline else file, lno = args:match"(%S+)%s*(%d+)" if file then file = "@"..file lno = tonumber(lno) end end if not lno then return self:error"A line number must be specified" end if not file then return self:error"The current context has no associated source file" end setbreakpoint(file, lno) end splain.breakfunc = [[EXPR [LINE] - Set a breakpoint in an function EXPR is evaluated and must return a function value or a string. If EXPR is a string: EXPR is interpreted as the value of the `source` getinfo field, and it should come from something like: .bf (here+3).source LINE defaults to 1. If EXPR is a Lua function: The breakpoint is not specific to the closure; it is set to the file position so it will apply to any closure using the same function prototype. LINE defaults to the first valid line in the function. In interactive mode, a warning is printed if the line is not inside the function's definition. If it is inside the definition, an error is produced if it is not a breakpointable line. If a warning is produced, the breakpoint is set anyway, so that you can use it to set breakpoints in the function's file. If the function is a CFunction: The breakpoint *is* specific to the closure. LINE may be 'call', 'return', or 'both' (which is the default). Note: unlike most ldb commands, the expression must fit in one line. It would not be possible to parse the LINE argument otherwise. ]] alias.breakfunc = "bf" do local calllines = {call = 'c', ["return"] = 'r', both = 'cr'} local function ls(s) local ok, err = loadstring(s, "arg") if ok then return true, ok else return ok, err end end function command:breakfunc(cmd) local func, line = cmd:match("^(.*)%s+(%S+)%s*$") if line then if tonumber(line) then line = tonumber(line) elseif calllines[line] then line = calllines[line] else func = cmd; line = nil end else func = cmd end local ok, f = self:do_in_context(ls("return "..func)) if not ok then return self:error(f) end if type(f) == "function" then local info = getinfo(f, "SL") if info.what == "C" then line = line or 'cr' if type(line) ~= "string" then return self:error"LINE for CFunction must be 'call', 'return' or 'both'" end if line:match'c' then setcallbreak(f) end if line:match'r' then setretbreak(f) end return else if not line then line = next(info.activelines) if not line then return self:error "No active lines in that function" end for l in next, info.activelines, line do if l < line then line = l end end elseif type(line) == "number" then if line < info.linedefined or line > info.lastlinedefined then if self.interactive then print "Warning: the line is not within the function" end elseif not info.activelines[line] then return self:error "not a valid line inside the function" end else return self:error "LINE for a Lua function must be a number" end f = info.source end elseif type(f) == "string" then line = line or 1 if type(line) ~= "number" then return self:error "LINE must be a number" end else return self:error "EXPR must be function or string" end -- At this point, either we've handled it (error or cfunction) or -- f is the source and line is the line number setbreakpoint(f, line) return end end splain.delete = [=[- Delete the current breakpoint]=] function command:delete() local source, line = self.here.source, self.here.currentline if not source or not line then return self:error"The current context has no associated source file" else local old = clearbreakpoint(source, line) if not old then return self:error"No breakpoint was set" end end end splain.clear = [=[[CLASS...] - clear all breakpoints CLASS may be any combination of "line", "call", "ret" or "all". If it's not specified, it defaults to "line" ]=] function command:clear(arg) local o, e for opt in arg:gmatch"(%S)%S*" do local a if opt == "l" or opt == "a" then clearbreakpoint(); a = true end if opt == "c" or opt == "a" then clearbreakcall(); a = true end if opt == "r" or opt == "a" then clearbreakret(); a = true end o = o or a e = e or not a end if e then return self:error"Unrecognized option" end if not o then clearbreakpoint() end end splain.blist = [[- list all breakpoints]] function command:blist() if breaklines then local list = {} for lno, sources in pairs(breaklines) do for source in pairs(sources) do list[#list+1] = ("%s:%d"):format(source, lno) end end table.sort(list) for _, e in ipairs(list) do self:output(e) end end local funcs = {} if breakcalls then for func in pairs(breakcalls) do funcs[func] = "call " end end if breakrets then for func in pairs(breakrets) do funcs[func] = (funcs[func] or "").."ret " end end for func, which in pairs(funcs) do self:output(func, which) end end -- Command line support local function debugf(f, ...) local err, ok = "debugf expects a filename or a function" if type(f) == "string" then f, err = loadfile(f) end if f then sethook(function() if f == getinfo(2, "f").func then sethook(ldb, "l") breaknext = true end end, "c") local nargs, args = select("#", ...), {...} local function g() return f(unpack(args, 1, nargs)) end local function callit() return xpcall(g, ldb) end ok, err = callit() breaknext = nil breaknextline = nil sethook() end return ok, err end breakignores[debugf] = function() return "ldb_dohook", "continue" end -- ldb.break redefines the continue command to allow an extra -- argument splain.continue = [=[[LINE]- continue execution until line LINE If LINE is not specified, execution will simply continue. If LINE is specified, it must be a valid linenumber in the current function. Note that LINE is associated with the current call frame, so that if the function calls itself recursively, the inner calls will not be interrupted. This is not the same as setting a breakpoint at the specified line, which would trigger at any calling level. ]=] alias.continue = 'c' function command:continue(cmd) local line = tonumber(cmd) if line then if getinfo(self.here.func, "L").activelines[line] then breaklevel = self.here.level - 1 breaknext = true breaknextline = line else return self:error(cmd .. " is not a valid line number in this context") end elseif cmd:match"%S" then return self:error("numeric argument expected") end return true end splain.next = [[- step to the next line]] function command:next() breaknext = true breaklevel = 0 return true end splain.step = [[- step to the next line, stepping into functions]] alias.step = 's' function command:step() breaknext = true return true end splain.finish = [[- step to the end of this function]] function command:finish() breaklevel = 1 return true end return debugf infon/libs/botmenu.lua0000644000076400001440000000145110552756356015064 0ustar dividuumusersdofile("menu") menu "Menu" .sub "Bot Functions" .add("Print Information", info) .add("Restart", restart) .add("Creature Tables", function () for id, creature in pairs(creatures) do print(creature) p(creature) end end) .add("Suicide", function () for id, creature in pairs(creatures) do suicide(id) end end) .super .sep .add("Error", function () error("Example error") end) .add("About", function () print("Example menu!") end) infon/libs/pp.lua0000644000076400001440000000502110603200763014006 0ustar dividuumusersfunction table.show(t, name, indent) local cart -- a container local autoref -- for self references --[[ counts the number of elements in a table local function tablecount(t) local n = 0 for _, _ in pairs(t) do n = n+1 end return n end ]] -- (RiciLake) returns true if the table is empty local function isemptytable(t) return next(t) == nil end local function basicSerialize (o) local so = tostring(o) if type(o) == "function" then return so -- return string.format("%q", so) --[[ local info = debug.getinfo(o, "S") -- info.name is nil because o is not a calling level if info.what == "C" then return string.format("%q", so .. ", C function") else -- the information is defined through lines return string.format("%q", so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) end ]]-- elseif type(o) == "number" then return so else return string.format("%q", so) end end local function addtocart (value, name, indent, saved, field) indent = indent or "" saved = saved or {} field = field or name cart = cart .. indent .. field if type(value) ~= "table" then cart = cart .. " = " .. basicSerialize(value) .. ";\n" else if saved[value] then cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n" autoref = autoref .. name .. " = " .. saved[value] .. ";\n" else saved[value] = name --if tablecount(value) == 0 then if isemptytable(value) then cart = cart .. " = {};\n" else cart = cart .. " = {\n" for k, v in pairs(value) do k = basicSerialize(k) local fname = string.format("%s[%s]", name, k) field = string.format("[%s]", k) -- three spaces between levels addtocart(v, fname, indent .. " ", saved, field) end cart = cart .. indent .. "};\n" end end end end name = name or "__unnamed__" if type(t) ~= "table" then return name .. " = " .. basicSerialize(t) end cart, autoref = "", "" addtocart(t, name, indent) return cart .. autoref end function pp(t) print(table.show(t)) end infon/libs/ldb.lua0000644000076400001440000011447610603240401014140 0ustar dividuumusers-- ldb - A Lua debugger -- $Id: ldb.lua,v 1.17 2007/04/18 21:24:24 jbloggs Exp $ -- -- Requires Lua 5.1 -- -- Written in a fit of boredom by Rici Lake. The author hereby -- releases the contents of this file into the public domain, -- disclaiming all rights and responsibilities. Do with it -- as you will. Caution: do not operate while under the influence -- of heavy machinery. -- local VERSION = ([[$Revision: 1.17 $]]):match":([^$]*)" local VERSION_DATE = ([[$Date: 2007/04/18 21:24:24 $]]):match":([^$]*)" local function Memoize(func) return setmetatable({}, {__index = function(t, k) local v = func(k); t[k] = v; return v end}) end local function words(s) local rv = {} for w in s:gmatch"%S+" do rv[w] = w end return rv end -- PLUGIN datastructures ---------------------------------------------------- -- -- SPLAIN -- the help/command parser -- command[name] -> function(state, args) -- The command functions -- By convention, the functions are written in O-O style, -- so that `self` is the state object. local command = {} -- splain[name] -> string -- If the key is present in command[], then this is help for a -- command. The first line of the string *must* have the format: -- "args - summary". The `- ` is mandatory, but `args` and the -- space which follows are optional. If an argument is optional, -- it should be surrounded by []. By convention, argument names -- are written in CAPITAL LETTERS. -- -- If the key is not present in command[], then this is a topic, -- and the first line of the string *must* have the format: -- "X summary" where `X` is either a `*` or a `-`. If it is -- a `*` then this is an "important" topic and the help system -- will print it first in the topics summary. -- -- If there is a long description, it should be separated from -- the summary line by a blank line, and be indented two spaces. -- Please keep lines to 78 characters including the indent. local splain = {} -- alias[string] -> string -- Commands can have at most one alias, and aliases should either -- be a single non-alphabetic character or a short alphabetic -- string (one or two characters). Topics cannot have aliases. -- If a non-alphabetic alias is more than one character long, -- it will not be recognized unless followed by a space. local alias = {} -- HANDLER hooks -- prehandler[string] -> function(arg2) -- handler[string] -> function(state, arg1, arg2) -- ldb() is always entered with two arguments, both of which are -- optional. When entered as an error function, the first argument -- will be the error object (usually a simple string message) and -- the second argument will usually be nil, but may be a hint from -- error() about which callframe is the user-visible error. When -- entered as a hook function, the first argument will be one of -- Lua's hook strings (line, call, count, return, 'tail return'). -- When called directly, the first argument could be anything, but -- all strings starting ldb_ are reserved. The only handler defined -- by the core system is ldb_cmd, which is used by the C glue. -- -- The prehandler is primarily used by the breakpoint system, in order -- to continue execution as fast as possible. It is called immediately -- when ldb is entered, and should either return nothing/nil/false as -- fast as possible, or return a new arg1, arg2 pair. In the first case, -- ldb is not entered at all; this is used to filter unwanted hook calls. -- It's probably not of much use otherwise. -- -- The handler is called once the debugger state has been set up, but -- before anything else has happened. It should either return: -- nil or nothing --> ldb will enter interactive mode -- true, value --> ldb will return the specified value. -- Note the different prototypes. prehandler was deliberately stripped -- to the minimum possible calling interface. -- local prehandler, handler = {}, {} -- STARTUP ------------------------------------------------------------------ local ldb -- Grab debug and other globals now, in case they get modified local _G = getfenv() local debug = debug local getfenv, getinfo = debug.getfenv, debug.getinfo local getupvalue, setupvalue = debug.getupvalue, debug.setupvalue local getlocal, setlocal = debug.getlocal, debug.setlocal local getmetatable, setmetatable = getmetatable, setmetatable local pcall = pcall local concat = table.concat local function prefer(pkgname) local ok, pkg = pcall(require, pkgname) return ok and pkg end -- valid keys in a stackframe (debug.getinfo + a few of our own) local infokeys = words[[ source short_src linedefined lastlinedefined what currentline name namewhat nups func var level ]] local infofuncs = {} function infofuncs.fenv(info) if info.func then return getfenv(info.func) else return {} end end -- Create an id line from an info table. This is similar -- but not identical to debug.traceback, but it can be customized -- TODO: Move this into the config system. local id do local function lineno(l, pfx) if l and l > 0 then return pfx..tostring(l) else return "" end end -- The default id doesn't use self function id(info) if info.what == "tail" then return "[tailcall]" end local segone if info.what == "main" then if info.source:sub(1,1) == "@" then segone = "file" elseif info.source:sub(1,1) == "=" then segone = info.source:sub(2) else segone = "??" end elseif info.namewhat and info.namewhat ~= "" then segone = info.namewhat else segone = "function" end local segs = { ("%-8s"):format(segone) } segs[#segs+1] = info.name local source = info.source and info.source:sub(1,1) == "@" and info.source:sub(2) or info.short_src segs[#segs+1] = source and ("<%s%s>"):format(source, lineno(info.linedefined, ":")) segs[#segs+1] = lineno(info.currentline, "at line ") return concat(segs, " ") end infofuncs.id = id end -- CONFIGURATION ------------------------------------------------------------ -- This is the pseudo-environment table which will be used -- by all instances of the debugger. It's not actually -- the debugger's environment table; rather, it's bound -- into the metamethods for debugger contexts, but it's -- pretty similar. A future version may allow multiple -- debuggers with different environments. local env = prefer"ldb-config" or {} if type(env) ~= "table" then print"ldb-config.lua must return a table of configuration settings" print"Ignoring ldb-config and using defaults" env = {} end -- Make it look like the config was loaded even if it wasn't. package.loaded["ldb-config"] = env -- Add the configuration hooks env.splain = splain env.alias = alias env.command = command env.prehandler = prehandler env.handler = handler -- Set up the default configuration env.PROMPT = env.PROMPT or "(ldb) " env.PROMPT2 = env.PROMPT2 or " >>> " env.input = env.input or function(prompt) io.write(prompt); return io.read"*l" end env.output = env.output or print env.error = env.error or env.output do local function donothing() end local function selfidentity(self, ...) return ... end env.enterframe = env.enterframe or selfidentity env.leave = env.leave or selfidentity env.edit = env.edit or donothing env.load_plugins = env.load_plugins or donothing end env.g = _G env.id = env.id or id setmetatable(env, {__index = _G}) -- This function finds the frame which invoked the debugger. -- It starts by finding the sentinel frame (placed on the -- callstack by the debugger) and then works backwards, -- skipping over the debugger frame itself and also -- error or assert, if present. It also tries to identify -- and skip the trampoline pushed onto the stack by lua.c. -- That would be easier if lua.c used a constant closure which -- we knew about. -- --[[ local function getoffset(sentinel) for base = 3, 1e6 do if getinfo(base, "f").func == sentinel then base = base + 2 local _, val = getlocal(base, 2) if val == debug and not getlocal(base, 3) then base = base + 1 end local errfunc = getinfo(base, "f").func if errfunc == error or errfunc == assert then base = base + 1 end return base - 2 end end end ]] local function getoffset(sentinel) for base = 3, 1e6 do if getinfo(base, "f").func == sentinel then return base end end end local function geterroffset(sentinel) local base = getoffset(sentinel) if base then local rv = 0 local _, val = getlocal(base+1, 2) if val == debug and not getlocal(base+1, 3) then rv = rv + 1 end local errfunc = getinfo(base+1+rv, "f").func if errfunc == error or errfunc == assert then rv = rv + 1 end return base - 1, rv end end -- Create the debugger State, which encapsulates everything needed -- during a single invocation of the debugger. This was called -- Context in earlier versions, but that was too confusing. -- -- The State does not persist between calls, so it can't be used -- for things which have to persist (breakpoints, for example). -- Such things could probably go into env; we'll see when I -- actually write the breakpoint handling stuff. -- FIXME There's only one local being protected by this whole -- do block, now that I've hiked statemeta out of it. But -- reindenting will create too big a diff for now. Also, -- change statemeta to statemethods. local statemeta = {}; statemeta.__index = statemeta local State do -- Methods on the state object -- The double indirection here is to allow run-time customization -- of the functions. Maybe it's dumb... -- -- CUSTOMIZABLE CONFIGURATION FUNCTIONS -- We reflect the configurable functions into the state object, -- throwing away self (in most cases) to make the state object's -- interface consistent. -- -- input(prompt) should display prompt to the user and return one -- line of input. function statemeta:input(prompt) return self.var.input(prompt) end -- output should display its arguments in a fashion similar to -- print(). There is no guarantee about the arguments; they may -- be simple values or multi-line help-text. function statemeta:output(...) return self.var.output(...) end -- error should display its argument in a fashion similar to print. -- Indeed, it's possible to use the same function for output and -- error; however, it may be desirable to distinguish style in -- some way. function statemeta:error(...) self.var.error(...) if not self.ignore_error then return false end end -- edit is called to implement the edit command. -- IMPORTANT: edit must return true if it handled the edit; otherwise, -- false and an error message. If nothing or only false is returned, -- ldb will produce a "no editor configured" message. function statemeta:edit(name, line) return self.var.edit(name, line) end -- enterframe is called whenever the debugger enters a different call frame function statemeta:enterframe() return self.var.enterframe(self) end -- leave is called with a value when control is about to return to the program -- the value should be returned as an argument function statemeta:leave(val) return self.var.leave(self, val) end -- id is called to produce an id line for a stackframe. function statemeta:id(info) return self.var.id(info) end -- END OF CUSTOMIZABLE INTERFACE -- Get the offset using getoffset and the cached erroffset function statemeta:getoffset() return getoffset(self.sentinel) + self.erroffset - 1 end -- This is used to read expressions, chunks, etc. from commands function statemeta:getchunk(cmd) local chunk, err = loadstring(cmd, "arg") if chunk then return true, chunk elseif self.interactive and err:match"" then local more = self:input(self.var.PROMPT2) if more then return self:getchunk(cmd.."\n"..more) end end return false, err end function statemeta:do_in_context(flag, chunk) if flag then setfenv(chunk, self.context.var or {}) return pcall(chunk) else return false, chunk end end -- Announce where we are in the callframe function statemeta:announce() self:enterframe() self:output( ("*%2d %s"):format(self.here.level, self.here.id) ) end -- The proxy stack contains information about the current stack -- (all of it :) ) It probably should be constructed more lazily, -- and with more caching. Otherwise, debugging deep stack frames -- will be painful. -- The stack is indexed by 'level'; currently, that's the same as -- the Lua level, but it might not hurt to remove empty tailcall -- frames from the level count. Each level contains the full -- information returned by debug.getinfo (except available -- breakpoints), plus some computed information. -- We export the stack as a (memoised) array of proxy info -- objects, which are defined here. The proxy object can be -- indexed by the fixed info fields (the complete list of -- available fields is in infokeys at the top of this file); any -- other key is resolved in the context of the callframe. (If an -- infokey collides with a variable, use .env.varname to get at -- the actual variable name.) The proxy objects understand simple -- addition and subtraction as though they were C pointers. It -- seemed convenient. -- Uses an explicit argument name to avoid confusion with the -- meta methods below. function statemeta.proxystack(state) local stack -- defined below local meta = {} local function StackFrame() return setmetatable({}, meta) end function meta:__add(offset) if type(offset) == "number" then return stack[stack[self] + offset] end end function meta:__sub(offset) if type(offset) == "number" then return stack[stack[self] - offset] end end function meta:__index(key) local info = state[stack[self]] if infokeys[key] then return info[key] elseif infofuncs[key] then return infofuncs[key](info) else return info.var[key] end end function meta:__newindex(key, val) local info = state[stack[self]] if infokeys[key] or infofuncs[key] then error(key.." cannot be modified") else info.var[key] = val end end stack = Memoize(function(level) if type(level) == "number" and state[level] then local rv = StackFrame() stack[rv] = level return rv end end) return stack end -- This is the "debugger context", which can be used as an -- alternative to the local context. A few debugger internals -- are exported. -- -- For historical reasons, the context is actually `state.var`, -- which matches the current context being `state.here.var`. It -- might have been better to have called it `context` -- -- Any other key is resolved in the `env` table and then in the -- globals table, but setting is always done in the `env` table. -- -- To expose new internals, you must define both a getter and a -- setter; readonly internals should have an empty setter (although -- I suppose there's nothing wrong with throwing an error). This -- can also be used to "lock" settings in the `env` table as is -- done with `g` (to avoid typos, mostly). -- function statemeta:makecontext(env) local getter, setter = {}, {} function getter.here() return self.here end function getter.stack() return self.stack end function getter.g() return env.g end function setter.here(new) local info = self.stack[new] if type(info) == "number" then self.here = new elseif info then self.here = info end end function setter.stack() end function setter.g() end local meta = {} function meta:__index(key) local g = getter[key] if g then return g() else return env[key] end end function meta:__newindex(key, val) local s = setter[key] if s then s(val) else env[key] = val end end return setmetatable({}, meta) end -- This function builds the local context from information -- hopefully cached by State. -- -- TODO Construct the context lazily local function makeinfovar(info, sentinel, erroffset) info.var = setmetatable({}, { __index = function(_, key) local name, val local index = info.visible[key] if index then if index < 0 then name, val = getupvalue(info.func, -index) else name, val = getlocal(getoffset(sentinel) + erroffset + info.level, index) end else local word, index = key:match"^(%l+)(%d+)$" if word == "upval" then name, val = getupvalue(info.func, tonumber(index)) elseif word == "local" then name, val = getlocal(getoffset(sentinel) + erroffset + info.level, tonumber(index)) end if not name then val = getfenv(info.func)[key] end end return val end, __newindex = function(_, key, val) local index = info.visible[key] if index then if index < 0 then setupvalue(info.func, -index, val) else setlocal(getoffset(sentinel) + erroffset + info.level, index, val) end else local word, index = key:match"^(%l+)(%d+)$" if word == "upval" then setupvalue(info.func, tonumber(index), val) elseif word == "local" then setlocal(getoffset(sentinel) + erroffset + info.level, tonumber(index), val) else getfenv(info.func)[key] = val end end end }) end function State(sentinel, env) local base, erroffset = geterroffset(sentinel) --[[ DEBUG print ("State", base, erroffset) --]] local self if base then base = base + erroffset self = setmetatable({sentinel = sentinel, erroffset = erroffset}, statemeta) self.stack = self:proxystack() self.var = self:makecontext(env) for level = 1, 1e6 do local info = getinfo(base + level, "nSluf") if not info then break end self[level] = info info.level = level local func = info.func if func then local visible = {} if info.what ~= "C" then for index = 1, 1000 do local name = getupvalue(func, index) if name == nil then break end visible[name] = -index end for index = 1, 1000 do local name = getlocal(base + level, index) if name == nil then break end if name:match"^[%a_]" then visible[name] = index end end end info.visible = visible makeinfovar(info, sentinel, erroffset) end -- if func (not a tailcall) end -- for level self.here = self.stack[1] end -- if base return self end end -- SPLAIN -- Command parser and help system --------------------------------- -- Any unambiguous prefix of a command is allowed. Aliases must be -- typed exactly, but may be otherwise ambiguous local resolve_command = Memoize(function (cmd) if command[cmd] then return cmd end for real, short in pairs(alias) do if cmd == short then return real end end local possible for real in pairs(command) do if cmd == real:sub(1, #cmd) then if possible then return "Ambiguous" end possible = real end end return possible or "Unknown" end) function statemeta:do_a_command(input) local bang, dot, args = input:match"%s*(!?)%s*(%.?)%s*(.*)" if args ~= "" then local cmd = args:match"^%W" if cmd then if args:sub(2,2) == cmd then dot = cmd args = args:sub(3) else args = args:sub(2) end else cmd, args = args:match"(%S+)%s*(.*)" if args:sub(1,1) == '=' then args = cmd .. " " .. args:match".%s*(.*)" cmd = "set" end end self.context = dot == "" and self.here or self self.ignore_error = bang == "!" return command[resolve_command[cmd]](self, args) end end -- These save a couple of tests. function command:Ambiguous() return self:error "Ambiguous command" end function command:Unknown() return self:error "Huh?" end -- CORE COMMANDS ------------------------------------------------------------ splain.backtrace = "- print a backtrace" alias.backtrace = "bt" function command:backtrace() local l = self.here.level for i, info in ipairs(self) do self:output((i == l and "*%2d %s" or "%3d %s"):format(i, self:id(info))) end end splain.up = "[N] - move up N levels, default 1" alias.up = 'u' function command:up(i) local here = self.here + (tonumber(i) or 1) if here then self.here = here end end splain.down = "[N] - move down N levels, default 1" alias.down = 'd' function command:down(i) local here = self.here - (tonumber(i) or 1) if here then self.here = here end end splain.edit = [[- open the file of the current context in an external editor For this command to work, `edit` must be defined in ldb-config. See the `ldb-config.example` file in the distribution for examples and more information. ]] function command:edit(filename) local lineno if filename == "" then filename = self.here.source:match"^@(.*)" lineno = self.here.currentline or 1 end if filename then if not self:edit(filename, lineno) then return self:error "No editor configured" end else return self:error "No current file" end end local function safestring(s) s = s:gsub("[%z\1-\31]", function(c) return ("\\%2x"):format(c:byte()) end) if #s > 40 then s = s:sub(1, 37).."..." end return "'"..s.."'" end local function safeshow(x) return (type(x) == "string" and safestring or tostring)(x) end splain.show = [[- show all locals and upvalues at the current level Locals and upvalues which are shadowed are marked with an exclamation point (!). ]] function command:show(cmd) local maxclocals = tonumber(cmd) or 40 local currentlevel = self.here.level local info = self[currentlevel] if info then local level = self:getoffset() + currentlevel local func = info.func if func == nil then self:output"[tailcall]" elseif info.what == "C" then for index = 1, 1000 do local name, val = getupvalue(func, index) if name == nil then break end if index == 1 then self:output"Upvalues:" end self:output( ("%4d: %s"):format(index, safeshow(val)) ) end for index = 1, maxclocals do local name, val = getlocal(level, index) if name == nil then break end if index == 1 then self:output"Locals:" end self:output ( ("%4d: %s"):format(index, safeshow(val)) ) end else local visible = info.visible local upvalue = {} for index = 1, 1000 do local name, val = getupvalue(func, index) if name == nil then break end local vis = index == -visible[name] and " " or "!" upvalue[#upvalue+1] = ("%s %-12s: %s"):format(vis, name, safeshow(val)) end if upvalue[1] then self:output"Upvalues:" table.sort(upvalue) for _, l in ipairs(upvalue) do self:output(l) end end for index = 1, 1000 do local name, val = getlocal(level, index) if name == nil then break end if index == 1 then self:output"Locals:" end local vis = index == visible[name] and " " or "!" self:output( ("%s%3d %-12s: %s"):format(vis, index, name, safeshow(val)) ) end end end end splain.set = [[VAR EXPR - set debugger variable VAR to EXPR EXPR is evaluated in the indicated context (that is, the debugger context if invoked as `.set` and otherwise the current context. The named VAR (which currently must be a simple name) is set in the debugger context. You cannot use this command to set global variables. Normally you don't need to use the `set` command, because ldb interprets any command line whose second token is `=` as a set command. For example, the following are equivalent: foo = getmetamethod(local1) set foo getmetamethod(local1) and the following three commands are equivalent: .here = here+1 .set here here+1 ,,here=here + 1 Note that the `=` must be preceded by a space to be recognized as a `set` command. ]] function command:set(cmd) local var, chunk = cmd:match"(%S+)%s*(.*)" if not var:match"^[%a_][%w_]*$" then return self:error "Only simple variable names can be set" elseif chunk == "" then return self:error "No value specified for set" else local ok, val = self:do_in_context(self:getchunk("return "..chunk)) if ok then self.var[var] = val else return self:error(val) end end end splain.print = [[EXPR - evaluate and print EXPR If invoked as `print` or `=`, the EXPR is evaluated in the current context. If invoked as `.print` or `==`, the EXPR is evaluated in the debugger context. See `help context` for more information. ]] alias.print = '=' function command:print(cmd) self:output(select(2, self:do_in_context(self:getchunk("return "..cmd)))) end splain.exec = [[CHUNK - evaluate CHUNK If invoked as `exec` or `,`, the CHUNK is evaluated in the current context. If invoked as `.exec` or `..` the CHUNK is evaluated in the debugger context. See `help context` for more information. ]] alias.exec = "," function command:exec(cmd) local ok, err = self:do_in_context(self:getchunk(cmd)) if ok then if self.interactive then self:output"Ok!" end else return self:error(err) end end splain.quit = [=[[EXPR] - return from ldb, with an optional value Causes the current invocation of ldb to return. If an EXPR is provided, it will be returned from the call to ldb (which is only useful if ldb is invoked directly). Currently, only a single value may be returned. If the evaluation of EXPR throws an error and the command was not being executed interactively, ldb will return ]=] function command:quit(cmd) if cmd:match"%S" then local ok, val = self:do_in_context(self:getchunk("return "..cmd)) if ok then return true, val elseif not self.interactive then return true, false, val else return self:error(val) end end return true end splain["if"] = [=[EXPR - return from ldb if EXPR is a true value Causes the current invocation of ldb to return with value EXPR if EXPR evaluates to a value other than `false` or `nil`. If an error is thrown, the invocation does not return. ]=] command["if"] = function(self, cmd) local ok, val = self:do_in_context(self:getchunk("return "..cmd)) if ok and val then return ok, val end end splain.unless = [=[EXPR - return from ldb if EXPR is `false` or `nil` Causes the current invocation of ldb to return (with no return value) if EXPR evalutes to `false` or `nil`, or throws an error. ]=] function command:unless(cmd) local ok, val = self:do_in_context(self:getchunk("return "..cmd)) return not ok or not val end splain.continue = [[- return from ldb]] alias.continue = 'c' function command:continue() return true end -- Topics splain.intro = [[* quick introduction to ldb ldb is a very basic interactive debugger. Currently it only allows stack inspection, although breakpoints and watches will be supported in the future. The usual way of setting ldb up is: ldb = require"ldb" debug.traceback = ldb This will trigger ldb when any error occurs. You can also call ldb directly in your code, as a sort of manual breakpoint. There are only a few commands (so far) and all of them are documented in the help system. Take a few minutes to review them. The most common ones are: bt print a backtrace = print the value of an expression in the current context == print the value of an expression in the debug context , execute a statement in the current context ,, execute a statement in the debug context show show all of the variables in the current context Read `help context` for an explanation of contexts. It's really important. ]] splain.context = [[- how contexts work in ldb A context is essentially a variable scope; the combination of (visible) locals, upvalues and "globals" (i.e. the function environment.) ldb always has two contexts: the current context and the debugger context. When ldb is called, it sets the current context to the context of the caller, or the point at which an error was thrown, if ldb is being used as an error function (such as debug.traceback). You can move up and down in the call stack with the `up` and `down` commands; as you move, the current context will shift to reflect where you are. ldb also has its own context, which is persistent between invocations of ldb. You can set values in this context which will be available on subsequent invocations of the debugger. The ldb context also contains ldb configuration variables, such as `PROMPT` and `output`, and `g`, which refers to the global environment in which `ldb` was originally loaded. There are also a few 'magic' variables. ldb commands which take an expression or a chunk as an argument evaluate the expression or chunk in the current context by default. If you prefix the command with `.`, then the debugger context will be used instead. For convenience, `.,` can be typed as `,,` and `.=` can be typed as `==`. For more details, see `help magic`, `help here`, `help clocal` and `help tailcall`. ]] splain.clocal = [[- debugging inside C frames In C frames, there are no named variables -- ldb doesn't integrate with gdb, unfortunately -- but the stack and upvalues are still available as numbered variables in the form `local#` and `upval#` where # is a decimal number, possibly with leading zeros. For example, `local1` is stack slot 1 in the C frame, and `upval1` is the first upvalue (if there is one). You can use these as though they were ordinary variables. You can also use this format to get at shadowed locals and in a Lua frame. Note that the variable is first looked up in the context, so you if you have a local variable called `local1`, you would need to use `local01` to get at the first stack slot. Another issue you may run into with C frames is that ldb uses the CFunction's environment, not the thread environment, as the environment when the current context is a C frame. Most C functions operate on `LUA_GLOBALSINDEX` rather than `LUA_ENVIRONINDEX`, so the results might be surprising. ]] splain.tailcall = [[- gotchas with tailcall frames The Lua debug interface includes the concept of 'deleted' tailcall stack frames; i.e. the frames which have been recycled by a tail call of the form: return other_func() These deleted frames have no information -- they really have been deleted -- but they show up in backtraces anyway. At some point this might irritate me enough to remove them from the backtraces, but for now they are there. Deleted frames have any empty context. There are no variables, not even standard library functions. If you get an error that some global which obviously exists is `nil`, you should make sure that the current frame is not a tailcall frame. (ldb doesn't insert "the" globals table, because it's not at all clear what that would mean -- had the frame not been deleted, the function would have had an environment table which might well not be the "global" environment.) ]] splain.magic = [[- 'magic' fields in the ldb context ldb maintains its own environment, which you can use as a scratchpad; assignments to the ldb environment persist between calls to ldb, but do not affect the global environment. For convenience, the ldb environment has an __index metamethod which provides access to the initial global environment, but the __newindex metamethod does not direct modification of the global environment. The global environment is available as the variable `g` in the ldb environment, so you can set a global variable like this: (ldb) ,, g.some_global = 42 Here is a list of all 'magic' variables in the ldb context: here information about the current stack frame. See `help here` for details. g (RO) The value of _G when the debugger was entered stack (RO) An array of stack frame info objects, as above. stack[here.level] == here PROMPT The debugger comand prompt PROMPT2 The debugger continuation prompt ]] splain.here = [[- the 'here' field in the ldb context The variable `here` in the ldb context is a reference to the 'current' stack frame. When ldb is invoked the current stackframe is the place where ldb was invoked (either directly or via an error function); you can view the stack with `backtrace` (usually written `bt`, in which the current stackframe is marked with a '*', and you can move up and down in the stack with the `up` and `down` commands. `here` contains all of the fields returned by `debug.getinfo` except for the table of valid breakpoints. It also contains some variables added by ldb itself. See `help getinfo` for a list. `here` is special; it can be added to or subtracted from to get at other levels. So instead of writing (ldb) == stack[here.level - 1].foo (to see the value of 'foo' in the calling frame), you can simply type: (ldb) == (here-1).foo You can assign `here` to any valid stack frame, or to the number of a valid stack frame, allowing you to navigate in the stack. For example, (ldb) ,, here = here + 1 is exactly the same as the `up` command, and: (ldb) ,, here = 7 takes you to stackframe 7 directly. ]] splain.getinfo = [[- fields in the getinfo table The getinfo fields are described in the Lua reference manual, although ldb adds a few of its own. Here is a complete list: currentline The line currently being executed by the function fenv The function's environment (that is, getfenv(func) ) func The function itself id The id line ldb uses to identify the stackframe linedefined The line in the source where the function is defined lastlinedefined The line where the definition of the function ends level Level of the frame in the call stack name A possible name for the function, if Lua can figure it out. This will be `nil` in a stackframe discarded by a tailcall; otherwise it will be the empty string if Lua can't find a name. namewhat "global", "local", "method", "field", "upvalue" or "" nups The number of upvalues of the function short_src A shorter version of `source` source `@` followed by the filename, or "=stdin", or whatever was provided as the last argument to loadfile var The stackframe context; locals, upvalues and the fenv are reflected into this table. You can also use local# and upval# (where # is any integer) to get at locals and upvalues by number. Assignment is allowed (and will be to the fenv if there is no local or upvalue with the given name.) what "Lua", "C", "main" or "tail" ]] splain.copyright = [[* ldb is public domain ldb was originally written by Rici Lake, and released into the public domain. Do with it as you see fit. The author disclaims all rights and responsibilities. ]] splain.version = [[* this is version]]..VERSION.."-"..VERSION_DATE splain.help = "[CMD] - show help for CMD or all commands" alias.help = "?" do local function sorted(filter) local t = {} for k, v in pairs(splain) do if filter(k, v) then t[#t+1] = k end end table.sort(t) local i = 0 return function() i = i + 1; if t[i] then return t[i], splain[t[i]] end end end local function align(col1, col2) local intro = "" if #col1 > 15 then intro, col1 = col1.."\n", intro end return ("%s%-16s %s"):format(intro, col1, col2) end function command:help(cmd) cmd = cmd:gsub("%s", "") if cmd == "topics" then self:output"topics - help for details" self:output"" for key, descr in sorted( function(key, descr) return not command[key] and descr:sub(1,1) == "*" end ) do self:output(align(key, descr:match"^%*[ \t]*([^\n]*)")) end self:output"" for key, descr in sorted( function(key, descr) return not command[key] and descr:sub(1,1) ~= "*" end ) do self:output(align(key, descr:match"^.[ \t]*([^\n]*)")) end elseif cmd == "" then for cmd, descr in sorted(function(key) return command[key] end) do local arg, desc = descr:match"^([^-\n]-) ?%- ([^\n]*)" self:output(align( ("%-3s%s"):format(alias[cmd] or "", cmd.." "..arg), desc) ) end self:output"\nuse `help topics` for help on particular issues" elseif splain[cmd] then self:output(cmd.." "..splain[cmd]) else local real = resolve_command[cmd] self:output(cmd.." ("..real..") "..(splain[real] or "")) end end end -- Do a single command and return function handler:ldb_cmd(token, cmd) self:do_a_command(cmd) return true end function env.ldb (arg1, arg2) local check = prehandler[arg1] if check then local newarg1, newarg2 = check(arg2) if not newarg1 then return end arg1 = newarg1; arg2 = newarg2 end local function sentinel(arg1, arg2) local self = State(sentinel, env) assert(self, "Couldn't find myself in the backtrace!") self.var.arg1 = arg1 self.var.arg2 = arg2 local f = handler[arg1] if f then local flag, val = f(self, arg1, arg2) if flag then return self:leave(val) end else if type(arg2) == "string" then local flag, val = self:do_a_command(arg2) if flag then return self:leave(val) end elseif type(arg2) == "table" then for _, cmd in ipairs(arg2) do local flag, val = self:do_a_command(cmd) if flag ~= nil then return self:leave(val) end end end if arg1 then self:output(arg1) end end self.interactive = true local here while true do if here ~= self.here then self:announce() here = self.here end local flag, val = self:do_a_command(self:input(env.PROMPT) or "continue") if flag then return self:leave(val) end end end -- the tailcall will put a pseudoframe on the stack, but it -- should still be skipped over by getinfo return sentinel(arg1, arg2) end -- In case we were started in some other way than "require'ldb'": package.loaded.ldb = env.ldb env.load_plugins() return env.ldb infon/libs/debugger.lua0000644000076400001440000000703010603200763015155 0ustar dividuumusersneeds_api("oo") function debug_trace_hook(creature, source, line) local lsource = creature.debug_last_source local lline = creature.debug_last_line creature.debug_last_source = source creature.debug_last_line = line if lsource == source and lline == line then return false end if creature.break_points[line] then print("breakpoint hit creature " .. creature.id .. " at " .. _TRACEBACK(nil, 3)) creature.stopped = true return true -- yield please end if creature.stop_next then print("stopped creature " .. creature.id .. " at " .. _TRACEBACK(nil, 3)) creature.stopped = true return true -- yield please else return false end end function debug_hook(creature) if creature.hooked and not creature.installed_hook then linehook(creature.thread, function (source, line) return debug_trace_hook(creature, source, line) end) creature.installed_hook = true elseif not creature.hooked and creature.installed_hook then linehook(creature.thread) creature.installed_hook = nil end return not creature.stopped end function debug_stop(creature) print("stopping creature " .. creature.id) creature.stopped = true end function debug_next(creature) -- print("tracing creature " .. creature.id) creature.stop_next = true creature.stopped = false end function debug_continue(creature) -- print("restarting creature" .. creature.id) creature.stop_next = false creature.stopped = false end function debug_break(creature, line) if not line then print("breakpoints for " .. creature.id .. ":") for line, _ in pairs(creature.break_points) do print(string.format("%4", line)) end else if creature.break_points[tonumber(line)] then creature.break_points[tonumber(line)] = nil print("removed breakpoint @" .. line) else creature.break_points[tonumber(line)] = true print("added breakpoint @" .. line) end end end function debug_info(creature) print("info for " .. creature) print(_TRACEBACK(creature.thread)) end function debug_init(arg) local creature = creatures[tonumber(arg)] if not creature then print("creature " .. arg .. " does not exist") return end debug_cid = creature.id print("debugging creature " .. creature.id) creature.hooked = true creature.stop_next = false creature.break_points = {} creature.stopped = false end function onCommand(cmd) local cmd, arg = cmd:match("^d(.?)(.*)$") if not cmd then print("huh?") elseif cmd == "" then print("debugger usage") print("-----------------------") print("d[command][arg]") elseif cmd == "d" then debug_init(arg) elseif not debug_cid then print("no debug creature set") elseif not creatures[debug_cid] then print("creature " .. debug_cid .. " no longer exists") debug_cid = nil elseif cmd == "s" then debug_stop(creatures[debug_cid]) elseif cmd == "n" then debug_next(creatures[debug_cid]) elseif cmd == "c" then debug_continue(creatures[debug_cid]) elseif cmd == "b" then debug_break(creatures[debug_cid], arg) elseif cmd == "i" then debug_info(creatures[debug_cid]) else print("unknown debug command?") end end print("Debugger loaded. Be sure to enable command forwarding (type 'fwd')") infon/libs/ldb-config.lua0000644000076400001440000001463710603240401015401 0ustar dividuumusers-- At initialization, ldb.lua attempts to require "ldb-config", and if it -- works, it uses it for the initial configuration. You can use this to -- customize ldb's functions for input and output (for example to use -- lrcon); the prompts; and to configure an external editor. If it doesn't -- find an ldb-config module, it uses sensible defaults and the external -- editor command won't do anything. -- Anything in this file will be executed before ldb sets up anything, -- including its command table. In the future, there will be an option -- for adding custom commands to ldb using this or a similar mechanism. -- Until I get around to writing documentation, you can use this -- file as an example :) ----- CONFIGURATION (see below for various uses of these locals) -- -- -- These will be used in the configuration of lrcon. -- local REMOTE = false -- local PORT = 7022 -- -- This is *my* configuration; it will not work in general. It's -- only been tested on one system (xubuntu 6.10 with vim-full; -- I had to apt-get wmctrl for the raise command). The :Move -- command is defined in ldb.vim, included as well. -- local FN = ":Move %s" -- local FNLN = ":Move %s | :%d" -- local RAISE = "wmctrl -R ldbvim" -- local VIEW = 'gvim --servername ldbvim --remote-send %q' -- local EDIT = VIEW .. " && " .. RAISE -- local function FL(filename, lineno) -- if lineno then return FNLN:format(filename, lineno) -- else return FN:format(filename) -- end -- end -- This only works on xubuntu, and maybe not on xubuntu installs other than mine. -- But I left it in here, so you can gaze at the nuttiness of doing simple things -- like "start an application without giving it focus" -- In practice, the best bet is to just write a shell script which fires up -- gvim with the --servername option, and then fires up a shell running Lua, -- in that order. You'll still quite possibly get them overlaid if you don't -- specify the -geometry. -- This is all one line: -- local STARTVIM = [[gvim --serverlist | grep -q ^LDBVIM$ || ]] -- ..[[{ id=`xwininfo -id $WINDOWID -children | grep Parent]] -- ..[[ | sed 's/.*\(0x[0-9a-fA-F]\+\) .*/\1/'` ;]] -- ..[[gvim --servername ldbvim; wmctrl -i -a $id ; }]] -- -- -- If you need globals, this would be a good time to capture them as -- -- upvalues -- -- local osexec = os.execute -- -- PREINITIALIZATION -- -- If you're using lrcon, you'd probably want to initialize it here: -- -- local con = require"lrcon"("loopback", 7022) -- con:setbanner"Connected to ldb on port 7022\r\n" -- con:get() -- force a connection -- -- osexec(STARTVIM) -- -- RETURN THE CONFIGURATION return { -- The prompts used for commands and continuations, respectively: PROMPT = "(ldb) ", PROMPT2 = " >>> ", -- -- Functions used for input, output, and errors. These are the defaults: input = coroutine.yield, output = function (...) return print(...) end, error = function (...) return print(...) end, -- If you're using lrcon, -- -- you might want: -- -- input = function(prompt) -- con:write(prompt) -- return con:read() -- end, -- output = function(...) -- return con:print(...) -- end, -- error = function(...) -- return con:print(...) -- end, -- External editor interface. The edit function does what is necessary -- to fire up an external editor given a filename and (optional) line -- number. This function must return a true value if it works. If it -- returns , the error message will be shown; if it just -- returns nil or false, the default error message will be shown. -- ("No editor configured"). -- -- The default function returns nil. -- This is the one I use: -- edit = function(filename, lineno) return false, "external editor not available within infon" -- return osexec(EDIT:format(FL(filename, lineno))) end, -- This function is called whenever a new callframe is entered, -- which almost always means there is a new line number at least, -- and maybe filename. The following is what I use to keep the -- gvim window in synch with the debugger. enterframe = function(state) -- local filename = state.here.source:match"^@(.*)" -- if filename then -- osexec(VIEW:format(FL(filename, state.here.currentline or 1))) -- end end, -- This function is called at the end of the ldb.lua file, -- to load any plugins. The plugins can freely call -- require"ldb" and require"ldb-config" (even if the corresponding -- files were not loaded through the module system, or at all), -- which will give them access to ldb internals. load_plugins = function() -- Does not work in infon (yet) -- require"ldb-break" end } -- Here are some other possibilities for external editor configuration, -- mostly untested. If you've got more, put them on the CVSTrac. All of -- these use the following -- -- local FL(filename, lineno) -- if lineno then return FNLN:format(lineno, filename) -- else return FN:format(filename) -- end -- end -- function edit(filename, linenumber) -- return osexec(EDIT:format(FL(filename, lineno)) -- end -- vim -- --- -- To just fire up vim in a subprocess, which works fine, you could -- use: -- local FN = "%q" -- local FNLN = "+%d %q" -- local EDIT = "vim %s" -- -- Alternatively, if you've got a vim running in clientserver -- mode (available on Windows or X11 -- in the case of X11, although -- vim uses X11 messaging, I believe it will still work with a vim -- in a terminal shell): -- -- local FN = "%q" -- local FNLN = "+%d %q" -- local EDIT = 'vim --servername ldbvim --remote-tab-silent %s %q' -- -- Getting enterframe to work is trickier, which is why I went to the -- trouble of writing the stuff above. -- emacs, courtesy of my friends in #oasis. I haven't tried this. -- ----- -- You'll need to put (start-server) in your .emacs file, or you can -- get it to fallback to vim (as shown here) -- -- local EDIT = 'emacsclient --alternate-editor vim --no-wait %s' -- -- Use the same definitions of FN and FNLN as for vim. -- See: -- http://www.gnu.org/software/emacs/manual/html_node/Invoking-emacsclient.html -- Visual Studio, courtesy of Slade from #lua -- -- local FN = "%q" -- local FNLN = '/command "Edit.Goto %d" %q' -- local EDIT = '"c:\program files\microsoft visual studio 8\common7\ide\devenv" %s' -- -- -- Note: the above apparently does not work if you use .lua as a file -- -- extension; possibly, a VS bug of some form. infon/client.c0000644000076400001440000003145410545111721013366 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef WIN32 #include #include #include #else #include #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "packet.h" #include "global.h" #include "client.h" #include "misc.h" #include "renderer.h" #include "client_player.h" #include "client_world.h" #include "client_creature.h" #include "client_game.h" static int clientfd; static struct event rd_event; static struct event wr_event; static struct evbuffer *in_buf; static struct evbuffer *packet_buf; static struct evbuffer *out_buf; static int is_file_source; static int next_packet_countdown = 0; static int traffic = 0; static int compression; static z_stream strm; void client_destroy(const char *reason); void client_writeto(const void *data, size_t size); static void client_handshake_from_network(packet_t *packet) { uint8_t serverprotocol; if (!packet_read08(packet, &serverprotocol)) PROTOCOL_ERROR(); if (serverprotocol != PROTOCOL_VERSION) { die("%s has %s protocol version %d. I have %d.\n" "visit the infon homepage for more information.", is_file_source ? "demo" : "server", serverprotocol < PROTOCOL_VERSION ? "older" : "newer", serverprotocol, PROTOCOL_VERSION); } } static void client_round_info_from_network(packet_t *packet) { uint8_t delta; if (!packet_read08(packet, &delta)) PROTOCOL_ERROR(); next_packet_countdown += delta; } static void client_scroller_from_network(packet_t *packet) { char buf[256]; snprintf(buf, sizeof(buf), "%.*s", packet->len, packet->data); renderer_scroll_message(buf); } static void client_start_compression() { if (compression) PROTOCOL_ERROR(); if (getenv("UNCOMPRESSED_DEMO_COMPATIBILITY") && is_file_source) return; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = NULL; if (inflateInit(&strm) != Z_OK) die("cannot initialize decompression"); compression = 1; } static void client_handle_packet(packet_t *packet) { switch (packet->type) { case PACKET_PLAYER_UPDATE: client_player_from_network(packet); break; case PACKET_WORLD_UPDATE: client_world_from_network(packet); break; case PACKET_SCROLLER_MSG: client_scroller_from_network(packet); break; case PACKET_CREATURE_UPDATE: client_creature_from_network(packet); break; case PACKET_QUIT_MSG: if (!is_file_source) infomsg("Server wants us to disconnect:\n%.*s", packet->len, packet->data); client_destroy("done"); break; case PACKET_KOTH_UPDATE: client_player_king_from_network(packet); break; case PACKET_WORLD_INFO: client_world_info_from_network(packet); break; case PACKET_CREATURE_SMILE: client_creature_smile_from_network(packet); break; case PACKET_GAME_INFO: break; case PACKET_ROUND: client_round_info_from_network(packet); break; case PACKET_INTERMISSION: client_game_intermission_from_network(packet); break; case PACKET_WELCOME_MSG: client_writeto("guiclient\n", 10); break; case PACKET_START_COMPRESS: client_start_compression(); break; case PACKET_HANDSHAKE: client_handshake_from_network(packet); break; default: fprintf(stderr, "packet->type %d unknown\n", packet->type); break; } } // returns 0 on error // returns 1 if more data is needed // returns 2 if more time is needed static int client_parse_in_buf() { restart: if (compression) { char buf[8192]; strm.next_in = EVBUFFER_DATA(in_buf); strm.avail_in = EVBUFFER_LENGTH(in_buf); do { strm.next_out = (unsigned char*)buf; strm.avail_out = sizeof(buf); int ret = inflate(&strm, Z_SYNC_FLUSH); if (ret != Z_OK && ret != Z_BUF_ERROR) { client_destroy("decompression error"); return 0; } evbuffer_add(packet_buf, buf, sizeof(buf) - strm.avail_out); if (EVBUFFER_LENGTH(packet_buf) > 1024 * 1024) { client_destroy("too much to decompress. funny data?"); return 0; } } while (strm.avail_out == 0); evbuffer_drain(in_buf, EVBUFFER_LENGTH(in_buf) - strm.avail_in); } else { evbuffer_add_buffer(packet_buf, in_buf); evbuffer_drain(in_buf, EVBUFFER_LENGTH(in_buf)); } while (EVBUFFER_LENGTH(packet_buf) >= PACKET_HEADER_SIZE) { int packet_len = PACKET_HEADER_SIZE + EVBUFFER_DATA(packet_buf)[0]; // Nicht genuegend Daten da? if (EVBUFFER_LENGTH(packet_buf) < packet_len) return 1; // Alten Kompressionszustand merken int old_compression = compression; // Packet rauspopeln... static packet_t packet; memcpy(&packet, EVBUFFER_DATA(packet_buf), packet_len); packet_rewind(&packet); client_handle_packet(&packet); // Disconnect Packet? if (!client_is_connected()) return 0; // Weg damit evbuffer_drain(packet_buf, packet_len); // Wurde Kompression aktiviert? Dann Rest des packet_buf zurueck // in den in_buf, da es sich dabei bereits um komprimierte Daten // handelt und diese oben erst dekomprimiert werden muessen. if (compression != old_compression) { evbuffer_add_buffer(in_buf, packet_buf); evbuffer_drain(packet_buf, EVBUFFER_LENGTH(packet_buf)); goto restart; } // Beim Demo abspielen muss erst pausiert werden if (is_file_source && next_packet_countdown > 0) return 2; } return 1; } static void client_readable(int fd, short event, void *arg) { int ret = evbuffer_read(in_buf, fd, 8192); if (ret < 0) { client_destroy(strerror(errno)); } else if (ret == 0) { client_destroy("eof reached"); } else { traffic += ret; client_parse_in_buf(); } } static void client_writable(int fd, short event, void *arg) { int ret = evbuffer_write(out_buf, fd); if (ret < 0) { client_destroy(strerror(errno)); } else if (ret == 0) { client_destroy("null write?"); } else if (EVBUFFER_LENGTH(out_buf) > 0) { event_add(&wr_event, NULL); } } void client_writeto(const void *data, size_t size) { if (is_file_source) return; if (size == 0) return; if (EVBUFFER_LENGTH(in_buf) > 1024*1024) return; evbuffer_add(out_buf, (void*)data, size); event_add(&wr_event, NULL); } int client_is_file_source() { return is_file_source; } void client_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); char buf[4096]; vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); client_writeto(buf, strlen(buf)); } int client_is_connected() { return clientfd != -1; } void file_loop(int delta) { next_packet_countdown -= delta; while (next_packet_countdown <= 0) { int status = client_parse_in_buf(); if (status == 0 || // error -> disconnected status == 2) // call again later return; char buf[64]; int ret = read(clientfd, buf, sizeof(buf)); if (ret < 0) { client_destroy(strerror(errno)); return; } else if (ret == 0) { client_destroy("eof"); return; } evbuffer_add(in_buf, buf, ret); traffic += ret; } } int client_traffic() { return traffic; } void client_tick(int delta) { if (is_file_source) { file_loop(delta); } else { event_loop(EVLOOP_NONBLOCK); } } int client_open_socket(char *addr) { int port = 1234; struct hostent *host; char *colon = strchr(addr, ':'); if (colon) { *colon = '\0'; port = atoi(colon + 1); } struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(port); fprintf(stderr, "resolving %s\n", addr); host = gethostbyname(addr); if (!host) #ifdef WIN32 die("gethostbyname failed: %s", ErrorString(WSAGetLastError())); #else die("gethostbyname failed: %s", hstrerror(h_errno)); #endif if (host->h_length != 4) die("h_length != 4"); memcpy(&serveraddr.sin_addr, host->h_addr_list[0], host->h_length); fprintf(stderr, "connecting to %s:%d (%s:%d)\n", addr, port, inet_ntoa(serveraddr.sin_addr), port); /* Socket erzeugen */ int fd = socket(AF_INET, SOCK_STREAM, 0); /* Fehler beim Socket erzeugen? */ #ifdef WIN32 if (fd == INVALID_SOCKET) die("cannot open socket: %s", ErrorString(WSAGetLastError())); #else if (fd == -1) die("cannot open socket: %s", strerror(errno)); #endif #ifdef WIN32 if (connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR) die("cannot connect socket: %s", ErrorString(WSAGetLastError())); #else if (connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) die("cannot connect socket: %s", strerror(errno)); #endif fprintf(stderr, "connected!\n"); /* Non Blocking setzen */ #ifdef WIN32 DWORD notblock = 1; ioctlsocket(fd, FIONBIO, ¬block); #else if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) die("cannot set socket nonblocking: %s", strerror(errno)); #endif return fd; } int client_open_file(char *filename) { #ifdef WIN32 int fd = open(filename, O_RDONLY | O_BINARY); #else int fd = open(filename, O_RDONLY); #endif if (fd < 0) die("cannot open file %s: %s", filename, strerror(errno)); return fd; } void client_init(char *source) { struct stat stat_buf; if (!strcmp(source, "-")) source = "/dev/stdin"; if (stat(source, &stat_buf) < 0) { #ifdef WIN32 WSADATA wsa; if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) die("WSAStartup failed"); #endif clientfd = client_open_socket(source); is_file_source = 0; event_init(); event_set(&rd_event, clientfd, EV_READ | EV_PERSIST, client_readable, &rd_event); event_set(&wr_event, clientfd, EV_WRITE, client_writable, &wr_event); event_add(&rd_event, NULL); } else { clientfd = client_open_file(source); is_file_source = 1; } in_buf = evbuffer_new(); out_buf = evbuffer_new(); packet_buf = evbuffer_new(); } void client_destroy(const char *reason) { assert(clientfd != -1); fprintf(stderr, "datasource destroyed: %s\n", reason); evbuffer_free(in_buf); evbuffer_free(out_buf); evbuffer_free(packet_buf); if (compression) inflateEnd(&strm); close(clientfd); clientfd = -1; if (!is_file_source) { event_del(&rd_event); event_del(&wr_event); #ifdef WIN32 WSACleanup(); #endif } } void client_shutdown() { if (client_is_connected()) client_destroy("shutdown"); } infon/client.h0000644000076400001440000000206610544631570013400 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef CLIENT_H #define CLIENT_H void client_tick(int delta); int client_is_connected(); int client_traffic(); void client_printf(const char *fmt, ...); int client_is_file_source(); void client_init(char *source); void client_shutdown(); #endif infon/listener.c0000644000076400001440000001161310552756441013744 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include "infond.h" #include "global.h" #include "server.h" #include "listener.h" #include "server.h" static int listenfd = -1; static struct event listener_event; static void listener_cb(int fd, short event, void *arg) { struct sockaddr_in peer; socklen_t addrlen = sizeof(struct sockaddr_in); int clientfd; /* Neue Verbindung accept()ieren */ clientfd = accept(listenfd, (struct sockaddr*)&peer, &addrlen); if (clientfd == -1) { /* Warning nur anzeigen, falls accept() fehlgeschlagen hat allerdings ohne dabei EAGAIN (was bei non-blocking sockets auftreten kann) zu melden. */ if (errno != EAGAIN) fprintf(stderr, "cannot accept() new incoming connection: %s\n", strerror(errno)); goto error; } /* TCP_NODELAY setzen. Dadurch werden Daten fruehestmoeglich versendet */ static const int one = 1; if (setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) { fprintf(stderr, "cannot enable TCP_NODELAY: %s\n", strerror(errno)); goto error; } /* SO_LINGER setzen. Falls sich noch Daten in der Sendqueue der Verbindung befinden, werden diese verworfen. */ static const struct linger l = { 1, 0 }; if (setsockopt(clientfd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) { fprintf(stderr, "cannot set SO_LINGER: %s\n", strerror(errno)); goto error; } static char address[128]; sprintf(address, "ip4:%s:%d", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port)); if (!server_accept(clientfd, address)) goto error; return; error: if (clientfd != -1) close(clientfd); } void listener_shutdown() { if (listenfd == -1) return; event_del(&listener_event); close(listenfd); listenfd = -1; } int listener_init(const char *listenaddr, int port) { struct sockaddr_in addr; static const int one = 1; /* Alten Listener, falls vorhanden, schliessen */ listener_shutdown(); /* Keinen neuen starten? */ if (strlen(listenaddr) == 0) return 1; /* Adressstruktur fllen */ memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(listenaddr); addr.sin_port = htons(port); /* Socket erzeugen */ listenfd = socket(AF_INET, SOCK_STREAM, 0); /* Fehler beim Socket erzeugen? */ if (listenfd == -1) { fprintf(stderr, "cannot open socket: %s\n", strerror(errno)); goto error; } /* Auf nonblocking setzen */ if (fcntl(listenfd, F_SETFL, O_NONBLOCK) == -1) { fprintf(stderr, "cannot set socket nonblocking: %s\n", strerror(errno)); goto error; } /* SO_REUSEADDR verwenden. Falls sich zuvor ein Programm unschn beendet hat, so ist der port normalerweise fr einen bestimmten Zeitrahmen weiterhin belegt. SO_REUSEADDR verwendet dann den belegten Port weiter. */ if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { fprintf(stderr, "cannot enable SO_REUSEADDR: %s\n", strerror(errno)); goto error; } /* Socket bind()en */ if (bind(listenfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1) { fprintf(stderr, "cannot bind socket: %s\n", strerror(errno)); goto error; } /* Und listen() mit einem backlog von 128 Verbindungen. Wobei dies eventuell ignoriert wird, falls SYN cookies aktiviert sind */ if (listen(listenfd, 128) == -1) { fprintf(stderr, "cannot listen() on socket: %s\n", strerror(errno)); goto error; } event_set(&listener_event, listenfd, EV_READ | EV_PERSIST, listener_cb, &listener_event); event_add(&listener_event, NULL); return 1; error: if (listenfd != -1) { close(listenfd); listenfd = -1; } return 0; } infon/COPYING0000600000076400001440000004311010505727454012773 0ustar dividuumusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. infon/common_creature.h0000600000076400001440000000354110505727454015277 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef COMMON_CREATURE_H #define COMMON_CREATURE_H #define MAXCREATURES 256 #define CREATURE_COLORS 16 typedef enum { CREATURE_SMALL, CREATURE_BIG, CREATURE_FLYER, CREATURE_UNUSED } creature_type; #define CREATURE_TYPES 4 #define CREATURE_DIRECTIONS 32 #define CREATURE_ANIMS 2 typedef enum { CREATURE_IDLE, CREATURE_WALK, CREATURE_HEAL, CREATURE_EAT, CREATURE_ATTACK, CREATURE_CONVERT, CREATURE_SPAWN, CREATURE_FEED, } creature_state; #define CREATURE_STATES 8 #define CREATURE_POS_RESOLUTION 16 #define CREATURE_SPEED_RESOLUTION 4 #define CREATURE_DIRTY_ALIVE (1 << 0) #define CREATURE_DIRTY_TYPE (1 << 1) #define CREATURE_DIRTY_FOOD_HEALTH (1 << 2) #define CREATURE_DIRTY_STATE (1 << 3) #define CREATURE_DIRTY_PATH (1 << 4) #define CREATURE_DIRTY_TARGET (1 << 5) #define CREATURE_DIRTY_MESSAGE (1 << 6) #define CREATURE_DIRTY_SPEED (1 << 7) #define CREATURE_DIRTY_ALL 0xFF #define CREATURE_DIRTY_NONE 0x00 #endif infon/world.c0000644000076400001440000002312710544615107013243 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include "infond.h" #include "global.h" #include "world.h" #include "path.h" #include "misc.h" static int world_w; static int world_h; static int koth_x; static int koth_y; static int has_plains; // TODO: Jeder Kreaturtype sollte eigene Pfadsuche haben static map_t *walkmap; static pathfinder_t finder; typedef struct maptile_s { int food; maptype_e type; mapgfx_e gfx; } maptile_t; static maptile_t *map = NULL; #define MAPTILE(x, y) (map[(y) * world_w + (x)]) int world_is_on_map(int x, int y) { return x >= 0 && x < world_w && y >= 0 && y < world_h; } int world_is_within_border(int x, int y) { return x >= 1 && x < world_w - 1 && y >= 1 && y < world_h - 1; } int world_walkable(int x, int y) { return world_is_on_map(x, y) && map_walkable(walkmap, x, y); } static int food_to_network_food(int food) { // 0 = 0, 1 - 999 = 1, 1000 - 1999 = 2 ... 9000 - 9999 = 10 return food == 0 ? 0 : food / 1000 + 1; } void world_to_network(int x, int y, client_t *client) { packet_t packet; packet_init(&packet, PACKET_WORLD_UPDATE); packet_write08(&packet, x); packet_write08(&packet, y); packet_write08(&packet, food_to_network_food(MAPTILE(x, y).food) | MAPTILE(x, y).type << 4); packet_write08(&packet, MAPTILE(x, y).gfx); server_send_packet(&packet, client); } int world_set_gfx(int x, int y, int gfx) { if (gfx < 0 || gfx >= TILE_GFX_LAST_DEFINED) return 0; if (!world_is_on_map(x, y)) return 0; int old_gfx = MAPTILE(x, y).gfx; MAPTILE(x, y).gfx = gfx; if (gfx != old_gfx) world_to_network(x, y, SEND_BROADCAST); return 1; } int world_set_type(int x, int y, maptype_e type) { if (type != TILE_PLAIN) return 0; if (!world_is_within_border(x, y)) return 0; if (MAPTILE(x, y).type == TILE_PLAIN) return 1; // Pfadsuche fuer Bodenbasierte Viecher aktualisieren map_dig(walkmap, x, y); MAPTILE(x, y).type = type; world_to_network(x, y, SEND_BROADCAST); has_plains = 1; return 1; } pathnode_t *world_findpath(int x1, int y1, int x2, int y2) { return finder_find(&finder, walkmap, x1, y1, x2, y2); } int world_get_food(int x, int y) { if (!world_is_on_map(x, y)) return 0; return MAPTILE(x, y).food; } maptype_e world_get_type(int x, int y) { if (!world_is_on_map(x, y)) return 0; return MAPTILE(x, y).type; } int world_add_food(int x, int y, int amount) { if (!world_is_on_map(x, y)) return 0; if (MAPTILE(x, y).type != TILE_PLAIN) return 0; int old = MAPTILE(x, y).food; int new = old + amount; if (new > MAX_TILE_FOOD) new = MAX_TILE_FOOD; if (new < 0) new = 0; MAPTILE(x, y).food = new; if (food_to_network_food(new) != food_to_network_food(old)) world_to_network(x, y, SEND_BROADCAST); return new - old; } int world_food_eat(int x, int y, int amount) { if (!world_is_on_map(x, y)) return 0; if (MAPTILE(x, y).type != TILE_PLAIN) return 0; int ontile = MAPTILE(x, y).food; if (amount > ontile) amount = ontile; int old = MAPTILE(x, y).food; int new = MAPTILE(x, y).food -= amount; if (food_to_network_food(new) != food_to_network_food(old)) world_to_network(x, y, SEND_BROADCAST); return amount; } int world_width() { return world_w; } int world_height() { return world_h; } int world_koth_x() { return koth_x; } int world_koth_y() { return koth_y; } int world_find_plain(int *x, int *y) { if (!has_plains) return 0; // TODO: effizienter machen. while (1) { int xx = rand() % world_w; int yy = rand() % world_h; if (MAPTILE(xx, yy).type == TILE_PLAIN) { *x = xx; *y = yy; return 1; } } } void world_send_info(client_t *client) { packet_t packet; packet_init(&packet, PACKET_WORLD_INFO); packet_write08(&packet, world_w); packet_write08(&packet, world_h); packet_write08(&packet, koth_x); packet_write08(&packet, koth_y); server_send_packet(&packet, client); } void world_send_initial_update(client_t *client) { world_send_info(client); for (int x = 0; x < world_w; x++) { for (int y = 0; y < world_h; y++) { world_to_network(x, y, client); } } } void world_tick() { lua_pushliteral(L, "world_tick"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error calling world_tick: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } } #define check_world_initialized() \ do { if (!map) luaL_error(L, "world not yet initialized"); } while (0) static int luaWorldSetType(lua_State *L) { check_world_initialized(); lua_pushboolean(L, world_set_type(luaL_checklong(L, 1), luaL_checklong(L, 2), luaL_checklong(L, 3))); return 1; } static int luaWorldGetType(lua_State *L) { check_world_initialized(); int x = luaL_checklong(L, 1); int y = luaL_checklong(L, 2); if (!world_is_on_map(x, y)) luaL_error(L, "%d,%d is not on map", x, y); lua_pushnumber(L, MAPTILE(x, y).type); return 1; } static int luaWorldSetGfx(lua_State *L) { check_world_initialized(); lua_pushboolean(L, world_set_gfx(luaL_checklong(L, 1), luaL_checklong(L, 2), luaL_checklong(L, 3))); return 1; } static int luaWorldGetGfx(lua_State *L) { check_world_initialized(); int x = luaL_checklong(L, 1); int y = luaL_checklong(L, 2); if (!world_is_on_map(x, y)) luaL_error(L, "%d,%d is not on map", x, y); lua_pushnumber(L, MAPTILE(x, y).gfx); return 1; } static int luaWorldAddFood(lua_State *L) { check_world_initialized(); lua_pushnumber(L, world_add_food(luaL_checklong(L, 1), luaL_checklong(L, 2), luaL_checklong(L, 3))); return 1; } static int luaWorldWalkable(lua_State *L) { check_world_initialized(); lua_pushboolean(L, world_walkable(luaL_checklong(L, 1), luaL_checklong(L, 2))); return 1; } static int luaWorldFindDigged(lua_State *L) { check_world_initialized(); int x, y; if (!world_find_plain(&x, &y)) return 0; lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; } void world_init() { lua_register(L, "world_set_type", luaWorldSetType); lua_register(L, "world_set_gfx", luaWorldSetGfx); lua_register(L, "world_get_type", luaWorldGetType); lua_register(L, "world_get_gfx", luaWorldGetGfx); lua_register(L, "world_add_food", luaWorldAddFood); lua_register(L, "world_is_walkable", luaWorldWalkable); lua_register(L, "world_find_digged", luaWorldFindDigged); lua_register_constant(L, TILE_SOLID); lua_register_constant(L, TILE_PLAIN); lua_register_constant(L, TILE_GFX_SOLID); lua_register_constant(L, TILE_GFX_PLAIN); lua_register_constant(L, TILE_GFX_BORDER); lua_register_constant(L, TILE_GFX_SNOW_SOLID); lua_register_constant(L, TILE_GFX_SNOW_PLAIN); lua_register_constant(L, TILE_GFX_SNOW_BORDER); lua_register_constant(L, TILE_GFX_WATER); lua_register_constant(L, TILE_GFX_LAVA); lua_register_constant(L, TILE_GFX_NONE); lua_register_constant(L, TILE_GFX_KOTH); lua_register_constant(L, TILE_GFX_DESERT); lua_register_constant(L, TILE_WIDTH); lua_register_constant(L, TILE_HEIGHT); lua_pushliteral(L, "world_init"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 4, 0) != 0) { fprintf(stderr, "error calling world_init: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); world_w = world_h = 3; koth_x = koth_y = 1; } else { world_w = lua_tonumber(L, -4); world_h = lua_tonumber(L, -3); koth_x = lua_tonumber(L, -2); koth_y = lua_tonumber(L, -1); lua_pop(L, 4); } world_w = limit(world_w, 3, 255); world_h = limit(world_h, 3, 255); koth_x = limit(koth_x, 0, world_w - 1); koth_y = limit(koth_y, 0, world_h - 1); walkmap = map_alloc(); map_init(walkmap, world_w, world_h); finder_init(&finder); map = malloc(world_w * world_h * sizeof(maptile_t)); memset(map, 0, world_w * world_h * sizeof(maptile_t)); has_plains = 0; // World Informationen an GUI Clients schicken world_send_info(SEND_BROADCAST); } void world_shutdown() { finder_shutdown(&finder); free(map); map = NULL; map_free(walkmap); } infon/listener.h0000644000076400001440000000165310540115023013732 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef LISTENER_H #define LISTENER_H int listener_init(const char *addr, int port); void listener_shutdown(); #endif infon/player.lua0000644000076400001440000002005710603240403013733 0ustar dividuumusers--[[ Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ]]-- ------------------------------------------------------------------------ -- load config.lua ------------------------------------------------------------------------ local config = {} setfenv(assert(loadfile(os.getenv("INFOND_CONFIG") or (PREFIX .. "config.lua"))), config)() ------------------------------------------------------------------------ -- save traceback in registry for usage within 'out of cycles' handler ------------------------------------------------------------------------ save_in_registry('traceback', debug.traceback) save_in_registry = nil -- save traceback function _TRACEBACK = debug.traceback ------------------------------------------------------------------------ -- Prevent high cpu usage by limiting some functions ------------------------------------------------------------------------ do local assert, type = assert, type -- new dofile function uses defined PREFIX local PREFIX, orig_dofile = PREFIX, dofile function dofile(file) return orig_dofile(PREFIX .. file .. ".lua") end -- limit strings accepted by loadstring to 16k local orig_loadstring = loadstring function loadstring(code, name) assert(#code <= 16384, "code too large") return orig_loadstring(code, name) end -- limit string.rep local orig_string_rep = string.rep function string.rep(s, n) assert(n <= 10000, "string.rep's n is limited to 10000") return orig_string_rep(s, n) end -- provide thread tracing function local sethook, getinfo = debug.sethook, debug.getinfo function thread_trace(thread, text) assert(type(thread) == "thread", "arg #1 is not a thread") text = text or tostring(thread) local dumper = type(text) == "function" and text or function(info) print(text .. ":" .. info.source .. ":" .. info.currentline) end local hook = function(what, where) dumper(getinfo(2, "nlS")) end sethook(thread, hook, "l") end function thread_untrace(thread) assert(type(thread) == "thread", "arg #1 is not a thread") sethook(thread) end end ------------------------------------------------------------------------ -- Load debugger if requested ------------------------------------------------------------------------ package.path = PREFIX .. "libs/?.lua" if config.debugger then ldb = require("ldb") end ------------------------------------------------------------------------ -- Disable dangerous functions ------------------------------------------------------------------------ PREFIX = nil -- no need to know debug = nil -- no debugging functions load = nil -- not needed require = nil -- no file loading loadfile = nil -- no file loading _VERSION = nil -- who cares newproxy = nil -- huh? gcinfo = nil -- no access to the garbage collector os = nil -- no os access package = nil -- package support is not needed io = nil -- disable io module = nil -- module support not needed collectgarbage = nil -- no access to the garbage collector ------------------------------------------------------------------------ -- Disable Linehook unless permitted ------------------------------------------------------------------------ if not config.linehook then linehook = nil end ------------------------------------------------------------------------ -- 'pretty'-print function ------------------------------------------------------------------------ function p(x) if type(x) == "table" then print("+--- Table: " .. tostring(x)) for key, val in pairs(x) do print("| " .. tostring(key) .. " " .. tostring(val)) end print("+-----------------------") else print(type(x) .. " - " .. tostring(x)) end end ------------------------------------------------------------------------ -- Functions called by the 'r' and 'i' commands ------------------------------------------------------------------------ function restart() for id, creature in pairs(creatures) do creature:restart() end end function info() for id, creature in pairs(creatures) do print(creature .. ":") print("------------------------------") if creature.message then print("current message: " .. creature.message) end if type(creature.thread) == 'thread' then print(_TRACEBACK(creature.thread, "thread status : " .. (creature.status or coroutine.status(creature.thread)), coroutine.status(creature.thread) == "dead" and 0 or 1)) end print() end end ------------------------------------------------------------------------ -- Compatibility ------------------------------------------------------------------------ function nearest_enemy(...) print(_TRACEBACK("calling 'nearest_enemy' is deprecated. use 'get_nearest_enemy' instead.", 2)) nearest_enemy = get_nearest_enemy return get_nearest_enemy(...) end function exists(...) print(_TRACEBACK("calling 'exists' is deprecated. use 'creature_exists' instead.", 2)) exists = creature_exists return creature_exists(...) end ------------------------------------------------------------------------ -- Install default onCommand ------------------------------------------------------------------------ function onCommand(cmd) print("huh? use '?' for help") end ------------------------------------------------------------------------ -- Load Highlevel API ------------------------------------------------------------------------ do local api = (...) -- Load API dofile("api/" .. api) -- Load Default Code for API dofile("api/" .. api .. "-default") function needs_api(needed) assert(needed == api, "This Code needs the API '" .. needed .. "' but '" .. api .. "' is loaded") end end ------------------------------------------------------------------------ -- Modify dofile to only load allowed files once. ------------------------------------------------------------------------ do local orig_dofile, assert, type, pairs = dofile, assert, type, pairs local loaded = {} function dofile(file) assert(type(file) == "string", "filename must be string") -- already loaded into this vm? if loaded[file] then return end -- not allowed to load this file? if not config.dofile_allowed or not config.dofile_allowed[file] then print(_TRACEBACK("dofile('" .. file .. "') denied. upload it using the batch (b) command")) return end loaded[file] = true return orig_dofile("libs/" .. file) end function dofile_list() print("You can load the following files:") print("-----------------------------------------------") for name, help in pairs(config.dofile_allowed) do print(string.format("%-10s - %s", name, help)) end print("-----------------------------------------------") end end ------------------------------------------------------------------------ -- Switch print ------------------------------------------------------------------------ print = client_print infon/Makefile0000644000076400001440000001532310603314646013407 0ustar dividuumusersall: targets ifndef REVISION -include REVISION endif # EVENT_NAME = Computer Night 2006 # EVENT_HOST = 172.30.100.1 CFLAGS += -pedantic -std=gnu99 -Wall -DREVISION="\"$(REVISION)\"" LUA = lua-5.1.2 ifdef EVENT_NAME CFLAGS += -DEVENT_NAME="\"$(EVENT_NAME)\"" endif ifdef EVENT_HOST CFLAGS += -DEVENT_HOST="\"$(EVENT_HOST)\"" endif ifdef WINDOWS OPTIMIZE=1 endif ifdef OPTIMIZE CFLAGS += -O3 -fexpensive-optimizations -finline-functions -fomit-frame-pointer -DNDEBUG else CFLAGS += -ggdb endif ifdef WINDOWS PREFIX ?= .\\\\ MINGW = $(HOME)/progs/mingw32/ SDLDIR = $(MINGW) CC = /opt/xmingw/bin/i386-mingw32msvc-gcc CFLAGS += -I$(MINGW)/include WINDRES = /opt/xmingw/bin/i386-mingw32msvc-windres STRIP = /opt/xmingw/bin/i386-mingw32msvc-strip LUAPLAT = mingw INFON_EXECUTABLE = infon.exe SDL_RENDERER = sdl_gui.dll GL_RENDERER = gl_gui.dll NULL_RENDERER = null_gui.dll RENDERER = $(SDL_RENDERER) $(GL_RENDERER) else PREFIX ?= ./ SDLDIR := $(shell sdl-config --prefix) ifdef OPTIMIZE LUAPLAT = optimize else LUAPLAT = debug endif INFON_EXECUTABLE = infon INFOND_EXECUTABLE = infond NULL_RENDERER = null_gui.so SDL_RENDERER = sdl_gui.so GL_RENDERER = gl_gui.so AA_RENDERER = aa_gui.so LILITH_RENDERER = lilith_gui.so RENDERER = $(SDL_RENDERER) $(NULL_RENDERER) $(GL_RENDERER) endif CFLAGS += -DPREFIX=\"$(PREFIX)\" ############################################################ # Target specific Configuration ############################################################ ifdef WINDOWS $(INFON_EXECUTABLE) : LDFLAGS += $(MINGW)/lib/libevent.a $(MINGW)/lib/libz.a \ -lmingw32 $(MINGW)/lib/libSDLmain.a -lwsock32 -mwindows -Wl,-s $(INFON_EXECUTABLE) : infon.res $(SDL_RENDERER) : CFLAGS += -I$(SDLDIR)/include/SDL $(SDL_RENDERER) : LDFLAGS += $(MINGW)/lib/libSGE.a $(MINGW)/lib/libevent.a $(MINGW)/lib/libSDL_image.a \ $(MINGW)/lib/libpng.a $(MINGW)/lib/libz.a $(MINGW)/lib/libSDL_gfx.a $(MINGW)/lib/libSDL.a \ -lmingw32 -lstdc++ -lwsock32 -lwinmm -mwindows -Wl,-s $(SDL_RENDERER) : infon.res $(GL_RENDERER) : CFLAGS += -I$(SDLDIR)/include/SDL $(GL_RENDERER) : LDFLAGS += $(MINGW)/lib/libSGE.a $(MINGW)/lib/libevent.a \ $(MINGW)/lib/libz.a $(MINGW)/lib/libSDL.a \ -lmingw32 -lopengl32 -lglu32 -lstdc++ -lwsock32 -lwinmm -mwindows -Wl,-s $(GL_RENDERER) : infon.res else $(INFON_EXECUTABLE) : LDFLAGS += -levent -lz -lm # Example for embedding a renderer ifdef NULL_INFON $(INFON_EXECUTABLE) : CFLAGS += -DNO_EXTERNAL_RENDERER -DBUILTIN_RENDERER=null_gui $(INFON_EXECUTABLE) : null_gui.o else ifdef SDL_INFON $(INFON_EXECUTABLE) : CFLAGS += -DNO_EXTERNAL_RENDERER -DBUILTIN_RENDERER=sdl_gui -I$(SDLDIR)/include/SDL $(INFON_EXECUTABLE) : LDFLAGS += -lSDL -lSDL_image -lSGE -lSDL_gfx $(INFON_EXECUTABLE) : sdl_video.o sdl_sprite.o sdl_gui.o else $(INFON_EXECUTABLE) : LDFLAGS += -ldl misc.o : CFLAGS += -fPIC endif endif $(INFOND_EXECUTABLE): CFLAGS += -I$(LUA)/src/ # -DCHEATS $(INFOND_EXECUTABLE): LDFLAGS += -levent -lz -lm # Experimental usage of 'all of lua in one file' as seen in lua-5.1.2/etc/all.c ifdef OPTIMIZE $(INFOND_EXECUTABLE): luacore.o luacore.o : CFLAGS += -DLUA_USE_POSIX else $(INFOND_EXECUTABLE): $(LUA)/src/liblua.a endif $(SDL_RENDERER) : CFLAGS += -fPIC -I$(SDLDIR)/include/SDL $(SDL_RENDERER) : LDFLAGS += -lSDL -lSDL_image -lSGE -lSDL_gfx $(GL_RENDERER) : CFLAGS += -fPIC -I$(SDLDIR)/include/SDL $(GL_RENDERER) : LDFLAGS += -lSDL -lGL -lGLU $(AA_RENDERER) : CFLAGS += -fPIC $(AA_RENDERER) : LDFLAGS += -laa $(LILITH_RENDERER) : CPPFLAGS += -fPIC $(LILITH_RENDERER) : LDFLAGS += -lSDL -lGL -lGLU -lstdc++ $(NULL_RENDERER) : CFLAGS += -fPIC endif gl_gui.o : CFLAGS += -Wno-unused ifdef DEFAULT_RENDERER $(INFON_EXECUTABLE) : CFLAGS += -DDEFAULT_RENDERER=$(DEFAULT_RENDERER) endif ############################################################ # Go Go Go! ############################################################ targets: infond $(INFON_EXECUTABLE) $(RENDERER) dist: $(MAKE) distclean $(MAKE) source-dist $(MAKE) clean WINDOWS=1 $(MAKE) win32-client-dist $(MAKE) clean OPTIMIZE=1 $(MAKE) linux-client-dist $(MAKE) clean $(MAKE) linux-server-dist source-dist: REVISION tar cvzh -C.. --exclude ".svn" --exclude "infon-source*" --file infon-source-r$(REVISION).tgz infon win32-client-dist: $(INFON_EXECUTABLE) $(SDL_RENDERER) $(GL_RENDERER) $(STRIP) $^ upx -9 --all-methods $(INFON_EXECUTABLE) upx -9 --all-methods $(SDL_RENDERER) upx -9 --all-methods $(GL_RENDERER) zip infon-win32-r$(REVISION).zip \ README.txt $^ gfx/*.fnt gfx/*.png gfx/*.bmp gfx/*.mdl \ contrib/bots/*.lua contrib/bots/*.txt linux-client-dist: $(INFON_EXECUTABLE) $(SDL_RENDERER) $(NULL_RENDERER) $(GL_RENDERER) strip $^ tar cfvz infon-linux-i386-r$(REVISION).tgz \ README.txt $^ gfx/*.fnt gfx/*.png gfx/*.bmp gfx/*.mdl \ contrib/bots/*.lua contrib/bots/*.txt linux-server-dist: $(INFOND_EXECUTABLE) infond-wrapper tar cfvz infond-linux-i386-r$(REVISION).tgz \ README.txt $(INFOND_EXECUTABLE) infond-wrapper $(INFOND_EXECUTABLE)-static \ *.lua level/*.lua rules/*.lua api/*.lua libs/*.lua \ contrib/bots/*.lua contrib/bots/*.txt $(INFOND_EXECUTABLE): infond.o server.o listener.o map.o path.o misc.o packet.o player.o world.o creature.o scroller.o game.o pinger.o $(CC) $^ $(LDFLAGS) -o $@ $(CC) $^ $(LDFLAGS) -static -o $@-static $(INFON_EXECUTABLE): infon.o client.o packet.o misc.o client_player.o client_world.o client_creature.o client_game.o renderer.o $(CC) $^ $(LDFLAGS) -o $@ $(NULL_RENDERER) : null_gui.o $(CC) $^ -shared -o $@ $(AA_RENDERER): aa_gui.o $(CC) $^ $(LDFLAGS) -shared -o $@ $(SDL_RENDERER): sdl_video.o sdl_sprite.o sdl_gui.o misc.o $(CC) $^ $(LDFLAGS) -shared -o $@ $(GL_RENDERER): gl_video.o gl_gui.o gl_mdl.o misc.o $(CC) $^ $(LDFLAGS) -shared -o $@ $(LILITH_RENDERER): lilith_gui.o misc.o lilith/lilith/liblilith.a $(CC) $^ $(LDFLAGS) -shared -o $@ infon.res: infon.rc $(WINDRES) -i $^ -DREVISION="\\\"$(REVISION)\\\"" --input-format=rc -o $@ -O coff $(LUA)/src/liblua.a: $(MAKE) -C $(LUA) $(LUAPLAT) %.o:%.c $(CC) $(CFLAGS) $^ -c -o $@ %.o:%.cpp $(CXX) $(CPPFLAGS) $^ -c -o $@ REVISION: echo "REVISION=`svnversion .`" > $@ clean: -rm -f *.o *.so *.dll infond infond-static infon infon.exe infon.res tags distclean: clean $(MAKE) -C $(LUA) clean -rm -f infon*.zip infon*.tgz *.orig *.rej infond-*.demo infond-wrapper REVISION infon/player.c0000644000076400001440000012347210603314646013414 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include "infond.h" #include "global.h" #include "player.h" #include "server.h" #include "creature.h" #include "world.h" #include "misc.h" #include "game.h" #include "rules.h" #include "scroller.h" #define PLAYER_USED(player) (!!((player)->L)) static player_t players[MAXPLAYERS]; static int num_players = 0; static player_t *king_player = NULL; void player_change_score(player_t *player, int scoredelta, const char *reason) { char buf[1024]; snprintf(buf, sizeof(buf), "%s %s %d point%s: %s", player->name, scoredelta > 0 ? "gained" : "lost", abs(scoredelta), abs(scoredelta) == 1 ? "" : "s", reason); add_to_scroller(buf); int oldscore = player->score; player->score += scoredelta; if (player->score < PLAYER_KICK_SCORE) player->score = PLAYER_KICK_SCORE; if (player->score > 9999) player->score = 9999; if (player->score != oldscore) player->dirtymask |= PLAYER_DIRTY_SCORE; // Rule Handler aufrufen lua_pushnumber(L, player_num(player)); lua_pushnumber(L, player->score); lua_pushstring(L, reason); game_call_rule_handler("onPlayerScoreChange", 3); } void player_init_events(player_t *player) { lua_pushliteral(player->L, "events"); lua_newtable(player->L); lua_settable(player->L, LUA_REGISTRYINDEX); } // erwartet values [key, value] Paare void player_add_event(player_t *player, vm_event event, int values) { lua_pushliteral(player->L, "events"); lua_rawget(player->L, LUA_REGISTRYINDEX); // kv* _events assert(!lua_isnil(player->L, -1)); lua_createtable(player->L, 3, 0); // kv* _events event lua_pushliteral(player->L, "type"); // kv* _events event 'type' lua_pushnumber(player->L, event); // kv* _events event 'type' id lua_rawset(player->L, -3); // kv* _events event lua_insert(player->L, -2); // kv* event _events lua_insert(player->L, -2 - 2 * values); // _events kv* event lua_insert(player->L, -1 - 2 * values); // _events event kv* for (int i = 0; i < values; i++) lua_rawset(player->L, - 1 - 2 * (values - i)); // _events event kv* size_t size = lua_objlen(player->L, -2); // _events lua_rawseti(player->L, -2, size + 1); // _events lua_pop(player->L, 1); // } void player_on_creature_spawned(player_t *player, creature_t *creature, creature_t *parent) { lua_pushliteral(player->L, "id"); lua_pushnumber(player->L, creature_id(creature)); lua_pushliteral(player->L, "parent"); lua_pushnumber(player->L, parent ? creature_id(parent) : -1); player_add_event(player, CREATURE_SPAWNED, 2); player->num_creatures++; // Rule Handler aufrufen lua_pushnumber(L, creature_id(creature)); if (parent) lua_pushnumber(L, creature_id(parent)); else lua_pushnil(L); game_call_rule_handler("onCreatureSpawned", 2); } void player_on_creature_killed(player_t *player, creature_t *victim, creature_t *killer) { lua_pushliteral(player->L, "id"); lua_pushnumber(player->L, creature_id(victim)); lua_pushliteral(player->L, "killer"); lua_pushnumber(player->L, killer ? creature_id(killer) : -1); player_add_event(player, CREATURE_KILLED, 2); player->num_creatures--; assert(player->num_creatures >= 0); if (player->num_creatures == 0) player->all_dead_time = game_time; // Rule Handler aufrufen lua_pushnumber(L, creature_id(victim)); if (killer) lua_pushnumber(L, creature_id(killer)); else lua_pushnil(L); game_call_rule_handler("onCreatureKilled", 2); } void player_on_creature_attacked(player_t *player, creature_t *victim, creature_t *attacker) { lua_pushliteral(player->L, "id"); lua_pushnumber(player->L, creature_id(victim)); lua_pushliteral(player->L, "attacker"); lua_pushnumber(player->L, creature_id(attacker)); player_add_event(player, CREATURE_ATTACKED, 2); } void player_on_all_dead(player_t *player, int time) { // Rule Handler aufrufen lua_pushnumber(L, player_num(player)); lua_pushnumber(L, time); game_call_rule_handler("onPlayerAllCreaturesDead", 2); } void player_on_created(player_t *player) { // Zeiten zuruecksetzen player->all_dead_time = game_time; player->all_disconnected_time = real_time; player->spawn_time = game_time; // Event eintragen lua_pushliteral(player->L, "id"); lua_pushnumber(player->L, player_num(player)); player_add_event(player, PLAYER_CREATED, 1); // Rule Handler aufrufen lua_pushnumber(L, player_num(player)); game_call_rule_handler("onPlayerCreated", 1); } static int player_at_panic(lua_State *L) { fprintf(stderr, "Aeiik! LUA panic. Cannot continue. Please file a bug report\n"); abort(); return 0; // never reached } static void *player_allocator(void *ud, void *ptr, size_t osize, size_t nsize) { player_t *player = (player_t*)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; } else { if (player->mem_enforce && lua_gc(player->L, LUA_GCCOUNT, 0) >= player->max_mem) return NULL; return realloc(ptr, nsize); } } static const char *exceeded_message = NULL; static int player_at_cpu_exceeded(lua_State *L) { lua_pushstring(L, exceeded_message); lua_pushliteral(L, "traceback"); lua_rawget(L, LUA_REGISTRYINDEX); lua_call(L, 0, 1); lua_concat(L, 2); return 1; } static player_t *alarm_player = NULL; static struct itimerval timer; static void alarm_signal(int sig) { assert(sig == SIGVTALRM); assert(alarm_player); // Cycles auf 0 => Bei naechster Anweisung wird die Ausfuehrung beendet. exceeded_message = "cpu time exceeded at "; lua_set_cycles(alarm_player->L, 0); // Spieler kicken. Es riecht nach DOS. free(alarm_player->kill_me); alarm_player->kill_me = strdup("player killed: used excessive amount of cpu. what are you doing?"); } // Erwartet Funktion sowie params Parameter auf dem Stack static int player_call_user_lua(const char *where, player_t *player, int params) { lua_pushliteral(player->L, "traceback"); // func params* 'traceback' lua_rawget(player->L, LUA_REGISTRYINDEX); // func params* traceback lua_insert(player->L, -2 - params); // traceback func params* // XXX: Geht davon aus, das vor dem installieren des Errorhandlers (setjmp, etc..) // kein Speicherbedingter Fehler auftritt. player->mem_enforce = 1; // Notfallzeitbeschraenkung einbauen. Kann auftreten, falls sehr viele // teure Lua Funktionen aufgerufen werden. alarm_player = player; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = LUA_MAX_REAL_CPU_SECONDS; timer.it_value.tv_usec = 0; signal(SIGVTALRM, alarm_signal); setitimer(ITIMER_VIRTUAL, &timer, NULL); // Normalerweise liegt ein "cpu exceeded" Fehler an Ueberschreitung der lua VM Cycles. // Nur im CPU Rechenzeit-Fall wird diese Meldung entsprechend angepasst. exceeded_message = "lua vm cycles exceeded at "; // Usercode aufrufen int ret = lua_pcall(player->L, params, 0, -2 - params); // Alarm aufheben timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 0; setitimer(ITIMER_VIRTUAL, &timer, NULL); alarm_player = NULL; // Keine Speicherbeschraenkung mehr (ab hier wird die VM wieder von infon gesteuert) player->mem_enforce = 0; // Ausfuehrung geklappt. Aufraeumen & raus. if (ret == 0) { lua_pop(player->L, 1); return 1; } // Fehler bei der Ausfuehrung. Fehlermeldung holen const char *errmsg = lua_tostring(player->L, -1); if (!errmsg) errmsg = "unknown error"; const char *why; switch (ret) { case LUA_ERRRUN: why = "runtime"; break; case LUA_ERRMEM: why = "memory"; break; case LUA_ERRERR: why = "error handling"; break; default: why = "unknown"; break; } char errorbuf[4096]; snprintf(errorbuf, sizeof(errorbuf), "%s error %s: %s\r\n", why, where, errmsg); player_writeto(player, errorbuf, strlen(errorbuf)); lua_pop(player->L, 2); return 0; } static int player_get_cpu_usage(player_t *player) { int cycles_left = lua_get_cycles(player->L); return 100 * (player->max_cycles - cycles_left) / player->max_cycles; } // Makros fuer die Verwendung innerhalb der C-Lua Creature-Funktionen. // Innerhalb einer Spieler VM wird ein Pointer auf die player-Struktur // als Upvalue abgelegt (siehe lua_register_player), welcher dann inner- // halb der Funktion wieder als 'player' zur Verfuegung steht. // // Werden die Funktionen von der HauptVM aus aufgerufen, so ist der // Upvalue nil und der Wert von Player NULL. #define get_player() \ player_t *player = lua_touserdata(L, lua_upvalueindex(1)); \ (void)player; /* Unused Warning weg */ #define get_player_and_creature() \ get_player(); \ creature_t *creature = creature_get_checked_lua(L, 1); #define assure_is_players_creature() \ do { if (player && creature->player != player) \ return luaL_error(L, "%d isn't your creature", \ creature_id(creature)); \ } while(0) static int luaSaveInRegistry(lua_State *L) { get_player(); lua_settable(player->L, LUA_REGISTRYINDEX); return 0; } void luaLineHook(lua_State *L, lua_Debug *ar) { lua_getinfo(L, "S", ar); lua_pushthread(L); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushstring(L, ar->source); lua_pushnumber(L, ar->currentline); lua_call(L, 2, 1); int yield = lua_toboolean(L, -1); lua_pop(L, 1); if (yield) lua_yield(L, 0); } static int luaSetLineHook(lua_State *L) { luaL_checktype(L, 1, LUA_TTHREAD); lua_State *thread = lua_tothread(L, 1); if (lua_gettop(L) == 1) { lua_sethook(thread, luaLineHook, 0, 0); } else { luaL_checktype(L, 2, LUA_TFUNCTION); lua_rawset(L, LUA_REGISTRYINDEX); lua_sethook(thread, luaLineHook, LUA_MASKLINE, 0); } return 0; } static int luaPrint(lua_State *L) { get_player(); int n = lua_gettop(L); for (int i = 1; i <= n; i++) { if (i > 1) player_writeto(player, "\t", 1); if (lua_isstring(L,i)) player_writeto(player, lua_tostring(L,i), lua_strlen(L, i)); else if (lua_isnil(L,i)) player_writeto(player, "nil", 3); else if (lua_isboolean(L,i)) lua_toboolean(L,i) ? player_writeto(player, "true", 4): player_writeto(player, "false", 5); else { char buffer[128]; snprintf(buffer, sizeof(buffer), "%s:%p", lua_typename(L,lua_type(L,i)), lua_topointer(L,i)); player_writeto(player, buffer, strlen(buffer)); } } player_writeto(player, "\r\n", 2); return 0; } static int luaCreatureSuicide(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); creature_suicide(creature); return 0; } static int luaCreatureSetPath(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushboolean(L, creature_set_path(creature, luaL_checklong(L, 2), luaL_checklong(L, 3))); return 1; } static int luaCreatureSetTarget(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushboolean(L, creature_set_target(creature, luaL_checklong(L, 2))); return 1; } static int luaCreatureSetConvert(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushboolean(L, creature_set_conversion_type(creature, luaL_checklong(L, 2))); return 1; } static int luaCreatureSetMessage(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); creature_set_message(creature, luaL_checkstring(L, 2)); return 0; } static int luaCreatureGetNearestEnemy(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); int mindist; const creature_t *nearest = creature_nearest_enemy(creature, &mindist); if (!nearest) return 0; lua_pushnumber(L, creature_id(nearest)); lua_pushnumber(L, nearest->x); lua_pushnumber(L, nearest->y); lua_pushnumber(L, player_num(nearest->player)); lua_pushnumber(L, mindist); return 5; } static int luaCreatureGetHealth(lua_State *L) { get_player_and_creature(); lua_pushnumber(L, 100 * creature->health / creature_max_health(creature)); return 1; } static int luaCreatureGetSpeed(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); lua_pushnumber(L, creature_speed(creature)); return 1; } static int luaCreatureGetType(lua_State *L) { get_player_and_creature(); lua_pushnumber(L, creature->type); return 1; } static int luaCreatureGetFood(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); lua_pushnumber(L, creature->food); return 1; } static int luaCreatureGetTileFood(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushnumber(L, creature_food_on_tile(creature)); return 1; } static int luaCreatureGetTileType(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushnumber(L, creature_tile_type(creature)); return 1; } static int luaCreatureGetMaxFood(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushnumber(L, creature_max_food(creature)); return 1; } static int luaCreatureGetPos(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); lua_pushnumber(L, creature->x); lua_pushnumber(L, creature->y); return 2; } static int luaCreatureGetDistance(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); const creature_t *target = creature_get_checked_lua(L, 2); lua_pushnumber(L, creature_dist(creature, target)); return 1; } static int luaCreatureGetState(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); lua_pushnumber(L, creature->state); return 1; } static int luaCreatureGetHitpoints(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); lua_pushnumber(L, creature_hitpoints(creature)); return 1; } static int luaCreatureGetAttackDistance(lua_State *L) { get_player_and_creature(); if (RESTRICTIVE) assure_is_players_creature(); lua_pushnumber(L, creature_attack_distance(creature)); return 1; } #ifdef CHEATS static int luaCreatureCheatGiveAll(lua_State *L) { get_player_and_creature(); creature->health = creature_max_health(creature); creature->food = creature_max_food(creature); return 0; } #endif static int luaCreatureSetState(lua_State *L) { get_player_and_creature(); assure_is_players_creature(); int state = luaL_checklong(L, 2); switch (state) { case CREATURE_IDLE: case CREATURE_WALK: case CREATURE_HEAL: case CREATURE_EAT: case CREATURE_ATTACK: case CREATURE_CONVERT: case CREATURE_SPAWN: case CREATURE_FEED: lua_pushboolean(L, creature_set_state(creature, state)); break; default: luaL_error(L, "invalid state %d", state); break; } return 1; } static int luaGetCPUUsage(lua_State *L) { get_player(); lua_pushnumber(L, player_get_cpu_usage(player)); return 1; } static int luaWorldSize(lua_State *L) { lua_pushnumber(L, TILE_X1(1)); lua_pushnumber(L, TILE_Y1(1)); lua_pushnumber(L, TILE_X2(world_width() - 2)); lua_pushnumber(L, TILE_Y2(world_height() - 2)); return 4; } static int luaGameTime(lua_State *L) { lua_pushnumber(L, game_time); return 1; } static int luaGetKothPos(lua_State *L) { lua_pushnumber(L, TILE_XCENTER(world_koth_x())); lua_pushnumber(L, TILE_YCENTER(world_koth_y())); return 2; } static int luaCreatureExists(lua_State *L) { if (RESTRICTIVE) luaL_error(L, "this function is not available in restricted mode"); lua_pushboolean(L, !!creature_by_id(luaL_checklong(L, 1))); return 1; } static int luaPlayerExists(lua_State *L) { if (RESTRICTIVE) luaL_error(L, "this function is not available in restricted mode"); lua_pushboolean(L, !!player_by_num(luaL_checklong(L, 1))); return 1; } static int luaCreatureGetPlayer(lua_State *L) { if (RESTRICTIVE) luaL_error(L, "this function is not available in restricted mode"); const creature_t *creature = creature_get_checked_lua(L, 1); lua_pushnumber(L, player_num(creature->player)); return 1; } static int luaPlayerScore(lua_State *L) { if (RESTRICTIVE) luaL_error(L, "this function is not available in restricted mode"); lua_pushnumber(L, player_get_checked_lua(L, 1)->score); return 1; } static int luaPlayerChangeScore(lua_State *L) { player_change_score(player_get_checked_lua(L, 1), luaL_checklong(L, 2), luaL_checkstring(L, 3)); return 0; } static int luaCreatureSetFood(lua_State *L) { get_player_and_creature(); lua_pushnumber(L, creature_set_food(creature, luaL_checklong(L, 2))); return 1; } static int luaCreatureSetType(lua_State *L) { get_player_and_creature(); lua_pushnumber(L, creature_set_type(creature, luaL_checklong(L, 2))); return 1; } static int luaKingPlayer(lua_State *L) { player_t *king = player_king(); if (king) { lua_pushnumber(L, player_num(king)); } else { lua_pushnil(L); } return 1; } static void player_set_color(player_t *player, int color) { player->color = color & 0xFF; player->dirtymask |= PLAYER_DIRTY_COLOR; } #define lua_register_player(p,n,f) \ (lua_pushstring((p)->L, n), \ lua_pushlightuserdata((p)->L, p), \ lua_pushcclosure((p)->L, f, 1), \ lua_settable((p)->L, LUA_GLOBALSINDEX)) player_t *player_create(const char *name, const char *pass, const char *highlevel) { int playerno; for (playerno = 0; playerno < MAXPLAYERS; playerno++) { if (!PLAYER_USED(&players[playerno])) break; } if (playerno == MAXPLAYERS) return NULL; player_t *player = &players[playerno]; memset(player, 0, sizeof(player_t)); if (name) { snprintf(player->name, sizeof(player->name), "%s", name); } else { snprintf(player->name, sizeof(player->name), "player%d", playerno); } snprintf(player->pass, sizeof(player->pass), "%s", pass); player->max_mem = LUA_MAX_MEM; player->mem_enforce = 0; player->max_cycles = LUA_MAX_CPU; player->no_client_kick_time = NO_CLIENT_KICK_TIME; player->L = lua_newstate(player_allocator, player); luaL_openlibs(player->L); lua_atcpu_exceeded(player->L, player_at_cpu_exceeded); lua_atpanic (player->L, player_at_panic); player_set_color(player, rand() % 256); lua_register_string_constant(player->L, PREFIX); lua_register_player(player, "save_in_registry", luaSaveInRegistry); lua_register_player(player, "linehook", luaSetLineHook); lua_register_player(player, "client_print", luaPrint); lua_register_player(player, "suicide", luaCreatureSuicide); lua_register_player(player, "set_path", luaCreatureSetPath); lua_register_player(player, "get_pos", luaCreatureGetPos); lua_register_player(player, "get_state", luaCreatureGetState); lua_register_player(player, "set_state", luaCreatureSetState); lua_register_player(player, "set_target", luaCreatureSetTarget); lua_register_player(player, "set_convert", luaCreatureSetConvert); lua_register_player(player, "get_nearest_enemy", luaCreatureGetNearestEnemy); lua_register_player(player, "get_type", luaCreatureGetType); lua_register_player(player, "get_food", luaCreatureGetFood); lua_register_player(player, "get_health", luaCreatureGetHealth); lua_register_player(player, "get_speed", luaCreatureGetSpeed); lua_register_player(player, "get_tile_food", luaCreatureGetTileFood); lua_register_player(player, "get_tile_type", luaCreatureGetTileType); lua_register_player(player, "get_max_food", luaCreatureGetMaxFood); lua_register_player(player, "get_distance", luaCreatureGetDistance); lua_register_player(player, "set_message", luaCreatureSetMessage); lua_register_player(player, "get_hitpoints", luaCreatureGetHitpoints); lua_register_player(player, "get_attack_distance", luaCreatureGetAttackDistance); #ifdef CHEATS lua_register_player(player, "cheat_give_all", luaCreatureCheatGiveAll); #endif lua_register_player(player, "get_cpu_usage", luaGetCPUUsage); lua_register(player->L, "world_size", luaWorldSize); lua_register(player->L, "game_time", luaGameTime); lua_register(player->L, "get_koth_pos", luaGetKothPos); lua_register(player->L, "creature_exists", luaCreatureExists); lua_register(player->L, "creature_player", luaCreatureGetPlayer); lua_register(player->L, "player_exists", luaPlayerExists); lua_register(player->L, "king_player", luaKingPlayer); lua_register(player->L, "player_score", luaPlayerScore); lua_register_constant(player->L, CREATURE_IDLE); lua_register_constant(player->L, CREATURE_WALK); lua_register_constant(player->L, CREATURE_HEAL); lua_register_constant(player->L, CREATURE_EAT); lua_register_constant(player->L, CREATURE_ATTACK); lua_register_constant(player->L, CREATURE_CONVERT); lua_register_constant(player->L, CREATURE_SPAWN); lua_register_constant(player->L, CREATURE_FEED); lua_register_constant(player->L, TILE_SOLID); lua_register_constant(player->L, TILE_PLAIN); lua_register_constant(player->L, CREATURE_SPAWNED); lua_register_constant(player->L, CREATURE_KILLED); lua_register_constant(player->L, CREATURE_ATTACKED); lua_register_constant(player->L, PLAYER_CREATED); lua_pushnumber(player->L, playerno); lua_setglobal(player->L, "player_number"); // Initiale Cyclen setzen lua_set_cycles(player->L, player->max_cycles); player_init_events(player); // player.lua sourcen if (luaL_loadfile(player->L, PREFIX "player.lua")) { fprintf(stderr, "cannot load 'player.lua': %s\n", lua_tostring(player->L, -1)); goto failed; } lua_pushstring(player->L, highlevel); // starten if (lua_pcall(player->L, 1, 0, 0) != 0) { fprintf(stderr, "cannot execute 'player.lua': %s\n", lua_tostring(player->L, -1)); goto failed; } player_to_network(player, PLAYER_DIRTY_ALL, SEND_BROADCAST); num_players++; player_on_created(player); return player; failed: lua_close(player->L); player->L = NULL; return NULL; } void player_destroy(player_t *player) { creature_kill_all_players_creatures(player); client_t *client; while ((client = player->clients)) { player_detach_client(client, player); }; free(player->kill_me); lua_close(player->L); player->L = NULL; num_players--; player_to_network(player, PLAYER_DIRTY_ALIVE, SEND_BROADCAST); } void player_set_name(player_t *player, const char *name) { snprintf(player->name, sizeof(player->name), "%s", name); player->dirtymask |= PLAYER_DIRTY_NAME; } int player_num(player_t *player) { return player - players; } void player_writeto(player_t *player, const void *data, size_t size) { if (!player->clients) { assert(player->num_clients == 0); return; } client_t *client = player->clients; do { if (!player->output_client || player->output_client == client) server_writeto(client, data, size); client = client->next; } while (client != player->clients); } player_t *player_by_num(int playerno) { if (playerno < 0 || playerno >= MAXPLAYERS) return NULL; player_t *player = &players[playerno]; if (!PLAYER_USED(player)) return NULL; return player; } player_t *player_get_checked_lua(lua_State *L, int idx) { int playerno = luaL_checklong(L, idx); if (playerno < 0 || playerno >= MAXPLAYERS) luaL_error(L, "player number %d out of range", playerno); player_t *player = &players[playerno]; if (!PLAYER_USED(player)) luaL_error(L, "player %d not in use", playerno); return player; } int player_attach_client(client_t *client, player_t *player, const char *pass) { if (!client || !player) return 0; if (!PLAYER_USED(player)) return 0; // Passwort fhslca? if (strcmp(pass, player->pass)) return 0; if (client->player) { if (client->player == player) return 1; player_detach_client(client, client->player); } client->player = player; player->num_clients++; if (player->clients) { client->prev = player->clients; client->next = player->clients->next; client->next->prev = client; client->prev->next = client; } else { client->prev = client->next = player->clients = client; } assert(client->next->prev == client); assert(client->prev->next == client); assert(player->clients->next->prev == player->clients); assert(player->clients->prev->next == player->clients); return 1; } int player_detach_client(client_t *client, player_t *player) { if (!client || !player) return 0; if (!client->player) return 0; if (client->player != player) return 0; if (player->bot_output_client == client) player->bot_output_client = NULL; player->num_clients--; assert(player->num_clients >= 0); if (player->num_clients == 0) player->all_disconnected_time = real_time; client->player = NULL; if (player->num_clients == 0) { player->clients = NULL; } else { client->next->prev = client->prev; client->prev->next = client->next; player->clients = client->next; assert(client->next->next->prev == client->next); assert(client->next->prev->next == client->next); assert(player->clients->next->prev == player->clients); assert(player->clients->prev->next == player->clients); } client->next = NULL; client->prev = NULL; return 1; } int player_execute_code(player_t *player, client_t *output_client, const char *code, size_t codelen, const char *where) { int success; player->output_client = output_client; if (luaL_loadbuffer(player->L, code, codelen, where) == 0) { success = player_call_user_lua("during interactive execution", player, 0); } else { const char *msg = lua_tostring(player->L, -1); if (!msg) msg = "(error with no message)"; player_writeto(player, msg, strlen(msg)); player_writeto(player, "\r\n", 2); lua_pop(player->L, 1); success = 0; } player->output_client = NULL; return success; } void player_round() { int playerno; player_t *player = &players[0]; for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { if (!PLAYER_USED(player)) continue; // Spieler CPU cyclen zuruecksetzen. Der Spieler // kann damit sowohl seine Kreaturen steuern, als // auch Befehle ueber Netzwerk ausfuehren. lua_set_cycles(player->L, player->max_cycles); // Incremental Garbage Collection lua_gc(player->L, LUA_GCSTEP, 1); // Alle Viecher tot? if (player->num_creatures == 0) player_on_all_dead(player, game_time - player->all_dead_time); // Killen? if (player->kill_me) { player_writeto(player, player->kill_me, strlen(player->kill_me)); player_writeto(player, "\r\n", 2); player_destroy(player); continue; } // Zu wenig Score? if (player->score <= PLAYER_KICK_SCORE) { player_writeto(player, "score too low. try harder!\r\n", 28); player_destroy(player); continue; } // Kein Client mehr da & soll in diesem Fall gekickt werden? if (player->num_clients == 0 && player->no_client_kick_time && player->all_disconnected_time + player->no_client_kick_time < real_time) { player_destroy(player); continue; } } } void player_think() { int playerno; player_t *player = &players[0]; for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { if (!PLAYER_USED(player)) continue; // Player Code aufrufen lua_pushliteral(player->L, "player_think"); lua_rawget(player->L, LUA_GLOBALSINDEX); lua_pushliteral(player->L, "events"); lua_rawget(player->L, LUA_REGISTRYINDEX); player->output_client = player->bot_output_client; player_call_user_lua("during botcode execution", player, 1); player->output_client = NULL; // Events Strukur neu initialisieren player_init_events(player); } } void player_sync() { int playerno; player_t *player = &players[0]; for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { if (!PLAYER_USED(player)) continue; // Verbrauchte CPU Zeit speichern: // Dies ist die rein fuer player_think verbrauchte // Zeit. Darauf folgende Konsolenbefehle werden fuer // die Anzeige im Client nicht mehr beachtet. int newcpu = player_get_cpu_usage(player); if (newcpu != player->cpu_usage) { player->dirtymask |= PLAYER_DIRTY_CPU; player->cpu_usage = newcpu; } player_to_network(player, player->dirtymask, SEND_BROADCAST); player->dirtymask = PLAYER_DIRTY_NONE; } } void player_send_king_update(client_t *client) { // Network Sync packet_t packet; packet_init(&packet, PACKET_KOTH_UPDATE); if (king_player) packet_write08(&packet, player_num(king_player)); else packet_write08(&packet, 0xFF); server_send_packet(&packet, client); } void player_is_king_of_the_hill(player_t *player, int delta) { player_t *old_king = king_player; king_player = player; lua_pushnumber(L, player_num(player)); lua_pushnumber(L, delta); game_call_rule_handler("onKingPlayer", 2); if (king_player != old_king) player_send_king_update(SEND_BROADCAST); } void player_there_is_no_king() { player_t *old_king = king_player; king_player = NULL; game_call_rule_handler("onNoKing", 0); if (old_king) player_send_king_update(SEND_BROADCAST); } player_t *player_king() { if (king_player && PLAYER_USED(king_player)) return king_player; else return NULL; } void player_send_initial_update(client_t *client) { int playerno; player_t *player = &players[0]; for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { if (!PLAYER_USED(player)) continue; player_to_network(player, PLAYER_DIRTY_ALL, client); } player_send_king_update(client); } void player_to_network(player_t *player, int dirtymask, client_t *client) { if (dirtymask == PLAYER_DIRTY_NONE) return; packet_t packet; packet_init(&packet, PACKET_PLAYER_UPDATE); packet_write08(&packet, player_num(player)); packet_write08(&packet, dirtymask); if (dirtymask & PLAYER_DIRTY_ALIVE) packet_write08(&packet, PLAYER_USED(player)); if (dirtymask & PLAYER_DIRTY_NAME) { packet_write08(&packet, strlen(player->name)); packet_writeXX(&packet, &player->name, strlen(player->name)); } if (dirtymask & PLAYER_DIRTY_COLOR) packet_write08(&packet, player->color); if (dirtymask & PLAYER_DIRTY_CPU) packet_write08(&packet, player->cpu_usage); if (dirtymask & PLAYER_DIRTY_SCORE) packet_write16(&packet, player->score - PLAYER_KICK_SCORE); server_send_packet(&packet, client); } static int luaPlayerKill(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); free(player->kill_me); player->kill_me = strdup(luaL_checkstring(L, 2)); return 0; } static int luaPlayerNumClients(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); lua_pushnumber(L, player->num_clients); return 1; } static int luaPlayerNumCreatures(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); lua_pushnumber(L, player->num_creatures); return 1; } static int luaPlayerSpawnTime(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); lua_pushnumber(L, player->spawn_time); return 1; } static int luaPlayerCreate(lua_State *L) { player_t *player = player_create(lua_isstring(L, 1) ? luaL_checkstring(L, 1) : NULL, luaL_checkstring(L, 2), luaL_checkstring(L, 3)); if (player) { lua_pushnumber(L, player_num(player)); } else { lua_pushnil(L); } return 1; } static int luaPlayerSetName(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); player_set_name(player, luaL_checkstring(L, 2)); return 0; } static int luaPlayerSetColor(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); player_set_color(player, luaL_checklong(L, 2)); return 0; } static int luaPlayerGetName(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); lua_pushstring(L, player->name); return 1; } static int luaPlayerGetUsedMem(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); lua_pushnumber(L, lua_gc(player->L, LUA_GCCOUNT, 0) << 10 | lua_gc(player->L, LUA_GCCOUNTB, 0)); return 1; } static int luaPlayerGetCPUUsage(lua_State *L) { lua_pushnumber(L, player_get_cpu_usage(player_get_checked_lua(L, 1))); return 1; } static int luaPlayerSetScore(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); int newscore = luaL_checklong(L, 2); int diff = newscore - player->score; char buf[128]; snprintf(buf, sizeof(buf), "set to %d", newscore); player_change_score(player, diff, buf); return 0; } static int luaPlayerKillAllCreatures(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); creature_kill_all_players_creatures(player); return 0; } static int luaCreatureSpawn(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); creature_t *parent = lua_isnil(L, 2) ? NULL : creature_get_checked_lua(L, 2); int x = luaL_checklong(L, 3); int y = luaL_checklong(L, 4); creature_type type = luaL_checklong(L, 5); if (type < 0 || type >= CREATURE_TYPES) luaL_error(L, "creature type %d invalid", type); creature_t *creature = creature_spawn(player, parent, x, y, type); if (!creature) lua_pushnil(L); else lua_pushnumber(L, creature_id(creature)); return 1; } static int luaPlayerSetOutputClient(lua_State *L) { int success = 1; player_t *player = player_get_checked_lua(L, 1); if (lua_isnil(L, 2)) { player->bot_output_client = NULL; } else { client_t *output = client_get_checked_lua(L, 2); client_t *client = player->clients; do { if (client == output) { player->bot_output_client = output; goto out; } client = client->next; } while (client != player->clients); success = 0; } out: lua_pushboolean(L, success); return 1; } static int luaPlayerSetNoClientKickTime(lua_State *L) { player_get_checked_lua(L, 1)->no_client_kick_time = luaL_checklong(L, 2); return 0; } static int luaPlayerGetNoClientKickTime(lua_State *L) { lua_pushnumber(L, player_get_checked_lua(L, 1)->no_client_kick_time); return 1; } static int luaPlayerIterator(lua_State *L) { if (lua_gettop(L) == 0) { lua_pushcfunction(L, luaPlayerIterator); return 1; } int pno = lua_isnumber(L, 2) ? lua_tonumber(L, 2) + 1 : 0; while (pno >= 0 && pno < MAXPLAYERS) { if (PLAYER_USED(&players[pno])) { lua_pushnumber(L, pno); return 1; } pno++; } return 0; } static int luaPlayerExecute(lua_State *L) { player_t *player = player_get_checked_lua(L, 1); client_t *client = lua_isnumber(L, 2) ? client_get_checked_lua(L, 2) : NULL; size_t codelen; const char *code = luaL_checklstring(L, 3, &codelen); const char *name = luaL_checkstring(L, 4); lua_pushboolean(L, player_execute_code(player, client, code, codelen, name)); return 1; } int player_num_players() { return num_players; } void player_init() { memset(players, 0, sizeof(players)); lua_register(L, "player_create", luaPlayerCreate); lua_register(L, "player_num_clients", luaPlayerNumClients); lua_register(L, "player_num_creatures", luaPlayerNumCreatures); lua_register(L, "player_kill", luaPlayerKill); lua_register(L, "player_set_color", luaPlayerSetColor); lua_register(L, "player_set_name", luaPlayerSetName); lua_register(L, "player_get_name", luaPlayerGetName); lua_register(L, "player_set_score", luaPlayerSetScore); lua_register(L, "player_kill_all_creatures", luaPlayerKillAllCreatures); lua_register(L, "player_score", luaPlayerScore); lua_register(L, "player_exists", luaPlayerExists); lua_register(L, "player_spawntime", luaPlayerSpawnTime); lua_register(L, "player_change_score", luaPlayerChangeScore); lua_register(L, "player_get_used_mem", luaPlayerGetUsedMem); lua_register(L, "player_get_used_cpu", luaPlayerGetCPUUsage); lua_register(L, "player_set_output_client", luaPlayerSetOutputClient); lua_register(L, "player_set_no_client_kick_time",luaPlayerSetNoClientKickTime); lua_register(L, "player_get_no_client_kick_time",luaPlayerGetNoClientKickTime); lua_register(L, "player_execute", luaPlayerExecute); lua_register(L, "each_player", luaPlayerIterator); lua_register(L, "creature_spawn", luaCreatureSpawn); lua_register(L, "creature_get_pos", luaCreatureGetPos); lua_register(L, "creature_get_state", luaCreatureGetState); lua_register(L, "creature_get_nearest_enemy", luaCreatureGetNearestEnemy); lua_register(L, "creature_get_type", luaCreatureGetType); lua_register(L, "creature_get_food", luaCreatureGetFood); lua_register(L, "creature_get_health", luaCreatureGetHealth); lua_register(L, "creature_get_speed", luaCreatureGetSpeed); lua_register(L, "creature_get_tile_food", luaCreatureGetTileFood); lua_register(L, "creature_get_max_food", luaCreatureGetMaxFood); lua_register(L, "creature_get_distance", luaCreatureGetDistance); lua_register(L, "creature_get_hitpoints", luaCreatureGetHitpoints); lua_register(L, "creature_get_attack_distance", luaCreatureGetAttackDistance); lua_register(L, "creature_get_player", luaCreatureGetPlayer); lua_register(L, "creature_set_food", luaCreatureSetFood); lua_register(L, "creature_set_type", luaCreatureSetType); lua_register_constant(L, CREATURE_SMALL); lua_register_constant(L, CREATURE_BIG); lua_register_constant(L, CREATURE_FLYER); } void player_game_start() { int playerno; for (playerno = 0; playerno < MAXPLAYERS; playerno++) { if (PLAYER_USED(&players[playerno])) player_on_created(&players[playerno]); } } void player_shutdown() { int playerno; for (playerno = 0; playerno < MAXPLAYERS; playerno++) { if (PLAYER_USED(&players[playerno])) player_destroy(&players[playerno]); } } infon/world.h0000644000076400001440000000310410536573613013247 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef WORLD_H #define WORLD_H #include "path.h" #include "packet.h" #include "server.h" #include "common_world.h" int world_is_within_border(int x, int y); int world_walkable(int x, int y); int world_get_food(int x, int y); maptype_e world_get_type(int x, int y); int world_add_food(int x, int y, int amount); int world_food_eat(int x, int y, int amount); int world_width(); int world_height(); int world_koth_x(); int world_koth_y(); pathnode_t *world_findpath(int x1, int y1, int x2, int y2); int world_find_plain(int *x, int *y); void world_tick(); /* Network */ void world_send_initial_update(client_t *client); void world_init(); void world_shutdown(); #endif infon/client.rb0000644000076400001440000001123310536637517013560 0ustar dividuumusersrequire 'socket' require 'zlib' TCPSocket.open(ARGV[0] || 'localhost', 1234) { |socket| class << socket alias_method :orig_read, :read attr_accessor :traffic attr_accessor :compress attr_accessor :zstream attr_accessor :buf def read(x) if @compress while @buf.size < x @buf << @zstream.inflate(orig_read(1)) @traffic += 1 end ret = @buf[0...x] @buf = @buf[x..-1] else ret = orig_read(x) @traffic += x end ret end def read8 read(1)[0] end def read16 ret = read8 ret = ret & 0x7F | read8 << 7 if ret & 0x80 != 0 ret end def read32 read(4).unpack("N")[0] end def readXX(len) read(len).unpack("A*")[0] end end socket.traffic = 0 socket.buf = "" socket.compress = false socket.zstream = Zlib::Inflate.new Thread.start do last = socket.traffic loop do print "TRAFFIC: % dbyte/sec" % [socket.traffic - last] if socket.compress puts " (%d => %d)" % [socket.zstream.total_in, socket.zstream.total_out] else puts end last = socket.traffic sleep 1 end end loop do len = socket.read8 type = socket.read8 print "type=%3d len=%3d " % [type, len] case type when 0: print "player upd: " print "pno=%d " % socket.read8 print "mask=%d " % mask = socket.read8 print "alive=%s " % [socket.read8.zero? ? "quit" : "joined"] if mask & 1 != 0 print "name=%s " % socket.readXX(socket.read8) if mask & 2 != 0 print "color=%d " % socket.read8 if mask & 4 != 0 print "cpu=%d " % socket.read8 if mask & 8 != 0 print "score=%d " % (socket.read16 - 500) if mask & 16 != 0 puts when 1: puts "%d, %d => %d %d " % [socket.read8, socket.read8, socket.read8, socket.read8] when 2: puts "msg: %s " % socket.readXX(len) when 3: print "creature upd: " print "cno=%d " % socket.read16 print "mask=%d " % mask = socket.read8 if mask & 1 != 0 print "alive=%s " % [socket.read8 == 0xFF ? "dead" : "spawned %d %d,%d" % [socket.read16, socket.read16, socket.read16] ] end print "type=%d " % socket.read8 if mask & 2 != 0 if mask & 4 != 0 fh = socket.read8 print "food=%d, health=%d " % [ fh >> 4, fh & 0x0F ] end print "state=%d " % socket.read8 if mask & 8 != 0 if mask & 16 != 0 dx, dy = socket.read16, socket.read16 x = ((dx & 1) == 1 ? -1 : 1) * (dx >> 1) y = ((dy & 1) == 1 ? -1 : 1) * (dy >> 1) print "path=%d,%d => %d,%d " % [dx, dy, x, y] end print "target=%d " % socket.read16 if mask & 32 != 0 print "message=%s " % socket.readXX(socket.read8) if mask & 64 != 0 print "speed=%d " % socket.read8 if mask &128 != 0 puts when 4: puts "quit msg: %s " % socket.readXX(len) break when 5: puts "king: %d " % socket.read8 when 6: puts "world info %dx%d koth: %d,%d" % [socket.read8, socket.read8, socket.read8, socket.read8] when 7: puts "smile %d" % socket.read16 when 8: puts "game info time:%d" % socket.read32 when 9: puts "round tick, delta=%d" % socket.read8 when 10: puts "intermission: %s" % socket.readXX(len) when 32: socket.write("guiclient\n") puts "welcome: %s" % socket.read(len).delete("\n").strip when 254: puts "compression start" socket.compress = true when 255: puts "server protocol version %d" % socket.read8 else puts "???: unknown packet type #{type}" socket.readXX(len) end end } infon/player.h0000644000076400001440000000622510603314646013415 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PLAYER_H #define PLAYER_H #include #include #include "server.h" #include "packet.h" #include "common_player.h" typedef struct player_s { char name[16]; char pass[16]; int color; lua_State *L; int num_creatures; int num_clients; client_t *clients; client_t *output_client; // if set, output is limited to this client client_t *bot_output_client; // output client used during botcode execution int score; int spawn_time; int all_dead_time; int all_disconnected_time; int no_client_kick_time; int max_cycles; int cpu_usage; int max_mem; int mem_enforce; char *kill_me; unsigned char dirtymask; } player_t; typedef enum { CREATURE_SPAWNED, CREATURE_KILLED, CREATURE_ATTACKED, PLAYER_CREATED } vm_event; struct creature_s; int player_num(player_t *player); player_t *player_by_num(int playerno); player_t *player_get_checked_lua(lua_State *L, int idx); int player_attach_client(client_t *client, player_t *player, const char *pass); int player_detach_client(client_t *client, player_t *player); void player_on_creature_spawned(player_t *player, struct creature_s *creature, struct creature_s *parent); void player_on_creature_killed(player_t *player, struct creature_s *victim, struct creature_s *killer); void player_on_creature_attacked(player_t *player, struct creature_s *victim, struct creature_s *attacker); void player_writeto(player_t *player, const void *data, size_t size); void player_set_name(player_t *player, const char *name); player_t *player_create(const char *name, const char *pass, const char *highlevel); void player_round(); void player_think(); void player_sync(); void player_is_king_of_the_hill(player_t *player, int delta); void player_there_is_no_king(); player_t *player_king(); int player_num_players(); /* Network */ void player_send_initial_update(client_t *client); void player_to_network(player_t *player, int dirtymask, client_t *client); void player_init(); void player_game_start(); void player_shutdown(); #endif infon/global.h0000644000076400001440000000323110552756360013361 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef GLOBAL_H #define GLOBAL_H #ifdef EVENT_NAME #define GAME_NAME "Infon Battle Arena (" EVENT_NAME " Edition)" #else #define GAME_NAME "Infon Battle Arena " REVISION #endif // Pfadsuche, bei der mehrere beieinanderliegende // Tiles zu einem Area zusammengefasst werden. Die // Pfadsuche verwendet dann diese Areas fuer die // Pfadsuche. Dies ist schneller und die gefundenen // Pfade sehen natuerlicher aus. Allerdings ergeben // sich gelegentlich aufgrund der zusammenfassung // der Tiles komische Pfade. #define PATHFIND_AREA_MERGE // Netzwerk Protokoll #define PROTOCOL_VERSION 7 // do not open stdin (console) client? // #define NO_CONSOLE_CLIENT // warn if no coredumps possible // #define WARN_COREDUMP #ifdef BUILTIN_RENDERER #define DEFAULT_RENDERER BUILTIN_RENDERER #endif #ifndef DEFAULT_RENDERER #define DEFAULT_RENDERER sdl_gui #endif #endif infon/server.lua0000644000076400001440000004557010603314646013767 0ustar dividuumusers--[[ Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ]]-- ----------------------------------------------------------- -- Client Handling Code ----------------------------------------------------------- function Client:joinmenu() if not self:rate_limit("joining", 3) then return end self:writeln("------------------------------") local numplayers = 0 for pno in each_player() do numplayers = numplayers + 1 self:writeln(string.format("%3d - %s", pno, player_get_name(pno))) end if numplayers == 0 then self:writeln("no one here") end self:writeln("------------------------------") local playerno local password = nil if numplayers == 0 then playerno = "" else self:write("enter or press enter for new player: ") playerno = self:readln() end if playerno == "" then self:write("password for new player: ") password = self:readln() if password == "" then self:writeln("you cannot join with an empty password.") return end if config.disable_joining then self:writeln("joining is currently disabled: " .. config.disable_joining) return end playerno = player_create(nil, password, self.highlevel) if playerno == nil then self:writeln("cannot join: full?") return end stats.num_players = stats.num_players + 1 else if not isnumber(playerno) then self:writeln("the player number must be numeric!") return end self:write("password for player " .. playerno .. ": ") password = self:readln() end local errormsg = self:attach_to_player(playerno, password) if errormsg then self:writeln("could not attach to player " .. playerno .. ": " .. errormsg) else self:writeln("joined. player " .. playerno .. " has now " .. player_num_clients(playerno) .. " client(s)") end end function Client:partmenu() local playerno = self:get_player() local disconnect_time = player_get_no_client_kick_time(playerno) local warning = player_num_clients(playerno) == 1 and disconnect_time ~= 0 and string.format(" reattach within %d seconds or your player will be killed.", disconnect_time / 1000) or "" self:detach() self:writeln("detached from player " .. playerno .. "." .. warning) end function Client:namemenu() if not self:rate_limit("changing name", 2) then return end self:write("Player Name: ") if not self:set_name(self:readln()) then self:writeln("cannot set name") end end function Client:colormenu() if not self:rate_limit("changing color", 2) then return end self:write("color (0 - 255): ") local color = self:readln() if not isnumber(color) then self:writeln("not numeric") else self:set_color(color) end end function Client:luamenu() while true do local paste = self:nextpaste() self:write("lua(" .. self:paste_name(paste) .. ")> ") local line = self:readln() if line == "" then break elseif line:match("^=") then self:execute('print(' .. line:sub(2) .. ')', self:paste_full_name(paste)) else self:execute(line, self:paste_full_name(paste)) end end end function Client:batchmenu() local paste = self:nextpaste() self:writeln("enter your lua code for paste " .. self:paste_name(paste) .. ". '.' ends input.") local code = "" while true do local input = self:readln() if input == "." then break else code = code .. input .. "\n" end if #code > 262144 then self:writeln("your code is too large.") return end end self:execute(code, self:paste_full_name(paste)) end function Client:hexbatchmenu() local paste = self:nextpaste() self:writeln("enter your hex-encoded lua code for paste " .. self:paste_name(paste) .. ". '.' ends input") local code = "" while true do local input = self:readln() if input == "." then break else code = code .. input end if #code > 262144 then self:writeln("your code is too large.") return end end self:execute(hex_decode(code), self:paste_full_name(paste)) end function Client:killmenu() self:write("kill all your creatures? [y/N] ") if self:readln() == "y" then self:kill() end end function Client:highmenu() self:writeln("------------------------------") for n, file in ipairs(config.highlevel) do self:writeln(string.format("%3d - %-s", n, file)) end self:writeln("------------------------------") self:write("choose your api: ") local num = self:readln() if not isnumber(num) then self:writeln("not numeric") return end local api = config.highlevel[tonumber(num)] if not api then self:writeln("no highlevel api " .. num) else self.highlevel = api self:writeln("highlevel api set to '" .. api .. "'") end end function Client:shell() local ok = false if self.authorized then ok = true else if not config.debugpass or config.debugpass == "" then self:writeln("password must be set in config.lua") return end if not self:rate_limit("entering the shell", 5) then return end self:write("password: ") ok = self:readln() == config.debugpass end if ok then self.authorized = true while true do self:write("admin("..self.fd..")> ") local code = self:readln() if code == "" then break elseif code == "?" then admin_help() else local chunk, msg = loadstring(code, "input from client '" .. self.addr .. "'") if not chunk then self:writeln(msg .. ". use '?' for help") else local ok, msg = xpcall(chunk, debug.traceback) if not ok then self:writeln(msg) end end end end else self.failed_shell = self.failed_shell + 1 if self.failed_shell > 5 then self:kick_ban("you tried to hack the shell. banning 5 minutes.", 5 * 60) elseif self.failed_shell == 5 then self:writeln("don't try again or you will be banned!") else self:writeln("go away!") end end end function Client:showscores() local players = {} for pno in each_player() do table.insert(players, { num = pno, clients = player_num_clients(pno), name = player_get_name(pno), score = player_score(pno), creatures = player_num_creatures(pno), age = (game_time() - player_spawntime(pno)) / 1000 / 60, mem = player_get_used_mem(pno), cpu = player_get_used_cpu(pno) }) end table.sort(players, function (a,b) return a.score > b.score end) self:writeln("Scores | Creatures | Time | Mem | CPU | #Cl | No | Name") self:writeln("-------+-----------+------+---------+-----+-----+----+-------------") for i,player in ipairs(players) do self:writeln(string.format("%s%5d | %9d | %4dm| %7d | %3d%%| %3d | %2d | %s", self:get_player() == player.num and "*" or " ", player.score, player.creatures, player.age, player.mem, player.cpu, player.clients, player.num, player.name)) end self:writeln("-------+-----------+------+---------+-----+-----+----+-------------") end function Client:nokick() if not config.nokickpass or config.nokickpass == "" then self:writeln("no kick mode disabled. sorry") else if not self:rate_limit("no kicking", 3) then return end self:write("enter nokick password: ") if self:readln() == config.nokickpass then player_set_no_client_kick_time(self:get_player(), 0) self:writeln("no-client kicking disabled. hurray!") else self:writeln("wrong password") end end end function Client:info() local clients, players, creatures = server_info() self:writeln("-------------------------------------------------") self:writeln("Server Information") self:writeln("-------------------+-----------------------------") self:writeln("server name | " .. (config.servername or 'default server')) self:writeln("version | " .. GAME_NAME) self:writeln("uptime | " .. string.format("%ds", real_time())) self:writeln("cpu usage | " .. os.clock() .. "s") self:writeln("memory | " .. string.format("%d", collectgarbage("count")) .. "kb") self:writeln("traffic | " .. server_get_traffic()) self:writeln("-------------------+------------------------------") self:writeln("accepted clients | " .. stats.num_clients) self:writeln("refused clients | " .. stats.num_refused) self:writeln("joined players | " .. stats.num_players) self:writeln("played maps | " .. stats.num_maps) self:writeln("code executions | " .. stats.num_exec) self:writeln("-------------------+------------------------------") self:writeln("current players | " .. players) self:writeln("current clients | " .. clients) self:writeln("current creatures | " .. creatures) self:writeln("-------------------+------------------------------") local w, h = world.level_size() self:writeln("rules | " .. config.rules) self:writeln("map | " .. map .. " (" .. w .. "x" .. h .. ")") self:writeln("game time | " .. string.format("%ds", game_time() / 1000)) self:writeln("time limit | " .. (config.time_limit and string.format("%ds", config.time_limit / 1000) or "none")) self:writeln("score limit | " .. (config.score_limit or "none")) self:writeln("-------------------------------------------------") end function Client:menu_header() self:writeln("-------------------------------------------------") self:writeln(GAME_NAME) self:writeln("visit http://infon.dividuum.de/ for documentation") self:writeln("-------------------------------------------------") end function Client:menu_footer() self:writeln("-------------------------------------------------") end function Client:mainmenu() while true do self:write(self.prompt) local input = self:readln() if input == "q" then self:disconnect("quitting") break elseif input == "s" then self:showscores() elseif input == "prompt" then self:write("new prompt: ") self.prompt = self:readln() elseif input == "shell" then self:shell() elseif input == "colorize" then self:write("pre string: ") local pre = self:readln() self:write("post string: ") local post = self:readln() self.pre_string, self.post_string = pre, post elseif input == "info" then self:info() elseif input == "" then -- nix elseif self:get_player() then if input == "p" then self:partmenu() elseif input == "l" then self:luamenu() elseif input == "c" then self:colormenu() elseif input == "b" then self:batchmenu() elseif input == "bb" then self:hexbatchmenu() elseif input == "n" then self:namemenu() elseif input == "r" then self:execute("restart()", "restart") elseif input == "i" then self:execute("info()", "info") elseif input:match("^[0-9]$") then self:execute("onInput" .. input .. "()", "calling onInput" .. input) elseif input == "k" then self:killmenu() elseif input == "nk" then self:nokick() elseif input == "lio" then self:write("limit interactive output to local connection? [Y/n] ") self.local_output = self:readln() ~= "n" elseif input == "lbo" then self:write("limit botcode output to this connection? [y/N] ") local bot_output_client = self:readln() == "y" and self.fd or nil player_set_output_client(self:get_player(), bot_output_client) -- elseif input == "fwd" then -- self:write("forward unknown commands to onCommand function? [y/N] ") -- self.forward_unknown = self:readln() == "y" elseif input == "?" then self:menu_header() self:writeln("n - ame") self:writeln("c - olor") self:writeln("p - art game") self:writeln("l - ua shell") self:writeln("b - atch. enter bunch of lua code") self:writeln("r - estart all your creatures") self:writeln("i - nformation on your creatures") self:writeln("k - ill me") self:writeln("s - how scores") self:writeln("q - uit use '??' for more help") self:menu_footer() elseif input == "??" then self:menu_header() self:writeln("lbo - limit bot output") self:writeln("lio - limit interactive output") -- self:writeln("fwd - set unknown command forward") self:writeln("prompt - change prompt") self:writeln("nk - disable no-client kicking") self:writeln("bb - hex batch (load precompiled code)") self:writeln("0 - 9 - execute onInputX()") self:writeln("info - server information") if self.forward_unknown then self:writeln("") self:writeln("Any other input will be passed to the onCommand") self:writeln("function defined within your lua vm.") end self:menu_footer() elseif self.forward_unknown then if not self:execute("onCommand(" .. string.format("%q", input) .. ")", "onCommand") then self:writeln("huh? use '?' for help") end else self:writeln("huh? use '?' for help") end else if input == "j" then self:joinmenu() elseif input == "hl" then self:highmenu() elseif input == "?" then self:menu_header() if config.disable_joining then self:writeln("j - oin game (currently disabled)") else self:writeln("j - oin game") end self:writeln("s - how scores") self:writeln("q - uit use '??' for more help") self:menu_footer() elseif input == "??" then self:menu_header() self:writeln("hl - choose highlevel api") self:writeln("info - server information") self:menu_footer() else self:writeln("huh? use '?' for help") end end end end function Client:gui_mode() self:turn_into_guiclient() while true do self:readln() end end function Client:telnet_mode() self:centerln("Hello " .. self.addr .. "!") self:centerln("Welcome to " .. GAME_NAME) self:writeln("") if config.banner then self:write(config.banner:match("\r\n") and config.banner or config.banner:gsub("\n", "\r\n")) self:writeln("") end self:writeln("enter '?' for help") self:mainmenu() end function Client:www_mode() if config.verbose_http_error then self:writeln() self:writeln("This is an infon game server, not a webserver.") self:writeln("You'll need a telnet client to access this game.") self:writeln("See http://infon.dividuum.de for more information") self:writeln() self:info() self:writeln() self:writeln() self:showscores() self:writeln() self:writeln() end self:disconnect("please use telnet") end function Client:handler() if self.addr == "special:console" then self.authorized = true self:writeln("") self:telnet_mode() else self:welcome("Press ") local mode = self:readln() if mode == "guiclient" then self:gui_mode() elseif mode:match("^GET") then self:www_mode() else self:telnet_mode() end end end function ServerMain() scroller_add("Welcome to " .. GAME_NAME .. "!") local info_time = game_time() local ping_time = -10000 while true do -- Add info message to the scroller if game_time() > info_time + 10000 then info_time = game_time() if config.join_info and config.join_info ~= "" then scroller_add(config.join_info) end end -- Announce this server to the master server. if config.master_ip and real_time() > ping_time + 60 then ping_time = real_time() server_ping_master(config.master_ip, config.master_port or 1234, config.servername or 'default server') end coroutine.yield() end end infon/server.c0000644000076400001440000004521310603314646013422 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "infond.h" #include "server.h" #include "packet.h" #include "global.h" #include "player.h" #include "world.h" #include "listener.h" #include "misc.h" #include "game.h" #include "creature.h" #include "pinger.h" #define CLIENT_USED(client) ((client)->in_buf) static client_t *guiclients = NULL; static client_t clients[MAXCLIENTS]; static int num_clients = 0; static client_t *output_client = NULL; static int traffic = 0; static void server_readable(int fd, short event, void *arg); static void server_writable(int fd, short event, void *arg); int client_num(client_t *client) { return client - clients; } client_t *server_accept(int fd, const char *address) { if (fd >= MAXCLIENTS) { fprintf(stderr, "cannot accept() new incoming connection: file descriptor too large\n"); return NULL; } memset(&clients[fd], 0, sizeof(client_t)); client_t *client = &clients[fd]; // File Writer wird leicht unterschiedlich behandelt client->is_file_writer = strstr(address, "special:file") == address; // Non Blocking setzen if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr, "cannot set accept()ed socket nonblocking: %s\n", strerror(errno)); return NULL; } // Soll Verbindung angenommen werden? lua_pushliteral(L, "on_new_client"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushstring(L, address); if (lua_pcall(L, 1, 2, 0) != 0) { fprintf(stderr, "error calling on_new_client: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); return NULL; } if (!lua_toboolean(L, -2)) { size_t len; const char *msg = lua_tolstring(L, -1, &len); write(fd, msg, len); lua_pop(L, 2); return NULL; } lua_pop(L, 2); // Libevent aktivieren event_set(&client->rd_event, fd, EV_READ | EV_PERSIST, server_readable, &client->rd_event); event_set(&client->wr_event, fd, EV_WRITE , server_writable, &client->wr_event); client->in_buf = evbuffer_new(); client->out_buf = evbuffer_new(); client->compress = 0; client->kill_me = NULL; client->player = NULL; client->next = NULL; client->prev = NULL; client->is_gui_client = 0; client->next_gui = NULL; client->prev_gui = NULL; num_clients++; // Annehmen lua_pushliteral(L, "on_client_accepted"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushnumber(L, fd); lua_pushstring(L, address); if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error calling on_client_accepted: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } if (!client->is_file_writer) event_add(&client->rd_event, NULL); return client; } static void server_readable(int fd, short event, void *arg) { client_t *client = &clients[fd]; // Der Client wurde 'extern' gekickt, allerdings noch // nicht entfernt. Dann wird dieser Readcallback aufgerufen, // sollte allerdings nichts mehr machen. if (client->kill_me) return; int ret = evbuffer_read(client->in_buf, fd, 128); if (ret < 0) { server_destroy(client, strerror(errno)); } else if (ret == 0) { server_destroy(client, "eof reached"); } else if (EVBUFFER_LENGTH(client->in_buf) > 8192) { server_destroy(client, "line too long. go away."); } else { char *line; while ((line = evbuffer_readline(client->in_buf))) { lua_pushliteral(L, "on_client_input"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushnumber(L, fd); lua_pushstring(L, line); free(line); // Cycles fuer die Verarbeitung hochsetzen lua_set_cycles(L, 0xFFFFFF); // Input verarbeiten output_client = client; if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error calling on_client_input: %s\n", lua_tostring(L, -1)); server_writeto(client, lua_tostring(L, -1), lua_strlen(L, -1)); lua_pop(L, 1); } output_client = NULL; // Kill Me Flag waehrend Aufruf von on_client_input // gesetzt? Direkt rausschmeissen! if (client->kill_me) { server_destroy(client, client->kill_me); return; } } } } static void server_flush_compression(client_t *client) { if (!client->compress) return; char buf[1024]; client->strm.next_in = NULL; client->strm.avail_in = 0; do { client->strm.next_out = (unsigned char*)buf; client->strm.avail_out = sizeof(buf); if (deflate(&client->strm, Z_SYNC_FLUSH) != Z_OK) { fprintf(stderr, "urgh. deflate (Z_SYNC_FLUSH) didn't return Z_OK"); // XXX: handle } evbuffer_add(client->out_buf, buf, sizeof(buf) - client->strm.avail_out); } while (client->strm.avail_out == 0); } static void server_writable(int fd, short event, void *arg) { client_t *client = &clients[fd]; #ifndef NO_CONSOLE_CLIENT // HACK um die Ausgabe des Consolenclients an // stdout statt stdin zu schicken. if (fd == STDIN_FILENO) fd = STDOUT_FILENO; #endif // Kompressionsrest flushen server_flush_compression(client); // Schreiben int ret = evbuffer_write(client->out_buf, fd); if (ret < 0) { server_destroy(client, strerror(errno)); } else if (ret == 0) { server_destroy(client, "null write?"); } else { if (EVBUFFER_LENGTH(client->out_buf) > 0) event_add(&client->wr_event, NULL); } } void server_start_compression(client_t *client) { // Kompression bereits aktiviert? if (client->compress) return; // Demos sind immer unkomprimiert. Eine Kompression ueber // die erstellte Datei macht wesentlich mehr Sinn. if (client->is_file_writer) return; client->strm.zalloc = Z_NULL; client->strm.zfree = Z_NULL; client->strm.opaque = NULL; if (deflateInit(&client->strm, 9) != Z_OK) { fprintf(stderr, "cannot alloc new zstream\n"); return; } packet_t packet; packet_init(&packet, PACKET_START_COMPRESS); server_send_packet(&packet, client); client->compress = 1; } void server_writeto(client_t *client, const void *data, size_t size) { if (size == 0) return; traffic += size; // Fileclients werden direkt ueber write abgewickelt. if (client->is_file_writer) { write(client_num(client), data, size); return; } if (EVBUFFER_LENGTH(client->out_buf) > 1024*1024) return; if (client->compress) { char buf[1024]; client->strm.next_in = (void*)data; // not const? client->strm.avail_in = size; while (client->strm.avail_in > 0) { client->strm.next_out = (unsigned char*)buf; client->strm.avail_out = sizeof(buf); int ret = deflate(&client->strm, 0); if (ret != Z_OK) { fprintf(stderr, "urgh. deflate didn't return Z_OK: %d\n", ret); // XXX: handle } evbuffer_add(client->out_buf, buf, sizeof(buf) - client->strm.avail_out); } } else { evbuffer_add(client->out_buf, (void*)data, size); } event_add(&client->wr_event, NULL); } void server_writeto_all_gui_clients(const void *data, size_t size) { client_t *client = guiclients; if (client) do { server_writeto(client, data, size); client = client->next_gui; } while (client != guiclients); } void server_send_packet(packet_t *packet, client_t *client) { packet->len = packet->offset; if (!client) server_writeto_all_gui_clients(packet, PACKET_HEADER_SIZE + packet->len); else server_writeto(client, packet, PACKET_HEADER_SIZE + packet->len); } void server_destroy(client_t *client, const char *reason) { int fd = client_num(client); lua_pushliteral(L, "on_client_close"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushnumber(L, fd); lua_pushstring(L, reason); if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error calling on_client_close: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } // Quitmeldung senden if (client->is_gui_client) { packet_t packet; packet_init(&packet, PACKET_QUIT_MSG); packet_writeXX(&packet, reason, strlen(reason)); server_send_packet(&packet, client); } else { server_writeto(client, "connection terminated: ", 23); server_writeto(client, reason, strlen(reason)); server_writeto(client, "\r\n", 2); } // Kompressionsrest flushen server_flush_compression(client); // Rest rausschreiben (hier keine Fehlerbehandlung mehr, da eh egal). // Bei Filewritern muss nichts geschrieben werden, da deren Daten // immer direkt rausgeschrieben werden. if (!client->is_file_writer) evbuffer_write(client->out_buf, fd); evbuffer_free(client->in_buf); evbuffer_free(client->out_buf); free(client->kill_me); if (client->compress) deflateEnd(&client->strm); event_del(&client->rd_event); event_del(&client->wr_event); client->in_buf = NULL; client->out_buf = NULL; if (client->player) player_detach_client(client, client->player); assert(client->next == NULL); assert(client->prev == NULL); if (client->is_gui_client) { if (client->next_gui == client) { assert(client->prev_gui == client); guiclients = NULL; } else { client->next_gui->prev_gui = client->prev_gui; client->prev_gui->next_gui = client->next_gui; guiclients = client->next_gui; } } num_clients--; #ifndef NO_CONSOLE_CLIENT if (fd != STDIN_FILENO) #endif close(fd); } static void initial_update(client_t *client) { // Protokoll Version senden packet_t packet; packet_init(&packet, PACKET_HANDSHAKE); packet_write08(&packet, PROTOCOL_VERSION); server_send_packet(&packet, client); server_start_compression(client); game_send_initial_update(client); world_send_initial_update(client); player_send_initial_update(client); creature_send_initial_update(client); } static void client_turn_into_gui_client(client_t *client) { assert(!client->is_gui_client); client->is_gui_client = 1; if (guiclients) { client->prev_gui = guiclients; client->next_gui = guiclients->next_gui; client->next_gui->prev_gui = client; client->prev_gui->next_gui = client; } else { client->prev_gui = client->next_gui = guiclients = client; } initial_update(client); } client_t *server_start_file_writer(const char *filename) { int fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC|O_EXCL, 0644); if (fd < 0) return NULL; static char address[512]; snprintf(address, sizeof(address), "special:file:%s", filename); return server_accept(fd, address); } client_t *client_get_checked_lua(lua_State *L, int idx) { int clientno = luaL_checklong(L, idx); if (clientno < 0 || clientno >= MAXCLIENTS) luaL_error(L, "client number %d out of range", clientno); client_t *client = &clients[clientno]; if (!CLIENT_USED(client)) luaL_error(L, "client %d not in use", clientno); return client; } static int luaStartFileWriter(lua_State *L) { const char *file = luaL_checkstring(L, 1); int one_game = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : 1; int is_gui_client = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : 1; client_t *filewriter = server_start_file_writer(file); if (!filewriter) luaL_error(L, "cannot start file %s", file); if (is_gui_client) client_turn_into_gui_client(filewriter); if (one_game) filewriter->kick_at_end_of_game = one_game; lua_pushnumber(L, client_num(filewriter)); return 1; } static int luaClientWrite(lua_State *L) { size_t msglen; const char *msg = luaL_checklstring(L, 2, &msglen); client_t *client = client_get_checked_lua(L, 1); // Nur schreiben, falls der Client kein GUI Client if (!client->is_gui_client) server_writeto(client, msg, msglen); return 0; } static int luaClientAttachToPlayer(lua_State *L) { lua_pushboolean(L, player_attach_client(client_get_checked_lua(L, 1), player_get_checked_lua(L, 2), luaL_checkstring(L, 3))); return 1; } static int luaClientDetachFromPlayer(lua_State *L) { lua_pushboolean(L, player_detach_client(client_get_checked_lua(L, 1), player_get_checked_lua(L, 2))); return 1; } static int luaClientMakeGuiClient(lua_State *L) { client_turn_into_gui_client(client_get_checked_lua(L, 1)); return 0; } static int luaClientIsGuiClient(lua_State *L) { lua_pushboolean(L, client_get_checked_lua(L, 1)->is_gui_client); return 1; } static int luaClientPlayerNumber(lua_State *L) { client_t *client = client_get_checked_lua(L, 1); if (!client->player) { lua_pushnil(L); } else { lua_pushnumber(L, player_num(client->player)); } return 1; } static int luaClientDisconnect(lua_State *L) { client_t *client = client_get_checked_lua(L, 1); const char *reason = luaL_checkstring(L, 2); free(client->kill_me); client->kill_me = strdup(reason); return 0; } static int luaClientPrint(lua_State *L) { // No output client set? => Discard if (!output_client || !CLIENT_USED(output_client)) return 0; int n=lua_gettop(L); for (int i=1; i <= n; i++) { if (i > 1) server_writeto(output_client, "\t", 1); if (lua_isstring(L,i)) server_writeto(output_client, lua_tostring(L,i), lua_strlen(L, i)); else if (lua_isnil(L,i)) server_writeto(output_client, "nil", 3); else if (lua_isboolean(L,i)) lua_toboolean(L,i) ? server_writeto(output_client, "true", 4): server_writeto(output_client, "false", 5); else { char buffer[128]; snprintf(buffer, sizeof(buffer), "%s:%p", lua_typename(L,lua_type(L,i)), lua_topointer(L,i)); server_writeto(output_client, buffer, strlen(buffer)); } } server_writeto(output_client, "\r\n", 2); return 0; } static int luaGetTraffic(lua_State *L) { lua_pushnumber(L, traffic); return 1; } static int luaSetupListener(lua_State *L) { lua_pushboolean(L, listener_init(luaL_checkstring(L, 1), luaL_checklong(L, 2))); return 1; } static int luaPingMaster(lua_State *L) { ping_master(luaL_checkstring(L, 1), luaL_checklong(L, 2), luaL_checkstring(L, 3), server_num_clients(), player_num_players(), creature_num_creatures()); return 0; } static int luaServerInfo(lua_State *L) { lua_pushnumber(L, server_num_clients()); lua_pushnumber(L, player_num_players()); lua_pushnumber(L, creature_num_creatures()); return 3; } void server_tick() { lua_set_cycles(L, 0xFFFFFF); lua_pushliteral(L, "server_tick"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error calling server_tick: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } event_loop(EVLOOP_NONBLOCK); // Ungefaehr jede Sekunde alle zu kickenden Clients entfernen. static int kicktick = 0; if (++kicktick % 10 == 0) { int clientno; for (clientno = 0; clientno < MAXCLIENTS; clientno++) { if (!CLIENT_USED(&clients[clientno])) continue; if (clients[clientno].kill_me) server_destroy(&clients[clientno], clients[clientno].kill_me); } } } int server_num_clients() { return num_clients; } void server_init() { #ifdef WIN32 WSADATA wsa; if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) die("WSAStartup failed"); #endif event_init(); memset(clients, 0, sizeof(clients)); lua_register(L, "client_write", luaClientWrite); lua_register(L, "client_attach_to_player", luaClientAttachToPlayer); lua_register(L, "client_detach_from_player",luaClientDetachFromPlayer); lua_register(L, "client_make_guiclient", luaClientMakeGuiClient); lua_register(L, "client_is_gui_client", luaClientIsGuiClient); lua_register(L, "client_player_number", luaClientPlayerNumber); lua_register(L, "client_disconnect", luaClientDisconnect); lua_register(L, "client_print", luaClientPrint); lua_register(L, "cprint", luaClientPrint); lua_register(L, "server_start_writer", luaStartFileWriter); lua_register(L, "server_get_traffic", luaGetTraffic); lua_register(L, "server_ping_master", luaPingMaster); lua_register(L, "server_info", luaServerInfo); lua_register(L, "setup_listener", luaSetupListener); } void server_game_end() { int clientno; for (clientno = 0; clientno < MAXCLIENTS; clientno++) { if (CLIENT_USED(&clients[clientno]) && clients[clientno].kick_at_end_of_game) server_destroy(&clients[clientno], "game ended"); } } void server_shutdown() { int clientno; for (clientno = 0; clientno < MAXCLIENTS; clientno++) { if (CLIENT_USED(&clients[clientno])) server_destroy(&clients[clientno], "server shutdown"); } listener_shutdown(); #ifdef WIN32 WSACleanup(); #endif } infon/game.c0000644000076400001440000001721510603314646013026 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include "scroller.h" #include "world.h" #include "global.h" #include "player.h" #include "creature.h" #include "misc.h" static int should_end_game = 0; static struct timeval game_start; static time_t server_start; static char intermission[256] = {0}; static int realtime = 1; static int get_tick(const struct timeval *ref) { struct timeval now; gettimeofday(&now , NULL); return (now.tv_sec - ref->tv_sec) * 1000 + (now.tv_usec - ref->tv_usec) / 1000; } void game_send_info(client_t *client) { packet_t packet; packet_init(&packet, PACKET_GAME_INFO); packet_write32(&packet, game_time); server_send_packet(&packet, client); } void game_send_round_info(client_t *client, int delta) { packet_t packet; packet_init(&packet, PACKET_ROUND); packet_write08(&packet, delta); server_send_packet(&packet, client); } void game_send_intermission(client_t *client) { packet_t packet; packet_init(&packet, PACKET_INTERMISSION); packet_writeXX(&packet, intermission, strlen(intermission)); server_send_packet(&packet, client); } void game_send_initial_update(client_t *client) { game_send_info(client); game_send_intermission(client); } void game_call_rule_handler(const char *name, int params) { lua_pushliteral(L, "rules_call"); // arg* 'rules_call' lua_rawget(L, LUA_GLOBALSINDEX); // arg* rules_call lua_insert(L, -1 - params); // rules_call arg* lua_pushstring(L, name); // rules_call arg* name lua_insert(L, -1 - params); // rules_call name arg* if (lua_pcall(L, 1 + params, 0, 0) != 0) { fprintf(stderr, "error calling rules_call: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } } static int luaGameEnd(lua_State *L) { should_end_game = 1; return 0; } static int luaGameTime(lua_State *L) { lua_pushnumber(L, game_time); return 1; } static int luaRealTime(lua_State *L) { lua_pushnumber(L, real_time); return 1; } static int luaScrollerAdd(lua_State *L) { add_to_scroller(luaL_checkstring(L, 1)); return 0; } static int luaShutdown(lua_State *L) { game_exit = 1; return 0; } static int luaSetRealtime(lua_State *L) { realtime = lua_toboolean(L, 1); return 0; } static int luaSetPaused(lua_State *L) { game_paused = lua_toboolean(L, 1); return 0; } static int luaGameIntermission(lua_State *L) { snprintf(intermission, sizeof(intermission), "%s", luaL_checkstring(L, 1)); game_send_intermission(SEND_BROADCAST); return 0; } static int luaHexDecode(lua_State *L) { size_t left; const char *ptr = luaL_checklstring(L, 1, &left); luaL_Buffer out; luaL_buffinit(L, &out); int hi = 1; char cur = 0; while (left > 0) { int val = -1; switch (*ptr) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val = *ptr - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': val = *ptr - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': val = *ptr - 'A' + 10; break; } ptr++; left--; if (val < 0) continue; if (hi) { cur = val << 4; } else { luaL_addchar(&out, cur | val); } hi ^= 1; } luaL_pushresult(&out); return 1; } void game_init() { server_start = time(NULL); lua_register(L, "game_end", luaGameEnd); lua_register(L, "game_time", luaGameTime); lua_register(L, "real_time", luaRealTime); lua_register(L, "set_intermission", luaGameIntermission); lua_register(L, "scroller_add", luaScrollerAdd); lua_register(L, "hex_decode", luaHexDecode); lua_register(L, "set_realtime", luaSetRealtime); lua_register(L, "set_paused", luaSetPaused); lua_register(L, "shutdown", luaShutdown); lua_register_constant (L, MAXPLAYERS); lua_register_string_constant(L, GAME_NAME); } void game_one_game() { should_end_game = 0; game_time = 0; // Zeitinfo an Client game_send_info(SEND_BROADCAST); // Regeln laden lua_pushliteral(L, "rules_init"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error calling rules_init: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } // Karte laden world_init(); // Alle Viecher tot. vm_id = 0 creature_init(); // Initialer Worldtick. ruft level_init und ersten level_tick auf. world_tick(); // Beginn der Zeitrechnung... int lasttick = 0; gettimeofday(&game_start, NULL); // onPlayerCreated Event an Rules, PLAYER_CREATED an VM player_game_start(); // Spiel gestartet lua_pushliteral(L, "on_game_started"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error calling on_game_started: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } // Rule Handler game_call_rule_handler("onNewGame", 0); while (!game_exit && !should_end_game) { int tick = get_tick(&game_start); int delta; if (realtime) { delta = tick - lasttick; if (delta < 0 || delta > 200) { // Timewarp? lasttick = tick; continue; } else if (delta < 100) { usleep(max(95000 - delta * 1000, 1000)); continue; } } else { delta = 100; } lasttick = tick; // Realtime update real_time = time(NULL) - server_start; // GC lua_gc(L, LUA_GCSTEP, 1); if (!game_paused) { // Runde starten game_send_round_info(SEND_BROADCAST, delta); // Rule Handler game_call_rule_handler("onRound", 0); // World Zeugs world_tick(); } player_round(); if (!game_paused) { // Spielerprogramme ausfuehren player_think(); } player_sync(); if (!game_paused) { // Viecher bewegen creature_moveall(delta); // Zeit weiterlaufen lassen game_time += delta; } // IO Lesen/Schreiben server_tick(); } // Spiel beendet lua_pushliteral(L, "on_game_ended"); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error calling on_game_ended: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); } server_game_end(); creature_shutdown(); world_shutdown(); } infon/creature.c0000644000076400001440000007370210603314646013732 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include "infond.h" #include "global.h" #include "creature.h" #include "player.h" #include "world.h" #include "map.h" #include "misc.h" static creature_t creatures[MAXCREATURES]; static int num_creatures = 0; #define CREATURE_USED(creature) (!!((creature)->player)) #define HASHTABLE_SIZE ((MAXCREATURES) * 4) static creature_t *creature_hash[HASHTABLE_SIZE] = {0}; #define HASHVALUE(id) ((id) % (HASHTABLE_SIZE)) static int next_free_vm_id = 0; static creature_t *creature_find_unused() { for (int i = 0; i < MAXCREATURES; i++) { creature_t *creature = &creatures[i]; if (!CREATURE_USED(creature)) return creature; } return NULL; } static int creature_num(const creature_t *creature) { return creature - creatures; } creature_t *creature_by_num(int creature_num) { if (creature_num < 0 || creature_num >= MAXCREATURES) return NULL; creature_t *creature = &creatures[creature_num]; if (!CREATURE_USED(creature)) return NULL; return creature; } int creature_id(const creature_t *creature) { return creature->vm_id; } creature_t *creature_by_id(int vm_id) { if (vm_id < 0) return NULL; const int hash = HASHVALUE(vm_id); creature_t *creature = creature_hash[hash]; while (creature) { assert(CREATURE_USED(creature)); if (creature->vm_id == vm_id) return creature; creature = creature->hash_next; } return NULL; } creature_t *creature_get_checked_lua(lua_State *L, int idx) { const int vm_id = luaL_checklong(L, idx); creature_t *creature = creature_by_id(vm_id); if (creature) return creature; luaL_error(L, "creature %d not in use", vm_id); return NULL; // never reached } int creature_dist(const creature_t *a, const creature_t *b) { // XXX: Hier Pfadsuche? const int distx = a->x - b->x; const int disty = a->y - b->y; return sqrt(distx * distx + disty * disty); } static void creature_make_smile(const creature_t *creature, client_t *client) { packet_t packet; packet_init(&packet, PACKET_CREATURE_SMILE); packet_write16(&packet, creature_num(creature)); server_send_packet(&packet, client); } int creature_groundbased(const creature_t *creature) { return creature->type != CREATURE_FLYER; } maptype_e creature_tile_type(const creature_t *creature) { return world_get_type(X_TO_TILEX(creature->x), Y_TO_TILEY(creature->y)); } int creature_food_on_tile(const creature_t *creature) { return world_get_food(X_TO_TILEX(creature->x), Y_TO_TILEY(creature->y)); } int creature_eat_from_tile(creature_t *creature, int amount) { return world_food_eat(X_TO_TILEX(creature->x), Y_TO_TILEY(creature->y), amount); } int creature_max_health(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 10000; case CREATURE_BIG: return 20000; case CREATURE_FLYER: return 5000; default: assert(0); return 0; } } int creature_max_food(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 10000; case CREATURE_BIG: return 20000; case CREATURE_FLYER: return 5000; default: assert(0); return 0; } } int creature_aging(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 5; case CREATURE_BIG: return 7; case CREATURE_FLYER: return 5; default: assert(0); return 0; } } creature_t *creature_nearest_enemy(const creature_t *reference, int *distptr) { int mindist = 1000000; creature_t *nearest = NULL; creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature) || creature->player == reference->player) continue; const int dist = creature_dist(creature, reference); if (dist > mindist) continue; nearest = creature; mindist = dist; } if (distptr) *distptr = mindist; return nearest; } // ------------- Bewegung ------------- int creature_speed(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 200 + creature->health / 16; case CREATURE_BIG: return 400; case CREATURE_FLYER: return 800; default: assert(0); return 0; } } static int creature_can_walk_path(creature_t *creature) { return creature->path != NULL && creature_speed(creature) > 0; } void creature_do_walk_path(creature_t *creature, int delta) { int travelled = creature_speed(creature) * delta / 1000; if (travelled == 0) travelled = 1; again: if (!creature->path) { creature_set_state(creature, CREATURE_IDLE); return; } const int dx = creature->path->x - creature->x; const int dy = creature->path->y - creature->y; const int dist_to_waypoint = sqrt(dx*dx + dy*dy); if (travelled >= dist_to_waypoint) { creature->x = creature->path->x; creature->y = creature->path->y; travelled -= dist_to_waypoint; pathnode_t *old = creature->path; creature->path = creature->path->next; free(old); goto again; } creature->x += dx * travelled / dist_to_waypoint; creature->y += dy * travelled / dist_to_waypoint; assert(!creature_groundbased(creature) || world_walkable(X_TO_TILEX(creature->x), Y_TO_TILEY(creature->y))); } // ------------- Food -> Health ------------- int creature_can_heal(const creature_t *creature) { return creature->health < creature_max_health(creature) && creature->food > 0; } int creature_heal_rate(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 500; case CREATURE_BIG: return 300; case CREATURE_FLYER: return 600; default: assert(0); return 0; } } void creature_do_heal(creature_t *creature, int delta) { int max_heal = creature_heal_rate(creature) * delta / 1000; const int can_heal = creature_max_health(creature) - creature->health; int finished = 0; // Nicht mehr als notwendig heilen if (max_heal >= can_heal) max_heal = can_heal, finished = 1; // Nicht mehr als moeglich heilen if (max_heal >= creature->food) max_heal = creature->food, finished = 1; creature->health += max_heal; creature->food -= max_heal; if (finished) creature_set_state(creature, CREATURE_IDLE); } // ------------- Eat ------------- int creature_can_eat(const creature_t *creature) { return creature_food_on_tile(creature) > 0 && creature->food < creature_max_food(creature); } int creature_eat_rate(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 800; case CREATURE_BIG: return 400; case CREATURE_FLYER: return 600; default: assert(0); return 0; } } void creature_do_eat(creature_t *creature, int delta) { int max_eat = creature_eat_rate(creature) * delta / 1000; const int can_eat = creature_max_food(creature) - creature->food; if (max_eat > can_eat) max_eat = can_eat; const int eaten = creature_eat_from_tile(creature, max_eat); creature->food += eaten; if (eaten == 0) creature_set_state(creature, CREATURE_IDLE); } // ------------- Attack ------------- static const int attack_possible[CREATURE_TYPES][CREATURE_TYPES] = // TARGET { { 0, 0, 1, 0 },// ATTACKER { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; int creature_can_attack(const creature_t *creature, const creature_t *target) { return attack_possible[creature->type][target->type]; } int creature_hitpoints(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 1000; case CREATURE_BIG: return 1500; case CREATURE_FLYER: return 0; default: assert(0); return 0; } } int creature_attack_distance(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 3 * TILE_SCALE; case CREATURE_BIG: return 2 * TILE_SCALE; case CREATURE_FLYER: return 0; default: assert(0); return 0; } } void creature_do_attack(creature_t *creature, int delta) { const int hitpoints = creature_hitpoints(creature) * delta / 1000; if (hitpoints == 0) goto finished_attacking; creature_t *target = creature_by_id(creature->target_id); // Nicht gefunden? if (!target) goto finished_attacking; // Kann nicht angreifen? if (!creature_can_attack(creature, target)) goto finished_attacking; // Ziel zu jung? // if (target->spawn_time + 500 > game_time) // goto finished_attacking; // Eigenes Viech? if (target->player == creature->player) goto finished_attacking; // Zu weit weg? if (creature_dist(creature, target) > creature_attack_distance(creature)) goto finished_attacking; target->health -= hitpoints; if (target->health > 0) { player_on_creature_attacked(target->player, target, creature); return; } creature_make_smile(creature, SEND_BROADCAST); creature_kill(target, creature); finished_attacking: creature_set_state(creature, CREATURE_IDLE); } // ------------- Creature Conversion ------------- int creature_conversion_speed(creature_t *creature) { return 1000; } static const int conversion_food_needed[CREATURE_TYPES][CREATURE_TYPES] = // TO { { 0, 8000, 5000, 0 },// FROM { 8000, 0, 0, 0 }, { 5000, 0, 0, 0 }, { 0, 0, 0, 0 } }; int creature_conversion_food(const creature_t *creature, creature_type type) { return conversion_food_needed[creature->type][type]; } int creature_can_convert(const creature_t *creature) { if (creature_conversion_food(creature, creature->convert_type) == 0) return 0; if (!world_walkable(X_TO_TILEX(creature->x), Y_TO_TILEY(creature->y))) return 0; return 1; } void creature_do_convert(creature_t *creature, int delta) { int used_food = creature_conversion_speed(creature) * delta / 1000; const int needed_food = creature_conversion_food(creature, creature->convert_type) - creature->convert_food; if (used_food > needed_food) used_food = needed_food; if (used_food > creature->food) used_food = creature->food; if (used_food == 0) creature_set_state(creature, CREATURE_IDLE); creature->convert_food += used_food; creature->food -= used_food; if (creature->convert_food == creature_conversion_food(creature, creature->convert_type)) { creature_set_type(creature, creature->convert_type); creature_set_state(creature, CREATURE_IDLE); } } int creature_set_conversion_type(creature_t *creature, creature_type type) { if (type < 0 || type >= CREATURE_TYPES) return 0; // Geht Umwandung ueberhaupt? if (creature_conversion_food(creature, type) == 0) return 0; // Beim Type Wechsel geht Food verloren if (creature->convert_type != type) creature->convert_food = 0; creature->convert_type = type; return 1; } int creature_set_type(creature_t *creature, creature_type type) { if (type == creature->type) return 1; if (type < 0 || type >= CREATURE_TYPES) return 0; creature->type = type; creature->convert_type = type; creature_set_health(creature, creature->health); if (creature->food > creature_max_food(creature)) creature->food = creature_max_food(creature); creature->dirtymask |= CREATURE_DIRTY_TYPE; return 1; } // ------------- Creature Spawning ------------- // Waehrend des Spawnens verbrauchtes Futter int creature_spawn_food(const creature_t *creature) { return 5000; } // Spawngeschwindigkeit (wie schnell wird das obige Futter verbraucht) int creature_spawn_speed(const creature_t *creature) { return 2000; } // Beim Spawnstart verlorene Lebensenergie int creature_spawn_health(const creature_t *creature) { return 4000; } void creature_do_spawn(creature_t *creature, int delta) { int used_food = creature_spawn_speed(creature) * delta / 1000; const int needed_food = creature_spawn_food(creature) - creature->spawn_food; if (used_food > needed_food) used_food = needed_food; if (used_food > creature->food) used_food = creature->food; if (used_food == 0) creature_set_state(creature, CREATURE_IDLE); creature->spawn_food += used_food; creature->food -= used_food; if (creature->spawn_food == creature_spawn_food(creature)) { creature_t *baby = creature_spawn(creature->player, creature, creature->x, creature->y, CREATURE_SMALL); if (!baby) { static char msg[] = "uuh. sorry. couldn't spawn your new born creature\r\n"; player_writeto(creature->player, msg, sizeof(msg) - 1); } creature_set_state(creature, CREATURE_IDLE); } } int creature_can_spawn(const creature_t *creature) { return creature->type == 1 && creature->food >= creature_spawn_food(creature) && creature->health > creature_spawn_health(creature); } // ---------------- Feeding ----------------- int creature_can_feed(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return creature->food > 0; case CREATURE_BIG: return 0; case CREATURE_FLYER: return creature->food > 0; default: assert(0); return 0; } } int creature_feed_distance(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return TILE_SCALE; case CREATURE_BIG: return 0; case CREATURE_FLYER: return TILE_SCALE; default: assert(0); return 0; } } int creature_feed_speed(const creature_t *creature) { switch (creature->type) { case CREATURE_SMALL: return 400; case CREATURE_BIG: return 0; case CREATURE_FLYER: return 400; default: assert(0); return 0; } } void creature_do_feed(creature_t *creature, int delta) { int food = creature_feed_speed(creature) * delta / 1000; int finished = 0; creature_t *target = creature_by_id(creature->target_id); // Nicht gefunden? if (!target) goto finished_feeding; // Ziel zu jung? // if (target->spawn_time + 500 > game_time) // goto finished_feeding; // Zu weit weg? if (creature_dist(creature, target) > creature_feed_distance(creature)) goto finished_feeding; if (food >= creature->food) food = creature->food, finished = 1; if (food >= creature_max_food(target) - target->food) food = creature_max_food(target) - target->food, finished = 1; if (food == 0) goto finished_feeding; creature->food -= food; target->food += food; if (!finished) return; finished_feeding: creature_set_state(creature, CREATURE_IDLE); } int creature_set_target(creature_t *creature, int target_id) { // Sich selbst als Ziel macht nie Sinn. if (target_id == creature->vm_id) return 0; // Nicht vorhanden? if (!creature_by_id(target_id)) return 0; // Nicht mehr pruefen, da sich das Ziel bereits in dieser // Runde toeten koennte und daher ein true hier nicht heisst, // dass tatsaechlich attackiert/gefuettert werden kann. creature->target_id = target_id; return 1; } // ----------------------------------------- int creature_set_state(creature_t *creature, int newstate) { // Wechsel in gleichen State immer ok if (newstate == creature->state) return 1; // Kann neuer State betreten werden? switch (newstate) { case CREATURE_IDLE: break; case CREATURE_WALK: if (!creature_can_walk_path(creature)) return 0; break; case CREATURE_HEAL: if (!creature_can_heal(creature)) return 0; break; case CREATURE_EAT: if (!creature_can_eat(creature)) return 0; break; case CREATURE_ATTACK: // if (!creature_can_attack(creature)) // return 0; break; case CREATURE_CONVERT: if (!creature_can_convert(creature)) return 0; break; case CREATURE_SPAWN: if (!creature_can_spawn(creature)) return 0; creature->health -= creature_spawn_health(creature); assert(creature->health > 0); break; case CREATURE_FEED: if (!creature_can_feed(creature)) return 0; break; } // Alten State verlassen switch (creature->state) { case CREATURE_CONVERT: // Bei einem Statewechel geht in die Konvertierung // investiertes Futter verloren creature->convert_food = 0; break; case CREATURE_SPAWN: // Dito fuer Spawnen creature->spawn_food = 0; break; default: break; } creature->state = newstate; return 1; } void creature_update_network_variables(creature_t *creature) { // Leben/Food Prozentangaben aktualisieren int new_food_health = min(15, 16 * creature->food / creature_max_food(creature)) << 4 | min(15, 16 * creature->health / creature_max_health(creature)); if (new_food_health != creature->network_food_health) { creature->network_food_health = new_food_health; creature->dirtymask |= CREATURE_DIRTY_FOOD_HEALTH; } if (creature->state != creature->network_state) { creature->network_state = creature->state; creature->dirtymask |= CREATURE_DIRTY_STATE; } int path_x = creature->x / CREATURE_POS_RESOLUTION; int path_y = creature->y / CREATURE_POS_RESOLUTION; if (path_x != creature->network_path_x || path_y != creature->network_path_y) { creature->network_path_x = path_x; creature->network_path_y = path_y; creature->dirtymask |= CREATURE_DIRTY_PATH; } int new_speed = (creature_speed(creature) + 2) / CREATURE_SPEED_RESOLUTION; if (creature->state == CREATURE_WALK && new_speed != creature->network_speed) { creature->network_speed = new_speed; creature->dirtymask |= CREATURE_DIRTY_SPEED; } if ((creature->state == CREATURE_ATTACK || creature->state == CREATURE_FEED)) { const creature_t *target = creature_by_id(creature->target_id); if (target && creature_num(target) != creature->network_target) { creature->network_target = creature_num(target); creature->dirtymask |= CREATURE_DIRTY_TARGET; } } } void creature_moveall(int delta) { int koth_score = 1; creature_t *creature_on_koth = NULL; creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; if (creature->suicide) { creature_kill(creature, creature); continue; } // Alterungsprozess creature->age_action_deltas += delta; while (creature->age_action_deltas >= 100) { creature->age_action_deltas -= 100; creature->health -= creature_aging(creature); } // Tot? if (creature->health <= 0) { creature_kill(creature, NULL); continue; } // State Aktion switch (creature->state) { case CREATURE_IDLE: // Nichts machen break; case CREATURE_WALK: creature_do_walk_path(creature, delta); break; case CREATURE_HEAL: creature_do_heal(creature, delta); break; case CREATURE_EAT: creature_do_eat(creature, delta); break; case CREATURE_ATTACK: creature_do_attack(creature, delta); break; case CREATURE_CONVERT: creature_do_convert(creature, delta); break; case CREATURE_SPAWN: creature_do_spawn(creature, delta); break; case CREATURE_FEED: creature_do_feed(creature, delta); break; } // Erst hier auf IDLE pruefen. Oben kann eine Kreatur in den Zustand // IDLE gewechselt haben. XXX: Wieder nach oben verschieben? if (creature->state == CREATURE_IDLE) { if (X_TO_TILEX(creature->x) == world_koth_x() && Y_TO_TILEY(creature->y) == world_koth_y()) { // Wenn schon eins drauf ist, und diese von unterschiedlichen Spielern // sind, so gibt es keine Punkte if (creature_on_koth && creature->player != creature_on_koth->player) koth_score = 0; creature_on_koth = creature; } } } // Zweite Iteration fuer Network Sync creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; creature_update_network_variables(creature); creature_to_network(creature, creature->dirtymask, SEND_BROADCAST); creature->dirtymask = CREATURE_DIRTY_NONE; } // Gibt es einen Koenig? :) // Eventuell wurde die Koth Kreatur in dieser Runde gekillt if (koth_score && creature_on_koth && CREATURE_USED(creature_on_koth)) { player_is_king_of_the_hill(creature_on_koth->player, delta); } else { player_there_is_no_king(); } } int creature_set_path(creature_t *creature, int x, int y) { pathnode_t *newpath; if (creature_groundbased(creature)) { if (!world_walkable(X_TO_TILEX(x), Y_TO_TILEY(y))) return 0; newpath = world_findpath(creature->x, creature->y, x, y); if (!newpath) return 0; } else { // Fliegendes Vieh if (!world_is_within_border(X_TO_TILEX(x), Y_TO_TILEY(y))) return 0; newpath = pathnode_new(x, y); } path_delete(creature->path); creature->path = newpath; return 1; } int creature_set_health(creature_t *creature, int health) { if (health > creature_max_health(creature)) health = creature_max_health(creature); if (health < 0) health = 0; creature->health = health; return 1; } int creature_suicide(creature_t *creature) { creature->suicide = 1; return 1; } void creature_set_message(creature_t *creature, const char *message) { if (strncmp(creature->message, message, sizeof(creature->message) - 1)) { snprintf(creature->message, sizeof(creature->message), "%s", message); creature->dirtymask |= CREATURE_DIRTY_MESSAGE; } } int creature_set_food(creature_t *creature, int food) { if (food < 0) return 0; if (food > creature_max_food(creature)) return 0; creature->food = food; return 1; } creature_t *creature_spawn(player_t *player, creature_t *parent, int x, int y, creature_type type) { if (!world_walkable(X_TO_TILEX(x), Y_TO_TILEY(y))) return NULL; creature_t *creature = creature_find_unused(); if (!creature) return NULL; num_creatures++; memset(creature, 0, sizeof(creature_t)); creature->vm_id = next_free_vm_id++; creature->x = x; creature->y = y; creature->type = type; creature->food = 0; creature->health = creature_max_health(creature); creature->player = player; creature->target_id = creature->vm_id; // muesste nicht gesetzt werden creature->path = NULL; creature->convert_food = 0; creature->convert_type = type; creature->spawn_food = 0; creature->state = CREATURE_IDLE; creature->suicide = 0; creature->message[0] = '\0'; creature->spawn_time = game_time; creature->age_action_deltas = 0; const int hash = HASHVALUE(creature->vm_id); creature->hash_next = creature_hash[hash]; creature_hash[hash] = creature; player_on_creature_spawned(player, creature, parent); creature_update_network_variables(creature); creature_to_network(creature, CREATURE_DIRTY_ALL, SEND_BROADCAST); creature->dirtymask = CREATURE_DIRTY_NONE; creature_make_smile(creature, SEND_BROADCAST); return creature; } void creature_kill(creature_t *creature, creature_t *killer) { player_on_creature_killed(creature->player, creature, killer); path_delete(creature->path); creature->player = NULL; num_creatures--; const int hash = HASHVALUE(creature->vm_id); creature_t *tmp = creature_hash[hash]; if (tmp == creature) { creature_hash[hash] = creature_hash[hash]->hash_next; } else { while (tmp->hash_next != creature) { tmp = tmp->hash_next; assert(tmp); } tmp->hash_next = creature->hash_next; } creature_to_network(creature, CREATURE_DIRTY_ALIVE, SEND_BROADCAST); } void creature_kill_all_players_creatures(player_t *player) { creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; if (creature->player != player) continue; creature_kill(creature, NULL); } } void creature_send_initial_update(client_t *client) { creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; creature_to_network(creature, CREATURE_DIRTY_ALL, client); } } void creature_to_network(creature_t *creature, int dirtymask, client_t *client) { if (dirtymask == CREATURE_DIRTY_NONE) return; packet_t packet; packet_init(&packet, PACKET_CREATURE_UPDATE); packet_write16(&packet, creature_num(creature)); packet_write08(&packet, dirtymask); if (dirtymask & CREATURE_DIRTY_ALIVE) { if (CREATURE_USED(creature)) { packet_write08(&packet, player_num(creature->player)); packet_write16(&packet, creature->vm_id); packet_write16(&packet, creature->network_last_x = creature->network_path_x); packet_write16(&packet, creature->network_last_y = creature->network_path_y); } else { packet_write08(&packet, 0xFF); } } if (dirtymask & CREATURE_DIRTY_TYPE) packet_write08(&packet, creature->type); if (dirtymask & CREATURE_DIRTY_FOOD_HEALTH) packet_write08(&packet, creature->network_food_health); if (dirtymask & CREATURE_DIRTY_STATE) packet_write08(&packet, creature->network_state); if (dirtymask & CREATURE_DIRTY_PATH) { int dx = creature->network_path_x - creature->network_last_x; int dy = creature->network_path_y - creature->network_last_y; packet_write16(&packet, (dx < 0) | (abs(dx) << 1)); packet_write16(&packet, (dy < 0) | (abs(dy) << 1)); creature->network_last_x = creature->network_path_x; creature->network_last_y = creature->network_path_y; } if (dirtymask & CREATURE_DIRTY_TARGET) packet_write16(&packet, creature->network_target); if (dirtymask & CREATURE_DIRTY_MESSAGE) { packet_write08(&packet, strlen(creature->message)); packet_writeXX(&packet, &creature->message, strlen(creature->message)); } if (dirtymask & CREATURE_DIRTY_SPEED) packet_write08(&packet, creature->network_speed); server_send_packet(&packet, client); } int creature_num_creatures() { return num_creatures; } void creature_init() { for (int i = 0; i < MAXCREATURES; i++) { creature_t *creature = &creatures[i]; creature->player = NULL; } next_free_vm_id = 0; assert(num_creatures == 0); } void creature_shutdown() { for (int i = 0; i < MAXCREATURES; i++) { creature_t *creature = &creatures[i]; if (CREATURE_USED(creature)) creature_kill(&creatures[i], NULL); } } infon/server.h0000644000076400001440000000446510603314646013433 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef SERVER_H #define SERVER_H #ifdef WIN32 #include #include #include #else #include #include #endif #include #include #include "packet.h" #include "infond.h" #include "global.h" #define MAXCLIENTS 1024 #define SEND_BROADCAST NULL typedef struct client_s { struct event rd_event; struct event wr_event; struct evbuffer *in_buf; struct evbuffer *out_buf; int is_file_writer; int compress; z_stream strm; char *kill_me; int kick_at_end_of_game; // Verbindung von: 1-player <-> N-client struct player_s *player; struct client_s *next; struct client_s *prev; // Client, welcher kontinuierlich Updates erhaelt int is_gui_client; struct client_s *next_gui; struct client_s *prev_gui; } client_t; client_t *server_accept(int fd, const char *address); void server_writeto(client_t *client, const void *data, size_t size); void server_writeto_all_gui_clients(const void *data, size_t size); void server_destroy(client_t *client, const char *reason); client_t *client_get_checked_lua(lua_State *L, int idx); void server_send_packet(packet_t *packet, client_t *client); client_t *server_start_demo_writer(const char *demoname, int one_game); void server_tick(); int server_num_clients(); void server_init(); void server_game_end(); void server_shutdown(); #endif infon/infond.lua0000644000076400001440000005420010603314646013724 0ustar dividuumusers--[[ Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ]]-- ----------------------------------------------------------- -- Konfiguration laden ----------------------------------------------------------- config = setmetatable({}, {__index = _G}) setfenv(assert(loadfile(os.getenv("INFOND_CONFIG") or (PREFIX .. "config.lua"))), config)() stats = { num_clients = 0; num_refused = 0; num_players = 0; num_maps = 0; num_exec = 0; } ----------------------------------------------------------- -- Klasse fuer Clientverbindung ----------------------------------------------------------- clients= {} Client = {} function Client.create(fd, addr) stats.num_clients = stats.num_clients + 1 local obj = {} setmetatable(obj, { __index = function(self, what) -- Nach Klassenmethode suchen if Client[what] then return Client[what] end -- Nix? Dann per default in Objekttabelle suchen end }) clients[fd] = obj obj.fd = fd obj:on_new_client(addr) end function Client.check_accept(addr) for n, rule in ipairs(config.acl) do if rule.time and rule.time < os.time() then table.remove(config.acl, n) elseif string.match(addr, rule.pattern) then if rule.deny then stats.num_refused = stats.num_refused + 1 return false, "infon refused your connection from " .. addr .. ": " .. rule.deny .. "\r\n" else return true end end end return true end function Client:readln() return coroutine.yield(self.thread) end paste = 0 function Client:nextpaste() paste = paste + 1 return paste end function Client:paste_name(num) return num end function Client:paste_full_name(num) return "paste " .. self:paste_name(num) .. " from client " .. self.fd end function Client:kick_ban(reason, time) local addr = self.addr:match("^([^:]+:[^:]+:?)") local time = time and os.time() + time or nil table.insert(config.acl, 1, { pattern = "^" .. addr .. ".*$", deny = reason, time = time }) self:disconnect(reason) end function Client:on_new_client(addr) self.addr = addr self.local_output = true self.prompt = "> " self.failed_shell = 0 self.forward_unknown = true self.pre_string = "" self.post_string = "" self.highlevel = config.highlevel[1] self.last_action = {} -- print(self.addr .. " accepted") scroller_add(self.addr .. " joined") self:start_thread() end function Client:start_thread() self.thread = coroutine.create(self.handler) local ok, msg = coroutine.resume(self.thread, self) if not ok then self:disconnect(msg) end end function Client:on_destroy(reason) -- print(self.addr .. " closed: " .. reason) scroller_add(self.addr .. " disconnected: " .. reason) end function Client:on_input(line) local ok, msg = coroutine.resume(self.thread, line) if not ok then self:writeln(msg) self:writeln("restarting mainloop...") self:start_thread() end end function Client:disconnect(reason) client_disconnect(self.fd, reason) end function Client:write(data) client_write(self.fd, self.pre_string .. data .. self.post_string) end function Client:turn_into_guiclient() client_make_guiclient(self.fd) end function Client:is_guiclient() return client_is_gui_client(self.fd) end function Client:attach_to_player(playerno, pass) local ok, ret = pcall(client_attach_to_player, self.fd, playerno, pass) if not ok then return ret elseif not ret then return "attach failed. password wrong?" else return nil end end function Client:detach() local playerno = self:get_player() if playerno then client_detach_from_player(self.fd, playerno) else self:writeln("you cannot detach since you are not attached.") end end function Client:get_player() return client_player_number(self.fd) end function Client:check_name(name) if config.check_name_password and config.check_name_password(name, nil) then self:write("Name '" .. name .. "' requires a password: ") return config.check_name_password(name, self:readln()) else return true end end function Client:set_name(name) local playerno = self:get_player() if playerno and player_get_name(playerno) ~= name and name ~= '' then local oldname = player_get_name(playerno) if not self:check_name(name) then return false end player_set_name(playerno, name) local newname = player_get_name(playerno) scroller_add(oldname .. " renamed to " .. newname .. ".") return true else return false end end function Client:set_color(color) local playerno = self:get_player() if playerno then player_set_color(playerno, color) else self:writeln("you have no player!") end end function Client:kill() local playerno = self:get_player() if playerno then player_kill(playerno, player_get_name(playerno) .. " removed from the game.") else self:writeln("no need to kill. you have no player!") end end function Client:execute(code, name) local playerno = self:get_player() if playerno then stats.num_exec = stats.num_exec + 1 return player_execute(playerno, self.local_output and self.fd or nil, code, name) else self:writeln("you do not have a player. cannot execute your code.") return false end end function Client:writeln(line) if line then self:write(line .. "\r\n") else self:write("\r\n") end end function Client:rate_limit(action, every) local time, last = real_time(), self.last_action[action] if not last or last + every <= time then self.last_action[action] = real_time() return true else self:writeln(string.format("%s too fast. please wait %d seconds...", action, (every - (time - last)))) return false end end function Client:centerln(line) self:writeln(string.rep(" ", (60 - string.len(line)) / 2) .. line) end -- Speziell formatiert, so dass es von einem GUI Client -- wie andere in packet.h definierte Packete gelesen -- gelesen werden kann (len = 32 (space), type = 32 (space). function Client:welcome(msg) local msglen = string.len(msg) if msglen > 28 then print('welcome message too long') msg = "Press " msglen = string.len(msg) end self:write(" \r\n" .. msg .. string.rep(" ", 28 - msglen) .. "\r\n") end ----------------------------------------------------------- -- Server C Callbacks ----------------------------------------------------------- function on_new_client(addr) return Client.check_accept(addr) end function on_client_accepted(fd, addr) Client.create(fd, addr) end function on_client_input(fd, line) clients[fd]:on_input(line) end function on_client_close(fd, reason) clients[fd]:on_destroy(reason) clients[fd] = nil end ----------------------------------------------------------- -- Game C Callbacks ----------------------------------------------------------- function on_game_started() -- Demos starten? if type(config.demo) == "string" then server_start_writer(string.format("%s-%08X.demo", config.demo, os.time()), true, true); elseif type(config.demo) == "function" then server_start_writer(config.demo(), true, true) end -- Message scroller_add("Started map " .. map) -- wall("Started map " .. map) -- server_tick anlegen server_tick = coroutine.wrap(ServerMain) -- Handler fuer Dinge, welche nur beim ersten Spiel aufgerufen werden sollen if not first_game_init then first_game_init = true -- competition? if config.competition then set_realtime(false) competition_rounds = #config.maps config.disable_joining = "competition mode" for _, bot in pairs(config.competition.bots) do appendline(config.competition.log, "joining '%s' as %d", bot.source, start_bot(bot)) end end -- Nach dem Starten des ersten Spiels einmalig Funktion autoexec aufrufen if config.autoexec then local ok, msg = epcall(debug.traceback, config.autoexec) if not ok then print(msg) end end end -- Mapchange if config.competition then appendline(config.competition.log, "%d starting on map '%s'", os.time(), map) end end function on_game_ended() -- competition? if config.competition then for pno in each_player() do appendline(config.competition.log, "%d: score %d, creatures %d", pno, player_score(pno), player_num_creatures(pno)) end appendline(config.competition.log, "%d completed", os.time()) competition_rounds = competition_rounds - 1 if competition_rounds == 0 then shutdown() end end -- kill all creatures killall() -- reset score for pno in each_player() do player_set_score(pno, 0) end end ----------------------------------------------------------- -- World Funktionen ----------------------------------------------------------- current_map = 1 map = config.maps[current_map] function world_rotate_map() current_map = current_map + 1 if current_map > #config.maps then current_map = 1 end map = config.maps[current_map] end function world_get_dummy() return { level_size = function () return 3,3 end; level_koth_pos = function () return 1,1 end; level_init = function () end; level_tick = function () end; level_spawn_point = function () end; } end function world_load(map) local world_code = assert(loadfile(PREFIX .. "level/" .. map .. ".lua")) -- prepare safe world environment world = { -- lua functions print = print; pairs = pairs; ipairs = ipairs; unpack = unpack; math = { random = math.random; sqrt = math.sqrt; floor = math.floor }; string = { upper = string.upper; sub = string.sub; len = string.len; }; table = { getn = table.getn }; -- game functions world_dig = world_dig; world_set_type = world_set_type; world_set_gfx = world_set_gfx; world_get_type = world_get_type; world_get_gfx = world_get_gfx; world_find_digged = world_find_digged; world_add_food = world_add_food; world_make_border = world_make_border; world_fill_all = world_fill_all; world_tile_center = world_tile_center; game_time = game_time; level_spawn_point = world_find_digged_worldcoord; -- game constants TILE_WIDTH = TILE_WIDTH; TILE_HEIGHT = TILE_HEIGHT; TILE_SOLID = TILE_SOLID; TILE_PLAIN = TILE_PLAIN; TILE_WATER = 2; -- compatibility TILE_GFX_SOLID = TILE_GFX_SOLID; TILE_GFX_PLAIN = TILE_GFX_PLAIN; TILE_GFX_BORDER = TILE_GFX_BORDER; TILE_GFX_SNOW_SOLID = TILE_GFX_SNOW_SOLID; TILE_GFX_SNOW_PLAIN = TILE_GFX_SNOW_PLAIN; TILE_GFX_SNOW_BORDER = TILE_GFX_SNOW_BORDER; TILE_GFX_WATER = TILE_GFX_WATER; TILE_GFX_LAVA = TILE_GFX_LAVA; TILE_GFX_NONE = TILE_GFX_NONE; TILE_GFX_KOTH = TILE_GFX_KOTH; TILE_GFX_DESERT = TILE_GFX_DESERT; } -- activate environment for world code and load world setfenv(world_code, world)() local w, h = world.level_size() local kx, ky = world.level_koth_pos() return w, h, kx, ky end function world_init() stats.num_maps = stats.num_maps + 1 local ok, w, h, kx, ky = pcall(world_load, map) if not ok then print("cannot load world '" .. map .. "': " .. w .. ". using dummy world") world = world_get_dummy() w, h = world.level_size() kx, ky = world.level_koth_pos() end world_tick = coroutine.wrap(world_main) return w, h, kx, ky end function world_main() local ok, ret = pcall(world.level_init) if not ok then print("initializing world failed: " .. ret) end while true do ok, ret = pcall(world.level_tick) if not ok then print("calling level_tick failed: " .. ret) end coroutine.yield() end end function world_add_food_by_worldcoord(x, y, amount) return world_add_food(x / TILE_WIDTH, y / TILE_HEIGHT, amount) end function world_tile_center(x, y) return (x + 0.5) * TILE_WIDTH, (y + 0.5) * TILE_HEIGHT end function world_find_digged_worldcoord() local x, y = world_find_digged() if not x then return end return world_tile_center(x, y) end function world_get_spawn_point(player) return world.level_spawn_point(player) end -- compatibility function. do not use for new maps. function world_dig(x, y, typ, gfx) gfx = gfx or typ if typ == world.TILE_WATER then -- water world_set_gfx(x, y, TILE_GFX_WATER) return end local w, h = world.level_size() local kx, ky = world.level_koth_pos() if x == kx and y == ky then gfx = TILE_GFX_KOTH end return world_set_type(x, y, typ) and world_set_gfx(x, y, gfx) end function world_fill_all(gfx) local w, h = world.level_size() for x = 0, w - 1 do for y = 0, h - 1 do world_set_gfx(x, y, gfx) end end end function world_make_border(gfx) local w, h = world.level_size() for x = 0, w-1 do world_set_gfx(x, 0, gfx) world_set_gfx(x, h - 1, gfx) end for y = 0, h-1 do world_set_gfx(0 , y, gfx) world_set_gfx(w - 1, y, gfx) end end ----------------------------------------------------------- -- Rules Funktionen ----------------------------------------------------------- function rules_init() local rules_code = assert(loadfile(PREFIX .. "rules/" .. config.rules .. ".lua")) -- prepare safe rules environment rules = { -- lua functions print = print; -- game functions game_time = game_time; each_player = each_player; player_score = player_score; player_get_name = player_get_name; player_change_score = player_change_score; creature_spawn = creature_spawn; creature_set_food = creature_set_food; creature_get_food = creature_get_food; creature_get_pos = creature_get_pos; creature_get_player = creature_get_player; creature_get_type = creature_get_type; world_get_spawn_point = world_get_spawn_point; world_add_food_by_worldcoord= world_add_food_by_worldcoord; get_score_limit = function () return config.score_limit end; get_time_limit = function () return config.time_limit end; scroller_add = scroller_add; set_intermission = set_intermission; world_rotate_map = world_rotate_map; reset = reset; -- game constants CREATURE_SMALL = CREATURE_SMALL; CREATURE_BIG = CREATURE_BIG; CREATURE_FLYER = CREATURE_FLYER; } -- activate environment for rules code and load rules setfenv(rules_code, rules)() end function rules_call(name, ...) assert(type(rules) == "table", "'rules' is not a table. cannot call rule handler '" .. name .. "'") assert(rules[name], "rule handler '" .. name .. "' not defined") rules[name](...) end ----------------------------------------------------------- -- Praktisches? ----------------------------------------------------------- function isnumber(var) return tostring(tonumber(var)) == var end function p(x) if type(x) == "table" then cprint("+--- Table: " .. tostring(x)) for key, val in pairs(x) do cprint("| " .. tostring(key) .. " " .. tostring(val)) end cprint("+-----------------------") else cprint(type(x) .. " - " .. tostring(x)) end end function admin_help() cprint("-------------------------------------------------") cprint("Admin functions") cprint("-------------------------------------------------") cprint("acllist() - lists acl") cprint("aclrm(num) - removes acl rule") cprint("batch() - starts admin batch") cprint("changemap(map) - changes to new map") cprint("clientlist() - lists all clients") cprint("kick(cno, [msg]) - kicks client cno") cprint("kick_player(pno, [msg]) - kicks a player") cprint("kickall() - kicks all clients") cprint("kickban(cno, [msg], time) - kicks and bans") cprint("killall() - kills all creatures") cprint("reset() - restarts current map") cprint("shutdown() - shutdown the server") cprint("wall(msg) - writes to all clients") cprint("-------------------------------------------------") end function appendline(filename, fmt, ...) if not filename then return end local file = assert(io.open(filename, "a+")) file:write(string.format(fmt .. "\n", ...)) file:close() end function kick(fd, msg) clients[fd]:disconnect(msg or "kicked") end function kickban(fd, msg, time) clients[fd]:kick_ban(msg or "kickbanned", time) end function killall() for pno in each_player() do player_kill_all_creatures(pno) end end function kick_player(pno, msg) player_kill(pno, msg or "kicked") end function reset() game_end() end function changemap(next_map) map = next_map reset() end function kickall(msg) for fd, client in pairs(clients) do client:disconnect(msg or "kicked") end end function clientlist() for fd, client in pairs(clients) do cprint(string.format("%4d %s - %s", fd, client_is_gui_client(fd) and "*" or " ", client.addr)) end end function wall(msg) for fd, client in pairs(clients) do client:writeln() client:writeln("-[ Message from Admin ]-------") client:writeln(msg) client:writeln("------------------------------") end end function batch() cprint("enter lua code. '.' ends input.") local code = "" while true do local input = coroutine.yield() -- read next line if input == "." then break else code = code .. input .. "\n" end end assert(loadstring(code))() end function acllist() for n, rule in ipairs(config.acl) do cprint(string.format("%2d: %-30s - %9d - %s", n, rule.pattern, rule.time and rule.time - os.time() or -1, rule.deny or "accept")) end end function aclrm(num) assert(config.acl[num], "rule " .. num .. " does not exist") table.remove(config.acl, num) end function start_listener() assert(setup_listener(config.listenaddr, config.listenport), string.format("cannot setup listener on %s:%d", config.listenaddr, config.listenport)) end function stop_listener() setup_listener("", 0) end -- Options: -- source - bot source code -- log - log file -- api - highlevel api -- name - bot name -- password - password function start_bot(options) assert(type(options) == "table", "start_bot needs an options table") local highlevel = options.api or config.highlevel[1] local password = options.password or tostring(math.random(100000, 999999)) local botfile = assert(io.open(options.source, "rb")) local botsource = botfile:read("*a") botfile:close() local name = options.name or select(3, options.source:find("([^/\\]+)\.lua")) or options.source local playerno = player_create(name, password, highlevel) assert(playerno, "cannot create new player") cprint(string.format("player %d - %s (%s) joined with password '%s'", playerno, name, options.source, password)) player_set_no_client_kick_time(playerno, 0) if options.log then local ok, logclient = pcall(server_start_writer, options.log, false, false) if ok then client_attach_to_player(logclient, playerno, password) else cprint("cannot start log writer: " .. logclient) end end assert(player_execute(playerno, nil, botsource, options.source), "cannot load bot code") return playerno end ----------------------------------------------------------- -- Clienthandler laden ----------------------------------------------------------- assert(loadfile(PREFIX .. "server.lua"))() -- setup listen socket if config.listenaddr and config.listenport then start_listener() end infon/infond.c0000644000076400001440000000455410603314646013374 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef __linux__ #include #include #endif #ifdef DAEMONIZING #include "daemonize.h" #endif #include #include #include #include #include #include #include #include "global.h" #include "misc.h" #include "server.h" #include "world.h" #include "game.h" #include "player.h" lua_State *L; int real_time = 0; // Seconds since server start int game_time = 0; // Microseconds since game start int game_paused = 0; int game_exit = 0; void sighandler(int sig) { game_exit = 1; } int main(int argc, char *argv[]) { #if defined(__linux__) && defined(WARN_COREDUMP) struct rlimit rlim; getrlimit(RLIMIT_CORE, &rlim); if (rlim.rlim_cur == 0) fprintf(stderr, "no coredump possible. enable them to help debug crashes.\n"); #endif signal(SIGTERM, sighandler); signal(SIGINT, sighandler); signal(SIGPIPE, SIG_IGN); srand(time(NULL)); L = luaL_newstate(); luaL_openlibs(L); lua_register_string_constant(L, PREFIX); game_init(); server_init(); player_init(); if (luaL_dofile(L, PREFIX "infond.lua")) die("cannot execute 'infond.lua': %s", lua_tostring(L, -1)); // XXX: HACK: stdin client starten #ifndef NO_CONSOLE_CLIENT server_accept(STDIN_FILENO, "special:console"); #endif #ifdef DAEMONIZING daemonize(argc, argv); #endif while (!game_exit) { game_one_game(); } player_shutdown(); server_shutdown(); lua_close(L); return EXIT_SUCCESS; } infon/map.c0000644000076400001440000005473010536260414012673 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "path.h" #include "global.h" #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) #define DIR_UP 0 #define DIR_RIGHT 1 #define DIR_DOWN 2 #define DIR_LEFT 3 /* TILE Functions ******************************************/ void tile_init(tile_t *tile) { assert(tile); tile->walkable = 0; tile->region = REGION_NONE; tile->area = NULL; } /* PORTAL Functions ********************************************/ int portal_width(portal_t *portal) { return portal->s2 - portal->s1 + 1; } void portal_destroy(portal_t *portal) { free(portal); } /* Berechnet den veraenderlichen Koordinatenanteil * eines Portals neu. */ void portal_update_center(portal_t *portal) { if (portal->dir == PORTAL_DIR_VERTICAL) { portal->cy = TILE_Y1(portal->s1) + portal_width(portal) * TILE_HEIGHT / 2; } else { portal->cx = TILE_X1(portal->s1) + portal_width(portal) * TILE_WIDTH / 2; } } /* PORTALSIDE Functions ********************************************/ void portalside_destroy(portalside_t *side) { free(side); } /* Liefert von einer uebergebenen Portalseite deren Richtung */ int portalside_direction(const portalside_t *side) { assert(side->prev->next == side); assert(side->next->prev == side); assert(side->portal->sides[0] == side || side->portal->sides[1] == side); if (side->portal->sides[0] == side) { return side->portal->dir == PORTAL_DIR_HORIZONTAL ? DIR_DOWN : DIR_RIGHT; } else { return side->portal->dir == PORTAL_DIR_HORIZONTAL ? DIR_UP : DIR_LEFT; } } /* Ordnet einer Portalseite einen Wert zu, nach dem * unterschiedliche Portale reihum sortiert * werden koennen. */ int portalside_to_value(const portalside_t *side) { assert(side->portal->s1 <= side->portal->s2); switch (portalside_direction(side)) { case DIR_UP: return side->portal->s1; case DIR_RIGHT: return 100000 + side->portal->s1; case DIR_DOWN: return 300000 - side->portal->s2; case DIR_LEFT: return 400000 - side->portal->s2; } assert(0); return 0; } /* Verbindet das Portal der uebergebenen Portalseite mit deren * Nachbarn. side2, side3 und side->next->portal werden geloescht. * * prev--> * 4 <--next 3 * |--- side->otherside ----| |---- side->next->otherside----| * * [portal] [side->next->portal] * 1 2 * * |----------- side -------| |------- side->next -----------| * 1 next--> 2 * <--prev */ void portalside_merge_with_neighbour(portalside_t *side) { portalside_t *side1 = side; portalside_t *side2 = side->next; portalside_t *side3 = side2->otherside; portalside_t *side4 = side1->otherside; portal_t *portal1 = side1->portal; portal_t *portal2 = side2->portal; assert(side1->next->otherside->next->otherside == side1); assert(side1->otherside->prev->otherside->prev == side1); assert(side1->area == side2->area); assert(side3->area == side4->area); assert(side2->prev == side1); assert(side4->prev == side3); assert(side3->portal == side2->portal); assert(side1->portal == side4->portal); assert(side1->prev->next == side1); assert(side1->next->prev == side1); assert(side4->prev->next == side4); assert(side4->next->prev == side4); side4->prev = side3->prev; side3->prev->next = side4; side1->next = side2->next; side2->next->prev = side1; if (side2->area->portals == side2) side2->area->portals = side1; if (side3->area->portals == side3) side3->area->portals = side4; portalside_destroy(side2); portalside_destroy(side3); // Neue Dimension des Portals bestimmen portal1->s1 = MIN(portal1->s1, portal2->s1); portal1->s2 = MAX(portal1->s2, portal2->s2); portal_update_center(portal1); portal_destroy(portal2); assert((portal1->sides[0] == side1 && portal1->sides[1] == side4) || (portal1->sides[1] == side1 && portal1->sides[0] == side4)); assert(side1->prev->next == side1); assert(side1->next->prev == side1); assert(side4->prev->next == side4); assert(side4->next->prev == side4); } /* AREA Functions ********************************************/ void area_destroy(area_t *area) { free(area); } /* void area_get_info(area_t *area) { printf(" area %p, %d,%d - %d,%d\n", area, area->x1, area->y1, area->x2, area->y2); portalside_t *f, *side; f = side= area->portals; if (side) do { assert(side->area == area); printf("\n portalside %p, value=%d\n", side, portalside_to_value(side)); printf(" otherside: %p, portal: %p\n", side->otherside, side->portal); printf(" next: %p, prev: %p\n", side->next, side->prev); printf("\n"); printf(" s1=%d, s2=%d\n", side->portal->s1, side->portal->s2); printf(" cx=%d, cy=%d\n", side->portal->cx, side->portal->cy); printf(" otherside->area %p, %d,%d - %d,%d\n", side->otherside->area, side->otherside->area->x1, side->otherside->area->y1, side->otherside->area->x2, side->otherside->area->y2); side = side->next; } while (side != f); } */ int area_count_portals(const area_t *area) { const portalside_t *tmp = area->portals; const portalside_t *cur = area->portals; int count = 0; if (cur) do { assert(cur->next->prev == cur); count++; cur = cur->next; } while (cur != tmp); return count; } /* Verbindet zwei Areas durch ein Portal miteinander. * - Die beiden Areas liegen auf genau einer Seite aneinander. * - Es gibt eine gemeinsame Schnittflaeche * - Area1 liegt links/ueber Area2. * * Es werden zwei Portalseiten sowie ein Portal angelegt. */ portal_t *area_connect(area_t *a1, area_t *a2) { portalside_t *side1 = (portalside_t*)malloc(sizeof(portalside_t)); portalside_t *side2 = (portalside_t*)malloc(sizeof(portalside_t)); portal_t *portal = (portal_t*)malloc(sizeof(portal_t)); portal->path_id = 0; portal->path_prev = NULL; portal->sides[0] = side1; portal->sides[1] = side2; // Portal Richtung und Ausdehnung berechnen if (a1->x2 + 1 == a2->x1) { portal->dir = PORTAL_DIR_VERTICAL; portal->s1 = MAX(a1->y1, a2->y1); portal->s2 = MIN(a1->y2, a2->y2); portal->cx = TILE_X2(a1->x2); } else { portal->dir = PORTAL_DIR_HORIZONTAL; portal->s1 = MAX(a1->x1, a2->x1); portal->s2 = MIN(a1->x2, a2->x2); portal->cy = TILE_Y2(a1->y2); } portal_update_center(portal); // side1 eintragen in area a1 side1->area = a1; side1->otherside = side2; side1->portal = portal; if (!a1->portals) { a1->portals = side1->next = side1->prev = side1; } else { portalside_t *end = a1->portals; portalside_t *cur = a1->portals; if (cur == cur->next) { side1->next = cur->next; cur->next->prev = side1; cur->next = side1; side1->prev = cur; } else { a1->portals = side1->next = side1->prev = side1; // HACK fuer die Asserts int side1_value = portalside_to_value(side1); // Mindestens zwei andere Portale vorhanden do { int cur_value = portalside_to_value(cur); int next_value = portalside_to_value(cur->next); if ((next_value < cur_value && side1_value > cur_value) || (cur_value < side1_value && side1_value < next_value) || (next_value < cur_value && side1_value < next_value)) { // side1 hinter cur einhaengen side1->next = cur->next; cur->next->prev = side1; cur->next = side1; side1->prev = cur; break; } cur = cur->next; } while (cur != end); } } assert(side1->next); assert(side1->prev); // side2 eintragen in area a2 side2->area = a2; side2->otherside = side1; side2->portal = portal; if (!a2->portals) { a2->portals = side2->next = side2->prev = side2; } else { assert(a2->portals->next->prev == a2->portals); assert(a2->portals->prev->next == a2->portals); portalside_t *end = a2->portals; portalside_t *cur = a2->portals; if (cur == cur->next) { side2->next = cur->next; cur->next->prev = side2; cur->next = side2; side2->prev = cur; } else { a2->portals = side2->next = side2->prev = side2; // HACK fuer die Asserts int side2_value = portalside_to_value(side2); // Mindestens zwei ander Portale vorhanden do { int cur_value = portalside_to_value(cur); int next_value = portalside_to_value(cur->next); if ((next_value < cur_value && side2_value > cur_value) || (cur_value < side2_value && side2_value < next_value) || (next_value < cur_value && side2_value < next_value)) { // side2 hinter cur einhaengen side2->next = cur->next; cur->next->prev = side2; cur->next = side2; side2->prev = cur; break; } cur = cur->next; } while (cur != end); } } assert(side2->next); assert(side2->prev); assert(a1->portals->next->prev == a1->portals); assert(a1->portals->prev->next == a1->portals); assert(a1->portals->otherside->otherside == a1->portals); assert(a2->portals->next->prev == a2->portals); assert(a2->portals->prev->next == a2->portals); assert(a2->portals->otherside->otherside == a2->portals); return portal; } /* Prueft, ob ein Portal der ueberlieferten Portalside mit * dessen naechsten Portal verbunden werden kann. */ int portal_is_mergable_with_neighbour(const portalside_t *side) { const portalside_t *neighbour = side->next; if (side->otherside->area != neighbour->otherside->area) return 0; int this_value = portalside_to_value(side); int neighbour_value = portalside_to_value(neighbour); return this_value + portal_width(side->portal) == neighbour_value; } /* Geht alle Portalsides eines Area durch und prueft, ob zwei * hintereinander (siehe portalside_to_value) liegen. Liegen * sie hintereinander, so werden diese zu einem Portal * verschmolzen. */ void area_merge_portals(area_t *area) { portalside_t *first, *cur; again: first = cur = area->portals; if (cur) do { assert(cur->next->prev == cur); assert(cur->prev->next == cur); #ifndef NDEBUG int cur_value = portalside_to_value(cur); int next_value = portalside_to_value(cur->next); assert(cur == cur->next || cur_value != next_value); #endif if (portal_is_mergable_with_neighbour(cur)) { portalside_merge_with_neighbour(cur); goto again; } cur = cur->next; } while (cur != first); } /* MAP Functions ********************************************/ map_t *map_alloc() { return (map_t*)malloc(sizeof(map_t)); } void map_free(map_t *map) { assert(map); // Uuah! for (int x = 0; x < map->width; x++) { for (int y = 0; y < map->height; y++) { area_t *area = MAP_TILE(map, x, y)->area; if (!area) continue; portalside_t *portal = area->portals; for (int xx = area->x1; xx <= area->x2; xx++) { for (int yy = area->y1; yy <= area->y2; yy++) { MAP_TILE(map, xx, yy)->area = NULL; } } free(area); if (!portal) continue; portalside_t *cur = portal; do { if (cur->otherside) { free(cur->portal); cur->otherside->otherside = NULL; } portalside_t *tmp = cur; cur = cur->next; free(tmp); } while (cur != portal); } } free(map->tiles); free(map); } void map_init(map_t *map, int width, int height) { assert(map); map->width = width; map->height = height; map->next_region = 1; map->tiles = (tile_t*)malloc(width * height * sizeof(tile_t)); map->path_id = 0; assert(map->tiles); for (int n = 0; n < map->width * map->height; n++) { tile_init(&map->tiles[n]); } map->dir[0] = -width; map->dir[1] = 1; map->dir[2] = width; map->dir[3] = -1; } void map_changeregion(map_t *map, int oldregion, int newregion) { for (int n = 0; n < map->width * map->height; n++) { tile_t *tile = &map->tiles[n]; if (tile->region == oldregion) tile->region = newregion; } } /* Bestimmt die Region des Tile an x, y. Hat das * Tile keine Nachbarn, so wird eine neue Region * erstellt. Gibt es einen oder mehrere Nachbarn, * so werden die Regionen zusammengefuehrt. */ void map_set_region(map_t *map, int x, int y) { int new_tile_region = REGION_NONE; tile_t *tile = MAP_TILE(map, x, y); for (int d = 0; d < 4; d++) { tile_t *ntile = tile + map->dir[d]; if (ntile->region == REGION_NONE) continue; if (new_tile_region != REGION_NONE && new_tile_region != ntile->region) { map_changeregion(map, ntile->region, new_tile_region); } else { new_tile_region = ntile->region; } } if (new_tile_region == REGION_NONE) new_tile_region = map->next_region++; tile->region = new_tile_region; } /* Die beiden der ueberlieferten und der gegenueberliegenden * Portalseiten werden verschmolzen. */ void map_zap_portal(map_t *map, portalside_t *side1, int dir) { portalside_t *side2 = side1->otherside; area_t *a1 = side1->area; area_t *a2 = side2->area; assert(side1 != side2); assert(a1 != a2); assert(a1); assert(a2); assert(side1); assert(side2); assert(side1->portal == side2->portal); assert(side2->otherside == side1); portal_t *portal = side1->portal; assert((portal->sides[0] == side1 && portal->sides[1] == side2) || (portal->sides[1] == side1 && portal->sides[0] == side2)); // Area a1 fuer a2 Tiles eintragen for (int x = a2->x1; x <= a2->x2; x++) { for (int y = a2->y1; y <= a2->y2; y++) { tile_t *tile = MAP_TILE(map, x, y); assert(tile->area == a2); tile->area = a1; } } // neue Dimension fuer a1 if (dir == PORTAL_DIR_HORIZONTAL) { a1->y1 = MIN(a1->y1, a2->y1); a1->y2 = MAX(a1->y2, a2->y2); } else { a1->x1 = MIN(a1->x1, a2->x1); a1->x2 = MAX(a1->x2, a2->x2); } // verweise von portalseiten von area 2 aendern portalside_t *first = a2->portals; portalside_t *cur = a2->portals; do { assert(cur->next->prev == cur); assert(cur->prev->next == cur); assert(cur->area == a2); cur->area = a1; cur = cur->next; } while (cur != first); // portallisten von a1 und a2 verschmelzen // // s11 ->- ->- s21 // ^ \ / v // s12 side1 side2 s22 // ^ / \ v // s13 -<- -<- s23 // // side1 und side2 werden geloscht. if (side1->next == side1 && side2->next == side2) { // portale sind jeweils die einzigen auf beiden areas? a1->portals = NULL; } else if (side1->next == side1) { // side1 ist einziges Portal auf area1 side2->next->prev = side2->prev; side2->prev->next = side2->next; a1->portals = side2->next; } else if (side2->next == side2) { // side2 ist einziges Portal auf area2 side1->next->prev = side1->prev; side1->prev->next = side1->next; a1->portals = side1->next; } else { // side1 und side2 sind jeweils nicht die // einzigen portalsides assert(side1->next->prev == side1); assert(side1->prev->next == side1); assert(side2->next->prev == side2); assert(side2->prev->next == side2); assert(a1->portals->next->prev == a1->portals); assert(a1->portals->next->next->prev->prev == a1->portals); assert(a1->portals->prev->next == a1->portals); assert(a1->portals->prev->prev->next->next == a1->portals); assert(a2->portals->next->prev == a2->portals); assert(a2->portals->next->next->prev->prev == a2->portals); assert(a2->portals->prev->next == a2->portals); assert(a2->portals->prev->prev->next->next == a2->portals); side1->prev->next = side2->next; side2->next->prev = side1->prev; side1->next->prev = side2->prev; side2->prev->next = side1->next; a1->portals = side1->next; assert(a1->portals != side1); assert(a1->portals->next != side1); assert(a1->portals->next->next != side1); assert(a1->portals->next->next->next != side1); assert(a1->portals->next->prev == a1->portals); assert(a1->portals->prev->next == a1->portals); } assert(!a1->portals || a1->portals->next->prev == a1->portals); assert(!a1->portals || a1->portals->prev->next == a1->portals); assert(!a1->portals || a1->portals->otherside->otherside == a1->portals); // portal zwischen a1 und a2 loeschen portal_destroy(portal); // beide portalseiten Loeschen portalside_destroy(side1); portalside_destroy(side2); // uebernommenes Area loeschen area_destroy(a2); area_merge_portals(a1); } /* Prueft, ob ein Area mit seinen Nachbarn verschmelzbar ist. * Wenn ja, so wird das Area verschmolzen und das entstandene * Area wird erneut geprueft. */ void map_area_merge(map_t *map, area_t *area) { if (!area->portals) return; portalside_t *first, *cur; again: first = cur = area->portals; if (cur) do { assert(cur->next->prev == cur); assert(cur->prev->next == cur); assert(cur->otherside->otherside == cur); area_t *otherarea = cur->otherside->area; assert(cur->area != otherarea); if (cur->portal->dir == PORTAL_DIR_HORIZONTAL) { if (area->x1 == otherarea->x1 && area->x2 == otherarea->x2) { /* otherarea uebernehmen */ map_zap_portal(map, cur, PORTAL_DIR_HORIZONTAL); goto again; } } else { if (area->y1 == otherarea->y1 && area->y2 == otherarea->y2) { /* otherarea uebernehmen */ map_zap_portal(map, cur, PORTAL_DIR_VERTICAL); goto again; } } cur = cur->next; } while (cur != first); } /* Erzeugt ein neues 1x1 Area und verbindet es ueber * Portale mit seinen Nachbarn. */ area_t *map_area_add(map_t *map, int x, int y) { area_t *area = (area_t*)malloc(sizeof(area_t)); area->x1 = area->x2 = x; area->y1 = area->y2 = y; area->portals = NULL; tile_t *tile = MAP_TILE(map, x, y); tile->area = area; for (int d = 0; d < 4; d++) { tile_t *ntile = tile + map->dir[d]; if (ntile->region == REGION_NONE) continue; assert(ntile->area); switch (d) { case 0: area_connect(ntile->area, area); break; case 1: area_connect(area, ntile->area); break; case 2: area_connect(area, ntile->area); break; case 3: area_connect(ntile->area, area); break; } } return area; } void map_unsolid(map_t *map, int x, int y) { map_set_region(map, x, y); map_area_merge(map, map_area_add(map, x, y)); } /* Legt ein neues Feld an x, y frei, setzt Region, erzeugt * ein neues Area und verbindet es mit benachbarten Areas. */ int map_dig(map_t *map, int x, int y) { if (!MAP_IS_ON_MAP(map, x, y)) return 0; tile_t *tile = MAP_TILE(map, x, y); if (tile->walkable) return 1; tile->walkable = 1; map_set_region(map, x, y); #ifdef PATHFIND_AREA_MERGE map_area_merge(map, map_area_add(map, x, y)); #else map_area_add(map, x, y); #endif return 1; } /* void map_get_info(map_t *map, int x, int y) { tile_t *tile = MAP_TILE(map, x, y); printf("tile %p, region=%d\n", tile, tile->region); area_get_info(tile->area); } */ int map_get_region(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->region; } void map_get_area_dimensions(map_t *map, int x, int y, int *x1, int *y1, int *x2, int *y2) { area_t *area = MAP_TILE(map, x, y)->area; *x1 = area->x1; *y1 = area->y1; *x2 = area->x2; *y2 = area->y2; } int map_get_width(map_t *map) { return map->width; } int map_get_height(map_t *map) { return map->height; } int map_walkable(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->walkable; } int map_get_area_x1(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->area->x1; } int map_get_area_y1(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->area->y1; } int map_get_area_x2(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->area->x2; } int map_get_area_y2(map_t *map, int x, int y) { return MAP_TILE(map, x, y)->area->y2; } infon/game.h0000644000076400001440000000200210540100022012774 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef GAME_H #define GAME_H #include "server.h" void game_init(); void game_one_game(); void game_send_initial_update(client_t *client); void game_call_rule_handler(const char *name, int params); #endif infon/creature.h0000644000076400001440000000742510603314646013736 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef CREATURE_H #define CREATURE_H #include #include "path.h" #include "player.h" #include "server.h" #include "common_creature.h" #include "common_world.h" typedef struct creature_s { int x; int y; creature_type type; int food; int health; player_t *player; int target_id; pathnode_t *path; int convert_food; creature_type convert_type; int spawn_food; creature_state state; int suicide; int age_action_deltas; int spawn_time; char message[9]; unsigned char dirtymask; int network_food_health; int network_state; int network_path_x; int network_path_y; int network_speed; int network_target; // Letzte uebermittelte Koordinate (fuer Delta Kompression) int network_last_x; int network_last_y; int vm_id; struct creature_s *hash_next; } creature_t; creature_t *creature_by_id(int creature_num); int creature_id(const creature_t *creature); creature_t *creature_get_checked_lua(lua_State *L, int idx); creature_t *creature_spawn(player_t *player, creature_t *parent, int x, int y, creature_type type); void creature_kill(creature_t *creature, creature_t *killer); int creature_set_path(creature_t *creature, int x, int y); int creature_set_health(creature_t *creature, int health); int creature_set_target(creature_t *creature, int target); int creature_set_state(creature_t *creature, int state); int creature_set_conversion_type(creature_t *creature, creature_type type); void creature_set_message(creature_t *creature, const char *message); int creature_set_food(creature_t *creature, int food); int creature_set_type(creature_t *creature, creature_type type); int creature_suicide(creature_t *creature); creature_t *creature_nearest_enemy(const creature_t *reference, int *distptr); int creature_max_health(const creature_t *creature); int creature_speed(const creature_t *creature); int creature_dist(const creature_t *a, const creature_t *b); int creature_food_on_tile(const creature_t *creature); maptype_e creature_tile_type(const creature_t *creature); int creature_max_food(const creature_t *creature); int creature_hitpoints(const creature_t *creature); int creature_attack_distance(const creature_t *creature); void creature_kill_all_players_creatures(player_t *player); void creature_moveall(int delta); int creature_num_creatures(); /* Network */ void creature_send_initial_update(client_t *client); void creature_to_network(creature_t *creature, int dirtymask, client_t *client); void creature_init(); void creature_shutdown(); #endif infon/map.h0000644000076400001440000000637310517467541012711 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PATHFINDING_MAP_H #define PATHFINDING_MAP_H #ifdef __cplusplus extern "C" { #endif #define TILE_SCALE 256 typedef struct area_s area_t; typedef struct portalside_s portalside_t; typedef struct portal_s portal_t; /* Tile */ typedef struct tile_s { int walkable; int region; area_t *area; #define REGION_NONE (0) } tile_t; #define TILE_WIDTH TILE_SCALE #define TILE_HEIGHT TILE_SCALE #define TILE_X1(x) ((x) * TILE_WIDTH) #define TILE_Y1(y) ((y) * TILE_HEIGHT) #define TILE_X2(x) (TILE_X1(x) + TILE_WIDTH - 1) #define TILE_Y2(y) (TILE_Y1(y) + TILE_HEIGHT - 1) #define TILE_XCENTER(x) (TILE_X1(x) + TILE_WIDTH / 2) #define TILE_YCENTER(y) (TILE_Y1(y) + TILE_HEIGHT / 2) #define X_TO_TILEX(x) ((int)((x) / TILE_WIDTH)) #define Y_TO_TILEY(y) ((int)((y) / TILE_HEIGHT)) /* Area */ struct area_s { int x1; int y1; int x2; int y2; portalside_t *portals; }; /* Portal */ struct portalside_s { area_t *area; portalside_t *otherside; portal_t *portal; portalside_t *next; portalside_t *prev; }; struct portal_s { portalside_t *sides[2]; // 0 == LEFT/ABOVE 1 == RIGHT/BELOW int dir; #define PORTAL_DIR_HORIZONTAL 0 #define PORTAL_DIR_VERTICAL 1 int s1; int s2; int cx; int cy; // Von der Pfadsuche verwendet int path_id; int cost_from_start; portal_t *path_prev; }; /* Map */ typedef struct map_s { int path_id; int width; int height; tile_t *tiles; int next_region; int dir[4]; } map_t; #define MAP_TILE(map, x, y) (&(map)->tiles[(map)->width * (y) + (x)]) #define MAP_IS_ON_MAP(map, x, y) ((x) >= 0 && (x) < (map)->width && \ (y) >= 0 && (y) < (map)->height) int map_dig(map_t *map, int x, int y); void map_get_info(map_t *map, int x, int y); int map_get_region(map_t *map, int x, int y); void map_get_area_dimensions(map_t *map, int x, int y, int *x1, int *y1, int *x2, int *y2); int map_get_width(map_t *map); int map_get_height(map_t *map); int map_walkable(map_t *map, int x, int y); int map_get_area_x1(map_t *map, int x, int y); int map_get_area_y1(map_t *map, int x, int y); int map_get_area_x2(map_t *map, int x, int y); int map_get_area_y2(map_t *map, int x, int y); map_t *map_alloc(); void map_init(map_t *map, int width, int height); void map_free(map_t *map); #ifdef __cplusplus } #endif #endif infon/scroller.c0000600000076400001440000000217410505727454013736 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include "scroller.h" #include "packet.h" #include "server.h" void add_to_scroller(const char* msg) { // Network Sync packet_t packet; packet_init(&packet, PACKET_SCROLLER_MSG); packet_writeXX(&packet, msg, strlen(msg)); server_send_packet(&packet, SEND_BROADCAST); } infon/scroller.h0000600000076400001440000000161010505727454013735 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef SCROLLER_H #define SCROLLER_H void add_to_scroller(const char* msg); #endif infon/infon.rc0000644000076400001440000000113310540104462013371 0ustar dividuumusers#include icon ICON MOVEABLE PURE LOADONCALL DISCARDABLE "infon.ico" 1 VERSIONINFO FILETYPE VFT_APP { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "CompanyName", "fw@dividuum.de" VALUE "FileDescription", "Infon Battle Arena Client" VALUE "FileVersion", REVISION VALUE "InternalName", "infon" VALUE "LegalCopyright", "GPL" VALUE "OriginalFilename", "infon.exe" VALUE "ProductName", "Infon Battle Arena" VALUE "ProductVersion", REVISION } } } infon/misc.c0000644000076400001440000000441710603200766013045 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #ifdef WIN32 #include #endif #include #include "global.h" void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); #ifdef WIN32 char buf[1024]; vsnprintf(buf, sizeof(buf), fmt, ap); MessageBoxA(GetActiveWindow(), buf, "Fatal Error", MB_ICONSTOP); #else vprintf(fmt, ap); printf("\n"); #endif va_end(ap); exit(1); } void infomsg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); #ifdef WIN32 char buf[1024]; vsnprintf(buf, sizeof(buf), fmt, ap); MessageBoxA(GetActiveWindow(), buf, "Info", MB_ICONINFORMATION); #else printf("--[ Info ]--------------------\n"); vprintf(fmt, ap); printf("\n----------------------------\n"); #endif va_end(ap); } int yesno(const char *fmt, ...) { #ifdef WIN32 char buf[1024]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); return MessageBoxA(GetActiveWindow(), buf, GAME_NAME, MB_ICONQUESTION | MB_YESNO) == IDYES; #else assert(0); return 0; #endif } #ifdef WIN32 const char *ErrorString(int error) { static char buf[4096]; if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) buf, sizeof (buf), NULL)) snprintf(buf, sizeof(buf), "errorcode %d", error); return buf; } #endif infon/path.c0000644000076400001440000002514310544710167013052 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include "path.h" #define MIN(a,b) ((a)<(b)?(a):(b)) #define ABS(x) ((x)<0?-(x):(x)) inline int path_calc_cost(int x1, int y1, int x2, int y2) { //return ABS(x1 - x2) + ABS(y1 - y2); const int xd = x1 - x2; const int yd = y1 - y2; return (int)sqrt(xd * xd + yd * yd); } pathnode_t *pathnode_new(int x, int y) { pathnode_t *node = (pathnode_t*)malloc(sizeof(pathnode_t)); assert(node); node->x = x; node->y = y; node->next = NULL; return node; } void finder_openset_moveup(open_t *set, int curidx) { // und in Richtung wurzel des Heaps verschieben, // bis richtige position erreicht ist while (curidx > 0) { int loweridx = (curidx - 1) >> 1; if (set[curidx].cost >= set[loweridx].cost) break; open_t tmp = set[curidx]; set[curidx] = set[loweridx]; set[loweridx] = tmp; curidx = loweridx; } } void finder_openset_add(pathfinder_t *finder, portal_t *portal, int side, int cost) { if (finder->numopen >= finder->maxopen) return; open_t *set = finder->openset; // Neues open_t fuellen set[finder->numopen].portal = portal; set[finder->numopen].fromside = side; set[finder->numopen].cost = cost; finder_openset_moveup(set, finder->numopen); finder->numopen++; } void finder_openset_update(pathfinder_t *finder, int idx, int side, int cost) { open_t *set = finder->openset; set[idx].fromside = side; set[idx].cost = cost; finder_openset_moveup(set, idx); } // Entfernt set[0], indem das letzte element an // stelle 0 verschoben wird und dann an die richtige // stelle vertauscht wird. void finder_openset_shift(pathfinder_t *finder) { assert(finder->numopen > 0); finder->numopen--; open_t *set = finder->openset; set[0] = set[finder->numopen]; int curidx = 0; int maxidx = (finder->numopen >> 1) - 1; while (curidx <= maxidx) { int higheridx = (curidx << 1) + 1; if (higheridx < finder->numopen - 1 && set[higheridx].cost >= set[higheridx + 1].cost) higheridx++; if (set[curidx].cost <= set[higheridx].cost) break; open_t tmp = set[curidx]; set[curidx] = set[higheridx]; set[higheridx] = tmp; curidx = higheridx; } } int finder_openset_find(pathfinder_t *finder, portal_t *portal) { open_t *set = finder->openset; for (int idx = 0; idx < finder->numopen; idx++) { if (set[idx].portal == portal) return idx; } return -1; } pathfinder_t *finder_alloc() { return (pathfinder_t*)malloc(sizeof(pathfinder_t)); } void finder_init(pathfinder_t *finder) { finder->path_id = 0; finder->maxopen = 16384; finder->openset = (open_t*)malloc(finder->maxopen * sizeof(open_t)); finder->randcnt = 0; for (int i = 0; i < 256; i++) finder->random[i] = rand() % 50; } void finder_shutdown(pathfinder_t *finder) { free(finder->openset); } pathnode_t *finder_find(pathfinder_t *finder, map_t *map, int sx, int sy, int ex, int ey) { const int tsx = X_TO_TILEX(sx); const int tsy = Y_TO_TILEY(sy); const int tex = X_TO_TILEX(ex); const int tey = Y_TO_TILEY(ey); const tile_t *stile = MAP_TILE(map, tsx, tsy); const tile_t *etile = MAP_TILE(map, tex, tey); // Ziel und Quelle gleich if (sx == ex && sy == ey) return pathnode_new(ex, ey); // Gibt es ueberhaupt eine Verbindung? if (stile->region != etile->region) return NULL; assert(stile->walkable); assert(etile->walkable); // Spezialfall: Nur ein Tile if ((ABS(tsx - tex) == 1 && (tsy == tey)) || ((tsx == tex) && ABS(tsy - tey) == 1)) return pathnode_new(ex, ey); const area_t *sarea = stile->area; const area_t *earea = etile->area; // Ziel und Quelle im gleichen Area? if (sarea == earea) return pathnode_new(ex, ey); // Neue Path id zum eindeutigen erkennen, ob // path_prev in portal_t aktuell oder veraltet ist holen. finder->path_id = ++map->path_id; // Openset ruecksetzen finder->numopen = 0; const portalside_t *cur, *first; // Vom Ziel aus vorgehen und in Richtung Start // vorarbeiten. Haette vielleicht den Vorteil, das // bei einem Teilberechneten Pfad bereits in Richtung // des letzten Pathnodes losgelaufen werden kann. cur = first = earea->portals; assert(cur); // Moegliche Portale fuer erste Iteration in Openset // eintragen. do { portal_t *portal = cur->portal; portal->path_id = finder->path_id; portal->cost_from_start = path_calc_cost(ex, ey, portal->cx, portal->cy); portal->path_prev = NULL; finder_openset_add(finder, portal, portal->sides[1]->area == earea, portal->cost_from_start + path_calc_cost(portal->cx, portal->cy, sx, sy) * DEST_WEIGHT); cur = cur->next; } while (cur != first); portal_t *pathportal = NULL; while (1) { // Nichts gefunden? if (finder->numopen == 0) return NULL; // Openset Element mit den geringsten Kosten holen open_t *open = finder->openset; portal_t *portal = open->portal; int side = open->fromside; // Von aktuellem Portal aus ist das StartArea erreichbar? if (portal->sides[0]->area == sarea || portal->sides[1]->area == sarea) { pathportal = portal; break; } // Erstes Element loeschen. Ab hier ist open ungueltig! finder_openset_shift(finder); // Das gerade betrachtete Portal verbindet 2 Areas // miteinander. In side steht, von welcher Seite // aus wir das Portal betreten haben. // Area ist Area, dessen weitere Portale wir jetzt // durchschauen. area_t *area = portal->sides[1 - side]->area; // Moegliche Zielportale durchgehen cur = first = portal->sides[1 - side]; do { portal_t *nportal = cur->portal; //printf("moegliches Ziel: %p ... ", nportal); // Kandidat ist Portal, durch das wird aktuelles // Area betreten haben? if (nportal == portal) { if (cur->next == first) break; cur = cur->next; continue; } // Kosten zu diesem Portal sind die Kosten // zum bisherigen Portal plus die Kosten // von Portal zu Portal. const int ncosts = portal->cost_from_start + path_calc_cost(portal->cx, portal->cy, nportal->cx, nportal->cy) + //finder->random[++finder->randcnt & 0xFF]; 0; // Noch nicht bekanntes Portal? if (nportal->path_id != finder->path_id) { nportal->path_id = finder->path_id; nportal->cost_from_start = ncosts; nportal->path_prev = portal; finder_openset_add(finder, nportal, nportal->sides[1]->area == area, ncosts + path_calc_cost(nportal->cx, nportal->cy, sx, sy) * DEST_WEIGHT); } else if (ncosts < nportal->cost_from_start) { nportal->cost_from_start = ncosts; nportal->path_prev = portal; const int idx = finder_openset_find(finder, nportal); // Nicht mehr im Openset? if (idx < 0) { finder_openset_add(finder, nportal, nportal->sides[1]->area == area, ncosts + path_calc_cost(nportal->cx, nportal->cy, sx, sy) * DEST_WEIGHT); } else { finder_openset_update(finder, idx, nportal->sides[1]->area == area, ncosts + path_calc_cost(nportal->cx, nportal->cy, sx, sy) * DEST_WEIGHT); } } cur = cur->next; } while (cur != first); } // von pathportal zu pathportal vom pfandanfang zum // pfadende durchhangeln und dabei Ergebnispfad // zusammenbauen pathnode_t pathstart; pathnode_t *curpath = &pathstart; int lastx = sx, lasty = sy; do { if (pathportal->dir == PORTAL_DIR_HORIZONTAL) { curpath->next = pathnode_new(pathportal->cx, pathportal->cy + (lasty > pathportal->cy)); curpath = curpath->next; curpath->next = pathnode_new(pathportal->cx, pathportal->cy + (lasty <= pathportal->cy)); } else { curpath->next = pathnode_new(pathportal->cx + (lastx > pathportal->cx), pathportal->cy); curpath = curpath->next; curpath->next = pathnode_new(pathportal->cx + (lastx <= pathportal->cx), pathportal->cy); } curpath = curpath->next; lastx = curpath->x; lasty = curpath->y; pathportal = pathportal->path_prev; } while (pathportal); curpath->next = pathnode_new(ex, ey); return pathstart.next; } void path_delete(pathnode_t *path) { while (path) { pathnode_t *tmp = path; path = path->next; free(tmp); } } infon/client_world.c0000644000076400001440000000716210536567243014612 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include "renderer.h" #include "client_world.h" #include "misc.h" static int initialized; static client_maptile_t *map; static client_world_info_t info; #define MAPTILE(x, y) (map[(y) * info.width + (x)]) const client_world_info_t *client_world_get_info() { return initialized ? &info : NULL; } const client_maptile_t *client_world_get() { return initialized ? map : NULL; } const client_maptile_t *client_world_get_tile(int x, int y) { return &MAPTILE(x, y); } void client_world_destroy() { if (!initialized) return; free(map); initialized = 0; } void client_world_from_network(packet_t *packet) { if (!initialized) PROTOCOL_ERROR(); uint8_t x; uint8_t y; if (!packet_read08(packet, &x)) PROTOCOL_ERROR(); if (!packet_read08(packet, &y)) PROTOCOL_ERROR(); if (x >= info.width) PROTOCOL_ERROR(); if (y >= info.height) PROTOCOL_ERROR(); uint8_t food_type; if (!packet_read08(packet, &food_type)) PROTOCOL_ERROR(); uint8_t food = food_type & 0x0F; if (food > 10) PROTOCOL_ERROR(); MAPTILE(x, y).food = food; uint8_t type = (food_type & 0xF0) >> 4; if (type >= TILE_LAST_DEFINED) PROTOCOL_ERROR(); MAPTILE(x,y).type = type; uint8_t gfx; if (!packet_read08(packet, &gfx)) PROTOCOL_ERROR(); if (gfx >= TILE_GFX_LAST_DEFINED) PROTOCOL_ERROR(); MAPTILE(x,y).gfx = gfx; renderer_world_changed(x, y); } void client_world_info_from_network(packet_t *packet) { if (initialized) client_world_destroy(); uint8_t w, h, kx, ky; if (!packet_read08(packet, &w)) PROTOCOL_ERROR(); if (!packet_read08(packet, &h)) PROTOCOL_ERROR(); if (!packet_read08(packet, &kx)) PROTOCOL_ERROR(); if (!packet_read08(packet, &ky)) PROTOCOL_ERROR(); info.width = w; info.height = h; info.koth_x = kx; info.koth_y = ky; if (info.koth_x >= info.width) PROTOCOL_ERROR(); if (info.koth_y >= info.height) PROTOCOL_ERROR(); map = malloc(info.width * info.height * sizeof(client_maptile_t)); initialized = 1; // Tile Texturen setzen for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { MAPTILE(x,y).food = 0; MAPTILE(x,y).type = TILE_SOLID; MAPTILE(x,y).gfx = TILE_GFX_SOLID; } } renderer_world_info_changed(&info); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { renderer_world_changed(x, y); } } } void client_world_init() { initialized = 0; } void client_world_shutdown() { client_world_destroy(); } infon/renderer.c0000644000076400001440000001610110552756360013722 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "misc.h" #include "global.h" #include "renderer.h" #include "client.h" #include "client_game.h" #include "client_player.h" #include "client_creature.h" #include "client_world.h" #include "common_player.h" #if defined(NO_EXTERNAL_RENDERER) && !defined(BUILTIN_RENDERER) #error "this build can neither load external renderers nor contains an internal renderer." #endif #ifndef NO_EXTERNAL_RENDERER #ifdef WIN32 #include #include static HINSTANCE dlhandle; #else #include static void *dlhandle; #endif #endif static const renderer_api_t *renderer = 0; static int is_open = 0; static int render_shutdown = 0; static void renderer_set_shutdown() { render_shutdown = 1; } static const infon_api_t infon_api = { .version = GAME_NAME, .max_players = MAXPLAYERS, .max_creatures = MAXCREATURES, .each_creature = client_creature_each, .each_player = client_player_each, .get_creature = client_creature_get, .get_player = client_player_get, .get_king = client_player_get_king, .get_world = client_world_get, .get_world_info = client_world_get_info, .get_world_tile = client_world_get_tile, .get_intermission = client_get_intermission, .get_traffic = client_traffic, .shutdown = renderer_set_shutdown, .printf = client_printf, .is_demo = client_is_file_source, }; int renderer_init_from_pointer(render_loader loader) { renderer = loader(&infon_api); if (renderer->version == RENDERER_API_VERSION) return 1; fprintf(stderr, "version mismatch between renderer and engine: renderer api %d != engine api %d\n", renderer->version, RENDERER_API_VERSION); return 0; } #ifndef NO_EXTERNAL_RENDERER void renderer_close_file() { #ifdef WIN32 if (dlhandle) FreeLibrary(dlhandle); dlhandle = 0; #else if (dlhandle) dlclose(dlhandle); dlhandle = NULL; #endif } int renderer_open_file(const char *shared) { fprintf(stderr, "loading renderer plugin '%s'\n * ", shared); #ifdef WIN32 dlhandle = LoadLibrary(shared); if (!dlhandle) { fprintf(stderr, "LoadLibrary failed: %s\n", ErrorString(GetLastError())); goto failed; } render_loader loader = (render_loader)GetProcAddress(dlhandle, TOSTRING(RENDERER_SYM)); #else dlhandle = dlopen(shared, RTLD_NOW); if (!dlhandle) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); goto failed; } render_loader loader = (render_loader)dlsym(dlhandle, TOSTRING(RENDERER_SYM)); #endif if (!loader) { fprintf(stderr, "cannot find symbol '" TOSTRING(RENDERER_SYM) "'\n"); goto failed; } if (!renderer_init_from_pointer(loader)) goto failed; fprintf(stderr, "ok (renderer struct @ %p)\n", (void*)renderer); return 1; failed: renderer_close_file(); return 0; } int renderer_search_and_load(const char *name) { char buf[4096]; #ifdef WIN32 const char *ext = "dll"; #else const char *ext = "so"; #endif #define renderer_try(fmt, ...) \ do { \ snprintf(buf, sizeof(buf), fmt, __VA_ARGS__); \ if (renderer_open_file(buf)) return 1; \ } while (0) renderer_try("%s", name); #ifdef WIN32 renderer_try(".\\%s.%s", name, ext); if (getenv("USERPROFILE")) renderer_try("%s\\infon\\%s.%s", getenv("USERPROFILE"), name, ext); #else renderer_try("./%s.%s", name, ext); if (getenv("INFON_PATH")) renderer_try("%s/%s.%s", getenv("INFON_PATH"), name, ext); if (getenv("HOME")) renderer_try("%s/.infon/%s.%s", getenv("HOME"), name, ext); #endif #ifdef RENDERER_PATH renderer_try("%s/%s.%s", RENDERER_PATH, name, ext); #endif renderer_try("%s%s", PREFIX, name); return 0; } #endif int renderer_init(const char *name) { #ifndef NO_EXTERNAL_RENDERER if (renderer_search_and_load(name)) return 1; #endif #ifdef BUILTIN_RENDERER if (!strcmp(name, TOSTRING(BUILTIN_RENDERER))) { fprintf(stderr, "using builtin renderer '%s'\n", TOSTRING(BUILTIN_RENDERER)); renderer_init_from_pointer(RENDERER_SYM); return 1; } #endif return 0; } int renderer_open(int w, int h, int fs) { render_shutdown = 0; int ret = renderer->open(w, h, fs); if (ret) is_open = 1; return ret; } void renderer_close() { assert(is_open); renderer->close(); is_open = 0; } void renderer_tick(int game_time, int delta) { renderer->tick(game_time, delta); } void renderer_world_info_changed(const client_world_info_t *info) { if (renderer->world_info_changed) renderer->world_info_changed(info); } void renderer_world_changed(int x, int y) { if (renderer->world_changed) renderer->world_changed(x, y); } void renderer_player_joined(client_player_t *player) { if (renderer->player_joined) player->userdata = renderer->player_joined(player); } void renderer_player_changed(const client_player_t *player, int changed) { if (renderer->player_changed) renderer->player_changed(player, changed); } void renderer_player_left(const client_player_t *player) { if (renderer->player_left) renderer->player_left(player); } void renderer_creature_spawned(client_creature_t *creature) { if (renderer->creature_spawned) creature->userdata = renderer->creature_spawned(creature); } void renderer_creature_changed(const client_creature_t *creature, int changed) { if (renderer->creature_changed) renderer->creature_changed(creature, changed); } void renderer_creature_died(const client_creature_t *creature) { if (renderer->creature_died) renderer->creature_died(creature); } void renderer_scroll_message(const char *buf) { if (renderer->scroll_message) renderer->scroll_message(buf); } int renderer_wants_shutdown() { return render_shutdown; } void renderer_shutdown() { if (is_open) renderer_close(); #ifndef NO_EXTERNAL_RENDERER renderer_close_file(); #endif renderer = NULL; } infon/sdl_video.c0000644000076400001440000001167110603240403014052 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include "misc.h" #include "global.h" #include "sdl_sprite.h" #include "sdl_video.h" static SDL_Surface *screen; static Uint32 flags = SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_HWACCEL | SDL_RESIZABLE; static sge_bmpFont *font; static char tiny_font[1792]; // XXX Hardcoded void video_init(int w, int h, int fs) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) if (SDL_Init(0) == -1) die("Couldn't initialize SDL: %s", SDL_GetError()); const SDL_VideoInfo *vi = SDL_GetVideoInfo(); if (!vi) die("SDL_getVideoInfo() failed: %s", SDL_GetError()); if (!(vi->vfmt->BitsPerPixel == 16 || vi->vfmt->BitsPerPixel == 32)) die("insufficient color depth"); if (fs) flags |= SDL_FULLSCREEN; screen = SDL_SetVideoMode(w, h, vi->vfmt->BitsPerPixel, flags); if (!screen) die("Couldn't set display mode: %s", SDL_GetError()); video_set_title(GAME_NAME); SDL_ShowCursor(1); #if WIN32 SDL_SysWMinfo wminfo; if (SDL_GetWMInfo(&wminfo) == 1) { HWND hwnd = wminfo.window; HINSTANCE handle = GetModuleHandle(NULL); HICON icon = LoadIcon(handle, "icon"); SetClassLong(hwnd, GCL_HICON, (LONG) icon); } #endif // SDL_EnableUNICODE(1); font = sge_BF_OpenFont(PREFIX "gfx/font.png", SGE_BFTRANSP|SGE_BFPALETTE); if(!font) die("Cannot open font font.png: %s", SDL_GetError()); /* Load a font and draw with it */ FILE *file = fopen(PREFIX "gfx/5x7.fnt","r"); if (!file) die("Cannot open tiny font file 5x7.fnt: %s", strerror(errno)); fread(&tiny_font,sizeof(tiny_font), 1, file); fclose(file); gfxPrimitivesSetFont(tiny_font, 5, 7); } void video_set_title(const char *title) { SDL_WM_SetCaption(title, "infon"); } void video_shutdown() { sge_BF_CloseFont(font); SDL_QuitSubSystem(SDL_INIT_VIDEO); } void video_fullscreen_toggle() { #ifdef WIN32 flags ^= SDL_FULLSCREEN; screen = SDL_SetVideoMode(0, 0, 0, flags); if (!screen) die("couldn't toggle fullscreen. sorry"); #else SDL_WM_ToggleFullScreen(screen); #endif } void video_resize(int w, int h) { if (w < 320 || h < 200) return; screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) die("couldn't change resolution. sorry"); } void video_flip() { //SDL_UpdateRect(screen, 0, 0, 0, 0); SDL_Flip(screen); } int video_width() { return screen->w; } int video_height() { return screen->h; } void video_draw(int x, int y, SDL_Surface *sprite) { //if (x < 0 || y < 0) return; const int w = sprite->w; const int h = sprite->h; SDL_Rect dstrect = {x, y, x + w, y + h}; SDL_BlitSurface(sprite, NULL, screen, &dstrect); } void video_rect(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { SDL_Rect dstrect = {x1, y1, x2 - x1, y2 - y1}; SDL_FillRect(screen, &dstrect, SDL_MapRGBA(screen->format, r, g, b, a)); } void video_hline(Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { hlineRGBA(screen, x1, x2, y, r, g, b, a); } void video_line_green_red(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2) { sge_AAmcLine(screen, x1, y1, x2, y2, 0, 0xFF, 0, 0xFF, 0, 0); } void video_line_green(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2) { sge_AAmcLine(screen, x1, y1, x2, y2, 0, 0xFF, 0, 0, 0x9F, 0); } void video_write(Sint16 x, Sint16 y, const char *text) { sge_BF_textout(screen, font, (char*)text, x, y); } void video_tiny(Sint16 x, Sint16 y, const char *text) { stringRGBA(screen, x, y, text, 0, 0, 0, 128); stringRGBA(screen, x+1, y+1, text, 255, 255, 255, 128); } SDL_Surface *video_new_surface(int w, int h) { return SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); } infon/client_creature.c0000644000076400001440000002257410544676672015307 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include "infon.h" #include "renderer.h" #include "global.h" #include "client_creature.h" #include "common_player.h" #include "misc.h" #include "map.h" static client_creature_t creatures[MAXCREATURES]; #define CREATURE_USED(creature) ((creature)->used) const client_creature_t *client_creature_get(int num) { if (num < 0 || num >= MAXCREATURES) return NULL; const client_creature_t *creature = &creatures[num]; if (!CREATURE_USED(creature)) return NULL; return creature; } void client_creature_each(void (*callback)(const client_creature_t *creature, void *opaque), void *opaque) { for (int n = 0; n < MAXCREATURES; n++) { const client_creature_t *creature = &creatures[n]; if (!CREATURE_USED(creature)) continue; callback(creature, opaque); } } static void client_creature_add_path(client_creature_t *creature, int x, int y, int beam) { client_pathnode_t *node = malloc(sizeof(client_pathnode_t)); node->x = x; node->y = y; node->beam = beam; node->next = NULL; if (creature->pathlen == 0) { assert(!creature->last && !creature->path); creature->last = creature->path = node; } else { assert(creature->last); assert(creature->path); assert(creature->last->next == NULL); creature->last = creature->last->next = node; } creature->pathlen++; } static void client_creature_del_path(client_creature_t *creature) { assert(creature->pathlen > 0); assert(creature->path && creature->last); client_pathnode_t *tmp = creature->path; creature->path = creature->path->next; if (--creature->pathlen == 0) { assert(creature->last == tmp); creature->last = NULL; } free(tmp); } static void client_creature_kill(client_creature_t *creature) { renderer_creature_died(creature); while (creature->path) client_creature_del_path(creature); creature->used = 0; } void client_creature_move(int delta) { if (delta == 0) return; client_creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; int travelled = (creature->speed + 150 * max(0, creature->pathlen - 1)) * delta / 1000; again: if (!creature->path) continue; if (creature->path->beam) { creature->x = creature->path->x; creature->y = creature->path->y; client_creature_del_path(creature); goto again; } const int dx = creature->path->x - creature->x; const int dy = creature->path->y - creature->y; const int dist_to_waypoint = sqrt(dx*dx + dy*dy); if (travelled >= dist_to_waypoint) { creature->x = creature->path->x; creature->y = creature->path->y; travelled -= dist_to_waypoint; client_creature_del_path(creature); goto again; } creature->x += dx * travelled / dist_to_waypoint; creature->y += dy * travelled / dist_to_waypoint; int winkel_to_waypoint = 16 * ((atan2(-dx, dy == 0 ? 1 : dy) + M_PI) / M_PI); int dw = creature->dir - winkel_to_waypoint; if (dw < -16) dw += 32; if (dw > 16) dw -= 32; if (dw < -1) { creature->dir += dw < -5 ? 2 : 1; } else if (dw > 1) { creature->dir -= dw > 5 ? 2 : 1; } else { creature->dir = winkel_to_waypoint; } if (creature->dir >= 32) creature->dir -= 32; if (creature->dir < 0) creature->dir += 32; } } void client_creature_smile_from_network(packet_t *packet) { uint16_t creatureno; if (!packet_read16(packet, &creatureno)) PROTOCOL_ERROR(); if (creatureno >= MAXCREATURES) PROTOCOL_ERROR(); client_creature_t *creature = &creatures[creatureno]; if (!CREATURE_USED(creature)) PROTOCOL_ERROR(); creature->smile_time = game_time; } void client_creature_from_network(packet_t *packet) { uint16_t creatureno; if (!packet_read16(packet, &creatureno)) PROTOCOL_ERROR(); if (creatureno >= MAXCREATURES) PROTOCOL_ERROR(); client_creature_t *creature = &creatures[creatureno]; uint8_t updatemask; if (!packet_read08(packet, &updatemask)) PROTOCOL_ERROR(); if (updatemask & CREATURE_DIRTY_ALIVE) { uint8_t playerno; if (!packet_read08(packet, &playerno)) PROTOCOL_ERROR(); if (playerno == 0xFF) { if (!CREATURE_USED(creature)) PROTOCOL_ERROR(); client_creature_kill(creature); return; } else { if (CREATURE_USED(creature)) PROTOCOL_ERROR(); memset(creature, 0, sizeof(client_creature_t)); if (playerno >= MAXPLAYERS) PROTOCOL_ERROR(); creature->player = playerno; uint16_t vm_id, x, y; if (!packet_read16(packet, &vm_id)) PROTOCOL_ERROR(); if (!packet_read16(packet, &x)) PROTOCOL_ERROR(); if (!packet_read16(packet, &y)) PROTOCOL_ERROR(); creature->last_x = x; creature->last_y = y; creature->vm_id = vm_id; creature->num = creatureno; creature->x = x * CREATURE_POS_RESOLUTION; creature->y = y * CREATURE_POS_RESOLUTION; creature->used = 1; renderer_creature_spawned(creature); // XXX: x, y checken? client_creature_add_path(creature, creature->last_x * CREATURE_POS_RESOLUTION, creature->last_y * CREATURE_POS_RESOLUTION, 1); } } if (!CREATURE_USED(creature)) PROTOCOL_ERROR(); if (updatemask & CREATURE_DIRTY_TYPE) { uint8_t type; if (!packet_read08(packet, &type)) PROTOCOL_ERROR(); if (type >= CREATURE_TYPES) PROTOCOL_ERROR(); creature->type = type; } if (updatemask & CREATURE_DIRTY_FOOD_HEALTH) { uint8_t food_health; if (!packet_read08(packet, &food_health)) PROTOCOL_ERROR(); creature->food = food_health >> 4; creature->health = food_health & 0x0F; } if (updatemask & CREATURE_DIRTY_STATE) { uint8_t state; if (!packet_read08(packet, &state)) PROTOCOL_ERROR(); if (state >= CREATURE_STATES) PROTOCOL_ERROR(); creature->state = state; } if (updatemask & CREATURE_DIRTY_PATH) { uint16_t x, y; if (!packet_read16(packet, &x)) PROTOCOL_ERROR(); if (!packet_read16(packet, &y)) PROTOCOL_ERROR(); int dx = x >> 1; if (x & 1) dx *= -1; int dy = y >> 1; if (y & 1) dy *= -1; creature->last_x += dx; creature->last_y += dy; // XXX: x, y checken? client_creature_add_path(creature, creature->last_x * CREATURE_POS_RESOLUTION, creature->last_y * CREATURE_POS_RESOLUTION, 0); } if (updatemask & CREATURE_DIRTY_TARGET) { uint16_t target; if (!packet_read16(packet, &target)) PROTOCOL_ERROR(); if (target >= MAXCREATURES) PROTOCOL_ERROR(); creature->target = target; } if (updatemask & CREATURE_DIRTY_MESSAGE) { uint8_t len; char buf[256]; if (!packet_read08(packet, &len)) PROTOCOL_ERROR(); if (!packet_readXX(packet, buf, len)) PROTOCOL_ERROR(); buf[len] = '\0'; snprintf(creature->message, sizeof(creature->message), "%s", buf); // creature->last_msg_set = SDL_GetTicks(); } if (updatemask & CREATURE_DIRTY_SPEED) { uint8_t speed; if (!packet_read08(packet, &speed)) PROTOCOL_ERROR(); creature->speed = speed * CREATURE_SPEED_RESOLUTION; } if (updatemask & ~CREATURE_DIRTY_ALIVE) renderer_creature_changed(creature, updatemask & ~CREATURE_DIRTY_ALIVE); } void client_creature_init() { memset(creatures, 0, sizeof(creatures)); } void client_creature_shutdown() { client_creature_t *creature = &creatures[0]; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; client_creature_kill(creature); } } infon/renderer.h0000644000076400001440000001543110552756360013734 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef RENDERER_H #define RENDERER_H #ifdef __cplusplus extern "C" { #endif #include "client_creature.h" #include "client_player.h" #include "client_world.h" #define RENDERER_API_VERSION 4 typedef struct { /* the renderer version number. set this to RENDERER_API_VERSION. */ int version; /* called once before other rendering function. should initialize a new * output with size w x h and fullscreen if fs is set. should return 1 * if successfull, 0 on failure. */ int (*open )(int w, int h, int fs); /* called once before the client exits. do cleanups here */ void (*close)(void); /* called for every frame. game_time and delta contain game time and delta * to previous frame in milliseconds */ void (*tick)(int game_time, int delta); /* called if the world changes its size (at startup or on level change). */ void (*world_info_changed)(const client_world_info_t *info); /* called for every world_tile that changed (from being solid) */ void (*world_changed )(int x, int y); /* called after a player joins the game. you can return any pointer, which will * then be saved in player->userdata */ void *(*player_joined )(const client_player_t *player); /* called if some player value changed */ void (*player_changed )(const client_player_t *player, int changed); /* called before a player leaves the game */ void (*player_left )(const client_player_t *player); /* called after a new creature spawned. you can return any pointer, which will * then be saved in creature->userdata */ void *(*creature_spawned)(const client_creature_t *creature); /* called if some creature value changed */ void (*creature_changed)(const client_creature_t *creature, int changed); /* called before a creature died */ void (*creature_died )(const client_creature_t *creature); /* called for each (scroll?) message. */ void (*scroll_message )(const char *message); } renderer_api_t; typedef struct { /* infon version string */ const char *version; /* maximum number of players. */ int max_players; /* maximum number of creatures. */ int max_creatures; /* calls function 'callback' for each creature in the game. opaque is passed to the callback function. */ void (*each_creature)(void (*callback)(const client_creature_t *creature, void *opaque), void *opaque); /* calls function 'callback' for each player in the game. opaque is passed to the callback function. */ void (*each_player )(void (*callback)(const client_player_t *player, void *opaque), void *opaque); /* returns information on creature num or NULL if creature does not exist. */ const client_creature_t* (*get_creature)(int num); /* returns information on player num or NULL or the player does not exist. */ const client_player_t* (*get_player )(int num); /* returns player information on the current king player or NULL if there is no king. */ const client_player_t* (*get_king )(); /* returns a pointer to world_with * world_height world tile information or NULL * if there is no world. you can reuse the returned pointer during one tick */ const client_maptile_t * (*get_world )(); /* returns information about the current world or NULL if there is no world. */ const client_world_info_t* (*get_world_info)(); /* returns information on world tile at x, y. must not be called if there * is no world. x and y must be within world coordinates. */ const client_maptile_t * (*get_world_tile)(int x, int y); /* returns the current intermission message or NULL if there * is no message. */ const char * (*get_intermission)(); /* return the amount of network traffic the client received. */ int (*get_traffic)(); /* tell the infon client to shutdown. */ void (*shutdown)(); /* write a string to the server */ void (*printf)(const char *fmt, ...); /* Is it a demo replay? */ int (*is_demo)(); } infon_api_t; /* the function called after loading the renderer. it receives the infon api and must * return the renderer api. */ typedef const renderer_api_t *(*render_loader)(const infon_api_t *); /* api provided by infon */ extern const infon_api_t *infon; #ifdef WIN32 #define RENDERER_EXPORT_SPEC __declspec(dllexport) #else #define RENDERER_EXPORT_SPEC #endif #ifdef __cplusplus #define RENDERER_EXTERN_SPEC extern "C" #else #define RENDERER_EXTERN_SPEC extern #endif #define RENDERER_SYM renderer_load RENDERER_EXPORT_SPEC RENDERER_EXTERN_SPEC const renderer_api_t *RENDERER_SYM (const infon_api_t *api); #define RENDERER_EXPORT(renderer) \ const infon_api_t *infon; \ RENDERER_EXPORT_SPEC RENDERER_EXTERN_SPEC \ const renderer_api_t *RENDERER_SYM (const infon_api_t *api) { \ infon = api; return &(renderer); \ } #ifdef __cplusplus } #endif /* infon seitige API */ int renderer_init(const char *name); void renderer_shutdown(); int renderer_open(int w, int h, int fs); void renderer_close(); void renderer_tick(int game_time, int delta); void renderer_world_info_changed(const client_world_info_t *info); void renderer_world_changed (int x, int y); void renderer_player_joined (client_player_t *player); void renderer_player_changed (const client_player_t *player, int changed); void renderer_player_left (const client_player_t *player); void renderer_creature_spawned (client_creature_t *creature); void renderer_creature_changed (const client_creature_t *creature, int changed); void renderer_creature_died (const client_creature_t *creature); void renderer_scroll_message(const char *buf); int renderer_wants_shutdown(); #endif infon/sdl_video.h0000644000076400001440000000357710603240403014065 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef SDL_VIDEO_H #define SDL_VIDEO_H #include #include "sdl_sprite.h" #define X_TO_SCREENX(x) ((x) * SPRITE_TILE_SIZE / TILE_WIDTH) #define Y_TO_SCREENY(y) ((y) * SPRITE_TILE_SIZE / TILE_HEIGHT) void video_draw(int x, int y, SDL_Surface *sprite); void video_fullscreen_toggle(); void video_flip(); void video_set_title(const char *title); int video_width(); int video_height(); void video_resize(int w, int h); void video_line_green_red(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2); void video_line_green(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2); void video_hline(Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); void video_rect(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a); void video_write(Sint16 x, Sint16 y, const char *text); void video_tiny(Sint16 x, Sint16 y, const char *text); SDL_Surface *video_new_surface(int w, int h); void video_init(int w, int h, int fs); void video_shutdown(); #endif infon/client_creature.h0000644000076400001440000000430110536637517015274 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef CLIENT_CREATURE_H #define CLIENT_CREATURE_H #include "common_creature.h" #include "packet.h" typedef struct client_pathnode_s client_pathnode_t; struct client_pathnode_s { int x; int y; int beam; client_pathnode_t *next; }; typedef struct client_creature_s { int num; int vm_id; int used; void *userdata; int x; int y; int speed; int player; int dir; creature_type type; int food; int health; int target; creature_state state; client_pathnode_t *path; client_pathnode_t *last; int pathlen; int last_x; int last_y; char message[9]; int smile_time; } client_creature_t; /* Renderer */ const client_creature_t *client_creature_get(int num); void client_creature_each(void (*callback)(const client_creature_t *creature, void *opaque), void *opaque); /* Movement */ void client_creature_move(int delta); /* Network */ void client_creature_from_network(packet_t *packet); void client_creature_smile_from_network(packet_t *packet); void client_creature_init(); void client_creature_shutdown(); #endif infon/sdl_gui.c0000644000076400001440000005726410603263057013552 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include "renderer.h" #include "global.h" #include "map.h" #include "misc.h" #include "sdl_video.h" #include "common_player.h" static Uint32 render_real_time; static int render_game_time; static int center_x; static int center_y; static int offset_x; static int offset_y; static struct evbuffer *scrollbuffer; static int rand_table[256]; static int debug = 0; static int send_events = 0; static int show_scores = 0; static int highlight_player = -1; static void recenter() { const client_world_info_t *info = infon->get_world_info(); if (!info) return; center_x = info->width * SPRITE_TILE_SIZE / 2; center_y = info->height * SPRITE_TILE_SIZE / 2; } static void sdl_scroll_message(const char *msg) { // Zuviel insgesamt? if (EVBUFFER_LENGTH(scrollbuffer) > 10000) return; evbuffer_add(scrollbuffer, (char*)msg, strlen(msg)); evbuffer_add(scrollbuffer, " - ", 5); } static void handle_events() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_RETURN: if (event.key.keysym.mod & KMOD_ALT) video_fullscreen_toggle(); break; case SDLK_F9: { int new_highlight = highlight_player; do { if (--new_highlight < -1) new_highlight = infon->max_players - 1; } while (new_highlight != highlight_player && new_highlight != -1 && !infon->get_player(new_highlight)); highlight_player = new_highlight; break; } case SDLK_F10: { int new_highlight = highlight_player; do { if (++new_highlight >= infon->max_players) new_highlight = -1; } while (new_highlight != highlight_player && new_highlight != -1 && !infon->get_player(new_highlight)); highlight_player = new_highlight; break; } case SDLK_F11: send_events ^= 1; sdl_scroll_message(send_events ? "Forwarding input" : "Stopped forwarding input"); break; case SDLK_F12: debug ^= 1; break; case SDLK_TAB: show_scores = 1; break; case SDLK_1: video_resize( 640, 480); break; case SDLK_2: video_resize( 800, 600); break; case SDLK_3: video_resize(1024, 768); break; case SDLK_4: video_resize(1280, 1024); break; case SDLK_5: video_resize(1600, 1200); break; case SDLK_c: recenter(); break; case SDLK_ESCAPE: infon->shutdown(); break; default: break; } if (send_events) infon->printf("K%d\n", event.key.keysym.sym); break; case SDL_KEYUP: switch (event.key.keysym.sym) { case SDLK_TAB: show_scores = 0; break; default: break; } if (send_events) infon->printf("k%d\n", event.key.keysym.sym); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if (send_events) { int x = (event.button.x - offset_x) * TILE_WIDTH / SPRITE_TILE_SIZE; int y = (event.button.y - offset_y) * TILE_HEIGHT / SPRITE_TILE_SIZE; infon->printf("%c%d,%d,%d\n", event.type == SDL_MOUSEBUTTONDOWN ? 'M' : 'm', event.button.button, x, y); } break; case SDL_MOUSEMOTION: if (event.motion.state & 1) { center_x -= event.motion.xrel; center_y -= event.motion.yrel; } if (send_events && event.motion.state) { int x = (event.motion.x - offset_x) * TILE_WIDTH / SPRITE_TILE_SIZE; int y = (event.motion.y - offset_y) * TILE_HEIGHT / SPRITE_TILE_SIZE; infon->printf("D%d,%d,%d\n", event.motion.state, x, y); } break; case SDL_VIDEORESIZE: video_resize(event.resize.w, event.resize.h); break; case SDL_QUIT: infon->shutdown(); break; } } } static void draw_scroller() { static int last_time = 0; static float x = 0; static float curspeed = 0; int chars_per_screen = video_width() / 6 + 1; float speed = ((float)render_real_time - last_time) * (float)(EVBUFFER_LENGTH(scrollbuffer) - chars_per_screen - 3) / 200.0; if (curspeed < speed) curspeed += 0.1; //(speed - curspeed)/30.0; if (curspeed > speed) curspeed = speed; if (curspeed < 0.1) curspeed = 0; x -= curspeed; last_time = render_real_time; while (x < -6) { evbuffer_drain(scrollbuffer, 1); x += 6; } while (EVBUFFER_LENGTH(scrollbuffer) <= chars_per_screen + 1) evbuffer_add(scrollbuffer, " ", 1); video_rect(0, video_height() - 16, video_width(), video_height(), 0, 0, 0, 0); assert(chars_per_screen < EVBUFFER_LENGTH(scrollbuffer)); unsigned char *end = &EVBUFFER_DATA(scrollbuffer)[chars_per_screen]; char saved = *end; *end = '\0'; video_write(x, video_height() - 15, (char*)EVBUFFER_DATA(scrollbuffer)); *end = saved; } static void draw_creature(const client_creature_t *creature, void *opaque) { const int x = X_TO_SCREENX(creature->x) - 7 + offset_x; const int y = Y_TO_SCREENY(creature->y) - 7 + offset_y; const int max_x = video_width() + 10; const int max_y = video_height() - 32 + 10; if (x < -30 || x > max_x || y < -20 || y > max_y) return; const int hw = creature->health; const int fw = creature->food; if (fw != 15) video_rect(x + fw, y - 4, x + 15, y - 2, 0x00, 0x00, 0x00, 0xB0); if (fw != 0) video_rect(x, y - 4, x + fw, y - 2, 0xFF, 0xFF, 0xFF, 0xB0); if (hw != 15) video_rect(x + hw, y - 2, x + 15, y, 0xFF, 0x00, 0x00, 0xB0); if (hw != 0) video_rect(x, y - 2, x + hw, y, 0x00, 0xFF, 0x00, 0xB0); if (creature->player == highlight_player) video_draw(x - 8, y - 8, sprite_get(SPRITE_HALO)); video_draw(x, y, sprite_get(CREATURE_SPRITE(creature->player, creature->type, creature->dir, (render_real_time >> 7) % 2))); if (creature->smile_time + 1000 > render_game_time) { video_draw(x + 15, y - 10, sprite_get(SPRITE_THOUGHT + 8)); } else { video_draw(x + 15, y - 10, sprite_get(SPRITE_THOUGHT + creature->state)); } video_tiny(x - strlen(creature->message) * 6 / 2 + 9, y + 14, creature->message); if (debug) { char tmp[128]; snprintf(tmp, sizeof(tmp), "%d(%d) p%d", creature->vm_id, creature->num, creature->player); video_tiny(x, y + 22, tmp); snprintf(tmp, sizeof(tmp), "f=%d h=%d", creature->food, creature->health); video_tiny(x, y + 30, tmp); snprintf(tmp, sizeof(tmp), "s=%d", creature->speed); video_tiny(x, y + 38, tmp); } switch (creature->state) { case CREATURE_ATTACK: { const client_creature_t *target = infon->get_creature(creature->target); if (target) { video_line_green_red(x + 6, y + 6, X_TO_SCREENX(target->x) - 3 + offset_x, Y_TO_SCREENY(target->y) - 3 + offset_y); video_line_green_red(x + 6, y + 6, X_TO_SCREENX(target->x) - 3 + offset_x, Y_TO_SCREENY(target->y) + 3 + offset_y); video_line_green_red(x + 6, y + 6, X_TO_SCREENX(target->x) + 3 + offset_x, Y_TO_SCREENY(target->y) - 3 + offset_y); video_line_green_red(x + 6, y + 6, X_TO_SCREENX(target->x) + 3 + offset_x, Y_TO_SCREENY(target->y) + 3 + offset_y); } break; } case CREATURE_FEED: { const client_creature_t *target = infon->get_creature(creature->target); if (target) video_line_green(x + 6, y + 6, X_TO_SCREENX(target->x) + offset_x, Y_TO_SCREENY(target->y) + offset_y); break; } default: ; } } static int player_sort_by_score(const void *a, const void *b) { const client_player_t *pa = *(client_player_t **)a; const client_player_t *pb = *(client_player_t **)b; return -(pa->score > pb->score) + (pa->score < pb->score); } static void draw_player_row() { static int lastturn = 0; static int page = 0; if (render_real_time > lastturn + 5000) { lastturn = render_real_time; page++; } int per_page = video_width() / 128; if (per_page == 0) per_page = 1; int n; int player_displayed = 0; int num_players = 0; const client_player_t *sorted[infon->max_players]; for (n = 0; n < infon->max_players; n++) { const client_player_t *player = infon->get_player(n); if (!player) continue; sorted[num_players++] = player; } //printf("%d\n", num_players); //if (infon->get_king()) king_player->score += 1000000; // HACKHACK qsort(sorted, num_players, sizeof(client_player_t*), player_sort_by_score); //if (king_player) king_player->score -= 1000000; int offset = per_page * page; if (offset >= num_players) { page = 0; offset = 0; } int num = num_players - offset; if (num > per_page) num = per_page; video_rect(0, video_height() - 32, video_width(), video_height() - 16, 0, 0, 0, 0); for (n = offset; n < offset + num; n++) { const client_player_t *player = sorted[n]; // King in dieser Runde? if (player == infon->get_king()) { video_draw(player_displayed * 128 + 32, video_height() - 86 - abs(20.0 * sin(M_PI * (render_real_time % 550) / 550.0)), sprite_get(SPRITE_CROWN)); } // Rotierendes Vieh if (player->num == highlight_player) { video_draw(player_displayed * 128 - 8, video_height() - 40 - 8, sprite_get(SPRITE_HALO)); video_draw(player_displayed * 128, video_height() - 40, sprite_get(CREATURE_SPRITE(player->num, 0, (render_real_time / 64) % CREATURE_DIRECTIONS, (render_real_time / 128) % 2))); } else { video_draw(player_displayed * 128, video_height() - 32, sprite_get(CREATURE_SPRITE(player->num, 0, (render_real_time / 64) % CREATURE_DIRECTIONS, (render_real_time / 128) % 2))); } // CPU Auslastung Anzeigen const int cpu = 80 * player->cpu_usage / 100; video_rect(player_displayed * 128 + 16, video_height() - 32, player_displayed * 128 + 16 + cpu, video_height() - 16, 2 * cpu, 160 - 2 * cpu , 0x00, 0x00); // Name / Punkte static char buf[18]; size_t namelen = strlen(player->name); int offset = 0; if (namelen > 9) { offset = (render_real_time / 500) % ((namelen - 8)*2); if (offset >= (namelen - 8)) offset = (namelen - 8)*2-1 - offset; } snprintf(buf, sizeof(buf), "%2d. %4d %s", n + 1, player->score, player->name + offset); video_write(player_displayed * 128 + 16, video_height() - 30, buf); player_displayed++; } } static void draw_scores(int xcenter, int y) { int n; int num_players = 0; const client_player_t *sorted[infon->max_players]; for (n = 0; n < infon->max_players; n++) { const client_player_t *player = infon->get_player(n); if (!player) continue; sorted[num_players++] = player; } qsort(sorted, num_players, sizeof(client_player_t*), player_sort_by_score); for (n = 0; n < num_players; n++) { const client_player_t *player = sorted[n]; if (player->num == highlight_player) video_draw(xcenter - 48 - 8, y + 14 * n - 8, sprite_get(SPRITE_HALO)); video_draw(xcenter - 48, y + 14 * n, sprite_get(CREATURE_SPRITE(player->num, 0, (render_real_time / 60) % CREATURE_DIRECTIONS, (render_real_time / 123) % 2))); static char buf[40]; snprintf(buf, sizeof(buf), "%2d. %4d %s", n + 1, player->score, player->name); video_write(xcenter - 70, y + 14 * n + 1, buf); } } static void draw_world() { const client_world_info_t *info = infon->get_world_info(); if (!info) return; const client_maptile_t *world = infon->get_world(); int screen_w = video_width(); int screen_cx = screen_w / 2; int screen_h = video_height() - 32; int screen_cy = screen_h / 2; int mapx1 = offset_x = screen_cx - center_x; int x1 = 0; if (mapx1 <= -SPRITE_TILE_SIZE) { x1 = -mapx1 / SPRITE_TILE_SIZE; mapx1 = -(-mapx1 % SPRITE_TILE_SIZE); } int x2 = x1 + (screen_w - mapx1) / SPRITE_TILE_SIZE + 1; if (x2 > info->width) x2 = info->width; int mapx2 = mapx1 + (x2 - x1) * SPRITE_TILE_SIZE; int mapy1 = offset_y = screen_cy - center_y; int y1 = 0; if (mapy1 <= -SPRITE_TILE_SIZE) { y1 = -mapy1 / SPRITE_TILE_SIZE; mapy1 = -(-mapy1 % SPRITE_TILE_SIZE); } int y2 = y1 + (screen_h - mapy1) / SPRITE_TILE_SIZE + 1; if (y2 > info->height) y2 = info->height; int mapy2 = mapy1 + (y2 - y1) * SPRITE_TILE_SIZE; int screenx = mapx1; int screeny = mapy1; for (int y = y1; y < y2; y++) { const client_maptile_t *tile = &world[y * info->width + x1]; for (int x = x1; x < x2; x++) { int pos_rand = rand_table[(x ^ y) & 0xFF]; int floor_sprite; switch (tile->gfx) { case TILE_GFX_SOLID: floor_sprite = SPRITE_SOLID + pos_rand % SPRITE_NUM_SOLID; break; case TILE_GFX_PLAIN: floor_sprite = SPRITE_PLAIN + pos_rand % SPRITE_NUM_PLAIN; break; case TILE_GFX_BORDER: floor_sprite = SPRITE_BORDER + pos_rand % SPRITE_NUM_BORDER; break; case TILE_GFX_SNOW_SOLID: floor_sprite = SPRITE_SNOW_SOLID + pos_rand % SPRITE_NUM_SNOW_SOLID; break; case TILE_GFX_SNOW_PLAIN: floor_sprite = SPRITE_SNOW_PLAIN + pos_rand % SPRITE_NUM_SNOW_PLAIN; break; case TILE_GFX_SNOW_BORDER: floor_sprite = SPRITE_SNOW_BORDER + pos_rand % SPRITE_NUM_SNOW_BORDER; break; case TILE_GFX_WATER: floor_sprite = SPRITE_WATER + ((render_real_time >> 7) + x + y) % SPRITE_NUM_WATER; break; case TILE_GFX_LAVA: floor_sprite = SPRITE_LAVA + ((render_real_time >> 7) + x + y) % SPRITE_NUM_LAVA; break; case TILE_GFX_NONE: floor_sprite = -1; break; case TILE_GFX_KOTH: floor_sprite = SPRITE_KOTH; break; case TILE_GFX_DESERT: floor_sprite = SPRITE_DESERT + pos_rand % SPRITE_NUM_DESERT; break; default: floor_sprite = -1; break; } if (debug) floor_sprite = tile->type == TILE_PLAIN ? SPRITE_SNOW_PLAIN : -1; if (floor_sprite < 0) video_rect(screenx, screeny, screenx + SPRITE_TILE_SIZE, screeny + SPRITE_TILE_SIZE, 30, 30, 30, 0); else video_draw(screenx, screeny, sprite_get(floor_sprite)); if (tile->food != 0) { if (tile->gfx == TILE_GFX_SNOW_PLAIN) video_draw(screenx, screeny, sprite_get(SPRITE_SNOW_FOOD - 1 + tile->food)); else video_draw(screenx, screeny, sprite_get(SPRITE_FOOD - 1 + tile->food)); } screenx += SPRITE_TILE_SIZE; tile++; } screeny += SPRITE_TILE_SIZE; screenx = mapx1; } if (mapx1 > 0) video_rect(0, max(0, mapy1), mapx1, min(screen_h, mapy2), 30, 30, 30, 0); if (mapy1 > 0) video_rect(0, 0, screen_w, mapy1, 30, 30, 30, 0); if (mapx2 <= screen_w) video_rect(mapx2, max(0, mapy1), screen_w, min(screen_h, mapy2), 30, 30, 30, 0); if (mapy2 <= screen_h) video_rect(0, mapy2, screen_w, screen_h, 30, 30, 30, 0); } static void sdl_world_info_changed(const client_world_info_t *info) { recenter(); } static void sdl_player_changed(const client_player_t *player, int changed) { if (changed & PLAYER_DIRTY_COLOR) { int colors[16][3] = { { 0xFF, 0x00, 0x00 }, { 0x00, 0xFF, 0x00 }, { 0x00, 0x00, 0xFF }, { 0xFF, 0xFF, 0x00 }, { 0x00, 0xFF, 0xFF }, { 0xFF, 0x00, 0xFF }, { 0xFF, 0xFF, 0xFF }, { 0x00, 0x00, 0x00 }, { 0xFF, 0x80, 0x80 }, { 0x80, 0xFF, 0x80 }, { 0x80, 0x80, 0xFF }, { 0xFF, 0xFF, 0x80 }, { 0x80, 0xFF, 0xFF }, { 0xFF, 0x80, 0xFF }, { 0x80, 0x80, 0x80 }, { 0x60, 0xA0, 0xFF }, }; int hi = (player->color & 0xF0) >> 4; int lo = (player->color & 0x0F); sprite_render_player_creatures(player->num, colors[hi][0], colors[hi][1], colors[hi][2], colors[lo][0], colors[lo][1], colors[lo][2]); } } static void sdl_tick(int gt, int delta) { static Uint32 frames = 0; static int last_net = 0; static Uint32 last_info = 0; static int stall = 0; render_real_time = SDL_GetTicks(); render_game_time = gt; handle_events(); const char *intermission = infon->get_intermission(); // char buf[20]; // snprintf(buf, sizeof(buf), "%4d:%02d", // render_game_time / (60 * 1000), // render_game_time % (60 * 1000) / 1000); if (show_scores) intermission = "Scores"; if (strlen(intermission) > 0) { int y = max(video_height() / 2 - 150, 20); video_rect(0, 0, video_width(), video_height() - 16, 0, 0, 0, 0); video_hline(0, video_width(), y + 20, 0x80, 0x80, 0x80, 0x80); video_write((video_width() - strlen(intermission) * 7) / 2, y, intermission); draw_scores(video_width() / 2, y + 30); // video_write(video_width() - 46, video_height() - 30, buf); } else { draw_world(); infon->each_creature(draw_creature, NULL); draw_player_row(); } draw_scroller(); // Bitte drinlassen. Danke if (render_real_time / 1000 % 60 < 5) video_draw(video_width() - 190, 20, sprite_get(SPRITE_LOGO)); // Informationen if (render_real_time >= last_info + 1000) { char buf[128]; int traffic = infon->get_traffic(); snprintf(buf, sizeof(buf), "%s - %d fps - %d byte/s", infon->version, frames, traffic - last_net); video_set_title(buf); stall = traffic > last_net ? 0 : stall + 1; last_net = traffic; last_info = render_real_time; frames = 0; } if (stall > 2) video_write(4, 4, "connection stalled?"); if (send_events) video_write(video_width() - 148, 4, "Input forwarding enabled"); if (infon->is_demo() && (render_real_time % 1000) < 500) video_write(4, video_height() - 48, "Replay"); video_flip(); frames++; #ifdef WIN32 Sleep(20); #else usleep(4000); #endif } static int sdl_open(int w, int h, int fs) { video_init(w, h, fs); center_x = 0; center_y = 0; offset_x = 0; offset_y = 0; scrollbuffer = evbuffer_new(); for (int i = 0; i < 20; i++) evbuffer_add(scrollbuffer, " ", 10); evbuffer_add(scrollbuffer, (char*)infon->version, strlen(infon->version)); evbuffer_add(scrollbuffer, " ", 10); sprite_init(); for (int i = 0; i < 256; i++) rand_table[i] = rand(); return 1; } static void sdl_close() { sprite_shutdown(); evbuffer_free(scrollbuffer); video_shutdown(); } const static renderer_api_t sdl_api = { .version = RENDERER_API_VERSION, .open = sdl_open, .close = sdl_close, .tick = sdl_tick, .world_info_changed = sdl_world_info_changed, .world_changed = NULL, .player_joined = NULL, .player_changed = sdl_player_changed, .player_left = NULL, .creature_spawned = NULL, .creature_changed = NULL, .creature_died = NULL, .scroll_message = sdl_scroll_message, }; RENDERER_EXPORT(sdl_api) infon/gl_mdl.c0000644000076400001440000005254310552756360013364 0ustar dividuumusers/* * mdl.c -- mdl model loader * last modification: dec. 19, 2005 * * Copyright (c) 2005 David HENRY * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "gl_mdl.h" #include "misc.h" /* table of precalculated normals */ vec3_t anorms_table[162] = { { -0.525731f, 0.000000f, 0.850651f }, { -0.442863f, 0.238856f, 0.864188f }, { -0.295242f, 0.000000f, 0.955423f }, { -0.309017f, 0.500000f, 0.809017f }, { -0.162460f, 0.262866f, 0.951056f }, { 0.000000f, 0.000000f, 1.000000f }, { 0.000000f, 0.850651f, 0.525731f }, { -0.147621f, 0.716567f, 0.681718f }, { 0.147621f, 0.716567f, 0.681718f }, { 0.000000f, 0.525731f, 0.850651f }, { 0.309017f, 0.500000f, 0.809017f }, { 0.525731f, 0.000000f, 0.850651f }, { 0.295242f, 0.000000f, 0.955423f }, { 0.442863f, 0.238856f, 0.864188f }, { 0.162460f, 0.262866f, 0.951056f }, { -0.681718f, 0.147621f, 0.716567f }, { -0.809017f, 0.309017f, 0.500000f }, { -0.587785f, 0.425325f, 0.688191f }, { -0.850651f, 0.525731f, 0.000000f }, { -0.864188f, 0.442863f, 0.238856f }, { -0.716567f, 0.681718f, 0.147621f }, { -0.688191f, 0.587785f, 0.425325f }, { -0.500000f, 0.809017f, 0.309017f }, { -0.238856f, 0.864188f, 0.442863f }, { -0.425325f, 0.688191f, 0.587785f }, { -0.716567f, 0.681718f, -0.147621f }, { -0.500000f, 0.809017f, -0.309017f }, { -0.525731f, 0.850651f, 0.000000f }, { 0.000000f, 0.850651f, -0.525731f }, { -0.238856f, 0.864188f, -0.442863f }, { 0.000000f, 0.955423f, -0.295242f }, { -0.262866f, 0.951056f, -0.162460f }, { 0.000000f, 1.000000f, 0.000000f }, { 0.000000f, 0.955423f, 0.295242f }, { -0.262866f, 0.951056f, 0.162460f }, { 0.238856f, 0.864188f, 0.442863f }, { 0.262866f, 0.951056f, 0.162460f }, { 0.500000f, 0.809017f, 0.309017f }, { 0.238856f, 0.864188f, -0.442863f }, { 0.262866f, 0.951056f, -0.162460f }, { 0.500000f, 0.809017f, -0.309017f }, { 0.850651f, 0.525731f, 0.000000f }, { 0.716567f, 0.681718f, 0.147621f }, { 0.716567f, 0.681718f, -0.147621f }, { 0.525731f, 0.850651f, 0.000000f }, { 0.425325f, 0.688191f, 0.587785f }, { 0.864188f, 0.442863f, 0.238856f }, { 0.688191f, 0.587785f, 0.425325f }, { 0.809017f, 0.309017f, 0.500000f }, { 0.681718f, 0.147621f, 0.716567f }, { 0.587785f, 0.425325f, 0.688191f }, { 0.955423f, 0.295242f, 0.000000f }, { 1.000000f, 0.000000f, 0.000000f }, { 0.951056f, 0.162460f, 0.262866f }, { 0.850651f, -0.525731f, 0.000000f }, { 0.955423f, -0.295242f, 0.000000f }, { 0.864188f, -0.442863f, 0.238856f }, { 0.951056f, -0.162460f, 0.262866f }, { 0.809017f, -0.309017f, 0.500000f }, { 0.681718f, -0.147621f, 0.716567f }, { 0.850651f, 0.000000f, 0.525731f }, { 0.864188f, 0.442863f, -0.238856f }, { 0.809017f, 0.309017f, -0.500000f }, { 0.951056f, 0.162460f, -0.262866f }, { 0.525731f, 0.000000f, -0.850651f }, { 0.681718f, 0.147621f, -0.716567f }, { 0.681718f, -0.147621f, -0.716567f }, { 0.850651f, 0.000000f, -0.525731f }, { 0.809017f, -0.309017f, -0.500000f }, { 0.864188f, -0.442863f, -0.238856f }, { 0.951056f, -0.162460f, -0.262866f }, { 0.147621f, 0.716567f, -0.681718f }, { 0.309017f, 0.500000f, -0.809017f }, { 0.425325f, 0.688191f, -0.587785f }, { 0.442863f, 0.238856f, -0.864188f }, { 0.587785f, 0.425325f, -0.688191f }, { 0.688191f, 0.587785f, -0.425325f }, { -0.147621f, 0.716567f, -0.681718f }, { -0.309017f, 0.500000f, -0.809017f }, { 0.000000f, 0.525731f, -0.850651f }, { -0.525731f, 0.000000f, -0.850651f }, { -0.442863f, 0.238856f, -0.864188f }, { -0.295242f, 0.000000f, -0.955423f }, { -0.162460f, 0.262866f, -0.951056f }, { 0.000000f, 0.000000f, -1.000000f }, { 0.295242f, 0.000000f, -0.955423f }, { 0.162460f, 0.262866f, -0.951056f }, { -0.442863f, -0.238856f, -0.864188f }, { -0.309017f, -0.500000f, -0.809017f }, { -0.162460f, -0.262866f, -0.951056f }, { 0.000000f, -0.850651f, -0.525731f }, { -0.147621f, -0.716567f, -0.681718f }, { 0.147621f, -0.716567f, -0.681718f }, { 0.000000f, -0.525731f, -0.850651f }, { 0.309017f, -0.500000f, -0.809017f }, { 0.442863f, -0.238856f, -0.864188f }, { 0.162460f, -0.262866f, -0.951056f }, { 0.238856f, -0.864188f, -0.442863f }, { 0.500000f, -0.809017f, -0.309017f }, { 0.425325f, -0.688191f, -0.587785f }, { 0.716567f, -0.681718f, -0.147621f }, { 0.688191f, -0.587785f, -0.425325f }, { 0.587785f, -0.425325f, -0.688191f }, { 0.000000f, -0.955423f, -0.295242f }, { 0.000000f, -1.000000f, 0.000000f }, { 0.262866f, -0.951056f, -0.162460f }, { 0.000000f, -0.850651f, 0.525731f }, { 0.000000f, -0.955423f, 0.295242f }, { 0.238856f, -0.864188f, 0.442863f }, { 0.262866f, -0.951056f, 0.162460f }, { 0.500000f, -0.809017f, 0.309017f }, { 0.716567f, -0.681718f, 0.147621f }, { 0.525731f, -0.850651f, 0.000000f }, { -0.238856f, -0.864188f, -0.442863f }, { -0.500000f, -0.809017f, -0.309017f }, { -0.262866f, -0.951056f, -0.162460f }, { -0.850651f, -0.525731f, 0.000000f }, { -0.716567f, -0.681718f, -0.147621f }, { -0.716567f, -0.681718f, 0.147621f }, { -0.525731f, -0.850651f, 0.000000f }, { -0.500000f, -0.809017f, 0.309017f }, { -0.238856f, -0.864188f, 0.442863f }, { -0.262866f, -0.951056f, 0.162460f }, { -0.864188f, -0.442863f, 0.238856f }, { -0.809017f, -0.309017f, 0.500000f }, { -0.688191f, -0.587785f, 0.425325f }, { -0.681718f, -0.147621f, 0.716567f }, { -0.442863f, -0.238856f, 0.864188f }, { -0.587785f, -0.425325f, 0.688191f }, { -0.309017f, -0.500000f, 0.809017f }, { -0.147621f, -0.716567f, 0.681718f }, { -0.425325f, -0.688191f, 0.587785f }, { -0.162460f, -0.262866f, 0.951056f }, { 0.442863f, -0.238856f, 0.864188f }, { 0.162460f, -0.262866f, 0.951056f }, { 0.309017f, -0.500000f, 0.809017f }, { 0.147621f, -0.716567f, 0.681718f }, { 0.000000f, -0.525731f, 0.850651f }, { 0.425325f, -0.688191f, 0.587785f }, { 0.587785f, -0.425325f, 0.688191f }, { 0.688191f, -0.587785f, 0.425325f }, { -0.955423f, 0.295242f, 0.000000f }, { -0.951056f, 0.162460f, 0.262866f }, { -1.000000f, 0.000000f, 0.000000f }, { -0.850651f, 0.000000f, 0.525731f }, { -0.955423f, -0.295242f, 0.000000f }, { -0.951056f, -0.162460f, 0.262866f }, { -0.864188f, 0.442863f, -0.238856f }, { -0.951056f, 0.162460f, -0.262866f }, { -0.809017f, 0.309017f, -0.500000f }, { -0.864188f, -0.442863f, -0.238856f }, { -0.951056f, -0.162460f, -0.262866f }, { -0.809017f, -0.309017f, -0.500000f }, { -0.681718f, 0.147621f, -0.716567f }, { -0.681718f, -0.147621f, -0.716567f }, { -0.850651f, 0.000000f, -0.525731f }, { -0.688191f, 0.587785f, -0.425325f }, { -0.587785f, 0.425325f, -0.688191f }, { -0.425325f, 0.688191f, -0.587785f }, { -0.425325f, -0.688191f, -0.587785f }, { -0.587785f, -0.425325f, -0.688191f }, { -0.688191f, -0.587785f, -0.425325f } }; /* palette */ unsigned char colormap[256][3] = { { 0, 0, 0}, { 15, 15, 15}, { 31, 31, 31}, { 47, 47, 47}, { 63, 63, 63}, { 75, 75, 75}, { 91, 91, 91}, {107, 107, 107}, {123, 123, 123}, {139, 139, 139}, {155, 155, 155}, {171, 171, 171}, {187, 187, 187}, {203, 203, 203}, {219, 219, 219}, {235, 235, 235}, { 15, 11, 7}, { 23, 15, 11}, { 31, 23, 11}, { 39, 27, 15}, { 47, 35, 19}, { 55, 43, 23}, { 63, 47, 23}, { 75, 55, 27}, { 83, 59, 27}, { 91, 67, 31}, { 99, 75, 31}, {107, 83, 31}, {115, 87, 31}, {123, 95, 35}, {131, 103, 35}, {143, 111, 35}, { 11, 11, 15}, { 19, 19, 27}, { 27, 27, 39}, { 39, 39, 51}, { 47, 47, 63}, { 55, 55, 75}, { 63, 63, 87}, { 71, 71, 103}, { 79, 79, 115}, { 91, 91, 127}, { 99, 99, 139}, {107, 107, 151}, {115, 115, 163}, {123, 123, 175}, {131, 131, 187}, {139, 139, 203}, { 0, 0, 0}, { 7, 7, 0}, { 11, 11, 0}, { 19, 19, 0}, { 27, 27, 0}, { 35, 35, 0}, { 43, 43, 7}, { 47, 47, 7}, { 55, 55, 7}, { 63, 63, 7}, { 71, 71, 7}, { 75, 75, 11}, { 83, 83, 11}, { 91, 91, 11}, { 99, 99, 11}, {107, 107, 15}, { 7, 0, 0}, { 15, 0, 0}, { 23, 0, 0}, { 31, 0, 0}, { 39, 0, 0}, { 47, 0, 0}, { 55, 0, 0}, { 63, 0, 0}, { 71, 0, 0}, { 79, 0, 0}, { 87, 0, 0}, { 95, 0, 0}, {103, 0, 0}, {111, 0, 0}, {119, 0, 0}, {127, 0, 0}, { 19, 19, 0}, { 27, 27, 0}, { 35, 35, 0}, { 47, 43, 0}, { 55, 47, 0}, { 67, 55, 0}, { 75, 59, 7}, { 87, 67, 7}, { 95, 71, 7}, {107, 75, 11}, {119, 83, 15}, {131, 87, 19}, {139, 91, 19}, {151, 95, 27}, {163, 99, 31}, {175, 103, 35}, { 35, 19, 7}, { 47, 23, 11}, { 59, 31, 15}, { 75, 35, 19}, { 87, 43, 23}, { 99, 47, 31}, {115, 55, 35}, {127, 59, 43}, {143, 67, 51}, {159, 79, 51}, {175, 99, 47}, {191, 119, 47}, {207, 143, 43}, {223, 171, 39}, {239, 203, 31}, {255, 243, 27}, { 11, 7, 0}, { 27, 19, 0}, { 43, 35, 15}, { 55, 43, 19}, { 71, 51, 27}, { 83, 55, 35}, { 99, 63, 43}, {111, 71, 51}, {127, 83, 63}, {139, 95, 71}, {155, 107, 83}, {167, 123, 95}, {183, 135, 107}, {195, 147, 123}, {211, 163, 139}, {227, 179, 151}, {171, 139, 163}, {159, 127, 151}, {147, 115, 135}, {139, 103, 123}, {127, 91, 111}, {119, 83, 99}, {107, 75, 87}, { 95, 63, 75}, { 87, 55, 67}, { 75, 47, 55}, { 67, 39, 47}, { 55, 31, 35}, { 43, 23, 27}, { 35, 19, 19}, { 23, 11, 11}, { 15, 7, 7}, {187, 115, 159}, {175, 107, 143}, {163, 95, 131}, {151, 87, 119}, {139, 79, 107}, {127, 75, 95}, {115, 67, 83}, {107, 59, 75}, { 95, 51, 63}, { 83, 43, 55}, { 71, 35, 43}, { 59, 31, 35}, { 47, 23, 27}, { 35, 19, 19}, { 23, 11, 11}, { 15, 7, 7}, {219, 195, 187}, {203, 179, 167}, {191, 163, 155}, {175, 151, 139}, {163, 135, 123}, {151, 123, 111}, {135, 111, 95}, {123, 99, 83}, {107, 87, 71}, { 95, 75, 59}, { 83, 63, 51}, { 67, 51, 39}, { 55, 43, 31}, { 39, 31, 23}, { 27, 19, 15}, { 15, 11, 7}, {111, 131, 123}, {103, 123, 111}, { 95, 115, 103}, { 87, 107, 95}, { 79, 99, 87}, { 71, 91, 79}, { 63, 83, 71}, { 55, 75, 63}, { 47, 67, 55}, { 43, 59, 47}, { 35, 51, 39}, { 31, 43, 31}, { 23, 35, 23}, { 15, 27, 19}, { 11, 19, 11}, { 7, 11, 7}, {255, 243, 27}, {239, 223, 23}, {219, 203, 19}, {203, 183, 15}, {187, 167, 15}, {171, 151, 11}, {155, 131, 7}, {139, 115, 7}, {123, 99, 7}, {107, 83, 0}, { 91, 71, 0}, { 75, 55, 0}, { 59, 43, 0}, { 43, 31, 0}, { 27, 15, 0}, { 11, 7, 0}, { 0, 0, 255}, { 11, 11, 239}, { 19, 19, 223}, { 27, 27, 207}, { 35, 35, 191}, { 43, 43, 175}, { 47, 47, 159}, { 47, 47, 143}, { 47, 47, 127}, { 47, 47, 111}, { 47, 47, 95}, { 43, 43, 79}, { 35, 35, 63}, { 27, 27, 47}, { 19, 19, 31}, { 11, 11, 15}, { 43, 0, 0}, { 59, 0, 0}, { 75, 7, 0}, { 95, 7, 0}, {111, 15, 0}, {127, 23, 7}, {147, 31, 7}, {163, 39, 11}, {183, 51, 15}, {195, 75, 27}, {207, 99, 43}, {219, 127, 59}, {227, 151, 79}, {231, 171, 95}, {239, 191, 119}, {247, 211, 139}, {167, 123, 59}, {183, 155, 55}, {199, 195, 55}, {231, 227, 87}, {127, 191, 255}, {171, 231, 255}, {215, 255, 255}, {103, 0, 0}, {139, 0, 0}, {179, 0, 0}, {215, 0, 0}, {255, 0, 0}, {255, 243, 147}, {255, 247, 199}, {255, 255, 255}, {159, 91, 83}, }; static GLuint MakeTexture(int n, mdl_model_t *mdl) { int i; GLuint id; GLubyte *pixels = (GLubyte *)malloc(sizeof (GLubyte) * mdl->header.skinwidth * mdl->header.skinheight * 3); /* convert indexed 8 bits texture to RGB 24 bits */ for (i = 0; i < mdl->header.skinwidth * mdl->header.skinheight; ++i) { pixels[(i * 3) + 0] = colormap[mdl->skins[n].data[i]][0]; pixels[(i * 3) + 1] = colormap[mdl->skins[n].data[i]][1]; pixels[(i * 3) + 2] = colormap[mdl->skins[n].data[i]][2]; } /* generate OpenGL texture */ glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, mdl->header.skinwidth, mdl->header.skinheight, GL_RGB, GL_UNSIGNED_BYTE, pixels); /* OpenGL has its own copy of image data */ free(pixels); return id; } int mdl_load(mdl_model_t *mdl, const char *filename) { FILE *fp; int i; fp = fopen(filename, "rb"); if (!fp) { die("error: couldn't open '%s'", filename); return 0; } /* read header */ fread (&mdl->header, 1, sizeof (mdl_header_t), fp); if ((mdl->header.ident != 1330660425) || (mdl->header.version != 6)) { /* error! */ fclose (fp); die("error: %s is not a mdl file", filename); return 0; } /* memory allocation */ mdl->skins = (mdl_skin_t *) malloc(sizeof (mdl_skin_t) * mdl->header.num_skins); mdl->texcoords = (mdl_texCoord_t *)malloc(sizeof (mdl_texCoord_t) * mdl->header.num_verts); mdl->triangles = (mdl_triangle_t *)malloc(sizeof (mdl_triangle_t) * mdl->header.num_tris); mdl->frames = (mdl_frame_t *) malloc(sizeof (mdl_frame_t) * mdl->header.num_frames); mdl->tex_id = (GLuint *) malloc(sizeof (GLuint) * mdl->header.num_skins); mdl->iskin = 0; /* read texture data */ for (i = 0; i < mdl->header.num_skins; ++i) { mdl->skins[i].data = (GLubyte *)malloc(sizeof (GLubyte) * mdl->header.skinwidth * mdl->header.skinheight); fread(&mdl->skins[i].group, sizeof (int), 1, fp); fread(mdl->skins[i].data, sizeof (GLubyte), mdl->header.skinwidth * mdl->header.skinheight, fp); mdl->tex_id[i] = MakeTexture (i, mdl); free (mdl->skins[i].data); mdl->skins[i].data = NULL; } fread (mdl->texcoords, sizeof (mdl_texCoord_t), mdl->header.num_verts, fp); fread (mdl->triangles, sizeof (mdl_triangle_t), mdl->header.num_tris, fp); /* read frames */ for (i = 0; i < mdl->header.num_frames; ++i) { /* memory allocation for vertices of this frame */ mdl->frames[i].frame.verts = (mdl_vertex_t *) malloc (sizeof (mdl_vertex_t) * mdl->header.num_verts); /* read frame data */ fread (&mdl->frames[i].type, sizeof (long), 1, fp); fread (&mdl->frames[i].frame.bboxmin, sizeof (mdl_vertex_t), 1, fp); fread (&mdl->frames[i].frame.bboxmax, sizeof (mdl_vertex_t), 1, fp); fread (mdl->frames[i].frame.name, sizeof (char), 16, fp); // printf("%d %s\n", i, mdl->frames[i].frame.name); fread (mdl->frames[i].frame.verts, sizeof (mdl_vertex_t), mdl->header.num_verts, fp); } fclose (fp); return 1; } void mdl_free(mdl_model_t *mdl) { int i; if (mdl->skins) free (mdl->skins); if (mdl->texcoords) free (mdl->texcoords); if (mdl->triangles) free (mdl->triangles); if (mdl->tex_id) { /* delete OpenGL textures */ glDeleteTextures (mdl->header.num_skins, mdl->tex_id); free (mdl->tex_id); } if (mdl->frames) { for (i = 0; i < mdl->header.num_frames; ++i) free(mdl->frames[i].frame.verts); free(mdl->frames); } } void mdl_render_frame(const mdl_model_t *mdl, int n) { int i, j; GLfloat s, t; vec3_t v; mdl_vertex_t *pvert; /* check if n is in a valid range */ if ((n < 0) || (n > mdl->header.num_frames - 1)) return; /* enable model's texture */ glBindTexture (GL_TEXTURE_2D, mdl->tex_id[mdl->iskin]); /* draw the model */ glBegin (GL_TRIANGLES); /* draw each triangle */ for (i = 0; i < mdl->header.num_tris; ++i) { /* draw each vertex */ for (j = 0; j < 3; ++j) { pvert = &mdl->frames[n].frame.verts[mdl->triangles[i].vertex[j]]; /* compute texture coordinates */ s = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].s; t = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].t; if (!mdl->triangles[i].facesfront && mdl->texcoords[mdl->triangles[i].vertex[j]].onseam) s += mdl->header.skinwidth * 0.5f; /* backface */ /* scale s and t to range from 0.0 to 1.0 */ s = (s + 0.5) / mdl->header.skinwidth; t = (t + 0.5) / mdl->header.skinheight; /* pass texture coordinates to OpenGL */ glTexCoord2f (s, t); /* normal vector */ glNormal3fv (anorms_table [pvert->normalIndex]); /* calculate real vertex position */ v[0] = (mdl->header.scale[0] * pvert->v[0]) + mdl->header.translate[0]; v[1] = (mdl->header.scale[1] * pvert->v[1]) + mdl->header.translate[1]; v[2] = (mdl->header.scale[2] * pvert->v[2]) + mdl->header.translate[2]; glVertex3fv (v); } } glEnd (); } #if 0 void RenderFrameItp (int n, float interp, mdl_model_t *mdl) { int i, j; GLfloat s, t; vec3_t norm, v; GLfloat *n_curr, *n_next; mdl_vertex_t *pvert1, *pvert2; /* check if n is in a valid range */ if ((n < 0) || (n > mdl->header.num_frames)) return; /* enable model's texture */ glBindTexture (GL_TEXTURE_2D, mdl->tex_id[mdl->iskin]); /* draw the model */ glBegin (GL_TRIANGLES); /* draw each triangle */ for (i = 0; i < mdl->header.num_tris; ++i) { /* draw each vertex */ for (j = 0; j < 3; ++j) { pvert1 = &mdl->frames[n].frame.verts[mdl->triangles[i].vertex[j]]; pvert2 = &mdl->frames[n + 1].frame.verts[mdl->triangles[i].vertex[j]]; /* compute texture coordinates */ s = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].s; t = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].t; if (!mdl->triangles[i].facesfront && mdl->texcoords[mdl->triangles[i].vertex[j]].onseam) s += mdl->header.skinwidth * 0.5f; /* backface */ /* scale s and t to range from 0.0 to 1.0 */ s = (s + 0.5) / mdl->header.skinwidth; t = (t + 0.5) / mdl->header.skinheight; /* pass texture coordinates to OpenGL */ glTexCoord2f (s, t); /* interpolate normals */ /* memcpy (n_curr, anorms_table[pvert1->normalIndex], sizeof (vec3_t)); memcpy (n_next, anorms_table[pvert2->normalIndex], sizeof (vec3_t)); */ n_curr = anorms_table[pvert1->normalIndex]; n_next = anorms_table[pvert2->normalIndex]; norm[0] = n_curr[0] + interp * (n_next[0] - n_curr[0]); norm[1] = n_curr[1] + interp * (n_next[1] - n_curr[1]); norm[2] = n_curr[2] + interp * (n_next[2] - n_curr[2]); glNormal3fv (norm); /* interpolate vertices */ v[0] = mdl->header.scale[0] * (pvert1->v[0] + interp * (pvert2->v[0] - pvert1->v[0])) + mdl->header.translate[0]; v[1] = mdl->header.scale[1] * (pvert1->v[1] + interp * (pvert2->v[1] - pvert1->v[1])) + mdl->header.translate[1]; v[2] = mdl->header.scale[2] * (pvert1->v[2] + interp * (pvert2->v[2] - pvert1->v[2])) + mdl->header.translate[2]; glVertex3fv (v); } } glEnd (); } #endif infon/gl_mdl.h0000644000076400001440000000652110533001515013344 0ustar dividuumusers/* * mdl.c -- mdl model loader * last modification: dec. 19, 2005 * * Copyright (c) 2005 David HENRY * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef GL_MDL_H #define GL_MDL_H #include /* vector */ typedef float vec3_t[3]; /* mdl header */ typedef struct { int ident; /* magic number: "IDPO" */ int version; /* version: 6 */ vec3_t scale; /* scale factor */ vec3_t translate; /* translation vector */ float boundingradius; vec3_t eyeposition; /* eyes' position */ int num_skins; /* number of textures */ int skinwidth; /* texture width */ int skinheight; /* texture height */ int num_verts; /* number of vertices */ int num_tris; /* number of triangles */ int num_frames; /* number of frames */ int synctype; /* 0 = synchron, 1 = random */ int flags; /* state flag */ float size; } mdl_header_t; /* skin */ typedef struct { int group; /* 0 = single, 1 = group */ GLubyte *data; /* texture data */ } mdl_skin_t; /* texture coords */ typedef struct { int onseam; int s; int t; } mdl_texCoord_t; /* triangle info */ typedef struct { int facesfront; /* 0 = backface, 1 = frontface */ int vertex[3]; /* vertex indices */ } mdl_triangle_t; /* compressed vertex */ typedef struct { unsigned char v[3]; unsigned char normalIndex; } mdl_vertex_t; /* simple frame */ typedef struct { mdl_vertex_t bboxmin; /* bouding box min */ mdl_vertex_t bboxmax; /* bouding box max */ char name[16]; mdl_vertex_t *verts; /* vertex list of the frame */ } mdl_simpleframe_t; /* model frame */ typedef struct { int type; /* 0 = simple, !0 = group */ mdl_simpleframe_t frame; /* this program can't read models composed of group frames! */ } mdl_frame_t; /* mdl model structure */ typedef struct { mdl_header_t header; mdl_skin_t *skins; mdl_texCoord_t *texcoords; mdl_triangle_t *triangles; mdl_frame_t *frames; GLuint *tex_id; int iskin; } mdl_model_t; int mdl_load (mdl_model_t *mdl, const char *filename); void mdl_free (mdl_model_t *mdl); void mdl_render_frame(const mdl_model_t *mdl, int n); #endif infon/sdl_sprite.c0000644000076400001440000002165010544566260014270 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "misc.h" #include "sdl_sprite.h" #include "sdl_video.h" static SDL_Surface *sprites[SPRITE_NUM] = {0}; static SDL_Surface *gfx = NULL ; static SDL_Surface *sprite_load_surface(const char *filename) { SDL_Surface *ret = IMG_Load(filename); if (!ret) die("Cannot load file %s: %s", filename, SDL_GetError()); return ret; } static void sprite_load_background() { const int tilepos[][2] = { // Border { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 0 }, { 5, 0 }, { 6, 0 }, { 7, 0 }, { 8, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, { 13, 0 }, { 14, 0 }, { 15, 0 }, // Solid { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 }, { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 }, // Plain { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 }, { 4, 2 }, { 5, 2 }, { 6, 2 }, { 7, 2 }, { 8, 2 }, { 9, 2 }, { 10, 2 }, { 11, 2 }, { 12, 2 }, { 13, 2 }, { 14, 2 }, { 15, 2 }, // Border Snow { 16, 0 }, { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 }, { 21, 0 }, { 22, 0 }, { 23, 0 }, { 24, 0 }, { 25, 0 }, { 26, 0 }, { 27, 0 }, { 28, 0 }, { 29, 0 }, { 30, 0 }, { 31, 0 }, // Solid Snow { 16, 1 }, { 17, 1 }, { 18, 1 }, { 19, 1 }, { 20, 1 }, { 21, 1 }, { 22, 1 }, { 23, 1 }, { 24, 1 }, { 25, 1 }, { 26, 1 }, { 27, 1 }, { 28, 1 }, { 29, 1 }, { 30, 1 }, { 31, 1 }, // Plain Snow { 16, 2 }, { 17, 2 }, { 18, 2 }, { 19, 2 }, { 20, 2 }, { 21, 2 }, { 22, 2 }, { 23, 2 }, { 24, 2 }, { 25, 2 }, { 26, 2 }, { 27, 2 }, { 28, 2 }, { 29, 2 }, { 30, 2 }, { 31, 2 }, // KOTH { 0, 3 }, // Water { 0, 6 }, { 1, 6 }, { 2, 6 }, { 3, 6 }, // Lava { 0, 7 }, { 1, 7 }, { 2, 7 }, { 3, 7 }, // Desert { 6, 3 }, { 7, 3 }, { 8, 3 }, { 9, 3 }, { 10, 3 }, { 11, 3 }, { 12, 3 }, { 13, 3 }, { 14, 3 }, { 15, 3 }, }; for (int i = 0; i < SPRITE_NUM_TILES; i++) { sprites[i] = video_new_surface(SPRITE_TILE_SIZE, SPRITE_TILE_SIZE); SDL_Rect srcrect = { tilepos[i][0] * 16, 192 + tilepos[i][1] * 16, SPRITE_TILE_SIZE, SPRITE_TILE_SIZE }; SDL_BlitSurface(gfx, &srcrect, sprites[i], NULL); } } static void sprite_load_food() { for (int f = 0; f < SPRITE_NUM_FOOD; f++) { sprites[SPRITE_FOOD + f] = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect srcrect = { f * 16, 256, 16, 16 }; SDL_BlitSurface(gfx, &srcrect, sprites[SPRITE_FOOD + f], NULL); } for (int f = 0; f < SPRITE_NUM_SNOW_FOOD; f++) { sprites[SPRITE_SNOW_FOOD + f] = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect srcrect = { f * 16, 256 + 16, 16, 16 }; SDL_BlitSurface(gfx, &srcrect, sprites[SPRITE_SNOW_FOOD + f], NULL); } } static void sprite_load_thought() { for (int t = 0; t < SPRITE_NUM_THOUGHT; t++) { // Mit video_new_alpha geht wahrscheinlich das bitgefuddel bei 16 bit nicht mehr. sprites[SPRITE_THOUGHT + t] = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect srcrect = { 0, 48 + t * 16, 16, 16 }; SDL_BlitSurface(gfx, &srcrect, sprites[SPRITE_THOUGHT + t], NULL); Uint32 *pixels = (Uint32*)sprites[SPRITE_THOUGHT + t]->pixels; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { Uint32 pixel = pixels[y * 16 + x]; pixels[y * 16 + x] = (pixel & 0xFFFFFF00) | (int)((pixel & 0xFF) / 3); } } } } static void sprite_load_images() { sprites[SPRITE_CROWN]= SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 64, 50, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect crect = { 0, 350, 64, 50 }; SDL_BlitSurface(gfx, &crect, sprites[SPRITE_CROWN], NULL); sprites[SPRITE_LOGO] = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 170, 80, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect lrect = { 0, 410, 170, 80}; SDL_BlitSurface(gfx, &lrect, sprites[SPRITE_LOGO], NULL); sprites[SPRITE_HALO] = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 32, 32, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect hrect = {16, 48, 32, 32}; SDL_BlitSurface(gfx, &hrect, sprites[SPRITE_HALO], NULL); } SDL_Surface *sprite_get(int i) { return sprites[i]; } int sprite_exists(int i) { if (i < 0 || i >= SPRITE_NUM) return 0; if (!sprites[i]) return 0; return 1; } void sprite_render_player_creatures(int playerno, int r1, int g1, int b1, int r2, int g2, int b2) { for (int t = 0; t < CREATURE_TYPES; t++) { for (int a = 0; a < CREATURE_ANIMS; a++) { SDL_Surface *base = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Surface *over = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Surface *done = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); SDL_Rect baserect = { a * 16, t * 16, 16, 16 }; SDL_BlitSurface(gfx, &baserect, base, NULL); SDL_Rect overrect = { a * 16 + 32, t * 16, 16, 16 }; SDL_BlitSurface(gfx, &overrect, over, NULL); Uint32 *basepixel = (Uint32*)base->pixels; Uint32 *donepixel = (Uint32*)done->pixels; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { int sat1 = (*basepixel >> 24) & 0xFF; int sat2 = (*basepixel >> 8) & 0xFF; *donepixel = ((min(0xFF, (sat1 * r1 + sat2 * r2) >> 8)) << 24) | ((min(0xFF, (sat1 * g1 + sat2 * g2) >> 8)) << 16) | ((min(0xFF, (sat1 * b1 + sat2 * b2) >> 8)) << 8) | //((*basepixel & 0xFF) > 0 ? 0xFF : 0); (min(0xFF, (*basepixel & 0xFF) * 3)); basepixel++; donepixel++; } } SDL_BlitSurface(over, NULL, done, NULL); for (int d = 0; d < CREATURE_DIRECTIONS; d++) { SDL_Surface **target = &sprites[CREATURE_SPRITE(playerno, t, d, a)]; if (*target) SDL_FreeSurface(*target); *target = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCALPHA, 16, 16, 32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); sge_transform(done, *target, 360.0 * d / 32, 0.75, 0.75, 7, 7, 7 , 7, SGE_TAA|SGE_TSAFE); } SDL_FreeSurface(base); SDL_FreeSurface(over); SDL_FreeSurface(done); } } } void sprite_init() { gfx = sprite_load_surface(PREFIX "gfx/theme.png"); SDL_SetAlpha(gfx, 0, 0); sprite_load_background(); sprite_load_food(); sprite_load_thought(); sprite_load_images(); } void sprite_shutdown() { for (int i = 0; i < SPRITE_NUM; i++) { if (sprites[i]) SDL_FreeSurface(sprites[i]); } SDL_FreeSurface(gfx); } infon/sdl_sprite.h0000644000076400001440000000737410544566163014306 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef SDL_SPRITE_H #define SDL_SPRITE_H #include #include "common_creature.h" #define SPRITE_NUM 16384 // Tiles Konstanten #define SPRITE_BORDER 0 #define SPRITE_NUM_BORDER 16 #define SPRITE_SOLID (SPRITE_BORDER + SPRITE_NUM_BORDER) #define SPRITE_NUM_SOLID 16 #define SPRITE_PLAIN (SPRITE_SOLID + SPRITE_NUM_SOLID) #define SPRITE_NUM_PLAIN 16 #define SPRITE_SNOW_BORDER (SPRITE_PLAIN + SPRITE_NUM_PLAIN) #define SPRITE_NUM_SNOW_BORDER 16 #define SPRITE_SNOW_SOLID (SPRITE_SNOW_BORDER + SPRITE_NUM_SNOW_BORDER) #define SPRITE_NUM_SNOW_SOLID 16 #define SPRITE_SNOW_PLAIN (SPRITE_SNOW_SOLID + SPRITE_NUM_SNOW_SOLID) #define SPRITE_NUM_SNOW_PLAIN 16 #define SPRITE_KOTH (SPRITE_SNOW_PLAIN + SPRITE_NUM_SNOW_PLAIN) #define SPRITE_NUM_KOTH 1 #define SPRITE_WATER (SPRITE_KOTH + SPRITE_NUM_KOTH) #define SPRITE_NUM_WATER 4 #define SPRITE_LAVA (SPRITE_WATER + SPRITE_NUM_WATER) #define SPRITE_NUM_LAVA 4 #define SPRITE_DESERT (SPRITE_LAVA + SPRITE_NUM_LAVA) #define SPRITE_NUM_DESERT 10 #define SPRITE_NUM_TILES (SPRITE_NUM_SOLID + \ SPRITE_NUM_PLAIN + \ SPRITE_NUM_BORDER + \ SPRITE_NUM_SNOW_SOLID + \ SPRITE_NUM_SNOW_PLAIN + \ SPRITE_NUM_SNOW_BORDER + \ SPRITE_NUM_KOTH + \ SPRITE_NUM_WATER + \ SPRITE_NUM_LAVA + \ SPRITE_NUM_DESERT) #define SPRITE_TILE_SIZE 16 // Food Konstanten #define SPRITE_FOOD 256 #define SPRITE_NUM_FOOD 10 #define SPRITE_SNOW_FOOD (SPRITE_FOOD + SPRITE_NUM_FOOD) #define SPRITE_NUM_SNOW_FOOD 10 // Thought Konstanten #define SPRITE_THOUGHT (SPRITE_SNOW_FOOD + SPRITE_NUM_SNOW_FOOD) #define SPRITE_NUM_THOUGHT CREATURE_STATES + 1 /* + Smile */ // Koth Krone #define SPRITE_CROWN (SPRITE_THOUGHT + SPRITE_NUM_THOUGHT) #define SPRITE_NUM_CROWN 1 // Logo #define SPRITE_LOGO (SPRITE_CROWN + SPRITE_NUM_CROWN) #define SPRITE_HALO (SPRITE_LOGO + 1) #define SPRITE_CREATURE 512 // Creature Konstanten #define CREATURE_SPRITE(player, type, direction, anim) \ (SPRITE_CREATURE + (player) * CREATURE_TYPES * CREATURE_DIRECTIONS * CREATURE_ANIMS + \ (type) * CREATURE_DIRECTIONS * CREATURE_ANIMS + \ (direction) * CREATURE_ANIMS + \ (anim)) SDL_Surface *sprite_get(int i); int sprite_exists(int i); void sprite_render_player_creatures(int playerno, int r1, int g1, int b1, int r2, int g2, int b2); void sprite_init(); void sprite_shutdown(); #endif infon/gl_video.c0000644000076400001440000000702310533001515013667 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include "misc.h" #include "global.h" #include "gl_video.h" #include "map.h" static SDL_Surface *screen; static Uint32 flags = SDL_OPENGL | SDL_RESIZABLE; void video_setup_opengl(int width, int height) { float ratio = (float) width / (float) height; /* Our shading model--Gouraud (smooth). */ glShadeModel(GL_SMOOTH); /* Culling. */ glCullFace(GL_BACK); glFrontFace(GL_CCW); glEnable(GL_CULL_FACE); glClearColor(0, 0, 0, 0); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // fov aspect minz maxz gluPerspective(60.0, ratio, 1.0, TILE_SCALE * 64); //static GLfloat ModelAmb[] = { 0.1, 0.1, 0.1, 1.0 }; //glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ModelAmb); //glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1.0); glEnable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); // FOG glEnable(GL_FOG); float fogColor[] = {0, 0, 0, 1}; glFogfv(GL_FOG_COLOR, fogColor); glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_DENSITY, 1.0); glHint(GL_FOG_HINT, GL_DONT_CARE); glFogf(GL_FOG_START, TILE_SCALE * 30); glFogf(GL_FOG_END, TILE_SCALE * 60); GLint depth; glGetIntegerv(GL_DEPTH_BITS, &depth); printf("Zbuffer depth = %d\n", depth); } void video_init(int w, int h, int fs) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) if (SDL_Init(0) == -1) die("Couldn't initialize SDL: %s", SDL_GetError()); if (fs) flags |= SDL_FULLSCREEN; screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) die("Couldn't set display mode: %s", SDL_GetError()); video_set_title(GAME_NAME); SDL_ShowCursor(1); SDL_EnableUNICODE(1); video_setup_opengl(w, h); } void video_set_title(const char *title) { SDL_WM_SetCaption(title, "infon"); } void video_shutdown() { // SDL_FreeSurface(screen); SDL_QuitSubSystem(SDL_INIT_VIDEO); } void video_fullscreen_toggle() { #ifdef WIN32 flags ^= SDL_FULLSCREEN; screen = SDL_SetVideoMode(0, 0, 0, flags); if (!screen) die("couldn't toggle fullscreen. sorry"); #else SDL_WM_ToggleFullScreen(screen); #endif video_setup_opengl(screen->w, screen->h); } void video_resize(int w, int h) { if (w < 320 || h < 200) return; screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) die("couldn't change resolution. sorry"); video_setup_opengl(screen->w, screen->h); } void video_flip() { SDL_GL_SwapBuffers(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } int video_width() { return screen->w; } int video_height() { return screen->h; } infon/aa_gui.c0000644000076400001440000001511710540100022013316 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #define SCALE 4 #include "renderer.h" #include "aalib.h" static aa_context *context; static unsigned char *bitmap; static aa_palette palette; static aa_renderparams *params; __AA_CONST static int pal[] = { 0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 8, 0, 0, 9, 0, 0, 10, 2, 0, 10, 4, 0, 9, 6, 0, 9, 8, 0, 8, 10, 0, 7, 12, 0, 7, 14, 0, 6, 16, 0, 5, 18, 0, 5, 20, 0, 4, 22, 0, 4, 24, 0, 3, 26, 0, 2, 28, 0, 2, 30, 0, 1, 32, 0, 0, 32, 0, 0, 33, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 0, 36, 0, 0, 37, 0, 0, 38, 0, 0, 39, 0, 0, 40, 0, 0, 40, 0, 0, 41, 0, 0, 42, 0, 0, 43, 0, 0, 44, 0, 0, 45, 0, 0, 46, 1, 0, 47, 1, 0, 48, 2, 0, 49, 2, 0, 50, 3, 0, 51, 3, 0, 52, 4, 0, 53, 4, 0, 54, 5, 0, 55, 5, 0, 56, 6, 0, 57, 6, 0, 58, 7, 0, 59, 7, 0, 60, 8, 0, 61, 8, 0, 63, 9, 0, 63, 9, 0, 63, 10, 0, 63, 10, 0, 63, 11, 0, 63, 11, 0, 63, 12, 0, 63, 12, 0, 63, 13, 0, 63, 13, 0, 63, 14, 0, 63, 14, 0, 63, 15, 0, 63, 15, 0, 63, 16, 0, 63, 16, 0, 63, 17, 0, 63, 17, 0, 63, 18, 0, 63, 18, 0, 63, 19, 0, 63, 19, 0, 63, 20, 0, 63, 20, 0, 63, 21, 0, 63, 21, 0, 63, 22, 0, 63, 22, 0, 63, 23, 0, 63, 24, 0, 63, 24, 0, 63, 25, 0, 63, 25, 0, 63, 26, 0, 63, 26, 0, 63, 27, 0, 63, 27, 0, 63, 28, 0, 63, 28, 0, 63, 29, 0, 63, 29, 0, 63, 30, 0, 63, 30, 0, 63, 31, 0, 63, 31, 0, 63, 32, 0, 63, 32, 0, 63, 33, 0, 63, 33, 0, 63, 34, 0, 63, 34, 0, 63, 35, 0, 63, 35, 0, 63, 36, 0, 63, 36, 0, 63, 37, 0, 63, 38, 0, 63, 38, 0, 63, 39, 0, 63, 39, 0, 63, 40, 0, 63, 40, 0, 63, 41, 0, 63, 41, 0, 63, 42, 0, 63, 42, 0, 63, 43, 0, 63, 43, 0, 63, 44, 0, 63, 44, 0, 63, 45, 0, 63, 45, 0, 63, 46, 0, 63, 46, 0, 63, 47, 0, 63, 47, 0, 63, 48, 0, 63, 48, 0, 63, 49, 0, 63, 49, 0, 63, 50, 0, 63, 50, 0, 63, 51, 0, 63, 52, 0, 63, 52, 0, 63, 52, 0, 63, 52, 0, 63, 52, 0, 63, 53, 0, 63, 53, 0, 63, 53, 0, 63, 53, 0, 63, 54, 0, 63, 54, 0, 63, 54, 0, 63, 54, 0, 63, 54, 0, 63, 55, 0, 63, 55, 0, 63, 55, 0, 63, 55, 0, 63, 56, 0, 63, 56, 0, 63, 56, 0, 63, 56, 0, 63, 57, 0, 63, 57, 0, 63, 57, 0, 63, 57, 0, 63, 57, 0, 63, 58, 0, 63, 58, 0, 63, 58, 0, 63, 58, 0, 63, 59, 0, 63, 59, 0, 63, 59, 0, 63, 59, 0, 63, 60, 0, 63, 60, 0, 63, 60, 0, 63, 60, 0, 63, 60, 0, 63, 61, 0, 63, 61, 0, 63, 61, 0, 63, 61, 0, 63, 62, 0, 63, 62, 0, 63, 62, 0, 63, 62, 0, 63, 63, 0, 63, 63, 1, 63, 63, 2, 63, 63, 3, 63, 63, 4, 63, 63, 5, 63, 63, 6, 63, 63, 7, 63, 63, 8, 63, 63, 9, 63, 63, 10, 63, 63, 10, 63, 63, 11, 63, 63, 12, 63, 63, 13, 63, 63, 14, 63, 63, 15, 63, 63, 16, 63, 63, 17, 63, 63, 18, 63, 63, 19, 63, 63, 20, 63, 63, 21, 63, 63, 21, 63, 63, 22, 63, 63, 23, 63, 63, 24, 63, 63, 25, 63, 63, 26, 63, 63, 27, 63, 63, 28, 63, 63, 29, 63, 63, 30, 63, 63, 31, 63, 63, 31, 63, 63, 32, 63, 63, 33, 63, 63, 34, 63, 63, 35, 63, 63, 36, 63, 63, 37, 63, 63, 38, 63, 63, 39, 63, 63, 40, 63, 63, 41, 63, 63, 42, 63, 63, 42, 63, 63, 43, 63, 63, 44, 63, 63, 45, 63, 63, 46, 63, 63, 47, 63, 63, 48, 63, 63, 49, 63, 63, 50, 63, 63, 51, 63, 63, 52, 63, 63, 52, 63, 63, 53, 63, 63, 54, 63, 63, 55, 63, 63, 56, 63, 63, 57, 63, 63, 58, 63, 63, 59, 63, 63, 60, 63, 63, 61, 63, 63, 62, 63, 63, 63}; static int aarenderer_open(int w, int h, int fs) { int argc = 1; char *argv[] = { "foo", NULL }; int i; if (!aa_parseoptions(NULL, NULL, &argc, argv) || argc != 1) { printf("%s\n", aa_help); return 0; } context = aa_autoinit(&aa_defparams); if (context == NULL) { printf("Can not intialize aalib\n"); return 0; } bitmap = aa_image (context); params = aa_getrenderparams (); for (i = 0; i < 256; i++) aa_setpalette(palette, i, pal[i * 3] * 4, pal[i * 3 + 1] * 4, pal[i * 3 + 2] * 4); aa_hidecursor(context); return 1; } static void aarenderer_close() { aa_close(context); } int ox = 0; int oy = 0; static void draw_creature(const client_creature_t *creature, void *opaque) { int x = creature->x / (256 / SCALE) - ox; int y = creature->y / (256 / SCALE) - oy; if (x < 0 || x >= aa_imgwidth(context) || y < 0 || y >= aa_imgheight(context)) return; bitmap[y * aa_imgwidth(context) + x] = 0xFF; } static void aarenderer_tick(int gt, int delta) { const client_world_info_t *worldsize = infon->get_world_info(); if (!worldsize) return; const client_maptile_t *world = infon->get_world(); unsigned char *p = bitmap; int x; int y; p--; for (y = 0; y < aa_imgheight(context); y++) { for (x = 0; x < aa_imgwidth(context); x++) { int terrainx = (x - ox) / SCALE; int terrainy = (y - oy) / SCALE; p++; if (terrainx < 0 || terrainx >= worldsize->width || terrainy < 0 || terrainy >= worldsize->height) continue; const client_maptile_t *tile = &world[terrainy * worldsize->width + terrainx]; switch (tile->type) { case TILE_SOLID: *p = 90; break; case TILE_PLAIN: *p = 0; break; default: *p = 50; break; } } } infon->each_creature(draw_creature, NULL); aa_renderpalette (context, palette, params, 0, 0, aa_scrwidth (context), aa_scrheight (context)); aa_printf(context, 0, 0, AA_SPECIAL, infon->version); aa_flush(context); } const static renderer_api_t aa_api = { .version = RENDERER_API_VERSION, .open = aarenderer_open, .close = aarenderer_close, .tick = aarenderer_tick, }; RENDERER_EXPORT(aa_api) infon/lilith_gui.cpp0000644000076400001440000002747510533001515014605 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "lilith/lilith/lilith3d.h" #include "lilith/lilith/import/md2.h" #include #include #include #include #include #include #include #include #include "renderer.h" using namespace grinliz; using namespace lilith3d; static SDL_Surface *surface = 0; static TextureManager *texman = 0; static MeshResManager *meshman = 0; static Lilith3D *lilith = 0; static Uint32 real_time; class LCreature : public Mob { public: LCreature(const client_creature_t *creature) : m_rand(real_time), m_toggle(0) { MeshResManager *meshman = MeshResManager::Instance(); m_mesh = new AnimatedMesh(meshman->GetAnimatedRes("Marine")); m_lastdir = 0; update(creature); for (int i = 0; i < 10; i++) smoke(); } ~LCreature() { for (int i = 0; i < 10; i++) smoke(); delete m_mesh; } void Update( TimeClock* tc ) { } void KillAnimation() { m_mesh->SetAction( AnimatedMesh::DEATH ); } void smoke() { Vector3F smoke_vel= { m_rand.FRand(1.0) + -0.5 , m_rand.FRand(1.0) + -0.5 , m_rand.FRand(1.0) + 0.5 }; float r = m_rand.FRand(0.3) + 0.7; Color3F smoke_col = { r, r, r }; lilith->GetGravParticles()->Create(m_mesh->Pos(), smoke_vel, smoke_col, 2, GravParticles::FLAME0); } void update(const client_creature_t *creature) { float x = (float)creature->x / TILE_WIDTH + 1.5; float y = (float)creature->y / TILE_HEIGHT + 1.5; int action; switch (creature->state) { case CREATURE_IDLE: case CREATURE_HEAL: case CREATURE_CONVERT: case CREATURE_SPAWN: case CREATURE_FEED: case CREATURE_EAT: if (creature->health == 0) action = AnimatedMesh::DEATH; else action = AnimatedMesh::STAND; break; case CREATURE_WALK: action = AnimatedMesh::RUN; break; case CREATURE_ATTACK: action = AnimatedMesh::ATTACK; break; } if (action != m_mesh->GetAction()) m_mesh->SetAction(action); float dir = creature->dir * 360.0 / 32.0 - 90; /* float dw = m_lastdir - dir; if (dw < -180) dw += 180; if (dw > 180) dw -= 180; if (dw < -6) { m_lastdir += 6; } else if (dw > 6) { m_lastdir -= 6; } else { m_lastdir = dir; } */ m_lastdir = dir; if (creature->type == 2) { float flow = creature->type == 2 ? sin(creature->num + (float)real_time / 1000.0) : 0; Vector3F at = { x - 0.5 + flow, y - 0.5 + flow, 3.0f + flow }; m_mesh->SetPos( at, m_lastdir ); m_mesh->AttachToTerrain(false); } else { Vector3F at = { x, y, 0 }; m_mesh->SetPos( at, m_lastdir ); m_mesh->AttachToTerrain(true); } static const Color3F colors[16] = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0 }, { 0.0, 1.0, 1.0 }, { 1.0, 0.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 0.0, 0.0, 0.0 }, { 1.0, 0.5, 0.5 }, { 0.5, 1.0, 0.5 }, { 0.5, 0.5, 1.0 }, { 1.0, 1.0, 0.5 }, { 0.5, 1.0, 1.0 }, { 1.0, 0.5, 1.0 }, { 0.5, 0.5, 0.5 }, { 0.3, 0.7, 1.0 }, }; Vector3F velocity = { 0, 0, m_rand.FRand(0.5) + 0.5 }; const client_player_t *player = infon->get_player(creature->player); int hi = (player->color & 0xF0) >> 4; int lo = (player->color & 0x0F); lilith->GetGravParticles()->Create(m_mesh->Pos(), velocity, colors[m_toggle ? hi : lo], 2, GravParticles::SMALL ); m_toggle ^= 1; switch (creature->state) { case CREATURE_CONVERT: case CREATURE_SPAWN: smoke(); break; default: break; } } private: float m_lastdir; Random m_rand; int m_toggle; AnimatedMesh *m_mesh; }; static int lilith_open(int w, int h, int fs) { if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER ) < 0 ) die("SDL initialization failed: %s\n", SDL_GetError( )); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); int videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */ videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */ videoFlags |= SDL_RESIZABLE; //int bpp = SDL_VideoModeOK(w, h, 32, videoFlags ); //GLASSERT( bpp ); surface = SDL_SetVideoMode(w, h, 32, videoFlags ); GLASSERT( surface ); SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); InitOpenGL(); // Tutorial 1: Textures and Models texman = new TextureManager(); meshman = new MeshResManager(); texman->SetImportPath ("lilith/lilith/graphics/"); meshman->SetImportPath("lilith/lilith/graphics/"); texman->LoadRequiredTextures(); meshman->LoadRequiredModels(); texman->SetImportPath ("gfx/"); meshman->SetImportPath("gfx/"); MD2Resource* marine = meshman->LoadMD2Res("bug.md2", "Marine"); marine->SetTexture( texman->LoadTexture("bug.pcx", "Marine"), MD2Resource::SPRITE ); lilith = new Lilith3D(); lilith->SetRenderMode( Lilith3D::RENDER_SHADER ); return 1; } static void creature_update(const client_creature_t *creature, void *opaque) { LCreature *lcreature = (LCreature*)creature->userdata; lcreature->update(creature); } static void lilith_tick(int gt, int delta) { real_time = SDL_GetTicks(); static bool ignoreJump = false; SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_RETURN: //if (event.key.keysym.mod & KMOD_ALT) // video_fullscreen_toggle(); break; case SDLK_ESCAPE: infon->shutdown(); break; case SDLK_F1: lilith->SetRenderMode( Lilith3D::RENDER_SHADER ); break; case SDLK_F2: lilith->SetRenderMode( Lilith3D::RENDER_FLAT ); break; case SDLK_F3: lilith->SetRenderMode( Lilith3D::RENDER_LOD ); break; case SDLK_F4: lilith->SetRenderMode( Lilith3D::RENDER_PATH ); break; case SDLK_F5: TimeClock::Instance()->ToggleSun(); break; case SDLK_F6: lilith->SetLineMode( !lilith->LineMode() ); break; default: ; } break; case SDL_MOUSEBUTTONDOWN: if ( event.button.button == SDL_BUTTON_RIGHT ) { SDL_WM_GrabInput( SDL_GRAB_ON ); SDL_ShowCursor( SDL_DISABLE ); ignoreJump = true; } break; case SDL_MOUSEBUTTONUP: if ( event.button.button == SDL_BUTTON_RIGHT ) { SDL_WM_GrabInput( SDL_GRAB_OFF ); SDL_ShowCursor( SDL_ENABLE ); } break; case SDL_MOUSEMOTION: if ( event.motion.state & SDL_BUTTON (SDL_BUTTON_RIGHT) ) { if ( !ignoreJump ) { Camera* camera = lilith->GetCamera(); float xVel = (float)event.motion.xrel * 20.0f; float yVel = (float)event.motion.yrel * 20.0f; camera->MoveCameraRotation( Camera::YAW, -xVel ); camera->MoveCameraRotation( Camera::PITCH, yVel ); } ignoreJump = false; } break; case SDL_VIDEORESIZE: break; case SDL_QUIT: infon->shutdown(); break; } } if ( SDL_GetMouseState(0, 0) == (SDL_BUTTON( SDL_BUTTON_LEFT ) | SDL_BUTTON( SDL_BUTTON_RIGHT ) ) ) lilith->GetCamera()->MoveCameraAxial3D( 20.0f ); if ( SDL_GetMouseState(0, 0) == (SDL_BUTTON( SDL_BUTTON_MIDDLE) | SDL_BUTTON( SDL_BUTTON_RIGHT ) ) ) lilith->GetCamera()->MoveCameraAxial3D(-20.0f ); infon->each_creature(creature_update, 0); lilith->BeginDraw(); lilith->Draw(); lilith->EndDraw(); } static void lilith_world_info_changed(const client_world_info_t *info) { assert(info->width < MAPSIZE); assert(info->height < MAPSIZE); TerrainMesh *tmesh = lilith->GetTerrainMesh(); tmesh->StartHeightChange(); for(int i=0; i<(int)VERTEXSIZE; ++i ) { for(int j=0; j<(int)VERTEXSIZE; ++j ) { tmesh->SetHeight(i, j, -0.3); } } tmesh->EndHeightChange(); } static void lilith_world_changed(int x, int y) { TerrainMesh *tmesh = lilith->GetTerrainMesh(); const client_maptile_t *tile = infon->get_world_tile(x, y); tmesh->StartHeightChange(); switch (tile->map) { case TILE_SOLID: tmesh->SetHeight(x + 2, y + 2, 1+sin(x+y)/10); break; case TILE_PLAIN: tmesh->SetHeight(x + 2, y + 2, 0.5+sin(x+y)/10); break; default: tmesh->SetHeight(x + 2, y + 2, -0.3); break; } tmesh->EndHeightChange(); } static void *lilith_creature_spawned(const client_creature_t *creature) { return new LCreature(creature); } static void lilith_creature_changed(const client_creature_t *creature, int changed) { } static void lilith_creature_died(const client_creature_t *creature) { LCreature *lcreature = (LCreature*)creature->userdata; delete lcreature; } static void lilith_close() { delete lilith; delete meshman; delete texman; SDL_Quit(); } static const renderer_api_t lilith_api = { RENDERER_API_VERSION, lilith_open, lilith_close, lilith_tick, lilith_world_info_changed, lilith_world_changed, NULL, NULL, NULL, lilith_creature_spawned, lilith_creature_changed, lilith_creature_died, NULL }; RENDERER_EXPORT(lilith_api) infon/client_world.h0000644000076400001440000000277110536310404014601 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef CLIENT_WORLD_H #define CLIENT_WORLD_H #include "packet.h" #include "common_world.h" typedef struct maptile_s { int food; maptype_e type; mapgfx_e gfx; } client_maptile_t; typedef struct world_info_s { int width; int height; int koth_x; int koth_y; } client_world_info_t; /* Renderer */ const client_world_info_t *client_world_get_info(); const client_maptile_t *client_world_get(); const client_maptile_t *client_world_get_tile(int x, int y); /* Network */ void client_world_from_network(packet_t *packet); void client_world_info_from_network(packet_t *packet); void client_world_init(); void client_world_shutdown(); #endif infon/client_player.c0000644000076400001440000001043010533001515014725 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include "global.h" #include "rules.h" #include "renderer.h" #include "client_player.h" #include "common_player.h" #define PLAYER_USED(player) ((player)->used) static client_player_t players[MAXPLAYERS]; static client_player_t *king_player = NULL; const client_player_t *client_player_get(int num) { if (num < 0 || num >= MAXPLAYERS) return NULL; const client_player_t *player = &players[num]; if (!PLAYER_USED(player)) return NULL; return player; } const client_player_t *client_player_get_king() { return king_player; } void client_player_each(void (*callback)(const client_player_t *player, void *opaque), void *opaque) { for (int n = 0; n < MAXPLAYERS; n++) { const client_player_t *player = &players[n]; if (!PLAYER_USED(player)) continue; callback(player, opaque); } } void client_player_from_network(packet_t *packet) { uint8_t playerno; if (!packet_read08(packet, &playerno)) PROTOCOL_ERROR(); if (playerno >= MAXPLAYERS) PROTOCOL_ERROR(); client_player_t *player = &players[playerno]; uint8_t updatemask; if (!packet_read08(packet, &updatemask)) PROTOCOL_ERROR(); if (updatemask & PLAYER_DIRTY_ALIVE) { uint8_t alive; if (!packet_read08(packet, &alive)) PROTOCOL_ERROR(); if (!alive) { renderer_player_left(player); player->used = 0; return; } else { memset(player, 0, sizeof(client_player_t)); player->used = 1; player->num = playerno; renderer_player_joined(player); } } if (!PLAYER_USED(player)) PROTOCOL_ERROR(); if (updatemask & PLAYER_DIRTY_NAME) { uint8_t len; char buf[256]; if (!packet_read08(packet, &len)) PROTOCOL_ERROR(); if (!packet_readXX(packet, buf, len)) PROTOCOL_ERROR(); buf[len] = '\0'; snprintf(player->name, sizeof(player->name), "%s", buf); } if (updatemask & PLAYER_DIRTY_COLOR) { uint8_t col; if (!packet_read08(packet, &col)) PROTOCOL_ERROR(); player->color = col; } if (updatemask & PLAYER_DIRTY_CPU) { uint8_t cpu; if (!packet_read08(packet, &cpu)) PROTOCOL_ERROR(); if (cpu > 100) PROTOCOL_ERROR(); player->cpu_usage = cpu; } if (updatemask & PLAYER_DIRTY_SCORE) { uint16_t score; if (!packet_read16(packet, &score)) PROTOCOL_ERROR(); player->score = score + PLAYER_KICK_SCORE; } if (updatemask & ~PLAYER_DIRTY_ALIVE) renderer_player_changed(player, updatemask & ~PLAYER_DIRTY_ALIVE); } void client_player_king_from_network(packet_t *packet) { uint8_t kingno; if (!packet_read08(packet, &kingno)) PROTOCOL_ERROR(); if (kingno == 0xFF) { king_player = NULL; } else { if (kingno >= MAXPLAYERS) PROTOCOL_ERROR(); if (!PLAYER_USED(&players[kingno])) PROTOCOL_ERROR(); king_player = &players[kingno]; } } void client_player_init() { memset(players, 0, sizeof(players)); } void client_player_shutdown() { for (int n = 0; n < MAXPLAYERS; n++) { const client_player_t *player = &players[n]; if (!PLAYER_USED(player)) continue; renderer_player_left(player); } } infon/gl_video.h0000644000076400001440000000221010533001515013665 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef GL_VIDEO_H #define GL_VIDEO_H void video_fullscreen_toggle(); void video_flip(); void video_set_title(const char *title); int video_width(); int video_height(); void video_resize(int w, int h); void video_init(int w, int h, int fs); void video_shutdown(); #endif infon/client_player.h0000644000076400001440000000307010533001515014734 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef GUI_PLAYER_H #define GUI_PLAYER_H #include #include "packet.h" typedef struct client_player_s { int num; int used; void *userdata; char name[16]; int color; int score; int cpu_usage; } client_player_t; /* Renderer */ const client_player_t *client_player_get(int num); const client_player_t *client_player_get_king(); void client_player_each(void (*callback)(const client_player_t *player, void *opaque), void *opaque); /* Network */ void client_player_from_network(packet_t *packet); void client_player_king_from_network(packet_t *packet); void client_player_init(); void client_player_shutdown(); #endif infon/gl_gui.c0000644000076400001440000006260410552756360013373 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include #include #include #include "renderer.h" #include "map.h" #include "misc.h" #include "gl_video.h" #include "gl_mdl.h" static Uint32 real_time; static const float colors[16][3] = { { 1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0}, { 1.0, 1.0, 0.0}, { 0.0, 1.0, 1.0}, { 1.0, 0.0, 1.0}, { 1.0, 1.0, 1.0}, { 0.0, 0.0, 0.0}, { 1.0, 0.5, 0.5}, { 0.5, 1.0, 0.5}, { 0.5, 0.5, 1.0}, { 1.0, 1.0, 0.5}, { 0.5, 1.0, 1.0}, { 1.0, 0.5, 1.0}, { 0.5, 0.5, 0.5}, { 0.2, 0.8, 1.0}, }; typedef struct { float x; float y; float z; } Vec; static float direction; static Vec lookat; static Vec eye; static Vec lookat_dest; static Vec eye_dest; static float vec_interpolate(float val, float dest, float divisor) { if (val - dest > -1 && val - dest < 1) return dest; return val + (dest - val) / divisor; } void vec_moveto(Vec *vec, Vec *dest, float ox, float oy, float oz) { vec->x = vec_interpolate(vec->x, dest->x + ox, 30); vec->y = vec_interpolate(vec->y, dest->y + oy, 30); vec->z = vec_interpolate(vec->z, dest->z + oz, 30); } #define PIdiv180 M_PI/180.0 static void cam_update_eye_dest() { if (eye_dest.z == 100) { eye_dest.x = lookat_dest.x + sin(direction * PIdiv180) * 200; eye_dest.y = lookat_dest.y - cos(direction * PIdiv180) * 200; } else if (eye_dest.z > 6000) { eye_dest.x = lookat_dest.x + sin(direction * PIdiv180) * 1500; eye_dest.y = lookat_dest.y - cos(direction * PIdiv180) * 1500; } else { eye_dest.x = lookat_dest.x + sin(direction * PIdiv180) * (eye_dest.z+ 200); eye_dest.y = lookat_dest.y - cos(direction * PIdiv180) * (eye_dest.z + 200); } } static void cam_tick(int msec) { cam_update_eye_dest(); vec_moveto(&eye, &eye_dest, 0, 0, 0); vec_moveto(&lookat, &lookat_dest, 0, 0, 0); gluLookAt(eye.x, eye.y, eye.z, lookat.x, lookat.y, lookat.z, 0.0, 0.0, -1.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT2); static GLfloat l1amb[] = { 0, 0, 0, 1.0 }; glLightfv(GL_LIGHT2, GL_AMBIENT, l1amb); GLfloat l1diffuse[] = {1.0, 1.0, 1.0, 1.0}; glLightfv(GL_LIGHT2, GL_DIFFUSE, l1diffuse); GLfloat l1specular [] = {1.0, 1.0, 1.0, 1.0}; glLightfv(GL_LIGHT2, GL_SPECULAR, l1specular); GLfloat l1pos[] = { eye.x, eye.y, eye.z, 1.0 }; glLightfv(GL_LIGHT2, GL_POSITION, l1pos); GLfloat l1dir[] = { lookat.x - eye.x, lookat.y - eye.y, lookat.z - eye.z }; glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, l1dir); glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 0.1); glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 120.0); glClearColor(0.5f, 0.5f, 0.5f, 0.0f); } /* static void cam_screen_to_plane(int x, int y, float *zx, float *zy, int *inFront) { double modelMatrix[16], projMatrix[16]; int viewport[4]; double xNear, yNear, zNear, xFar, yFar, zFar; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); glGetIntegerv(GL_VIEWPORT, viewport); gluUnProject(x, viewport[3] - y, 0.0f, modelMatrix, projMatrix, viewport, &xNear, &yNear, &zNear); gluUnProject(x, viewport[3] - y, 1.0f, modelMatrix, projMatrix, viewport, &xFar, &yFar, &zFar); float dx = (float)(xNear - xFar); float dy = (float)(yNear - yFar); float dz = (float)(zNear - zFar); *zx = eye.x - dx * (eye.z / dz); *zy = eye.y - dy * (eye.z / dz); *inFront = dz > 0; } static float cam_direction() { float w = 180 * atan2(eye.x - lookat.x, lookat.y - eye.y) / M_PI; if (w < 0) w += 360; return w; } */ static void cam_set_height(float height) { eye_dest.z = height; if (eye_dest.z < 100) eye_dest.z = 100; if (eye_dest.z == 100) { lookat_dest.z = 100; } else { lookat_dest.z = 0; } } static void cam_change_height(float dz) { cam_set_height(eye_dest.z + dz); } static void cam_set_direction(float dir) { direction = dir; } static void cam_change_direction(float delta) { assert(delta > -360 && delta < 360); direction += delta; if (direction >= 360) direction -= 360; if (direction < 0) direction += 360; assert(direction >= 0 && direction < 360); } static void cam_set_pos(float x, float y) { lookat_dest.x = x; lookat_dest.y = y; } static void cam_change_pos(float dx, float dy) { cam_set_pos(lookat_dest.x + dx, lookat_dest.y + dy); } static void cam_change_pos_rel(float dx, float dy) { cam_change_pos(dy * sin(direction * PIdiv180) -dx * cos(direction * PIdiv180), -dy * cos(direction * PIdiv180) -dx * sin(direction * PIdiv180)); } static void cam_recenter() { const client_world_info_t *info = infon->get_world_info(); if (!info) return; cam_set_pos(info->width * 256 / 2, info->height * 256 / 2); cam_set_height(7000); cam_set_direction(180); cam_update_eye_dest(); } static void cam_init() { eye.x = 3000; eye.y = 3000; eye.z = 3000; cam_set_pos(0, 0); cam_set_height(3000); cam_set_direction(90); cam_update_eye_dest(); } static void cam_free() { } /* Particle */ typedef struct { int used; GLfloat orig[3]; GLfloat pos[3]; GLfloat time; GLfloat vel[2]; GLfloat dir[2]; GLfloat color[4]; int disappear; } Particle; #define MAXPARTICLE 2000 Particle particles[MAXPARTICLE] = {{0}}; static int next = 0; static void particle_add_fountain(int x, int y, int z) { float angle = (float)(rand() % 30 + 30) * M_PI / 180.0; float dir = (float)(rand() % 360) * M_PI / 180.0; particles[next].orig[0] = x; particles[next].orig[1] = y; particles[next].orig[2] = z; particles[next].color[0] = 1.0; particles[next].color[1] = 1; particles[next].color[2] = 1; particles[next].color[3] = 1; particles[next].time = real_time; particles[next].dir[0] = cos(dir); particles[next].dir[1] = sin(dir); particles[next].vel[0] = cos(angle) * 10; particles[next].vel[1] = sin(angle) * 100; particles[next].used = 1; particles[next].disappear = 0; if (++next >= MAXPARTICLE) next = 0; } static void particle_add_blood(int x, int y, int z) { float angle = (float)(rand() % 30 + 30) * M_PI / 180.0; float dir = (float)(rand() % 360) * M_PI / 180.0; particles[next].orig[0] = x; particles[next].orig[1] = y; particles[next].orig[2] = z; particles[next].color[0] = 1.0; particles[next].color[1] = 1; particles[next].color[2] = 1; particles[next].color[3] = 1; particles[next].time = real_time; particles[next].dir[0] = cos(dir); particles[next].dir[1] = sin(dir); particles[next].vel[0] = cos(angle) * (rand() % 40); particles[next].vel[1] = sin(angle) * 40; particles[next].used = 1; particles[next].disappear = 1; if (++next >= MAXPARTICLE) next = 0; } static void particle_move(int delta) { for (int i = 0; i < MAXPARTICLE; i++) { if (!particles[i].used) continue; float lifetime = (real_time - particles[i].time) / 100.0; float distance = particles[i].vel[0] * lifetime; /* X and Z */ particles[i].pos[0] = particles[i].orig[0] + particles[i].dir[0] * distance; particles[i].pos[1] = particles[i].orig[1] + particles[i].dir[1] * distance; /* Z */ particles[i].pos[2] = particles[i].orig[2] + (particles[i].vel[1] - 9.81 * lifetime) * lifetime; if (particles[i].pos[2] < 5) switch (particles[i].disappear) { case 0: particles[i].vel[1] *= 0.6; if (particles[i].vel[1] < 0.5) { particles[i].used = 0; } else { particles[i].pos[2] = 5; particles[i].orig[0] = particles[i].pos[0]; particles[i].orig[1] = particles[i].pos[1]; particles[i].orig[2] = particles[i].pos[2]; particles[i].time = real_time; } break; case 1: particles[i].pos[2] = 5; particles[i].orig[0] = particles[i].pos[0]; particles[i].orig[1] = particles[i].pos[1]; particles[i].orig[2] = particles[i].pos[2]; particles[i].vel[0] = particles[i].vel[1] = 0; break; } } } static void particle_draw() { glDisable(GL_LIGHTING); glBegin(GL_TRIANGLES); for (int i = 0; i < MAXPARTICLE; i++) { if (!particles[i].used) continue; glColor3fv(particles[i].color); glVertex3f(particles[i].pos[0] + 14, particles[i].pos[1] + 14, particles[i].pos[2]); glVertex3fv(particles[i].pos); glVertex3f(particles[i].pos[0], particles[i].pos[1] + 14, particles[i].pos[2]); } glEnd(); } /* Texture */ typedef struct { GLuint textureID; GLsizei height; GLsizei width; int dimension; } Texture; static void texture_load(Texture *texture, const char *filename, Uint32 key) { int has_transparent_key = key != 0xFFFFFFFF; fprintf(stderr, "loading %s\n", filename); SDL_Surface *imageSurface = SDL_LoadBMP(filename); if (!imageSurface) die("cannot load %s: %s", filename, SDL_GetError()); /* Generate an OpenGL texture */ glGenTextures(1, &texture->textureID); /* Set up some parameters for the format of the OpenGL texture */ glBindTexture(GL_TEXTURE_2D, texture->textureID ); /* Bind Our Texture */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* Linear Filtered */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* Linear Filtered */ texture->height = imageSurface->h; texture->width = imageSurface->w; texture->dimension = 1; while (texture->dimension < texture->width && texture->dimension < texture->height) texture->dimension *= 2; #define _LITTLE_ENDIAN SDL_Surface *tempSurface; /* Create a blank SDL_Surface (of the smallest size to fit the image) & copy imageSurface into it*/ if (has_transparent_key) { #ifdef _LITTLE_ENDIAN tempSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, texture->dimension, texture->dimension, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000); #else tempSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, texture->dimension, texture->dimension, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000); #endif } else { #ifdef _LITTLE_ENDIAN tempSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, texture->dimension, texture->dimension, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0x000000); #else tempSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, texture->dimension, texture->dimension, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0x000000); #endif } SDL_BlitSurface(imageSurface, NULL, tempSurface, NULL); /* Fix the alpha values? */ if (has_transparent_key) { SDL_LockSurface(tempSurface); Uint32 *pixels = (Uint32*)tempSurface->pixels; //printf("%08x %08x\n", *pixels, key); for (int y = 0; y < texture->dimension; y++) { for (int x = 0; x < texture->dimension; x++) { if (pixels[y * texture->dimension + x] != key) { #ifdef _LITTLE_ENDIAN pixels[y * texture->dimension + x] |= 0xFF000000; #else pixels[y * texture->dimension + x] |= 0x000000FF; #endif } } } SDL_UnlockSurface(tempSurface); } /* actually create the OpenGL textures */ glTexImage2D(GL_TEXTURE_2D, 0, has_transparent_key ? GL_RGBA : GL_RGB, texture->dimension, texture->dimension, 0, has_transparent_key ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, tempSurface->pixels); SDL_FreeSurface(tempSurface); SDL_FreeSurface(imageSurface); } static void texture_activate(Texture *texture) { glBindTexture(GL_TEXTURE_2D, texture->textureID); } static void texture_free(Texture *texture) { glDeleteTextures(1, &texture->textureID); } /* WALL */ #define WALL_HEIGHT 30 static GLint wall_top; static Texture wall_top_texture; static GLint wall_side; static Texture wall_side_texture; static void wall_init() { texture_load(&wall_top_texture, "gfx/solid.bmp", 0xFFFFFFFF); texture_load(&wall_side_texture, "gfx/solid.bmp", 0xFFFFFFFF); wall_top = glGenLists(1); wall_side= glGenLists(1); glFrontFace(GL_CCW); glNewList(wall_side, GL_COMPILE); glBegin(GL_QUADS); glNormal3f(0, -1, 0); glTexCoord2f(0.0, 0.0); glVertex3f(0, 0, 0); glTexCoord2f(0.0, 1.0); glVertex3f(0, 0, WALL_HEIGHT); glTexCoord2f(1.0, 1.0); glVertex3f(TILE_WIDTH, 0, WALL_HEIGHT); glTexCoord2f(1.0, 0.0); glVertex3f(TILE_WIDTH, 0, 0); glNormal3f(1, 0, 0); glTexCoord2f(0.0, 0.0); glVertex3f(TILE_WIDTH, 0, 0); glTexCoord2f(0.0, 1.0); glVertex3f(TILE_WIDTH, 0, WALL_HEIGHT); glTexCoord2f(1.0, 1.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 0.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, 0); glNormal3f(0, 1, 0); glTexCoord2f(0.0, 0.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, 0); glTexCoord2f(0.0, 1.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 1.0); glVertex3f(0, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 0.0); glVertex3f(0, TILE_HEIGHT, 0); glNormal3f(-1, 0, 0); glTexCoord2f(0.0, 0.0); glVertex3f(0, TILE_HEIGHT, 0); glTexCoord2f(0.0, 1.0); glVertex3f(0, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 1.0); glVertex3f(0, 0, WALL_HEIGHT); glTexCoord2f(1.0, 0.0); glVertex3f(0, 0, 0); glEnd(); glEndList(); glNewList(wall_top, GL_COMPILE); glBegin(GL_QUADS); glNormal3f(0, 0, 1); glTexCoord2f(0.0, 0.0); glVertex3f(0, 0, WALL_HEIGHT); glTexCoord2f(0.0, 1.0); glVertex3f(0, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 1.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, WALL_HEIGHT); glTexCoord2f(1.0, 0.0); glVertex3f(TILE_WIDTH, 0, WALL_HEIGHT); glEnd(); glEndList(); } static void wall_draw() { texture_activate(&wall_side_texture); glCallList(wall_side); texture_activate(&wall_top_texture); glCallList(wall_top); } static void wall_free() { texture_free(&wall_side_texture); texture_free(&wall_top_texture); } /* Plain */ static Texture plain_texture; static GLint plain; static void plain_init() { texture_load(&plain_texture, "gfx/plain.bmp", 0xFFFFFFFF); plain = glGenLists(1); glFrontFace(GL_CCW); glNewList(plain, GL_COMPILE); glBegin(GL_QUADS); glNormal3f(0, 0, 1); glTexCoord2f(0.0, 0.0); glVertex3f(0, 0, 0); glTexCoord2f(0.0, 1.0); glVertex3f(0, TILE_HEIGHT, 0); glTexCoord2f(1.0, 1.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, 0); glTexCoord2f(1.0, 0.0); glVertex3f(TILE_WIDTH, 0, 0); glEnd(); glEndList(); } static void plain_draw() { texture_activate(&plain_texture); glCallList(plain); } static void plain_free() { texture_free(&plain_texture); } /* Koth */ static Texture koth_texture; static GLint koth; static void koth_init() { texture_load(&koth_texture, "gfx/koth.bmp", 0xFFFFFFFF); koth = glGenLists(1); glFrontFace(GL_CCW); glNewList(koth, GL_COMPILE); glBegin(GL_QUADS); glNormal3f(0, 0, 1); glTexCoord2f(0.0, 0.0); glVertex3f(0, 0, 0); glTexCoord2f(0.0, 1.0); glVertex3f(0, TILE_HEIGHT, 0); glTexCoord2f(1.0, 1.0); glVertex3f(TILE_WIDTH, TILE_HEIGHT, 0); glTexCoord2f(1.0, 0.0); glVertex3f(TILE_WIDTH, 0, 0); glEnd(); glEndList(); } static void koth_draw() { texture_activate(&koth_texture); glCallList(koth); } static void koth_free() { texture_free(&koth_texture); } /* World */ static void gl_world_info_changed(const client_world_info_t *info) { cam_recenter(); } static void world_draw() { const client_world_info_t *info = infon->get_world_info(); if (!info) return; const client_maptile_t *world = infon->get_world(); for (int y = 0; y < info->height; y++) { const client_maptile_t *tile = &world[y * info->width]; for (int x = 0; x < info->width; x++) { glPushMatrix(); glTranslatef(TILE_X1(x), TILE_Y1(y), 0.0); if (tile->food != 0) { GLfloat diffuse[] = {0.0, (float)tile->food / 10.0, 0.0, 0}; glLightfv(GL_LIGHT3, GL_DIFFUSE, diffuse); GLfloat amb[] = {0.0, (float)tile->food / 10.0, 0.0, 0}; glLightfv(GL_LIGHT3, GL_AMBIENT, amb); glEnable(GL_LIGHT3); } switch (tile->type) { case TILE_SOLID: wall_draw(); break; case TILE_PLAIN: if (tile->gfx == TILE_GFX_KOTH) koth_draw(); else plain_draw(); break; default: break; } if (tile->food != 0) { static const GLfloat zero[] = { 0, 0, 0, 0 }; glLightfv(GL_LIGHT3, GL_DIFFUSE, zero); glLightfv(GL_LIGHT3, GL_AMBIENT, zero); glDisable(GL_LIGHT3); } glPopMatrix(); tile++; } } } /* Creatures */ typedef struct { float dir; int animoffset; } CreatureInfo; mdl_model_t GLCreature[4]; static void creature_init() { // XXX: 3 mal das gleich nehmen, solange // nichts besseres vorhanden ist. mdl_load(&GLCreature[0], "gfx/creature.mdl"); mdl_load(&GLCreature[1], "gfx/creature.mdl"); mdl_load(&GLCreature[2], "gfx/creature.mdl"); } static void creature_free() { mdl_free(&GLCreature[0]); mdl_free(&GLCreature[1]); mdl_free(&GLCreature[2]); } static void creature_update_info(const client_creature_t *creature) { CreatureInfo *info = (CreatureInfo*)creature->userdata; float newdir = creature->dir * 360.0 / 32.0 - 90; float dw = info->dir - newdir; if (dw < -180) dw += 360; if (dw > 180) dw -= 360; if (dw < -1) { info->dir += dw < -5 ? 2 : 1; } else if (dw > 1) { info->dir -= dw > 5 ? 2 : 1; } else { info->dir = newdir; } } static void *creature_spawned(const client_creature_t *creature) { CreatureInfo *info = malloc(sizeof(CreatureInfo)); info->dir = 0.0; info->animoffset = rand() % 1000; return info; } static void creature_died(const client_creature_t *creature) { free(creature->userdata); } static void creature_draw(const client_creature_t *creature, void *opaque) { creature_update_info(creature); CreatureInfo *info = (CreatureInfo*)creature->userdata; const client_player_t *player = infon->get_player(creature->player); const mdl_model_t *model = &GLCreature[creature->type]; int hi = (player->color & 0xF0) >> 4; int lo = (player->color & 0x0F); //particle_add_fountain(creature->x, creature->y, 100); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); GLfloat l1[] = { colors[hi][0] * 40 - 20, colors[hi][1] * 40 - 20, colors[hi][2] * 40 - 20, 1.0}; glLightfv(GL_LIGHT0, GL_AMBIENT, l1); GLfloat l2[] = { colors[lo][0] * 40 - 20, colors[lo][1] * 40 - 20, colors[lo][2] * 40 - 20, 1.0}; glLightfv(GL_LIGHT1, GL_DIFFUSE, l2); glPushMatrix(); int scale1[] = { 3, 6, 1 }; int scale2[] = { 3, 6, 3 }; int z[] = { 80, 160, 180 }; int animb[] = { 69, 48, 0, 69, 0, 0, 0, 60 }; int animl[] = { 9, 12, 1, 3, 7, 1, 1, 9 }; int anims[] = {100, 50, 60, 70, 60, 60, 60, 50 }; glTranslatef(creature->x, creature->y, z[creature->type]); // particle_add_blood(creature->x, creature->y, z[creature->type]); glRotatef(info->dir, 0, 0, 1); glScalef (scale1[creature->type], scale2[creature->type], scale1[creature->type]); mdl_render_frame(model, ((real_time + info->animoffset) / anims[creature->state]) % animl[creature->state] + animb[creature->state]); //printf("%d\n",(real_time / 300) % 100); //mdl_render_frame(model, (real_time / 300) % 100); glPopMatrix(); glDisable(GL_LIGHT0); glDisable(GL_LIGHT1); } /* Init / Shutdown */ static void gl_init_resources() { wall_init(); plain_init(); koth_init(); creature_init(); } static void gl_free_resources() { creature_free(); koth_free(); plain_free(); wall_free(); } static int gl_open(int w, int h, int fs) { video_init(w, h, fs); cam_init(); gl_init_resources(); return 1; } static void gl_close() { gl_free_resources(); cam_free(); video_shutdown(); } static void gl_resize(int w, int h) { video_resize(w, h); #ifdef WIN32 /* * Der GL Context geht unter Windows beim resizen verloren. * Daher muessen Texturen und Displaylisten neu gebaut werden. * * http://www.libsdl.org/pipermail/sdl/2003-March/052962.html */ gl_free_resources(); gl_init_resources(); #endif } /* Event */ static void handle_events() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_RETURN: if (event.key.keysym.mod & KMOD_ALT) video_fullscreen_toggle(); break; case SDLK_1: gl_resize( 640, 480); break; case SDLK_2: gl_resize( 800, 600); break; case SDLK_3: gl_resize(1024, 768); break; case SDLK_4: gl_resize(1280, 1024); break; case SDLK_5: gl_resize(1600, 1200); break; case SDLK_c: cam_recenter(); break; case SDLK_ESCAPE: infon->shutdown(); break; default: ; } break; case SDL_MOUSEMOTION: if (event.motion.state & 1) { cam_change_pos_rel(event.motion.xrel * 10, event.motion.yrel * 10); } if (event.motion.state & 2) { cam_change_height(event.motion.yrel * 10); } if (event.motion.state & 4) { cam_change_direction((float)event.motion.xrel / 4); } break; case SDL_VIDEORESIZE: gl_resize(event.resize.w, event.resize.h); break; case SDL_QUIT: infon->shutdown(); break; } } } static void gl_tick(int gt, int delta) { real_time = SDL_GetTicks(); handle_events(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef (1., -1., 1.); glEnable(GL_DEPTH_TEST); cam_tick(delta); //cam_screen_to_plane(m_mousex, m_mousey, m_mouseworldx, m_mouseworldy, m_mouseinfront); // particle_move(delta); world_draw(); infon->each_creature(creature_draw, NULL); // particle_draw(); video_flip(); #ifdef WIN32 Sleep(20); #else usleep(4000); #endif } static const renderer_api_t gl_api = { .version = RENDERER_API_VERSION, .open = gl_open, .close = gl_close, .tick = gl_tick, .world_info_changed = gl_world_info_changed, .world_changed = NULL, .player_joined = NULL, .player_changed = NULL, .player_left = NULL, .creature_spawned = creature_spawned, .creature_changed = NULL, .creature_died = creature_died, .scroll_message = NULL, }; RENDERER_EXPORT(gl_api) infon/client_game.c0000644000076400001440000000274210533001515014351 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include "misc.h" #include "client_game.h" #include "client_creature.h" #include "client_world.h" #include "client_player.h" #include "global.h" #include "client.h" static char intermission [256] = {0}; void client_game_intermission_from_network(packet_t *packet) { snprintf(intermission, sizeof(intermission), "%.*s", packet->len, packet->data); } const char *client_get_intermission() { return intermission; } void client_game_init() { client_world_init(); client_player_init(); client_creature_init(); } void client_game_shutdown() { client_creature_shutdown(); client_player_shutdown(); client_world_shutdown(); } infon/client_game.h0000644000076400001440000000207110533001515014351 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef CLIENT_GAME_H #define CLIENT_GAME_H #include "packet.h" /* Renderer */ const char *client_get_intermission(); /* Network */ void client_game_intermission_from_network(packet_t *packet); void client_game_init(); void client_game_shutdown(); #endif infon/null_gui.c0000644000076400001440000000545310540115023013720 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include "renderer.h" static int null_open(int w, int h, int fs) { printf("open\n"); return 1; } static void null_close() { printf("close\n"); } static void null_tick(int gt, int delta) { printf("tick %d %d\n", delta, infon->get_traffic()); } static void null_world_info_changed(const client_world_info_t *info) { printf("new world\n"); } static void null_world_changed(int x, int y) { printf("change at %d,%d\n", x, y); } static void *null_player_joined(const client_player_t *player) { printf("new player %d\n", player->num); return NULL; } static void null_player_changed(const client_player_t *player, int changed) { printf("player %d changed: %d\n", player->num, changed); } static void null_player_left(const client_player_t *player) { printf("player %d left\n", player->num); } static void *null_creature_spawned(const client_creature_t *creature) { printf("creature spawned %d\n", creature->num); return NULL; } static void null_creature_changed(const client_creature_t *creature, int changed) { printf("creature %d changed: %d\n", creature->num, changed); } static void null_creature_died(const client_creature_t *creature) { printf("creature %d died\n", creature->num); } static void null_scroll_message(const char *message) { printf("scroll: %s\n", message); } const static renderer_api_t null_api = { .version = RENDERER_API_VERSION, .open = null_open, .close = null_close, .tick = null_tick, .world_info_changed = null_world_info_changed, .world_changed = null_world_changed, .player_joined = null_player_joined, .player_changed = null_player_changed, .player_left = null_player_left, .creature_spawned = null_creature_spawned, .creature_changed = null_creature_changed, .creature_died = null_creature_died, .scroll_message = null_scroll_message, }; RENDERER_EXPORT(null_api) infon/demo-compress.rb0000644000076400001440000000024010534032364015036 0ustar dividuumusersrequire 'zlib' File.open(ARGV[1], "wb") do |out| out.write("\x00\xFE") out.write(Zlib::Deflate.deflate(File.read(ARGV[0]), Zlib::BEST_COMPRESSION)) end infon/infon.h0000644000076400001440000000156110540100022013205 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef INFON_H #define INFON_H extern int game_time; #endif infon/infond.h0000644000076400001440000000173710540115023013365 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef INFOND_H #define INFOND_H #include extern lua_State *L; extern int real_time; extern int game_time; extern int game_paused; extern int game_exit; #endif infon/pinger.h0000644000076400001440000000174510603314646013407 0ustar dividuumusers/* Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PINGER_H #define PINGER_H void ping_master(const char *master_addr, int port, const char *servername, int clients, int players, int creatures); #endif infon/lua-5.1.2/0000755000076400001440000000000010603200765013161 5ustar dividuumusersinfon/lua-5.1.2/test/0000755000076400001440000000000010603200764014137 5ustar dividuumusersinfon/lua-5.1.2/test/printf.lua0000644000076400001440000000025110603200764016142 0ustar dividuumusers-- an implementation of printf function printf(...) io.write(string.format(...)) end printf("Hello %s from %s on %s\n",os.getenv"USER" or "there",_VERSION,os.date()) infon/lua-5.1.2/test/fib.lua0000644000076400001440000000113510603200764015402 0ustar dividuumusers-- fibonacci function with cache -- very inefficient fibonacci function function fib(n) N=N+1 if n<2 then return n else return fib(n-1)+fib(n-2) end end -- a general-purpose value cache function cache(f) local c={} return function (x) local y=c[x] if not y then y=f(x) c[x]=y end return y end end -- run and time it function test(s,f) N=0 local c=os.clock() local v=f(n) local t=os.clock()-c print(s,n,v,t,N) end n=arg[1] or 24 -- for other values, do lua fib.lua XX n=tonumber(n) print("","n","value","time","evals") test("plain",fib) fib=cache(fib) test("cached",fib) infon/lua-5.1.2/test/factorial.lua0000644000076400001440000000130310603200764016603 0ustar dividuumusers-- function closures are powerful -- traditional fixed-point operator from functional programming Y = function (g) local a = function (f) return f(f) end return a(function (f) return g(function (x) local c=f(f) return c(x) end) end) end -- factorial without recursion F = function (f) return function (n) if n == 0 then return 1 else return n*f(n-1) end end end factorial = Y(F) -- factorial is the fixed point of F -- now test it function test(x) io.write(x,"! = ",factorial(x),"\n") end for n=0,16 do test(n) end infon/lua-5.1.2/test/hello.lua0000644000076400001440000000012610603200764015744 0ustar dividuumusers-- the first program in every language io.write("Hello world, from ",_VERSION,"!\n") infon/lua-5.1.2/test/trace-calls.lua0000644000076400001440000000135510603200764017040 0ustar dividuumusers-- trace calls -- example: lua -ltrace-calls bisect.lua local level=0 local function hook(event) local t=debug.getinfo(3) io.write(level," >>> ",string.rep(" ",level)) if t~=nil and t.currentline>=0 then io.write(t.short_src,":",t.currentline," ") end t=debug.getinfo(2) if event=="call" then level=level+1 else level=level-1 if level<0 then level=0 end end if t.what=="main" then if event=="call" then io.write("begin ",t.short_src) else io.write("end ",t.short_src) end elseif t.what=="Lua" then -- table.foreach(t,print) io.write(event," ",t.name or "(Lua)"," <",t.linedefined,":",t.short_src,">") else io.write(event," ",t.name or "(C)"," [",t.what,"] ") end io.write("\n") end debug.sethook(hook,"cr") level=0 infon/lua-5.1.2/test/fibfor.lua0000644000076400001440000000037610603200764016117 0ustar dividuumusers-- example of for with generator functions function generatefib (n) return coroutine.wrap(function () local a,b = 1, 1 while a <= n do coroutine.yield(a) a, b = b, a+b end end) end for i in generatefib(1000) do print(i) end infon/lua-5.1.2/test/bisect.lua0000644000076400001440000000120510603200764016111 0ustar dividuumusers-- bisection method for solving non-linear equations delta=1e-6 -- tolerance function bisect(f,a,b,fa,fb) local c=(a+b)/2 io.write(n," c=",c," a=",a," b=",b,"\n") if c==a or c==b or math.abs(a-b) posted to lua-l -- modified to use ANSI terminal escape sequences -- modified to use for instead of while local write=io.write ALIVE="" DEAD="" ALIVE="O" DEAD="-" function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary for i=1,10000 do end -- local i=os.clock()+1 while(os.clock() 0 do local xm1,x,xp1,xi=self.w-1,self.w,1,self.w while xi > 0 do local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] + self[y][xm1] + self[y][xp1] + self[yp1][xm1] + self[yp1][x] + self[yp1][xp1] next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0 xm1,x,xp1,xi = x,xp1,xp1+1,xi-1 end ym1,y,yp1,yi = y,yp1,yp1+1,yi-1 end end -- output the array to screen function _CELLS:draw() local out="" -- accumulate to reduce flicker for y=1,self.h do for x=1,self.w do out=out..(((self[y][x]>0) and ALIVE) or DEAD) end out=out.."\n" end write(out) end -- constructor function CELLS(w,h) local c = ARRAY2D(w,h) c.spawn = _CELLS.spawn c.evolve = _CELLS.evolve c.draw = _CELLS.draw return c end -- -- shapes suitable for use with spawn() above -- HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 } GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 } EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 } FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 } BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 } -- the main routine function LIFE(w,h) -- create two arrays local thisgen = CELLS(w,h) local nextgen = CELLS(w,h) -- create some life -- about 1000 generations of fun, then a glider steady-state thisgen:spawn(GLIDER,5,4) thisgen:spawn(EXPLODE,25,10) thisgen:spawn(FISH,4,12) -- run until break local gen=1 write("\027[2J") -- ANSI clear screen while 1 do thisgen:evolve(nextgen) thisgen,nextgen = nextgen,thisgen write("\027[H") -- ANSI home cursor thisgen:draw() write("Life - generation ",gen,"\n") gen=gen+1 if gen>2000 then break end --delay() -- no delay end end LIFE(40,20) infon/lua-5.1.2/test/globals.lua0000644000076400001440000000064210603200764016267 0ustar dividuumusers-- reads luac listings and reports global variable usage -- lines where a global is written to are marked with "*" -- typical usage: luac -p -l file.lua | lua globals.lua | sort | lua table.lua while 1 do local s=io.read() if s==nil then break end local ok,_,l,op,g=string.find(s,"%[%-?(%d*)%]%s*([GS])ETGLOBAL.-;%s+(.*)$") if ok then if op=="S" then op="*" else op="" end io.write(g,"\t",l,op,"\n") end end infon/lua-5.1.2/test/trace-globals.lua0000644000076400001440000000133010603200764017356 0ustar dividuumusers-- trace assigments to global variables do -- a tostring that quotes strings. note the use of the original tostring. local _tostring=tostring local tostring=function(a) if type(a)=="string" then return string.format("%q",a) else return _tostring(a) end end local log=function (name,old,new) local t=debug.getinfo(3,"Sl") local line=t.currentline io.write(t.short_src) if line>=0 then io.write(":",line) end io.write(": ",name," is now ",tostring(new)," (was ",tostring(old),")","\n") end local g={} local set=function (t,name,value) log(name,g[name],value) g[name]=value end setmetatable(getfenv(),{__index=g,__newindex=set}) end -- an example a=1 b=2 a=10 b=20 b=nil b=200 print(a,b,c) infon/lua-5.1.2/test/luac.lua0000644000076400001440000000035210603200764015566 0ustar dividuumusers-- bare-bones luac in Lua -- usage: lua luac.lua file.lua assert(arg[1]~=nil and arg[2]==nil,"usage: lua luac.lua file.lua") f=assert(io.open("luac.out","wb")) assert(f:write(string.dump(assert(loadfile(arg[1]))))) assert(f:close()) infon/lua-5.1.2/test/sort.lua0000644000076400001440000000272610603200764015640 0ustar dividuumusers-- two implementations of a sort function -- this is an example only. Lua has now a built-in function "sort" -- extracted from Programming Pearls, page 110 function qsort(x,l,u,f) if ly end) show("after reverse selection sort",x) qsort(x,1,n,function (x,y) return x Lua 5.1 reference manual - contents

    Lua 5.1 Reference Manual

    This is an online version of
    Lua 5.1 Reference Manual
    by R. Ierusalimschy, L. H. de Figueiredo, W. Celes
    Lua.org, August 2006
    ISBN 85-903798-3-3
    [Buy from Amazon]

    Buy a paper copy and help to support the Lua project.

    start · contents · index · errata


    Copyright © 2006-2007 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.

    Contents

    Index

    Lua functions

    _G
    _VERSION
    assert
    collectgarbage
    dofile
    error
    getfenv
    getmetatable
    ipairs
    load
    loadfile
    loadstring
    module
    next
    pairs
    pcall
    print
    rawequal
    rawget
    rawset
    require
    select
    setfenv
    setmetatable
    tonumber
    tostring
    type
    unpack
    xpcall

     

    coroutine.create
    coroutine.resume
    coroutine.running
    coroutine.status
    coroutine.wrap
    coroutine.yield
    debug.debug
    debug.getfenv
    debug.gethook
    debug.getinfo
    debug.getlocal
    debug.getmetatable
    debug.getregistry
    debug.getupvalue
    debug.setfenv
    debug.sethook
    debug.setlocal
    debug.setmetatable
    debug.setupvalue
    debug.traceback
    file:close
    file:flush
    file:lines
    file:read
    file:seek
    file:setvbuf
    file:write
    io.close
    io.flush
    io.input
    io.lines
    io.open
    io.output
    io.popen
    io.read
    io.tmpfile
    io.type
    io.write
    math.abs
    math.acos
    math.asin
    math.atan2
    math.atan
    math.ceil
    math.cosh
    math.cos
    math.deg
    math.exp
    math.floor
    math.fmod
    math.frexp
    math.huge
    math.ldexp
    math.log10
    math.log
    math.max
    math.min
    math.modf
    math.pi
    math.pow
    math.rad
    math.random
    math.randomseed
    math.sinh
    math.sin
    math.sqrt
    math.tanh
    math.tan
    os.clock
    os.date
    os.difftime
    os.execute
    os.exit
    os.getenv
    os.remove
    os.rename
    os.setlocale
    os.time
    os.tmpname
    package.cpath
    package.loaded
    package.loadlib
    package.path
    package.preload
    package.seeall
    string.byte
    string.char
    string.dump
    string.find
    string.format
    string.gmatch
    string.gsub
    string.len
    string.lower
    string.match
    string.rep
    string.reverse
    string.sub
    string.upper
    table.concat
    table.insert
    table.maxn
    table.remove
    table.sort

    C API

    lua_Alloc
    lua_CFunction
    lua_Debug
    lua_Hook
    lua_Integer
    lua_Number
    lua_Reader
    lua_State
    lua_Writer
    lua_atpanic
    lua_call
    lua_checkstack
    lua_close
    lua_concat
    lua_cpcall
    lua_createtable
    lua_dump
    lua_equal
    lua_error
    lua_gc
    lua_getallocf
    lua_getfenv
    lua_getfield
    lua_getglobal
    lua_gethook
    lua_gethookcount
    lua_gethookmask
    lua_getinfo
    lua_getlocal
    lua_getmetatable
    lua_getstack
    lua_gettable
    lua_gettop
    lua_getupvalue
    lua_insert
    lua_isboolean
    lua_iscfunction
    lua_isfunction
    lua_islightuserdata
    lua_isnil
    lua_isnumber
    lua_isstring
    lua_istable
    lua_isthread
    lua_isuserdata
    lua_lessthan
    lua_load
    lua_newstate
    lua_newtable
    lua_newthread
    lua_newuserdata
    lua_next
    lua_objlen
    lua_pcall
    lua_pop
    lua_pushboolean
    lua_pushcclosure
    lua_pushcfunction
    lua_pushfstring
    lua_pushinteger
    lua_pushlightuserdata
    lua_pushlstring
    lua_pushnil
    lua_pushnumber
    lua_pushstring
    lua_pushthread
    lua_pushvalue
    lua_pushvfstring
    lua_rawequal
    lua_rawget
    lua_rawgeti
    lua_rawset
    lua_rawseti
    lua_register
    lua_remove
    lua_replace
    lua_resume
    lua_setallocf
    lua_setfenv
    lua_setfield
    lua_setglobal
    lua_sethook
    lua_setlocal
    lua_setmetatable
    lua_settable
    lua_settop
    lua_setupvalue
    lua_status
    lua_toboolean
    lua_tocfunction
    lua_tointeger
    lua_tolstring
    lua_tonumber
    lua_topointer
    lua_tostring
    lua_tothread
    lua_touserdata
    lua_type
    lua_typename
    lua_upvalueindex
    lua_xmove
    lua_yield

    auxiliary library

    luaL_Buffer
    luaL_Reg
    luaL_addchar
    luaL_addlstring
    luaL_addsize
    luaL_addstring
    luaL_addvalue
    luaL_argcheck
    luaL_argerror
    luaL_buffinit
    luaL_callmeta
    luaL_checkany
    luaL_checkint
    luaL_checkinteger
    luaL_checklong
    luaL_checklstring
    luaL_checknumber
    luaL_checkoption
    luaL_checkstack
    luaL_checkstring
    luaL_checktype
    luaL_checkudata
    luaL_dofile
    luaL_dostring
    luaL_error
    luaL_getmetafield
    luaL_getmetatable
    luaL_gsub
    luaL_loadbuffer
    luaL_loadfile
    luaL_loadstring
    luaL_newmetatable
    luaL_newstate
    luaL_openlibs
    luaL_optint
    luaL_optinteger
    luaL_optlong
    luaL_optlstring
    luaL_optnumber
    luaL_optstring
    luaL_prepbuffer
    luaL_pushresult
    luaL_ref
    luaL_register
    luaL_typename
    luaL_typerror
    luaL_unref
    luaL_where


    Last update: Fri Mar 23 08:33:19 BRT 2007 infon/lua-5.1.2/doc/lua.10000644000076400001440000000704310603200764014574 0ustar dividuumusers.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ .TH LUA 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS .B lua [ .I options ] [ .I script [ .I args ] ] .SH DESCRIPTION .B lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. (Precompiled binaries are output by .BR luac , the Lua compiler.) .B lua can be used as a batch interpreter and also interactively. .LP The given .I options (see below) are executed and then the Lua program in file .I script is loaded and executed. The given .I args are available to .I script as strings in a global table named .BR arg . If these arguments contain spaces or other characters special to the shell, then they should be quoted (but note that the quotes will be removed by the shell). The arguments in .B arg start at 0, which contains the string .RI ' script '. The index of the last argument is stored in .BR arg.n . The arguments given in the command line before .IR script , including the name of the interpreter, are available in negative indices in .BR arg . .LP At the very start, before even handling the command line, .B lua executes the contents of the environment variable .BR LUA_INIT , if it is defined. If the value of .B LUA_INIT is of the form .RI '@ filename ', then .I filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed. .LP Options start with .B '\-' and are described below. You can use .B "'\--'" to signal the end of options. .LP If no arguments are given, then .B "\-v \-i" is assumed when the standard input is a terminal; otherwise, .B "\-" is assumed. .LP In interactive mode, .B lua prompts the user, reads lines from the standard input, and executes them as they are read. If a line does not contain a complete statement, then a secondary prompt is displayed and lines are read until a complete statement is formed or a syntax error is found. So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a .B ';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with .BR '=' , then .B lua displays the values of all the expressions in the remainder of the line. The expressions must be separated by commas. The primary prompt is the value of the global variable .BR _PROMPT , if this value is a string; otherwise, the default prompt is used. Similarly, the secondary prompt is the value of the global variable .BR _PROMPT2 . So, to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter or on the command line (but in this case you have to be careful with quotes if the prompt string contains a space; otherwise you may confuse the shell.) The default prompts are "> " and ">> ". .SH OPTIONS .TP .B \- load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal. .TP .BI \-e " stat" execute statement .IR stat . You need to quote .I stat if it contains spaces, quotes, or other characters special to the shell. .TP .B \-i enter interactive mode after .I script is executed. .TP .BI \-l " name" call .BI require(' name ') before executing .IR script . Typically used to load libraries. .TP .B \-v show version information. .SH "SEE ALSO" .BR luac (1) .br http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS R. Ierusalimschy, L. H. de Figueiredo, and W. Celes .\" EOF infon/lua-5.1.2/doc/manual.html0000644000076400001440000073207010603200764016101 0ustar dividuumusers Lua 5.1 Reference Manual

    Lua 5.1 Reference Manual

    by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    Copyright © 2006-2007 Lua.org, PUC-Rio. Freely available under the terms of the Lua license.


    contents · index

    1 - Introduction

    Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++).

    Being an extension language, Lua has no notion of a "main" program: it only works embedded in a host client, called the embedding program or simply the host. This host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. The Lua distribution includes a sample host program called lua, which uses the Lua library to offer a complete, stand-alone Lua interpreter.

    Lua is free software, and is provided as usual with no guarantees, as stated in its license. The implementation described in this manual is available at Lua's official web site, www.lua.org.

    Like any other reference manual, this document is dry in places. For a discussion of the decisions behind the design of Lua, see the technical papers available at Lua's web site. For a detailed introduction to programming in Lua, see Roberto's book, Programming in Lua (Second Edition).

    2 - The Language

    This section describes the lexis, the syntax, and the semantics of Lua. In other words, this section describes which tokens are valid, how they can be combined, and what their combinations mean.

    The language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a's, and [a] means an optional a. Non-terminals are shown like non-terminal, keywords are shown like kword, and other terminal symbols are shown like `=´. The complete syntax of Lua can be found at the end of this manual.

    2.1 - Lexical Conventions

    Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, not beginning with a digit. This coincides with the definition of names in most languages. (The definition of letter depends on the current locale: any character considered alphabetic by the current locale can be used in an identifier.) Identifiers are used to name variables and table fields.

    The following keywords are reserved and cannot be used as names:

         and       break     do        else      elseif
         end       false     for       function  if
         in        local     nil       not       or
         repeat    return    then      true      until     while
    

    Lua is a case-sensitive language: and is a reserved word, but And and AND are two different, valid names. As a convention, names starting with an underscore followed by uppercase letters (such as _VERSION) are reserved for internal global variables used by Lua.

    The following strings denote other tokens:

         +     -     *     /     %     ^     #
         ==    ~=    <=    >=    <     >     =
         (     )     {     }     [     ]
         ;     :     ,     .     ..    ...
    

    Literal strings can be delimited by matching single or double quotes, and can contain the following C-like escape sequences: '\a' (bell), '\b' (backspace), '\f' (form feed), '\n' (newline), '\r' (carriage return), '\t' (horizontal tab), '\v' (vertical tab), '\\' (backslash), '\"' (quotation mark [double quote]), and '\'' (apostrophe [single quote]). Moreover, a backslash followed by a real newline results in a newline in the string. A character in a string may also be specified by its numerical value using the escape sequence \ddd, where ddd is a sequence of up to three decimal digits. (Note that if a numerical escape is to be followed by a digit, it must be expressed using exactly three digits.) Strings in Lua may contain any 8-bit value, including embedded zeros, which can be specified as '\0'.

    To put a double (single) quote, a newline, a backslash, or an embedded zero inside a literal string enclosed by double (single) quotes you must use an escape sequence. Any other character may be directly inserted into the literal. (Some control characters may cause problems for the file system, but Lua has no problem with them.)

    Literal strings can also be defined using a long format enclosed by long brackets. We define an opening long bracket of level n as an opening square bracket followed by n equal signs followed by another opening square bracket. So, an opening long bracket of level 0 is written as [[, an opening long bracket of level 1 is written as [=[, and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]. A long string starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. Literals in this bracketed form may run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. They may contain anything except a closing bracket of the proper level.

    For convenience, when the opening long bracket is immediately followed by a newline, the newline is not included in the string. As an example, in a system using ASCII (in which 'a' is coded as 97, newline is coded as 10, and '1' is coded as 49), the five literals below denote the same string:

         a = 'alo\n123"'
         a = "alo\n123\""
         a = '\97lo\10\04923"'
         a = [[alo
         123"]]
         a = [==[
         alo
         123"]==]
    

    A numerical constant may be written with an optional decimal part and an optional decimal exponent. Lua also accepts integer hexadecimal constants, by prefixing them with 0x. Examples of valid numerical constants are

         3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56
    

    A comment starts with a double hyphen (--) anywhere outside a string. If the text immediately after -- is not an opening long bracket, the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, which runs until the corresponding closing long bracket. Long comments are frequently used to disable code temporarily.

    2.2 - Values and Types

    Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.

    All values in Lua are first-class values. This means that all values can be stored in variables, passed as arguments to other functions, and returned as results.

    There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table. Nil is the type of the value nil, whose main property is to be different from any other value; it usually represents the absence of a useful value. Boolean is the type of the values false and true. Both nil and false make a condition false; any other value makes it true. Number represents real (double-precision floating-point) numbers. (It is easy to build Lua interpreters that use other internal representations for numbers, such as single-precision float or long integers; see file luaconf.h.) String represents arrays of characters. Lua is 8-bit clean: strings may contain any 8-bit character, including embedded zeros ('\0') (see §2.1).

    Lua can call (and manipulate) functions written in Lua and functions written in C (see §2.5.8).

    The type userdata is provided to allow arbitrary C data to be stored in Lua variables. This type corresponds to a block of raw memory and has no pre-defined operations in Lua, except assignment and identity test. However, by using metatables, the programmer can define operations for userdata values (see §2.8). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.

    The type thread represents independent threads of execution and it is used to implement coroutines (see §2.11). Do not confuse Lua threads with operating-system threads. Lua supports coroutines on all systems, even those that do not support threads.

    The type table implements associative arrays, that is, arrays that can be indexed not only with numbers, but with any value (except nil). Tables can be heterogeneous; that is, they can contain values of all types (except nil). Tables are the sole data structuring mechanism in Lua; they may be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc. To represent records, Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"]. There are several convenient ways to create tables in Lua (see §2.5.7).

    Like indices, the value of a table field can be of any type (except nil). In particular, because functions are first-class values, table fields may contain functions. Thus tables may also carry methods (see §2.5.9).

    Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

    The library function type returns a string describing the type of a given value.

    2.2.1 - Coercion

    Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format. For complete control over how numbers are converted to strings, use the format function from the string library (see string.format).

    2.3 - Variables

    Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields.

    A single name can denote a global variable or a local variable (or a function's formal parameter, which is a particular kind of local variable):

    	var ::= Name
    

    Name denotes identifiers, as defined in §2.1.

    Any variable is assumed to be global unless explicitly declared as a local (see §2.4.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §2.6).

    Before the first assignment to a variable, its value is nil.

    Square brackets are used to index a table:

    	var ::= prefixexp `[´ exp `]´
    

    The meaning of accesses to global variables and table fields can be changed via metatables. An access to an indexed variable t[i] is equivalent to a call gettable_event(t,i). (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

    The syntax var.Name is just syntactic sugar for var["Name"]:

    	var ::= prefixexp `.´ Name
    

    All global variables live as fields in ordinary Lua tables, called environment tables or simply environments (see §2.9). Each function has its own reference to an environment, so that all global variables in this function will refer to this environment table. When a function is created, it inherits the environment from the function that created it. To get the environment table of a Lua function, you call getfenv. To replace it, you call setfenv. (You can only manipulate the environment of C functions through the debug library; (see §5.9).)

    An access to a global variable x is equivalent to _env.x, which in turn is equivalent to

         gettable_event(_env, "x")
    

    where _env is the environment of the running function. (See §2.8 for a complete description of the gettable_event function. This function is not defined or callable in Lua. Similarly, the _env variable is not defined in Lua. We use them here only for explanatory purposes.)

    2.4 - Statements

    Lua supports an almost conventional set of statements, similar to those in Pascal or C. This set includes assignment, control structures, function calls, and variable declarations.

    2.4.1 - Chunks

    The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, which are executed sequentially. Each statement can be optionally followed by a semicolon:

    	chunk ::= {stat [`;´]}
    

    There are no empty statements and thus ';;' is not legal.

    Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §2.5.9). As such, chunks can define local variables, receive arguments, and return values.

    A chunk may be stored in a file or in a string inside the host program. When a chunk is executed, first it is pre-compiled into instructions for a virtual machine, and then the compiled code is executed by an interpreter for the virtual machine.

    Chunks may also be pre-compiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly.

    2.4.2 - Blocks

    A block is a list of statements; syntactically, a block is the same as a chunk:

    	block ::= chunk
    

    A block may be explicitly delimited to produce a single statement:

    	stat ::= do block end
    

    Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return or break statement in the middle of another block (see §2.4.4).

    2.4.3 - Assignment

    Lua allows multiple assignment. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas:

    	stat ::= varlist1 `=´ explist1
    	varlist1 ::= var {`,´ var}
    	explist1 ::= exp {`,´ exp}
    

    Expressions are discussed in §2.5.

    Before the assignment, the list of values is adjusted to the length of the list of variables. If there are more values than needed, the excess values are thrown away. If there are fewer values than needed, the list is extended with as many nil's as needed. If the list of expressions ends with a function call, then all values returned by this call enter in the list of values, before the adjustment (except when the call is enclosed in parentheses; see §2.5).

    The assignment statement first evaluates all its expressions and only then are the assignments performed. Thus the code

         i = 3
         i, a[i] = i+1, 20
    

    sets a[3] to 20, without affecting a[4] because the i in a[i] is evaluated (to 3) before it is assigned 4. Similarly, the line

         x, y = y, x
    

    exchanges the values of x and y.

    The meaning of assignments to global variables and table fields can be changed via metatables. An assignment to an indexed variable t[i] = val is equivalent to settable_event(t,i,val). (See §2.8 for a complete description of the settable_event function. This function is not defined or callable in Lua. We use it here only for explanatory purposes.)

    An assignment to a global variable x = val is equivalent to the assignment _env.x = val, which in turn is equivalent to

         settable_event(_env, "x", val)
    

    where _env is the environment of the running function. (The _env variable is not defined in Lua. We use it here only for explanatory purposes.)

    2.4.4 - Control Structures

    The control structures if, while, and repeat have the usual meaning and familiar syntax:

    	stat ::= while exp do block end
    	stat ::= repeat block until exp
    	stat ::= if exp then block {elseif exp then block} [else block] end
    

    Lua also has a for statement, in two flavors (see §2.4.5).

    The condition expression of a control structure may return any value. Both false and nil are considered false. All values different from nil and false are considered true (in particular, the number 0 and the empty string are also true).

    In the repeatuntil loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block.

    The return statement is used to return values from a function or a chunk (which is just a function). Functions and chunks may return more than one value, so the syntax for the return statement is

    	stat ::= return [explist1]
    

    The break statement is used to terminate the execution of a while, repeat, or for loop, skipping to the next statement after the loop:

    	stat ::= break
    

    A break ends the innermost enclosing loop.

    The return and break statements can only be written as the last statement of a block. If it is really necessary to return or break in the middle of a block, then an explicit inner block can be used, as in the idioms do return end and do break end, because now return and break are the last statements in their (inner) blocks.

    2.4.5 - For Statement

    The for statement has two forms: one numeric and one generic.

    The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax:

    	stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
    

    The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like

         for v = e1, e2, e3 do block end
    

    is equivalent to the code:

         do
           local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
           if not (var and limit and step) then error() end
           while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do
             local v = var
             block
             var = var + step
           end
         end
    

    Note the following:

    • All three control expressions are evaluated only once, before the loop starts. They must all result in numbers.
    • var, limit, and step are invisible variables. The names are here for explanatory purposes only.
    • If the third expression (the step) is absent, then a step of 1 is used.
    • You can use break to exit a for loop.
    • The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. If you need this value, assign it to another variable before breaking or exiting the loop.

    The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:

    	stat ::= for namelist in explist1 do block end
    	namelist ::= Name {`,´ Name}
    

    A for statement like

         for var_1, ···, var_n in explist do block end
    

    is equivalent to the code:

         do
           local f, s, var = explist
           while true do
             local var_1, ···, var_n = f(s, var)
             var = var_1
             if var == nil then break end
             block
           end
         end
    

    Note the following:

    • explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable.
    • f, s, and var are invisible variables. The names are here for explanatory purposes only.
    • You can use break to exit a for loop.
    • The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.

    2.4.6 - Function Calls as Statements

    To allow possible side-effects, function calls can be executed as statements:

    	stat ::= functioncall
    

    In this case, all returned values are thrown away. Function calls are explained in §2.5.8.

    2.4.7 - Local Declarations

    Local variables may be declared anywhere inside a block. The declaration may include an initial assignment:

    	stat ::= local namelist [`=´ explist1]
    

    If present, an initial assignment has the same semantics of a multiple assignment (see §2.4.3). Otherwise, all variables are initialized with nil.

    A chunk is also a block (see §2.4.1), and so local variables can be declared in a chunk outside any explicit block. The scope of such local variables extends until the end of the chunk.

    The visibility rules for local variables are explained in §2.6.

    2.5 - Expressions

    The basic expressions in Lua are the following:

    	exp ::= prefixexp
    	exp ::= nil | false | true
    	exp ::= Number
    	exp ::= String
    	exp ::= function
    	exp ::= tableconstructor
    	exp ::= `...´
    	exp ::= exp binop exp
    	exp ::= unop exp
    	prefixexp ::= var | functioncall | `(´ exp `)´
    

    Numbers and literal strings are explained in §2.1; variables are explained in §2.3; function definitions are explained in §2.5.9; function calls are explained in §2.5.8; table constructors are explained in §2.5.7. Vararg expressions, denoted by three dots ('...'), can only be used when directly inside a vararg function; they are explained in §2.5.9.

    Binary operators comprise arithmetic operators (see §2.5.1), relational operators (see §2.5.2), logical operators (see §2.5.3), and the concatenation operator (see §2.5.4). Unary operators comprise the unary minus (see §2.5.1), the unary not (see §2.5.3), and the unary length operator (see §2.5.5).

    Both function calls and vararg expressions may result in multiple values. If the expression is used as a statement (see §2.4.6) (only possible for function calls), then its return list is adjusted to zero elements, thus discarding all returned values. If the expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the call is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, discarding all values except the first one.

    Here are some examples:

         f()                -- adjusted to 0 results
         g(f(), x)          -- f() is adjusted to 1 result
         g(x, f())          -- g gets x plus all results from f()
         a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
         a,b = ...          -- a gets the first vararg parameter, b gets
                            -- the second (both a and b may get nil if there
                            -- is no corresponding vararg parameter)
         
         a,b,c = x, f()     -- f() is adjusted to 2 results
         a,b,c = f()        -- f() is adjusted to 3 results
         return f()         -- returns all results from f()
         return ...         -- returns all received vararg parameters
         return x,y,f()     -- returns x, y, and all results from f()
         {f()}              -- creates a list with all results from f()
         {...}              -- creates a list with all vararg parameters
         {f(), nil}         -- f() is adjusted to 1 result
    

    An expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f or nil if f does not return any values.)

    2.5.1 - Arithmetic Operators

    Lua supports the usual arithmetic operators: the binary + (addition), - (subtraction), * (multiplication), / (division), % (modulo), and ^ (exponentiation); and unary - (negation). If the operands are numbers, or strings that can be converted to numbers (see §2.2.1), then all operations have the usual meaning. Exponentiation works for any exponent. For instance, x^(-0.5) computes the inverse of the square root of x. Modulo is defined as

         a % b == a - math.floor(a/b)*b
    

    That is, it is the remainder of a division that rounds the quotient towards minus infinity.

    2.5.2 - Relational Operators

    The relational operators in Lua are

         ==    ~=    <     >     <=    >=
    

    These operators always result in false or true.

    Equality (==) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Numbers and strings are compared in the usual way. Objects (tables, userdata, threads, and functions) are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object (a table, userdata, thread, or function), this new object is different from any previously existing object.

    You can change the way that Lua compares tables and userdata by using the "eq" metamethod (see §2.8).

    The conversion rules of §2.2.1 do not apply to equality comparisons. Thus, "0"==0 evaluates to false, and t[0] and t["0"] denote different entries in a table.

    The operator ~= is exactly the negation of equality (==).

    The order operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the "lt" or the "le" metamethod (see §2.8).

    2.5.3 - Logical Operators

    The logical operators in Lua are and, or, and not. Like the control structures (see §2.4.4), all logical operators consider both false and nil as false and anything else as true.

    The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-cut evaluation; that is, the second operand is evaluated only if necessary. Here are some examples:

         10 or 20            --> 10
         10 or error()       --> 10
         nil or "a"          --> "a"
         nil and 10          --> nil
         false and error()   --> false
         false and nil       --> false
         false or nil        --> nil
         10 and 20           --> 20
    

    (In this manual, --> indicates the result of the preceding expression.)

    2.5.4 - Concatenation

    The string concatenation operator in Lua is denoted by two dots ('..'). If both operands are strings or numbers, then they are converted to strings according to the rules mentioned in §2.2.1. Otherwise, the "concat" metamethod is called (see §2.8).

    2.5.5 - The Length Operator

    The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

    The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n may be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t may be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).

    2.5.6 - Precedence

    Operator precedence in Lua follows the table below, from lower to higher priority:

         or
         and
         <     >     <=    >=    ~=    ==
         ..
         +     -
         *     /     %
         not   #     - (unary)
         ^
    

    As usual, you can use parentheses to change the precedences of an expression. The concatenation ('..') and exponentiation ('^') operators are right associative. All other binary operators are left associative.

    2.5.7 - Table Constructors

    Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. Constructors can be used to create empty tables, or to create a table and initialize some of its fields. The general syntax for constructors is

    	tableconstructor ::= `{´ [fieldlist] `}´
    	fieldlist ::= field {fieldsep field} [fieldsep]
    	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
    	fieldsep ::= `,´ | `;´
    

    Each field of the form [exp1] = exp2 adds to the new table an entry with key exp1 and value exp2. A field of the form name = exp is equivalent to ["name"] = exp. Finally, fields of the form exp are equivalent to [i] = exp, where i are consecutive numerical integers, starting with 1. Fields in the other formats do not affect this counting. For example,

         a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
    

    is equivalent to

         do
           local t = {}
           t[f(1)] = g
           t[1] = "x"         -- 1st exp
           t[2] = "y"         -- 2nd exp
           t.x = 1            -- t["x"] = 1
           t[3] = f(x)        -- 3rd exp
           t[30] = 23
           t[4] = 45          -- 4th exp
           a = t
         end
    

    If the last field in the list has the form exp and the expression is a function call or a vararg expression, then all values returned by this expression enter the list consecutively (see §2.5.8). To avoid this, enclose the function call (or the vararg expression) in parentheses (see §2.5).

    The field list may have an optional trailing separator, as a convenience for machine-generated code.

    2.5.8 - Function Calls

    A function call in Lua has the following syntax:

    	functioncall ::= prefixexp args
    

    In a function call, first prefixexp and args are evaluated. If the value of prefixexp has type function, then this function is called with the given arguments. Otherwise, the prefixexp "call" metamethod is called, having as first parameter the value of prefixexp, followed by the original call arguments (see §2.8).

    The form

    	functioncall ::= prefixexp `:´ Name args
    

    can be used to call "methods". A call v:name(args) is syntactic sugar for v.name(v,args), except that v is evaluated only once.

    Arguments have the following syntax:

    	args ::= `(´ [explist1] `)´
    	args ::= tableconstructor
    	args ::= String
    

    All argument expressions are evaluated before the call. A call of the form f{fields} is syntactic sugar for f({fields}); that is, the argument list is a single new table. A call of the form f'string' (or f"string" or f[[string]]) is syntactic sugar for f('string'); that is, the argument list is a single literal string.

    As an exception to the free-format syntax of Lua, you cannot put a line break before the '(' in a function call. This restriction avoids some ambiguities in the language. If you write

         a = f
         (g).x(a)
    

    Lua would see that as a single statement, a = f(g).x(a). So, if you want two statements, you must add a semi-colon between them. If you actually want to call f, you must remove the line break before (g).

    A call of the form return functioncall is called a tail call. Lua implements proper tail calls (or proper tail recursion): in a tail call, the called function reuses the stack entry of the calling function. Therefore, there is no limit on the number of nested tail calls that a program can execute. However, a tail call erases any debug information about the calling function. Note that a tail call only happens with a particular syntax, where the return has one single function call as argument; this syntax makes the calling function return exactly the returns of the called function. So, none of the following examples are tail calls:

         return (f(x))        -- results adjusted to 1
         return 2 * f(x)
         return x, f(x)       -- additional results
         f(x); return         -- results discarded
         return x or f(x)     -- results adjusted to 1
    

    2.5.9 - Function Definitions

    The syntax for function definition is

    	function ::= function funcbody
    	funcbody ::= `(´ [parlist1] `)´ block end
    

    The following syntactic sugar simplifies function definitions:

    	stat ::= function funcname funcbody
    	stat ::= local function Name funcbody
    	funcname ::= Name {`.´ Name} [`:´ Name]
    

    The statement

         function f () body end
    

    translates to

         f = function () body end
    

    The statement

         function t.a.b.c.f () body end
    

    translates to

         t.a.b.c.f = function () body end
    

    The statement

         local function f () body end
    

    translates to

         local f; f = function () body end
    

    not to

         local f = function () body end
    

    (This only makes a difference when the body of the function contains references to f.)

    A function definition is an executable expression, whose value has type function. When Lua pre-compiles a chunk, all its function bodies are pre-compiled too. Then, whenever Lua executes the function definition, the function is instantiated (or closed). This function instance (or closure) is the final value of the expression. Different instances of the same function may refer to different external local variables and may have different environment tables.

    Parameters act as local variables that are initialized with the argument values:

    	parlist1 ::= namelist [`,´ `...´] | `...´
    

    When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a variadic or vararg function, which is indicated by three dots ('...') at the end of its parameter list. A vararg function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, which is also written as three dots. The value of this expression is a list of all actual extra arguments, similar to a function with multiple results. If a vararg expression is used inside another expression or in the middle of a list of expressions, then its return list is adjusted to one element. If the expression is used as the last element of a list of expressions, then no adjustment is made (unless the call is enclosed in parentheses).

    As an example, consider the following definitions:

         function f(a, b) end
         function g(a, b, ...) end
         function r() return 1,2,3 end
    

    Then, we have the following mapping from arguments to parameters and to the vararg expression:

         CALL            PARAMETERS
         
         f(3)             a=3, b=nil
         f(3, 4)          a=3, b=4
         f(3, 4, 5)       a=3, b=4
         f(r(), 10)       a=1, b=10
         f(r())           a=1, b=2
         
         g(3)             a=3, b=nil, ... -->  (nothing)
         g(3, 4)          a=3, b=4,   ... -->  (nothing)
         g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
         g(5, r())        a=5, b=1,   ... -->  2  3
    

    Results are returned using the return statement (see §2.4.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results.

    The colon syntax is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement

         function t.a.b.c:f (params) body end
    

    is syntactic sugar for

         t.a.b.c.f = function (self, params) body end
    

    2.6 - Visibility Rules

    Lua is a lexically scoped language. The scope of variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. Consider the following example:

         x = 10                -- global variable
         do                    -- new block
           local x = x         -- new 'x', with value 10
           print(x)            --> 10
           x = x+1
           do                  -- another block
             local x = x+1     -- another 'x'
             print(x)          --> 12
           end
           print(x)            --> 11
         end
         print(x)              --> 10  (the global one)
    

    Notice that, in a declaration like local x = x, the new x being declared is not in scope yet, and so the second x refers to the outside variable.

    Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function.

    Notice that each execution of a local statement defines new local variables. Consider the following example:

         a = {}
         local x = 20
         for i=1,10 do
           local y = 0
           a[i] = function () y=y+1; return x+y end
         end
    

    The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y variable, while all of them share the same x.

    2.7 - Error Handling

    Because Lua is an embedded extension language, all Lua actions start from C code in the host program calling a function from the Lua library (see lua_pcall). Whenever an error occurs during Lua compilation or execution, control returns to C, which can take appropriate measures (such as printing an error message).

    Lua code can explicitly generate an error by calling the error function. If you need to catch errors in Lua, you can use the pcall function.

    2.8 - Metatables

    Every value in Lua may have a metatable. This metatable is an ordinary Lua table that defines the behavior of the original value under certain special operations. You can change several aspects of the behavior of operations over a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, Lua checks for a function in the field "__add" in its metatable. If it finds one, Lua calls this function to perform the addition.

    We call the keys in a metatable events and the values metamethods. In the previous example, the event is "add" and the metamethod is the function that performs the addition.

    You can query the metatable of any value through the getmetatable function.

    You can replace the metatable of tables through the setmetatable function. You cannot change the metatable of other types from Lua (except using the debug library); you must use the C API for that.

    Tables and userdata have individual metatables (although multiple tables and userdata can share their metatables); values of all other types share one single metatable per type. So, there is one single metatable for all numbers, and for all strings, etc.

    A metatable may control how an object behaves in arithmetic operations, order comparisons, concatenation, length operation, and indexing. A metatable can also define a function to be called when a userdata is garbage collected. For each of these operations Lua associates a specific key called an event. When Lua performs one of these operations over a value, it checks whether this value has a metatable with the corresponding event. If so, the value associated with that key (the metamethod) controls how Lua will perform the operation.

    Metatables control the operations listed next. Each operation is identified by its corresponding name. The key for each operation is a string with its name prefixed by two underscores, '__'; for instance, the key for operation "add" is the string "__add". The semantics of these operations is better explained by a Lua function describing how the interpreter executes the operation.

    The code shown here in Lua is only illustrative; the real behavior is hard coded in the interpreter and it is much more efficient than this simulation. All functions used in these descriptions (rawget, tonumber, etc.) are described in §5.1. In particular, to retrieve the metamethod of a given object, we use the expression

         metatable(obj)[event]
    

    This should be read as

         rawget(getmetatable(obj) or {}, event)
    

    That is, the access to a metamethod does not invoke other metamethods, and the access to objects with no metatables does not fail (it simply results in nil).

    • "add": the + operation.

      The function getbinhandler below defines how Lua chooses a handler for a binary operation. First, Lua tries the first operand. If its type does not define a handler for the operation, then Lua tries the second operand.

           function getbinhandler (op1, op2, event)
             return metatable(op1)[event] or metatable(op2)[event]
           end
      

      By using this function, the behavior of the op1 + op2 is

           function add_event (op1, op2)
             local o1, o2 = tonumber(op1), tonumber(op2)
             if o1 and o2 then  -- both operands are numeric?
               return o1 + o2   -- '+' here is the primitive 'add'
             else  -- at least one of the operands is not numeric
               local h = getbinhandler(op1, op2, "__add")
               if h then
                 -- call the handler with both operands
                 return h(op1, op2)
               else  -- no handler available: default behavior
                 error(···)
               end
             end
           end
      

    • "sub": the - operation. Behavior similar to the "add" operation.
    • "mul": the * operation. Behavior similar to the "add" operation.
    • "div": the / operation. Behavior similar to the "add" operation.
    • "mod": the % operation. Behavior similar to the "add" operation, with the operation o1 - floor(o1/o2)*o2 as the primitive operation.
    • "pow": the ^ (exponentiation) operation. Behavior similar to the "add" operation, with the function pow (from the C math library) as the primitive operation.
    • "unm": the unary - operation.
           function unm_event (op)
             local o = tonumber(op)
             if o then  -- operand is numeric?
               return -o  -- '-' here is the primitive 'unm'
             else  -- the operand is not numeric.
               -- Try to get a handler from the operand
               local h = metatable(op).__unm
               if h then
                 -- call the handler with the operand
                 return h(op)
               else  -- no handler available: default behavior
                 error(···)
               end
             end
           end
      

    • "concat": the .. (concatenation) operation.
           function concat_event (op1, op2)
             if (type(op1) == "string" or type(op1) == "number") and
                (type(op2) == "string" or type(op2) == "number") then
               return op1 .. op2  -- primitive string concatenation
             else
               local h = getbinhandler(op1, op2, "__concat")
               if h then
                 return h(op1, op2)
               else
                 error(···)
               end
             end
           end
      

    • "len": the # operation.
           function len_event (op)
             if type(op) == "string" then
               return strlen(op)         -- primitive string length
             elseif type(op) == "table" then
               return #op                -- primitive table length
             else
               local h = metatable(op).__len
               if h then
                 -- call the handler with the operand
                 return h(op)
               else  -- no handler available: default behavior
                 error(···)
               end
             end
           end
      

      See §2.5.5 for a description of the length of a table.

    • "eq": the == operation. The function getcomphandler defines how Lua chooses a metamethod for comparison operators. A metamethod only is selected when both objects being compared have the same type and the same metamethod for the selected operation.
           function getcomphandler (op1, op2, event)
             if type(op1) ~= type(op2) then return nil end
             local mm1 = metatable(op1)[event]
             local mm2 = metatable(op2)[event]
             if mm1 == mm2 then return mm1 else return nil end
           end
      

      The "eq" event is defined as follows:

           function eq_event (op1, op2)
             if type(op1) ~= type(op2) then  -- different types?
               return false   -- different objects
             end
             if op1 == op2 then   -- primitive equal?
               return true   -- objects are equal
             end
             -- try metamethod
             local h = getcomphandler(op1, op2, "__eq")
             if h then
               return h(op1, op2)
             else
               return false
             end
           end
      

      a ~= b is equivalent to not (a == b).

    • "lt": the < operation.
           function lt_event (op1, op2)
             if type(op1) == "number" and type(op2) == "number" then
               return op1 < op2   -- numeric comparison
             elseif type(op1) == "string" and type(op2) == "string" then
               return op1 < op2   -- lexicographic comparison
             else
               local h = getcomphandler(op1, op2, "__lt")
               if h then
                 return h(op1, op2)
               else
                 error(···);
               end
             end
           end
      

      a > b is equivalent to b < a.

    • "le": the <= operation.
           function le_event (op1, op2)
             if type(op1) == "number" and type(op2) == "number" then
               return op1 <= op2   -- numeric comparison
             elseif type(op1) == "string" and type(op2) == "string" then
               return op1 <= op2   -- lexicographic comparison
             else
               local h = getcomphandler(op1, op2, "__le")
               if h then
                 return h(op1, op2)
               else
                 h = getcomphandler(op1, op2, "__lt")
                 if h then
                   return not h(op2, op1)
                 else
                   error(···);
                 end
               end
             end
           end
      

      a >= b is equivalent to b <= a. Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is equivalent to not (b < a).

    • "index": The indexing access table[key].
           function gettable_event (table, key)
             local h
             if type(table) == "table" then
               local v = rawget(table, key)
               if v ~= nil then return v end
               h = metatable(table).__index
               if h == nil then return nil end
             else
               h = metatable(table).__index
               if h == nil then
                 error(···);
               end
             end
             if type(h) == "function" then
               return h(table, key)      -- call the handler
             else return h[key]          -- or repeat operation on it
             end
           end
      

    • "newindex": The indexing assignment table[key] = value.
           function settable_event (table, key, value)
             local h
             if type(table) == "table" then
               local v = rawget(table, key)
               if v ~= nil then rawset(table, key, value); return end
               h = metatable(table).__newindex
               if h == nil then rawset(table, key, value); return end
             else
               h = metatable(table).__newindex
               if h == nil then
                 error(···);
               end
             end
             if type(h) == "function" then
               return h(table, key,value)    -- call the handler
             else h[key] = value             -- or repeat operation on it
             end
           end
      

    • "call": called when Lua calls a value.
           function function_event (func, ...)
             if type(func) == "function" then
               return func(...)   -- primitive call
             else
               local h = metatable(func).__call
               if h then
                 return h(func, ...)
               else
                 error(···)
               end
             end
           end
      

    2.9 - Environments

    Besides metatables, objects of types thread, function, and userdata have another table associated with them, called their environment. Like metatables, environments are regular tables and multiple objects can share the same environment.

    Environments associated with userdata have no meaning for Lua. It is only a convenience feature for programmers to associate a table to a userdata.

    Environments associated with threads are called global environments. They are used as the default environment for their threads and non-nested functions created by the thread (through loadfile, loadstring or load) and can be directly accessed by C code (see §3.3).

    Environments associated with C functions can be directly accessed by C code (see §3.3). They are used as the default environment for other C functions created by the function.

    Environments associated with Lua functions are used to resolve all accesses to global variables within the function (see §2.3). They are used as the default environment for other Lua functions created by the function.

    You can change the environment of a Lua function or the running thread by calling setfenv. You can get the environment of a Lua function or the running thread by calling getfenv. To manipulate the environment of other objects (userdata, C functions, other threads) you must use the C API.

    2.10 - Garbage Collection

    Lua performs automatic memory management. This means that you have to worry neither about allocating memory for new objects nor about freeing it when the objects are no longer needed. Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects (that is, these objects that are no longer accessible from Lua). All objects in Lua are subject to automatic management: tables, userdata, functions, threads, and strings.

    Lua implements an incremental mark-and-sweep collector. It uses two numbers to control its garbage-collection cycles: the garbage-collector pause and the garbage-collector step multiplier.

    The garbage-collector pause controls how long the collector waits before starting a new cycle. Larger values make the collector less aggressive. Values smaller than 1 mean the collector will not wait to start a new cycle. A value of 2 means that the collector waits for the total memory in use to double before starting a new cycle.

    The step multiplier controls the relative speed of the collector relative to memory allocation. Larger values make the collector more aggressive but also increase the size of each incremental step. Values smaller than 1 make the collector too slow and may result in the collector never finishing a cycle. The default, 2, means that the collector runs at "twice" the speed of memory allocation.

    You can change these numbers by calling lua_gc in C or collectgarbage in Lua. Both get percentage points as arguments (so an argument of 100 means a real value of 1). With these functions you can also control the collector directly (e.g., stop and restart it).

    2.10.1 - Garbage-Collection Metamethods

    Using the C API, you can set garbage-collector metamethods for userdata (see §2.8). These metamethods are also called finalizers. Finalizers allow you to coordinate Lua's garbage collection with external resource management (such as closing files, network or database connections, or freeing your own memory).

    Garbage userdata with a field __gc in their metatables are not collected immediately by the garbage collector. Instead, Lua puts them in a list. After the collection, Lua does the equivalent of the following function for each userdata in that list:

         function gc_event (udata)
           local h = metatable(udata).__gc
           if h then
             h(udata)
           end
         end
    

    At the end of each garbage-collection cycle, the finalizers for userdata are called in reverse order of their creation, among those collected in that cycle. That is, the first finalizer to be called is the one associated with the userdata created last in the program.

    2.10.2 - Weak Tables

    A weak table is a table whose elements are weak references. A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, then the garbage collector will collect this object.

    A weak table can have weak keys, weak values, or both. A table with weak keys allows the collection of its keys, but prevents the collection of its values. A table with both weak keys and weak values allows the collection of both keys and values. In any case, if either the key or the value is collected, the whole pair is removed from the table. The weakness of a table is controlled by the __mode field of its metatable. If the __mode field is a string containing the character 'k', the keys in the table are weak. If __mode contains 'v', the values in the table are weak.

    After you use a table as a metatable, you should not change the value of its field __mode. Otherwise, the weak behavior of the tables controlled by this metatable is undefined.

    2.11 - Coroutines

    Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.

    You create a coroutine with a call to coroutine.create. Its sole argument is a function that is the main function of the coroutine. The create function only creates a new coroutine and returns a handle to it (an object of type thread); it does not start the coroutine execution.

    When you first call coroutine.resume, passing as its first argument the thread returned by coroutine.create, the coroutine starts its execution, at the first line of its main function. Extra arguments passed to coroutine.resume are passed on to the coroutine main function. After the coroutine starts running, it runs until it terminates or yields.

    A coroutine can terminate its execution in two ways: normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. In the first case, coroutine.resume returns true, plus any values returned by the coroutine main function. In case of errors, coroutine.resume returns false plus an error message.

    A coroutine yields by calling coroutine.yield. When a coroutine yields, the corresponding coroutine.resume returns immediately, even if the yield happens inside nested function calls (that is, not in the main function, but in a function directly or indirectly called by the main function). In the case of a yield, coroutine.resume also returns true, plus any values passed to coroutine.yield. The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.

    Like coroutine.create, the coroutine.wrap function also creates a coroutine, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function go as extra arguments to coroutine.resume. coroutine.wrap returns all the values returned by coroutine.resume, except the first one (the boolean error code). Unlike coroutine.resume, coroutine.wrap does not catch errors; any error is propagated to the caller.

    As an example, consider the following code:

         function foo (a)
           print("foo", a)
           return coroutine.yield(2*a)
         end
         
         co = coroutine.create(function (a,b)
               print("co-body", a, b)
               local r = foo(a+1)
               print("co-body", r)
               local r, s = coroutine.yield(a+b, a-b)
               print("co-body", r, s)
               return b, "end"
         end)
                
         print("main", coroutine.resume(co, 1, 10))
         print("main", coroutine.resume(co, "r"))
         print("main", coroutine.resume(co, "x", "y"))
         print("main", coroutine.resume(co, "x", "y"))
    

    When you run it, it produces the following output:

         co-body 1       10
         foo     2
         
         main    true    4
         co-body r
         main    true    11      -9
         co-body x       y
         main    true    10      end
         main    false   cannot resume dead coroutine
    

    3 - The Application Program Interface

    This section describes the C API for Lua, that is, the set of C functions available to the host program to communicate with Lua. All API functions and related types and constants are declared in the header file lua.h.

    Even when we use the term "function", any facility in the API may be provided as a macro instead. All such macros use each of their arguments exactly once (except for the first argument, which is always a Lua state), and so do not generate any hidden side-effects.

    As in most C libraries, the Lua API functions do not check their arguments for validity or consistency. However, you can change this behavior by compiling Lua with a proper definition for the macro luai_apicheck, in file luaconf.h.

    3.1 - The Stack

    Lua uses a virtual stack to pass values to and from C. Each element in this stack represents a Lua value (nil, number, string, etc.).

    Whenever Lua calls C, the called function gets a new stack, which is independent of previous stacks and of stacks of C functions that are still active. This stack initially contains any arguments to the C function and it is where the C function pushes its results to be returned to the caller (see lua_CFunction).

    For convenience, most query operations in the API do not follow a strict stack discipline. Instead, they can refer to any element in the stack by using an index: A positive index represents an absolute stack position (starting at 1); a negative index represents an offset relative to the top of the stack. More specifically, if the stack has n elements, then index 1 represents the first element (that is, the element that was pushed onto the stack first) and index n represents the last element; index -1 also represents the last element (that is, the element at the top) and index -n represents the first element. We say that an index is valid if it lies between 1 and the stack top (that is, if 1 ≤ abs(index) ≤ top).

    3.2 - Stack Size

    When you interact with Lua API, you are responsible for ensuring consistency. In particular, you are responsible for controlling stack overflow. You can use the function lua_checkstack to grow the stack size.

    Whenever Lua calls C, it ensures that at least LUA_MINSTACK stack positions are available. LUA_MINSTACK is defined as 20, so that usually you do not have to worry about stack space unless your code has loops pushing elements onto the stack.

    Most query functions accept as indices any value inside the available stack space, that is, indices up to the maximum stack size you have set through lua_checkstack. Such indices are called acceptable indices. More formally, we define an acceptable index as follows:

         (index < 0 && abs(index) <= top) ||
         (index > 0 && index <= stackspace)
    

    Note that 0 is never an acceptable index.

    3.3 - Pseudo-Indices

    Unless otherwise noted, any function that accepts valid indices can also be called with pseudo-indices, which represent some Lua values that are accessible to C code but which are not in the stack. Pseudo-indices are used to access the thread environment, the function environment, the registry, and the upvalues of a C function (see §3.4).

    The thread environment (where global variables live) is always at pseudo-index LUA_GLOBALSINDEX. The environment of the running C function is always at pseudo-index LUA_ENVIRONINDEX.

    To access and change the value of global variables, you can use regular table operations over an environment table. For instance, to access the value of a global variable, do

         lua_getfield(L, LUA_GLOBALSINDEX, varname);
    

    3.4 - C Closures

    When a C function is created, it is possible to associate some values with it, thus creating a C closure; these values are called upvalues and are accessible to the function whenever it is called (see lua_pushcclosure).

    Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function, produces an acceptable (but invalid) index.

    3.5 - Registry

    Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it should take care to choose keys different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code.

    The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, and therefore should not be used for other purposes.

    3.6 - Error Handling in C

    Internally, Lua uses the C longjmp facility to handle errors. (You can also choose to use exceptions if you use C++; see file luaconf.h.) When Lua faces any error (such as memory allocation errors, type errors, syntax errors, and runtime errors) it raises an error; that is, it does a long jump. A protected environment uses setjmp to set a recover point; any error jumps to the most recent active recover point.

    Almost any function in the API may raise an error, for instance due to a memory allocation error. The following functions run in protected mode (that is, they create a protected environment to run), so they never raise an error: lua_newstate, lua_close, lua_load, lua_pcall, and lua_cpcall.

    Inside a C function you can raise an error by calling lua_error.

    3.7 - Functions and Types

    Here we list all functions and types from the C API in alphabetical order.


    lua_Alloc

    typedef void * (*lua_Alloc) (void *ud,
                                 void *ptr,
                                 size_t osize,
                                 size_t nsize);

    The type of the memory-allocation function used by Lua states. The allocator function must provide a functionality similar to realloc, but not exactly the same. Its arguments are ud, an opaque pointer passed to lua_newstate; ptr, a pointer to the block being allocated/reallocated/freed; osize, the original size of the block; nsize, the new size of the block. ptr is NULL if and only if osize is zero. When nsize is zero, the allocator must return NULL; if osize is not zero, it should free the block pointed to by ptr. When nsize is not zero, the allocator returns NULL if and only if it cannot fill the request. When nsize is not zero and osize is zero, the allocator should behave like malloc. When nsize and osize are not zero, the allocator behaves like realloc. Lua assumes that the allocator never fails when osize >= nsize.

    Here is a simple implementation for the allocator function. It is used in the auxiliary library by luaL_newstate.

         static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                    size_t nsize) {
           (void)ud;  (void)osize;  /* not used */
           if (nsize == 0) {
             free(ptr);
             return NULL;
           }
           else
             return realloc(ptr, nsize);
         }
    

    This code assumes that free(NULL) has no effect and that realloc(NULL, size) is equivalent to malloc(size). ANSI C ensures both behaviors.


    lua_atpanic

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

    Sets a new panic function and returns the old one.

    If an error happens outside any protected environment, Lua calls a panic function and then calls exit(EXIT_FAILURE), thus exiting the host application. Your panic function may avoid this exit by never returning (e.g., doing a long jump).

    The panic function can access the error message at the top of the stack.


    lua_call

    void lua_call (lua_State *L, int nargs, int nresults);

    Calls a function.

    To call a function you must use the following protocol: first, the function to be called is pushed onto the stack; then, the arguments to the function are pushed in direct order; that is, the first argument is pushed first. Finally you call lua_call; nargs is the number of arguments that you pushed onto the stack. All arguments and the function value are popped from the stack when the function is called. The function results are pushed onto the stack when the function returns. The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In this case, all results from the function are pushed. Lua takes care that the returned values fit into the stack space. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack.

    Any error inside the called function is propagated upwards (with a longjmp).

    The following example shows how the host program may do the equivalent to this Lua code:

         a = f("how", t.x, 14)
    

    Here it is in C:

         lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */
         lua_pushstring(L, "how");                        /* 1st argument */
         lua_getfield(L, LUA_GLOBALSINDEX, "t");   /* table to be indexed */
         lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
         lua_remove(L, -2);                  /* remove 't' from the stack */
         lua_pushinteger(L, 14);                          /* 3rd argument */
         lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
         lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global 'a' */
    

    Note that the code above is "balanced": at its end, the stack is back to its original configuration. This is considered good programming practice.


    lua_CFunction

    typedef int (*lua_CFunction) (lua_State *L);

    Type for C functions.

    In order to communicate properly with Lua, a C function must use the following protocol, which defines the way parameters and results are passed: a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). So, when the function starts, lua_gettop(L) returns the number of arguments received by the function. The first argument (if any) is at index 1 and its last argument is at index lua_gettop(L). To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results. Any other value in the stack below the results will be properly discarded by Lua. Like a Lua function, a C function called by Lua can also return many results.

    As an example, the following function receives a variable number of numerical arguments and returns their average and sum:

         static int foo (lua_State *L) {
           int n = lua_gettop(L);    /* number of arguments */
           lua_Number sum = 0;
           int i;
           for (i = 1; i <= n; i++) {
             if (!lua_isnumber(L, i)) {
               lua_pushstring(L, "incorrect argument");
               lua_error(L);
             }
             sum += lua_tonumber(L, i);
           }
           lua_pushnumber(L, sum/n);        /* first result */
           lua_pushnumber(L, sum);         /* second result */
           return 2;                   /* number of results */
         }
    

    lua_checkstack

    int lua_checkstack (lua_State *L, int extra);

    Ensures that there are at least extra free stack slots in the stack. It returns false if it cannot grow the stack to that size. This function never shrinks the stack; if the stack is already larger than the new size, it is left unchanged.


    lua_close

    void lua_close (lua_State *L);

    Destroys all objects in the given Lua state (calling the corresponding garbage-collection metamethods, if any) and frees all dynamic memory used by this state. On several platforms, you may not need to call this function, because all resources are naturally released when the host program ends. On the other hand, long-running programs, such as a daemon or a web server, might need to release states as soon as they are not needed, to avoid growing too large.


    lua_concat

    void lua_concat (lua_State *L, int n);

    Concatenates the n values at the top of the stack, pops them, and leaves the result at the top. If n is 1, the result is the single string on the stack (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua (see §2.5.4).


    lua_cpcall

    int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

    Calls the C function func in protected mode. func starts with only one element in its stack, a light userdata containing ud. In case of errors, lua_cpcall returns the same error codes as lua_pcall, plus the error object on the top of the stack; otherwise, it returns zero, and does not change the stack. All values returned by func are discarded.


    lua_createtable

    void lua_createtable (lua_State *L, int narr, int nrec);

    Creates a new empty table and pushes it onto the stack. The new table has space pre-allocated for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have. Otherwise you can use the function lua_newtable.


    lua_dump

    int lua_dump (lua_State *L, lua_Writer writer, void *data);

    Dumps a function as a binary chunk. Receives a Lua function on the top of the stack and produces a binary chunk that, if loaded again, results in a function equivalent to the one dumped. As it produces parts of the chunk, lua_dump calls function writer (see lua_Writer) with the given data to write them.

    The value returned is the error code returned by the last call to the writer; 0 means no errors.

    This function does not pop the Lua function from the stack.


    lua_equal

    int lua_equal (lua_State *L, int index1, int index2);

    Returns 1 if the two values in acceptable indices index1 and index2 are equal, following the semantics of the Lua == operator (that is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid.


    lua_error

    int lua_error (lua_State *L);

    Generates a Lua error. The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns. (see luaL_error).


    lua_gc

    int lua_gc (lua_State *L, int what, int data);

    Controls the garbage collector.

    This function performs several tasks, according to the value of the parameter what:

    • LUA_GCSTOP: stops the garbage collector.
    • LUA_GCRESTART: restarts the garbage collector.
    • LUA_GCCOLLECT: performs a full garbage-collection cycle.
    • LUA_GCCOUNT: returns the current amount of memory (in Kbytes) in use by Lua.
    • LUA_GCCOUNTB: returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024.
    • LUA_GCSTEP: performs an incremental step of garbage collection. The step "size" is controlled by data (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of data. The function returns 1 if the step finished a garbage-collection cycle.
    • LUA_GCSETPAUSE: sets data/100 as the new value for the pause of the collector (see §2.10). The function returns the previous value of the pause.
    • LUA_GCSETSTEPMUL: sets data/100 as the new value for the step multiplier of the collector (see §2.10). The function returns the previous value of the step multiplier.

    lua_getallocf

    lua_Alloc lua_getallocf (lua_State *L, void **ud);

    Returns the memory-allocation function of a given state. If ud is not NULL, Lua stores in *ud the opaque pointer passed to lua_newstate.


    lua_getfenv

    void lua_getfenv (lua_State *L, int index);

    Pushes onto the stack the environment table of the value at the given index.


    lua_getfield

    void lua_getfield (lua_State *L, int index, const char *k);

    Pushes onto the stack the value t[k], where t is the value at the given valid index index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.8).


    lua_getglobal

    void lua_getglobal (lua_State *L, const char *name);

    Pushes onto the stack the value of the global name. It is defined as a macro:

         #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
    

    lua_getmetatable

    int lua_getmetatable (lua_State *L, int index);

    Pushes onto the stack the metatable of the value at the given acceptable index. If the index is not valid, or if the value does not have a metatable, the function returns 0 and pushes nothing on the stack.


    lua_gettable

    void lua_gettable (lua_State *L, int index);

    Pushes onto the stack the value t[k], where t is the value at the given valid index index and k is the value at the top of the stack.

    This function pops the key from the stack (putting the resulting value in its place). As in Lua, this function may trigger a metamethod for the "index" event (see §2.8).


    lua_gettop

    int lua_gettop (lua_State *L);

    Returns the index of the top element in the stack. Because indices start at 1, this result is equal to the number of elements in the stack (and so 0 means an empty stack).


    lua_insert

    void lua_insert (lua_State *L, int index);

    Moves the top element into the given valid index, shifting up the elements above this index to open space. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


    lua_Integer

    typedef ptrdiff_t lua_Integer;

    The type used by the Lua API to represent integral values.

    By default it is a ptrdiff_t, which is usually the largest signed integral type the machine handles "comfortably".


    lua_isboolean

    int lua_isboolean (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index has type boolean, and 0 otherwise.


    lua_iscfunction

    int lua_iscfunction (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a C function, and 0 otherwise.


    lua_isfunction

    int lua_isfunction (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a function (either C or Lua), and 0 otherwise.


    lua_islightuserdata

    int lua_islightuserdata (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a light userdata, and 0 otherwise.


    lua_isnil

    int lua_isnil (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is nil, and 0 otherwise.


    lua_isnone

    int lua_isnone (lua_State *L, int index);

    Returns 1 if the the given acceptable index is not valid (that is, it refers to an element outside the current stack), and 0 otherwise.


    lua_isnoneornil

    int lua_isnoneornil (lua_State *L, int index);

    Returns 1 if the the given acceptable index is not valid (that is, it refers to an element outside the current stack) or if the value at this index is nil, and 0 otherwise.


    lua_isnumber

    int lua_isnumber (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a number or a string convertible to a number, and 0 otherwise.


    lua_isstring

    int lua_isstring (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a string or a number (which is always convertible to a string), and 0 otherwise.


    lua_istable

    int lua_istable (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a table, and 0 otherwise.


    lua_isthread

    int lua_isthread (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a thread, and 0 otherwise.


    lua_isuserdata

    int lua_isuserdata (lua_State *L, int index);

    Returns 1 if the value at the given acceptable index is a userdata (either full or light), and 0 otherwise.


    lua_lessthan

    int lua_lessthan (lua_State *L, int index1, int index2);

    Returns 1 if the value at acceptable index index1 is smaller than the value at acceptable index index2, following the semantics of the Lua < operator (that is, may call metamethods). Otherwise returns 0. Also returns 0 if any of the indices is non valid.


    lua_load

    int lua_load (lua_State *L,
                  lua_Reader reader,
                  void *data,
                  const char *chunkname);

    Loads a Lua chunk. If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message. The return values of lua_load are:

    This function only loads a chunk; it does not run it.

    lua_load automatically detects whether the chunk is text or binary, and loads it accordingly (see program luac).

    The lua_load function uses a user-supplied reader function to read the chunk (see lua_Reader). The data argument is an opaque value passed to the reader function.

    The chunkname argument gives a name to the chunk, which is used for error messages and in debug information (see §3.8).


    lua_newstate

    lua_State *lua_newstate (lua_Alloc f, void *ud);

    Creates a new, independent state. Returns NULL if cannot create the state (due to lack of memory). The argument f is the allocator function; Lua does all memory allocation for this state through this function. The second argument, ud, is an opaque pointer that Lua simply passes to the allocator in every call.


    lua_newtable

    void lua_newtable (lua_State *L);

    Creates a new empty table and pushes it onto the stack. It is equivalent to lua_createtable(L, 0, 0).


    lua_newthread

    lua_State *lua_newthread (lua_State *L);

    Creates a new thread, pushes it on the stack, and returns a pointer to a lua_State that represents this new thread. The new state returned by this function shares with the original state all global objects (such as tables), but has an independent execution stack.

    There is no explicit function to close or to destroy a thread. Threads are subject to garbage collection, like any Lua object.


    lua_newuserdata

    void *lua_newuserdata (lua_State *L, size_t size);

    This function allocates a new block of memory with the given size, pushes onto the stack a new full userdata with the block address, and returns this address.

    Userdata represent C values in Lua. A full userdata represents a block of memory. It is an object (like a table): you must create it, it can have its own metatable, and you can detect when it is being collected. A full userdata is only equal to itself (under raw equality).

    When Lua collects a full userdata with a gc metamethod, Lua calls the metamethod and marks the userdata as finalized. When this userdata is collected again then Lua frees its corresponding memory.


    lua_next

    int lua_next (lua_State *L, int index);

    Pops a key from the stack, and pushes a key-value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns 0 (and pushes nothing).

    A typical traversal looks like this:

         /* table is in the stack at index 't' */
         lua_pushnil(L);  /* first key */
         while (lua_next(L, t) != 0) {
           /* uses 'key' (at index -2) and 'value' (at index -1) */
           printf("%s - %s\n",
                  lua_typename(L, lua_type(L, -2)),
                  lua_typename(L, lua_type(L, -1)));
           /* removes 'value'; keeps 'key' for next iteration */
           lua_pop(L, 1);
         }
    

    While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that lua_tolstring changes the value at the given index; this confuses the next call to lua_next.


    lua_Number

    typedef double lua_Number;

    The type of numbers in Lua. By default, it is double, but that can be changed in luaconf.h.

    Through the configuration file you can change Lua to operate with another type for numbers (e.g., float or long).


    lua_objlen

    size_t lua_objlen (lua_State *L, int index);

    Returns the "length" of the value at the given acceptable index: for strings, this is the string length; for tables, this is the result of the length operator ('#'); for userdata, this is the size of the block of memory allocated for the userdata; for other values, it is 0.


    lua_pcall

    int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

    Calls a function in protected mode.

    Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall always removes the function and its arguments from the stack.

    If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.

    Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

    The lua_pcall function returns 0 in case of success or one of the following error codes (defined in lua.h):

    • LUA_ERRRUN: a runtime error.
    • LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the error handler function.
    • LUA_ERRERR: error while running the error handler function.

    lua_pop

    void lua_pop (lua_State *L, int n);

    Pops n elements from the stack.


    lua_pushboolean

    void lua_pushboolean (lua_State *L, int b);

    Pushes a boolean value with value b onto the stack.


    lua_pushcclosure

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

    Pushes a new C closure onto the stack.

    When a C function is created, it is possible to associate some values with it, thus creating a C closure (see §3.4); these values are then accessible to the function whenever it is called. To associate values with a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then lua_pushcclosure is called to create and push the C function onto the stack, with the argument n telling how many values should be associated with the function. lua_pushcclosure also pops these values from the stack.


    lua_pushcfunction

    void lua_pushcfunction (lua_State *L, lua_CFunction f);

    Pushes a C function onto the stack. This function receives a pointer to a C function and pushes onto the stack a Lua value of type function that, when called, invokes the corresponding C function.

    Any function to be registered in Lua must follow the correct protocol to receive its parameters and return its results (see lua_CFunction).

    lua_pushcfunction is defined as a macro:

         #define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
    

    lua_pushfstring

    const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

    Pushes onto the stack a formatted string and returns a pointer to this string. It is similar to the C function sprintf, but has some important differences:

    • You do not have to allocate space for the result: the result is a Lua string and Lua takes care of memory allocation (and deallocation, through garbage collection).
    • The conversion specifiers are quite restricted. There are no flags, widths, or precisions. The conversion specifiers can only be '%%' (inserts a '%' in the string), '%s' (inserts a zero-terminated string, with no size restrictions), '%f' (inserts a lua_Number), '%p' (inserts a pointer as a hexadecimal numeral), '%d' (inserts an int), and '%c' (inserts an int as a character).

    lua_pushinteger

    void lua_pushinteger (lua_State *L, lua_Integer n);

    Pushes a number with value n onto the stack.


    lua_pushlightuserdata

    void lua_pushlightuserdata (lua_State *L, void *p);

    Pushes a light userdata onto the stack.

    Userdata represent C values in Lua. A light userdata represents a pointer. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). A light userdata is equal to "any" light userdata with the same C address.


    lua_pushlstring

    void lua_pushlstring (lua_State *L, const char *s, size_t len);

    Pushes the string pointed to by s with size len onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string can contain embedded zeros.


    lua_pushnil

    void lua_pushnil (lua_State *L);

    Pushes a nil value onto the stack.


    lua_pushnumber

    void lua_pushnumber (lua_State *L, lua_Number n);

    Pushes a number with value n onto the stack.


    lua_pushstring

    void lua_pushstring (lua_State *L, const char *s);

    Pushes the zero-terminated string pointed to by s onto the stack. Lua makes (or reuses) an internal copy of the given string, so the memory at s can be freed or reused immediately after the function returns. The string cannot contain embedded zeros; it is assumed to end at the first zero.


    lua_pushthread

    int lua_pushthread (lua_State *L);

    Pushes the thread represented by L onto the stack. Returns 1 if this thread is the main thread of its state.


    lua_pushvalue

    void lua_pushvalue (lua_State *L, int index);

    Pushes a copy of the element at the given valid index onto the stack.


    lua_pushvfstring

    const char *lua_pushvfstring (lua_State *L,
                                  const char *fmt,
                                  va_list argp);

    Equivalent to lua_pushfstring, except that it receives a va_list instead of a variable number of arguments.


    lua_rawequal

    int lua_rawequal (lua_State *L, int index1, int index2);

    Returns 1 if the two values in acceptable indices index1 and index2 are primitively equal (that is, without calling metamethods). Otherwise returns 0. Also returns 0 if any of the indices are non valid.


    lua_rawget

    void lua_rawget (lua_State *L, int index);

    Similar to lua_gettable, but does a raw access (i.e., without metamethods).


    lua_rawgeti

    void lua_rawgeti (lua_State *L, int index, int n);

    Pushes onto the stack the value t[n], where t is the value at the given valid index index. The access is raw; that is, it does not invoke metamethods.


    lua_rawset

    void lua_rawset (lua_State *L, int index);

    Similar to lua_settable, but does a raw assignment (i.e., without metamethods).


    lua_rawseti

    void lua_rawseti (lua_State *L, int index, int n);

    Does the equivalent of t[n] = v, where t is the value at the given valid index index and v is the value at the top of the stack,

    This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods.


    lua_Reader

    typedef const char * (*lua_Reader) (lua_State *L,
                                        void *data,
                                        size_t *size);

    The reader function used by lua_load. Every time it needs another piece of the chunk, lua_load calls the reader, passing along its data parameter. The reader must return a pointer to a block of memory with a new piece of the chunk and set size to the block size. The block must exist until the reader function is called again. To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero.


    lua_register

    void lua_register (lua_State *L,
                       const char *name,
                       lua_CFunction f);

    Sets the C function f as the new value of global name. It is defined as a macro:

         #define lua_register(L,n,f) \
                (lua_pushcfunction(L, f), lua_setglobal(L, n))
    

    lua_remove

    void lua_remove (lua_State *L, int index);

    Removes the element at the given valid index, shifting down the elements above this index to fill the gap. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.


    lua_replace

    void lua_replace (lua_State *L, int index);

    Moves the top element into the given position (and pops it), without shifting any element (therefore replacing the value at the given position).


    lua_resume

    int lua_resume (lua_State *L, int narg);

    Starts and resumes a coroutine in a given thread.

    To start a coroutine, you first create a new thread (see lua_newthread); then you push onto its stack the main function plus any arguments; then you call lua_resume, with narg being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. lua_resume returns LUA_YIELD if the coroutine yields, 0 if the coroutine finishes its execution without errors, or an error code in case of errors (see lua_pcall). In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack. To restart a coroutine, you put on its stack only the values to be passed as results from yield, and then call lua_resume.


    lua_setallocf

    void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

    Changes the allocator function of a given state to f with user data ud.


    lua_setfenv

    int lua_setfenv (lua_State *L, int index);

    Pops a table from the stack and sets it as the new environment for the value at the given index. If the value at the given index is neither a function nor a thread nor a userdata, lua_setfenv returns 0. Otherwise it returns 1.


    lua_setfield

    void lua_setfield (lua_State *L, int index, const char *k);

    Does the equivalent to t[k] = v, where t is the value at the given valid index index and v is the value at the top of the stack,

    This function pops the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.8).


    lua_setglobal

    void lua_setglobal (lua_State *L, const char *name);

    Pops a value from the stack and sets it as the new value of global name. It is defined as a macro:

         #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
    

    lua_setmetatable

    int lua_setmetatable (lua_State *L, int index);

    Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index.


    lua_settable

    void lua_settable (lua_State *L, int index);

    Does the equivalent to t[k] = v, where t is the value at the given valid index index, v is the value at the top of the stack, and k is the value just below the top.

    This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event (see §2.8).


    lua_settop

    void lua_settop (lua_State *L, int index);

    Accepts any acceptable index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack elements are removed.


    lua_State

    typedef struct lua_State lua_State;

    Opaque structure that keeps the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is kept in this structure.

    A pointer to this state must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch.


    lua_status

    int lua_status (lua_State *L);

    Returns the status of the thread L.

    The status can be 0 for a normal thread, an error code if the thread finished its execution with an error, or LUA_YIELD if the thread is suspended.


    lua_toboolean

    int lua_toboolean (lua_State *L, int index);

    Converts the Lua value at the given acceptable index to a C boolean value (0 or 1). Like all tests in Lua, lua_toboolean returns 1 for any Lua value different from false and nil; otherwise it returns 0. It also returns 0 when called with a non-valid index. (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.)


    lua_tocfunction

    lua_CFunction lua_tocfunction (lua_State *L, int index);

    Converts a value at the given acceptable index to a C function. That value must be a C function; otherwise, returns NULL.


    lua_tointeger

    lua_Integer lua_tointeger (lua_State *L, int idx);

    Converts the Lua value at the given acceptable index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tointeger returns 0.

    If the number is not an integer, it is truncated in some non-specified way.


    lua_tolstring

    const char *lua_tolstring (lua_State *L, int index, size_t *len);

    Converts the Lua value at the given acceptable index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; otherwise, the function returns NULL. If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.)

    lua_tolstring returns a fully aligned pointer to a string inside the Lua state. This string always has a zero ('\0') after its last character (as in C), but may contain other zeros in its body. Because Lua has garbage collection, there is no guarantee that the pointer returned by lua_tolstring will be valid after the corresponding value is removed from the stack.


    lua_tonumber

    lua_Number lua_tonumber (lua_State *L, int index);

    Converts the Lua value at the given acceptable index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tonumber returns 0.


    lua_topointer

    const void *lua_topointer (lua_State *L, int index);

    Converts the value at the given acceptable index to a generic C pointer (void*). The value may be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. Different objects will give different pointers. There is no way to convert the pointer back to its original value.

    Typically this function is used only for debug information.


    lua_tostring

    const char *lua_tostring (lua_State *L, int index);

    Equivalent to lua_tolstring with len equal to NULL.


    lua_tothread

    lua_State *lua_tothread (lua_State *L, int index);

    Converts the value at the given acceptable index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL.


    lua_touserdata

    void *lua_touserdata (lua_State *L, int index);

    If the value at the given acceptable index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. Otherwise, returns NULL.


    lua_type

    int lua_type (lua_State *L, int index);

    Returns the type of the value in the given acceptable index, or LUA_TNONE for a non-valid index (that is, an index to an "empty" stack position). The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA.


    lua_typename

    const char *lua_typename  (lua_State *L, int tp);

    Returns the name of the type encoded by the value tp, which must be one the values returned by lua_type.


    lua_Writer

    typedef int (*lua_Writer) (lua_State *L,
                               const void* p,
                               size_t sz,
                               void* ud);

    The writer function used by lua_dump. Every time it produces another piece of chunk, lua_dump calls the writer, passing along the buffer to be written (p), its size (sz), and the data parameter supplied to lua_dump.

    The writer returns an error code: 0 means no errors; any other value means an error and stops lua_dump from calling the writer again.


    lua_xmove

    void lua_xmove (lua_State *from, lua_State *to, int n);

    Exchange values between different threads of the same global state.

    This function pops n values from the stack from, and pushes them onto the stack to.


    lua_yield

    int lua_yield  (lua_State *L, int nresults);

    Yields a coroutine.

    This function should only be called as the return expression of a C function, as follows:

         return lua_yield (L, nresults);
    

    When a C function calls lua_yield in that way, the running coroutine suspends its execution, and the call to lua_resume that started this coroutine returns. The parameter nresults is the number of values from the stack that are passed as results to lua_resume.

    3.8 - The Debug Interface

    Lua has no built-in debugging facilities. Instead, it offers a special interface by means of functions and hooks. This interface allows the construction of different kinds of debuggers, profilers, and other tools that need "inside information" from the interpreter.


    lua_Debug

    typedef struct lua_Debug {
      int event;
      const char *name;           /* (n) */
      const char *namewhat;       /* (n) */
      const char *what;           /* (S) */
      const char *source;         /* (S) */
      int currentline;            /* (l) */
      int nups;                   /* (u) number of upvalues */
      int linedefined;            /* (S) */
      int lastlinedefined;        /* (S) */
      char short_src[LUA_IDSIZE]; /* (S) */
      /* private part */
      other fields
    } lua_Debug;

    A structure used to carry different pieces of information about an active function. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, call lua_getinfo.

    The fields of lua_Debug have the following meaning:

    • source: If the function was defined in a string, then source is that string. If the function was defined in a file, then source starts with a '@' followed by the file name.
    • short_src: a "printable" version of source, to be used in error messages.
    • linedefined: the line number where the definition of the function starts.
    • lastlinedefined: the line number where the definition of the function ends.
    • what: the string "Lua" if the function is a Lua function, "C" if it is a C function, "main" if it is the main part of a chunk, and "tail" if it was a function that did a tail call. In the latter case, Lua has no other information about the function.
    • currentline: the current line where the given function is executing. When no line information is available, currentline is set to -1.
    • name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: some functions may be the value of multiple global variables, while others may be stored only in a table field. The lua_getinfo function checks how the function was called to find a suitable name. If it cannot find a name, then name is set to NULL.
    • namewhat: explains the name field. The value of namewhat can be "global", "local", "method", "field", "upvalue", or "" (the empty string), according to how the function was called. (Lua uses the empty string when no other option seems to apply.)
    • nups: the number of upvalues of the function.

    lua_gethook

    lua_Hook lua_gethook (lua_State *L);

    Returns the current hook function.


    lua_gethookcount

    int lua_gethookcount (lua_State *L);

    Returns the current hook count.


    lua_gethookmask

    int lua_gethookmask (lua_State *L);

    Returns the current hook mask.


    lua_getinfo

    int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

    Returns information about a specific function or function invocation.

    To get information about a function invocation, the parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook).

    To get information about a function you push it onto the stack and start the what string with the character '>'. (In that case, lua_getinfo pops the function in the top of the stack.) For instance, to know in which line a function f was defined, you can write the following code:

         lua_Debug ar;
         lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global 'f' */
         lua_getinfo(L, ">S", &ar);
         printf("%d\n", ar.linedefined);
    

    Each character in the string what selects some fields of the structure ar to be filled or a value to be pushed on the stack:

    • 'n': fills in the field name and namewhat;
    • 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
    • 'l': fills in the field currentline;
    • 'u': fills in the field nups;
    • 'f': pushes onto the stack the function that is running at the given level;
    • 'L': pushes onto the stack a table whose indices are the numbers of the lines that are valid on the function. (A valid line is a line with some associated code, that is, a line where you can put a break point. Non-valid lines include empty lines and comments.)

    This function returns 0 on error (for instance, an invalid option in what).


    lua_getlocal

    const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);

    Gets information about a local variable of a given activation record. The parameter ar must be a valid activation record that was filled by a previous call to lua_getstack or given as argument to a hook (see lua_Hook). The index n selects which local variable to inspect (1 is the first parameter or active local variable, and so on, until the last active local variable). lua_getlocal pushes the variable's value onto the stack and returns its name.

    Variable names starting with '(' (open parentheses) represent internal variables (loop control variables, temporaries, and C function locals).

    Returns NULL (and pushes nothing) when the index is greater than the number of active local variables.


    lua_getstack

    int lua_getstack (lua_State *L, int level, lua_Debug *ar);

    Get information about the interpreter runtime stack.

    This function fills parts of a lua_Debug structure with an identification of the activation record of the function executing at a given level. Level 0 is the current running function, whereas level n+1 is the function that has called level n. When there are no errors, lua_getstack returns 1; when called with a level greater than the stack depth, it returns 0.


    lua_getupvalue

    const char *lua_getupvalue (lua_State *L, int funcindex, int n);

    Gets information about a closure's upvalue. (For Lua functions, upvalues are the external local variables that the function uses, and that are consequently included in its closure.) lua_getupvalue gets the index n of an upvalue, pushes the upvalue's value onto the stack, and returns its name. funcindex points to the closure in the stack. (Upvalues have no particular order, as they are active through the whole function. So, they are numbered in an arbitrary order.)

    Returns NULL (and pushes nothing) when the index is greater than the number of upvalues. For C functions, this function uses the empty string "" as a name for all upvalues.


    lua_Hook

    typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

    Type for debugging hook functions.

    Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Lua identifies these events with the following constants: LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILRET, LUA_HOOKLINE, and LUA_HOOKCOUNT. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo. For return events, event may be LUA_HOOKRET, the normal value, or LUA_HOOKTAILRET. In the latter case, Lua is simulating a return from a function that did a tail call; in this case, it is useless to call lua_getinfo.

    While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, this execution occurs without any calls to hooks.


    lua_sethook

    int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

    Sets the debugging hook function.

    Argument f is the hook function. mask specifies on which events the hook will be called: it is formed by a bitwise or of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below:

    • The call hook: is called when the interpreter calls a function. The hook is called just after Lua enters the new function, before the function gets its arguments.
    • The return hook: is called when the interpreter returns from a function. The hook is called just before Lua leaves the function. You have no access to the values to be returned by the function.
    • The line hook: is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
    • The count hook: is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)

    A hook is disabled by setting mask to zero.


    lua_setlocal

    const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);

    Sets the value of a local variable of a given activation record. Parameters ar and n are as in lua_getlocal (see lua_getlocal). lua_setlocal assigns the value at the top of the stack to the variable and returns its name. It also pops the value from the stack.

    Returns NULL (and pops nothing) when the index is greater than the number of active local variables.


    lua_setupvalue

    const char *lua_setupvalue (lua_State *L, int funcindex, int n);

    Sets the value of a closure's upvalue. It assigns the value at the top of the stack to the upvalue and returns its name. It also pops the value from the stack. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue).

    Returns NULL (and pops nothing) when the index is greater than the number of upvalues.

    4 - The Auxiliary Library

    The auxiliary library provides several convenient functions to interface C with Lua. While the basic API provides the primitive functions for all interactions between C and Lua, the auxiliary library provides higher-level functions for some common tasks.

    All functions from the auxiliary library are defined in header file lauxlib.h and have a prefix luaL_.

    All functions in the auxiliary library are built on top of the basic API, and so they provide nothing that cannot be done with this API.

    Several functions in the auxiliary library are used to check C function arguments. Their names are always luaL_check* or luaL_opt*. All of these functions raise an error if the check is not satisfied. Because the error message is formatted for arguments (e.g., "bad argument #1"), you should not use these functions for other stack values.

    4.1 - Functions and Types

    Here we list all functions and types from the auxiliary library in alphabetical order.


    luaL_addchar

    void luaL_addchar (luaL_Buffer *B, char c);

    Adds the character c to the buffer B (see luaL_Buffer).


    luaL_addlstring

    void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

    Adds the string pointed to by s with length l to the buffer B (see luaL_Buffer). The string may contain embedded zeros.


    luaL_addsize

    void luaL_addsize (luaL_Buffer *B, size_t n);

    Adds to the buffer B (see luaL_Buffer) a string of length n previously copied to the buffer area (see luaL_prepbuffer).


    luaL_addstring

    void luaL_addstring (luaL_Buffer *B, const char *s);

    Adds the zero-terminated string pointed to by s to the buffer B (see luaL_Buffer). The string may not contain embedded zeros.


    luaL_addvalue

    void luaL_addvalue (luaL_Buffer *B);

    Adds the value at the top of the stack to the buffer B (see luaL_Buffer). Pops the value.

    This is the only function on string buffers that can (and must) be called with an extra element on the stack, which is the value to be added to the buffer.


    luaL_argcheck

    void luaL_argcheck (lua_State *L,
                        int cond,
                        int narg,
                        const char *extramsg);

    Checks whether cond is true. If not, raises an error with the following message, where func is retrieved from the call stack:

         bad argument #<narg> to <func> (<extramsg>)
    

    luaL_argerror

    int luaL_argerror (lua_State *L, int narg, const char *extramsg);

    Raises an error with the following message, where func is retrieved from the call stack:

         bad argument #<narg> to <func> (<extramsg>)
    

    This function never returns, but it is an idiom to use it in C functions as return luaL_argerror(args).


    luaL_Buffer

    typedef struct luaL_Buffer luaL_Buffer;

    Type for a string buffer.

    A string buffer allows C code to build Lua strings piecemeal. Its pattern of use is as follows:

    • First you declare a variable b of type luaL_Buffer.
    • Then you initialize it with a call luaL_buffinit(L, &b).
    • Then you add string pieces to the buffer calling any of the luaL_add* functions.
    • You finish by calling luaL_pushresult(&b). This call leaves the final string on the top of the stack.

    During its normal operation, a string buffer uses a variable number of stack slots. So, while using a buffer, you cannot assume that you know where the top of the stack is. You can use the stack between successive calls to buffer operations as long as that use is balanced; that is, when you call a buffer operation, the stack is at the same level it was immediately after the previous buffer operation. (The only exception to this rule is luaL_addvalue.) After calling luaL_pushresult the stack is back to its level when the buffer was initialized, plus the final string on its top.


    luaL_buffinit

    void luaL_buffinit (lua_State *L, luaL_Buffer *B);

    Initializes a buffer B. This function does not allocate any space; the buffer must be declared as a variable (see luaL_Buffer).


    luaL_callmeta

    int luaL_callmeta (lua_State *L, int obj, const char *e);

    Calls a metamethod.

    If the object at index obj has a metatable and this metatable has a field e, this function calls this field and passes the object as its only argument. In this case this function returns 1 and pushes onto the stack the value returned by the call. If there is no metatable or no metamethod, this function returns 0 (without pushing any value on the stack).


    luaL_checkany

    void luaL_checkany (lua_State *L, int narg);

    Checks whether the function has an argument of any type (including nil) at position narg.


    luaL_checkint

    int luaL_checkint (lua_State *L, int narg);

    Checks whether the function argument narg is a number and returns this number cast to an int.


    luaL_checkinteger

    lua_Integer luaL_checkinteger (lua_State *L, int narg);

    Checks whether the function argument narg is a number and returns this number cast to a lua_Integer.


    luaL_checklong

    long luaL_checklong (lua_State *L, int narg);

    Checks whether the function argument narg is a number and returns this number cast to a long.


    luaL_checklstring

    const char *luaL_checklstring (lua_State *L, int narg, size_t *l);

    Checks whether the function argument narg is a string and returns this string; if l is not NULL fills *l with the string's length.


    luaL_checknumber

    lua_Number luaL_checknumber (lua_State *L, int narg);

    Checks whether the function argument narg is a number and returns this number.


    luaL_checkoption

    int luaL_checkoption (lua_State *L,
                          int narg,
                          const char *def,
                          const char *const lst[]);

    Checks whether the function argument narg is a string and searches for this string in the array lst (which must be NULL-terminated). Returns the index in the array where the string was found. Raises an error if the argument is not a string or if the string cannot be found.

    If def is not NULL, the function uses def as a default value when there is no argument narg or if this argument is nil.

    This is a useful function for mapping strings to C enums. (The usual convention in Lua libraries is to use strings instead of numbers to select options.)


    luaL_checkstack

    void luaL_checkstack (lua_State *L, int sz, const char *msg);

    Grows the stack size to top + sz elements, raising an error if the stack cannot grow to that size. msg is an additional text to go into the error message.


    luaL_checkstring

    const char *luaL_checkstring (lua_State *L, int narg);

    Checks whether the function argument narg is a string and returns this string.


    luaL_checktype

    void luaL_checktype (lua_State *L, int narg, int t);

    Checks whether the function argument narg has type t.


    luaL_checkudata

    void *luaL_checkudata (lua_State *L, int narg, const char *tname);

    Checks whether the function argument narg is a userdata of the type tname (see luaL_newmetatable).


    luaL_dofile

    int luaL_dofile (lua_State *L, const char *filename);

    Loads and runs the given file. It is defined as the following macro:

         (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
    

    It returns 0 if there are no errors or 1 in case of errors.


    luaL_dostring

    int luaL_dostring (lua_State *L, const char *str);

    Loads and runs the given string. It is defined as the following macro:

         (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
    

    It returns 0 if there are no errors or 1 in case of errors.


    luaL_error

    int luaL_error (lua_State *L, const char *fmt, ...);

    Raises an error. The error message format is given by fmt plus any extra arguments, following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, if this information is available.

    This function never returns, but it is an idiom to use it in C functions as return luaL_error(args).


    luaL_getmetafield

    int luaL_getmetafield (lua_State *L, int obj, const char *e);

    Pushes onto the stack the field e from the metatable of the object at index obj. If the object does not have a metatable, or if the metatable does not have this field, returns 0 and pushes nothing.


    luaL_getmetatable

    void luaL_getmetatable (lua_State *L, const char *tname);

    Pushes onto the stack the metatable associated with name tname in the registry (see luaL_newmetatable).


    luaL_gsub

    const char *luaL_gsub (lua_State *L,
                           const char *s,
                           const char *p,
                           const char *r);

    Creates a copy of string s by replacing any occurrence of the string p with the string r. Pushes the resulting string on the stack and returns it.


    luaL_loadbuffer

    int luaL_loadbuffer (lua_State *L,
                         const char *buff,
                         size_t sz,
                         const char *name);

    Loads a buffer as a Lua chunk. This function uses lua_load to load the chunk in the buffer pointed to by buff with size sz.

    This function returns the same results as lua_load. name is the chunk name, used for debug information and error messages.


    luaL_loadfile

    int luaL_loadfile (lua_State *L, const char *filename);

    Loads a file as a Lua chunk. This function uses lua_load to load the chunk in the file named filename. If filename is NULL, then it loads from the standard input. The first line in the file is ignored if it starts with a #.

    This function returns the same results as lua_load, but it has an extra error code LUA_ERRFILE if it cannot open/read the file.

    As lua_load, this function only loads the chunk; it does not run it.


    luaL_loadstring

    int luaL_loadstring (lua_State *L, const char *s);

    Loads a string as a Lua chunk. This function uses lua_load to load the chunk in the zero-terminated string s.

    This function returns the same results as lua_load.

    Also as lua_load, this function only loads the chunk; it does not run it.


    luaL_newmetatable

    int luaL_newmetatable (lua_State *L, const char *tname);

    If the registry already has the key tname, returns 0. Otherwise, creates a new table to be used as a metatable for userdata, adds it to the registry with key tname, and returns 1.

    In both cases pushes onto the stack the final value associated with tname in the registry.


    luaL_newstate

    lua_State *luaL_newstate (void);

    Creates a new Lua state. It calls lua_newstate with an allocator based on the standard C realloc function and then sets a panic function (see lua_atpanic) that prints an error message to the standard error output in case of fatal errors.

    Returns the new state, or NULL if there is a memory allocation error.


    luaL_openlibs

    void luaL_openlibs (lua_State *L);

    Opens all standard Lua libraries into the given state.


    luaL_optint

    int luaL_optint (lua_State *L, int narg, int d);

    If the function argument narg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. Otherwise, raises an error.


    luaL_optinteger

    lua_Integer luaL_optinteger (lua_State *L,
                                 int narg,
                                 lua_Integer d);

    If the function argument narg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. Otherwise, raises an error.


    luaL_optlong

    long luaL_optlong (lua_State *L, int narg, long d);

    If the function argument narg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. Otherwise, raises an error.


    luaL_optlstring

    const char *luaL_optlstring (lua_State *L,
                                 int narg,
                                 const char *d,
                                 size_t *l);

    If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.

    If l is not NULL, fills the position *l with the results's length.


    luaL_optnumber

    lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);

    If the function argument narg is a number, returns this number. If this argument is absent or is nil, returns d. Otherwise, raises an error.


    luaL_optstring

    const char *luaL_optstring (lua_State *L,
                                int narg,
                                const char *d);

    If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.


    luaL_prepbuffer

    char *luaL_prepbuffer (luaL_Buffer *B);

    Returns an address to a space of size LUAL_BUFFERSIZE where you can copy a string to be added to buffer B (see luaL_Buffer). After copying the string into this space you must call luaL_addsize with the size of the string to actually add it to the buffer.


    luaL_pushresult

    void luaL_pushresult (luaL_Buffer *B);

    Finishes the use of buffer B leaving the final string on the top of the stack.


    luaL_ref

    int luaL_ref (lua_State *L, int t);

    Creates and returns a reference, in the table at index t, for the object at the top of the stack (and pops the object).

    A reference is a unique integer key. As long as you do not manually add integer keys into table t, luaL_ref ensures the uniqueness of the key it returns. You can retrieve an object referred by reference r by calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and its associated object.

    If the object at the top of the stack is nil, luaL_ref returns the constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be different from any reference returned by luaL_ref.


    luaL_Reg

    typedef struct luaL_Reg {
      const char *name;
      lua_CFunction func;
    } luaL_Reg;

    Type for arrays of functions to be registered by luaL_register. name is the function name and func is a pointer to the function. Any array of luaL_Reg must end with an sentinel entry in which both name and func are NULL.


    luaL_register

    void luaL_register (lua_State *L,
                        const char *libname,
                        const luaL_Reg *l);

    Opens a library.

    When called with libname equal to NULL, it simply registers all functions in the list l (see luaL_Reg) into the table on the top of the stack.

    When called with a non-null libname, luaL_register creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in variable libname, reuses this table instead of creating a new one.

    In any case the function leaves the table on the top of the stack.


    luaL_typename

    const char *luaL_typename (lua_State *L, int idx);

    Returns the name of the type of the value at index idx.


    luaL_typerror

    int luaL_typerror (lua_State *L, int narg, const char *tname);

    Generates an error with a message like the following:

         location: bad argument narg to 'func' (tname expected, got rt)
    

    where location is produced by luaL_where, func is the name of the current function, and rt is the type name of the actual argument.


    luaL_unref

    void luaL_unref (lua_State *L, int t, int ref);

    Releases reference ref from the table at index t (see luaL_ref). The entry is removed from the table, so that the referred object can be collected. The reference ref is also freed to be used again.

    If ref is LUA_NOREF or LUA_REFNIL, luaL_unref does nothing.


    luaL_where

    void luaL_where (lua_State *L, int lvl);

    Pushes onto the stack a string identifying the current position of the control at level lvl in the call stack. Typically this string has the following format:

         chunkname:currentline:
    

    Level 0 is the running function, level 1 is the function that called the running function, etc.

    This function is used to build a prefix for error messages.

    5 - Standard Libraries

    The standard Lua libraries provide useful functions that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, but are quite useful or have critical performance requirements that deserve an implementation in C (e.g., sort).

    All libraries are implemented through the official C API and are provided as separate C modules. Currently, Lua has the following standard libraries:

    • basic library;
    • package library;
    • string manipulation;
    • table manipulation;
    • mathematical functions (sin, log, etc.);
    • input and output;
    • operating system facilities;
    • debug facilities.

    Except for the basic and package libraries, each library provides all its functions as fields of a global table or as methods of its objects.

    To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base (for the basic library), luaopen_package (for the package library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_io (for the I/O and the Operating System libraries), and luaopen_debug (for the debug library). These functions are declared in lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call.

    5.1 - Basic Functions

    The basic library provides some core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide implementations for some of its facilities.


    assert (v [, message])

    Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!"


    collectgarbage (opt [, arg])

    This function is a generic interface to the garbage collector. It performs different functions according to its first argument, opt:

    • "stop": stops the garbage collector.
    • "restart": restarts the garbage collector.
    • "collect": performs a full garbage-collection cycle.
    • "count": returns the total memory in use by Lua (in Kbytes).
    • "step": performs a garbage-collection step. The step "size" is controlled by arg (larger values mean more steps) in a non-specified way. If you want to control the step size you must experimentally tune the value of arg. Returns true if the step finished a collection cycle.
    • "setpause": sets arg/100 as the new value for the pause of the collector (see §2.10).
    • "setstepmul": sets arg/100 as the new value for the step multiplier of the collector (see §2.10).


    dofile (filename)

    Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).


    error (message [, level])

    Terminates the last protected function called and returns message as the error message. Function error never returns.

    Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.


    _G

    A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; changing its value does not affect any environment, nor vice-versa. (Use setfenv to change environments.)


    getfenv ([f])

    Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.


    getmetatable (object)

    If object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object.


    ipairs (t)

    Returns three values: an iterator function, the table t, and 0, so that the construction

         for i,v in ipairs(t) do body end
    

    will iterate over the pairs (1,t[1]), (2,t[2]), ···, up to the first integer key absent from the table.


    load (func [, chunkname])

    Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of nil (or no value) signals the end of the chunk.

    If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

    chunkname is used as the chunk name for error messages and debug information.


    loadfile ([filename])

    Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.


    loadstring (string [, chunkname])

    Similar to load, but gets the chunk from the given string.

    To load and run a given string, use the idiom

         assert(loadstring(s))()
    


    next (table [, index])

    Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and its associated value. When called with nil as its second argument, next returns an initial index and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil. In particular, you can use next(t) to check whether a table is empty.

    The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.)

    The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.


    pairs (t)

    Returns three values: the next function, the table t, and nil, so that the construction

         for k,v in pairs(t) do body end
    

    will iterate over all key–value pairs of table t.

    See function next for the caveats of modifying the table during its traversal.


    pcall (f, arg1, ···)

    Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.


    print (···)

    Receives any number of arguments, and prints their values to stdout, using the tostring function to convert them to strings. print is not intended for formatted output, but only as a quick way to show a value, typically for debugging. For formatted output, use string.format.


    rawequal (v1, v2)

    Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean.


    rawget (table, index)

    Gets the real value of table[index], without invoking any metamethod. table must be a table; index may be any value.


    rawset (table, index, value)

    Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value.

    This function returns table.


    select (index, ···)

    If index is a number, returns all arguments after argument number index. Otherwise, index must be the string "#", and select returns the total number of extra arguments it received.


    setfenv (f, table)

    Sets the environment to be used by the given function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling setfenv. setfenv returns the given function.

    As a special case, when f is 0 setfenv changes the environment of the running thread. In this case, setfenv returns no values.


    setmetatable (table, metatable)

    Sets the metatable for the given table. (You cannot change the metatable of other types from Lua, only from C.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error.

    This function returns table.


    tonumber (e [, base])

    Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns this number; otherwise, it returns nil.

    An optional argument specifies the base to interpret the numeral. The base may be any integer between 2 and 36, inclusive. In bases above 10, the letter 'A' (in either upper or lower case) represents 10, 'B' represents 11, and so forth, with 'Z' representing 35. In base 10 (the default), the number may have a decimal part, as well as an optional exponent part (see §2.1). In other bases, only unsigned integers are accepted.


    tostring (e)

    Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, use string.format.

    If the metatable of e has a "__tostring" field, then tostring calls the corresponding value with e as argument, and uses the result of the call as its result.


    type (v)

    Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".


    unpack (list [, i [, j]])

    Returns the elements from the given table. This function is equivalent to
         return list[i], list[i+1], ···, list[j]
    

    except that the above code can be written only for a fixed number of elements. By default, i is 1 and j is the length of the list, as defined by the length operator (see §2.5.5).


    _VERSION

    A global variable (not a function) that holds a string containing the current interpreter version. The current contents of this variable is "Lua 5.1".


    xpcall (f, err)

    This function is similar to pcall, except that you can set a new error handler.

    xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In this case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from err.

    5.2 - Coroutine Manipulation

    The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine. See §2.11 for a general description of coroutines.


    coroutine.create (f)

    Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread".


    coroutine.resume (co [, val1, ···])

    Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield.

    If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.


    coroutine.running ()

    Returns the running coroutine, or nil when called by the main thread.


    coroutine.status (co)

    Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error.


    coroutine.wrap (f)

    Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.


    coroutine.yield (···)

    Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume.

    5.3 - Modules

    The package library provides basic facilities for loading and building modules in Lua. It exports two of its functions directly in the global environment: require and module. Everything else is exported in a table package.


    module (name [, ···])

    Creates a module. If there is a table in package.loaded[name], this table is the module. Otherwise, if there is a global table t with the given name, this table is the module. Otherwise creates a new table t and sets it as the value of the global name and the value of package.loaded[name]. This function also initializes t._NAME with the given name, t._M with the module (t itself), and t._PACKAGE with the package name (the full module name minus last component; see below). Finally, module sets t as the new environment of the current function and the new value of package.loaded[name], so that require returns t.

    If name is a compound name (that is, one with components separated by dots), module creates (or reuses, if they already exist) tables for each component. For instance, if name is a.b.c, then module stores the module table in field c of field b of global a.

    This function may receive optional options after the module name, where each option is a function to be applied over the module.


    require (modname)

    Loads the given module. The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.

    To find a loader, first require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see below).

    When loading a C library, require first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside this library to be used as the loader. The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed. For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c.

    If require finds neither a Lua library nor a C library for a module, it calls the all-in-one loader. This loader searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.

    Once a loader is found, require calls the loader with a single argument, modname. If the loader returns any value, require assigns the returned value to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].

    If there is any error loading or running the module, or if it cannot find any loader for the module, then require signals an error.


    package.cpath

    The path used by require to search for a C loader.

    Lua initializes the C path package.cpath in the same way it initializes the Lua path package.path, using the environment variable LUA_CPATH (plus another default path defined in luaconf.h).


    package.loaded

    A table used by require to control which modules are already loaded. When you require a module modname and package.loaded[modname] is not false, require simply returns the value stored there.


    package.loadlib (libname, funcname)

    Dynamically links the host program with the C library libname. Inside this library, looks for a function funcname and returns this function as a C function. (So, funcname must follow the protocol (see lua_CFunction)).

    This is a low-level function. It completely bypasses the package and module system. Unlike require, it does not perform any path searching and does not automatically adds extensions. libname must be the complete file name of the C library, including if necessary a path and extension. funcname must be the exact name exported by the C library (which may depend on the C compiler and linker used).

    This function is not supported by ANSI C. As such, it is only available on some platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support the dlfcn standard).


    package.path

    The path used by require to search for a Lua loader.

    At start-up, Lua initializes this variable with the value of the environment variable LUA_PATH or with a default path defined in luaconf.h, if the environment variable is not defined. Any ";;" in the value of the environment variable is replaced by the default path.

    A path is a sequence of templates separated by semicolons. For each template, require will change each interrogation mark in the template by filename, which is modname with each dot replaced by a "directory separator" (such as "/" in Unix); then it will try to load the resulting file name. So, for instance, if the Lua path is

         "./?.lua;./?.lc;/usr/local/?/init.lua"
    

    the search for a Lua loader for module foo will try to load the files ./foo.lua, ./foo.lc, and /usr/local/foo/init.lua, in that order.


    package.preload

    A table to store loaders for specific modules (see require).


    package.seeall (module)

    Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module.

    5.4 - String Manipulation

    This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position 1 (not at 0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.

    The string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s, i) can be written as s:byte(i).


    string.byte (s [, i [, j]])

    Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i.

    Note that numerical codes are not necessarily portable across platforms.


    string.char (···)

    Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument.

    Note that numerical codes are not necessarily portable across platforms.


    string.dump (function)

    Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues.


    string.find (s, pattern [, init [, plain]])

    Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given as well.

    If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.


    string.format (formatstring, ···)

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. For instance, the call
         string.format('%q', 'a string with "quotes" and \n new line')
    

    will produce the string:

         "a string with \"quotes\" and \
          new line"
    

    The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string.

    This function does not accept string values containing embedded zeros, except as arguments to the q option.


    string.gmatch (s, pattern)

    Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. If pattern specifies no captures, then the whole match is produced in each call.

    As an example, the following loop

         s = "hello world from Lua"
         for w in string.gmatch(s, "%a+") do
           print(w)
         end
    

    will iterate over all the words from string s, printing one per line. The next example collects all pairs key=value from the given string into a table:

         t = {}
         s = "from=world, to=Lua"
         for k, v in string.gmatch(s, "(%w+)=(%w+)") do
           t[k] = v
         end
    

    For this function, a '^' at the start of a pattern does not work as an anchor, as this would prevent the iteration.


    string.gsub (s, pattern, repl [, n])

    Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made.

    If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %n, with n between 1 and 9, stands for the value of the n-th captured substring (see below). The sequence %0 stands for the whole match. The sequence %% stands for a single %.

    If repl is a table, then the table is queried for every match, using the first capture as the key; if the pattern specifies no captures, then the whole match is used as the key.

    If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; if the pattern specifies no captures, then the whole match is passed as a sole argument.

    If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is false or nil, then there is no replacement (that is, the original match is kept in the string).

    The optional last parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of pattern is replaced.

    Here are some examples:

         x = string.gsub("hello world", "(%w+)", "%1 %1")
         --> x="hello hello world world"
         
         x = string.gsub("hello world", "%w+", "%0 %0", 1)
         --> x="hello hello world"
         
         x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
         --> x="world hello Lua from"
         
         x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
         --> x="home = /home/roberto, user = roberto"
         
         x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
               return loadstring(s)()
             end)
         --> x="4+5 = 9"
         
         local t = {name="lua", version="5.1"}
         x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
         --> x="lua-5.1.tar.gz"
    


    string.len (s)

    Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000bc\000" has length 5.


    string.lower (s)

    Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale.


    string.match (s, pattern [, init])

    Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative.


    string.rep (s, n)

    Returns a string that is the concatenation of n copies of the string s.


    string.reverse (s)

    Returns a string that is the string s reversed.


    string.sub (s, i [, j])

    Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.


    string.upper (s)

    Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale.

    5.4.1 - Patterns

    Character Class:

    A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:

    • x: (where x is not one of the magic characters ^$()%.[]*+-?) represents the character x itself.
    • .: (a dot) represents all characters.
    • %a: represents all letters.
    • %c: represents all control characters.
    • %d: represents all digits.
    • %l: represents all lowercase letters.
    • %p: represents all punctuation characters.
    • %s: represents all space characters.
    • %u: represents all uppercase letters.
    • %w: represents all alphanumeric characters.
    • %x: represents all hexadecimal digits.
    • %z: represents the character with representation 0.
    • %x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) can be preceded by a '%' when used to represent itself in a pattern.
    • [set]: represents the class which is the union of all characters in set. A range of characters may be specified by separating the end characters of the range with a '-'. All classes %x described above may also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) represents all alphanumeric characters plus the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus the lowercase letters plus the '-' character.

      The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning.

    • [^set]: represents the complement of set, where set is interpreted as above.

    For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters.

    The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l.

    Pattern Item:

    A pattern item may be

    • a single character class, which matches any single character in the class;
    • a single character class followed by '*', which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
    • a single character class followed by '+', which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
    • a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. Unlike '*', these repetition items will always match the shortest possible sequence;
    • a single character class followed by '?', which matches 0 or 1 occurrence of a character in the class;
    • %n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);
    • %bxy, where x and y are two distinct characters; such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right, counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses.

    Pattern:

    A pattern is a sequence of pattern items. A '^' at the beginning of a pattern anchors the match at the beginning of the subject string. A '$' at the end of a pattern anchors the match at the end of the subject string. At other positions, '^' and '$' have no special meaning and represent themselves.

    Captures:

    A pattern may contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number 1); the character matching "." is captured with number 2, and the part matching "%s*" has number 3.

    As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the string "flaaap", there will be two captures: 3 and 5.

    A pattern cannot contain embedded zeros. Use %z instead.

    5.5 - Table Manipulation

    This library provides generic functions for table manipulation. It provides all its functions inside the table table.

    Most functions in the table library assume that the table represents an array or a list. For these functions, when we talk about the "length" of a table we mean the result of the length operator.


    table.concat (table [, sep [, i [, j]]])

    Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string.


    table.insert (table, [pos,] value)

    Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, where n is the length of the table (see §2.5.5), so that a call table.insert(t,x) inserts x at the end of table t.


    table.maxn (table)

    Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. (To do its job this function does a linear traversal of the whole table.)


    table.remove (table [, pos])

    Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, where n is the length of the table, so that a call table.remove(t) removes the last element of table t.


    table.sort (table [, comp])

    Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. If comp is given, then it must be a function that receives two table elements, and returns true when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead.

    The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.

    5.6 - Mathematical Functions

    This library is an interface to the standard C math library. It provides all its functions inside the table math.


    math.abs (x)

    Returns the absolute value of x.


    math.acos (x)

    Returns the arc cosine of x (in radians).


    math.asin (x)

    Returns the arc sine of x (in radians).


    math.atan (x)

    Returns the arc tangent of x (in radians).


    math.atan2 (x, y)

    Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.)


    math.ceil (x)

    Returns the smallest integer larger than or equal to x.


    math.cos (x)

    Returns the cosine of x (assumed to be in radians).


    math.cosh (x)

    Returns the hyperbolic cosine of x.


    math.deg (x)

    Returns the angle x (given in radians) in degrees.


    math.exp (x)

    Returns the the value ex.


    math.floor (x)

    Returns the largest integer smaller than or equal to x.


    math.fmod (x, y)

    Returns the remainder of the division of x by y.


    math.frexp (x)

    Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).


    math.huge

    The value HUGE_VAL, a value larger than or equal to any other numerical value.


    math.ldexp (m, e)

    Returns m2e (e should be an integer).


    math.log (x)

    Returns the natural logarithm of x.


    math.log10 (x)

    Returns the base-10 logarithm of x.


    math.max (x, ···)

    Returns the maximum value among its arguments.


    math.min (x, ···)

    Returns the minimum value among its arguments.


    math.modf (x)

    Returns two numbers, the integral part of x and the fractional part of x.


    math.pi

    The value of pi.


    math.pow (x, y)

    Returns xy. (You can also use the expression x^y to compute this value.)


    math.rad (x)

    Returns the angle x (given in degrees) in radians.


    math.random ([m [, n]])

    This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.)

    When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].


    math.randomseed (x)

    Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers.


    math.sin (x)

    Returns the sine of x (assumed to be in radians).


    math.sinh (x)

    Returns the hyperbolic sine of x.


    math.sqrt (x)

    Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)


    math.tan (x)

    Returns the tangent of x (assumed to be in radians).


    math.tanh (x)

    Returns the hyperbolic tangent of x.

    5.7 - Input and Output Facilities

    The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors.

    When using implicit file descriptors, all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods of the file descriptor.

    The table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr.

    Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success.


    io.close ([file])

    Equivalent to file:close(). Without a file, closes the default output file.


    io.flush ()

    Equivalent to file:flush over the default output file.


    io.input ([file])

    When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file.

    In case of errors this function raises the error, instead of returning an error code.


    io.lines ([filename])

    Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

         for line in io.lines(filename) do body end
    

    will iterate over all lines of the file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file.

    The call io.lines() (with no file name) is equivalent to io.input():lines(); that is, it iterates over the lines of the default input file. In this case it does not close the file when the loop ends.


    io.open (filename [, mode])

    This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message.

    The mode string can be any of the following:

    • "r": read mode (the default);
    • "w": write mode;
    • "a": append mode;
    • "r+": update mode, all previous data is preserved;
    • "w+": update mode, all previous data is erased;
    • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

    The mode string may also have a 'b' at the end, which is needed in some systems to open the file in binary mode. This string is exactly what is used in the standard C function fopen.


    io.output ([file])

    Similar to io.input, but operates over the default output file.


    io.popen (prog [, mode])

    Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").

    This function is system dependent and is not available on all platforms.


    io.read (···)

    Equivalent to io.input():read.


    io.tmpfile ()

    Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends.


    io.type (obj)

    Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle.


    io.write (···)

    Equivalent to io.output():write.


    file:close ()

    Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.


    file:flush ()

    Saves any written data to file.


    file:lines ()

    Returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

         for line in file:lines() do body end
    

    will iterate over all lines of the file. (Unlike io.lines, this function does not close the file when the loop ends.)


    file:read (···)

    Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).

    The available formats are

    • "*n": reads a number; this is the only format that returns a number instead of a string.
    • "*a": reads the whole file, starting at the current position. On end of file, it returns the empty string.
    • "*l": reads the next line (skipping the end of line), returning nil on end of file. This is the default format.
    • number: reads a string with up to this number of characters, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.


    file:seek ([whence] [, offset])

    Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:

    • "set": base is position 0 (beginning of the file);
    • "cur": base is current position;
    • "end": base is end of file;

    In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. If this function fails, it returns nil, plus a string describing the error.

    The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek("set") sets the position to the beginning of the file (and returns 0); and the call file:seek("end") sets the position to the end of the file, and returns its size.


    file:setvbuf (mode [, size])

    Sets the buffering mode for an output file. There are three available modes:

    • "no": no buffering; the result of any output operation appears immediately.
    • "full": full buffering; output operation is performed only when the buffer is full (or when you explicitly flush the file (see io.flush)).
    • "line": line buffering; output is buffered until a newline is output or there is any input from some special files (such as a terminal device).

    For the last two cases, size specifies the size of the buffer, in bytes. The default is an appropriate size.


    file:write (···)

    Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write.

    5.8 - Operating System Facilities

    This library is implemented through table os.


    os.clock ()

    Returns an approximation of the amount in seconds of CPU time used by the program.


    os.date ([format [, time]])

    Returns a string or a table containing date and time, formatted according to the given string format.

    If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.

    If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), wday (weekday, Sunday is 1), yday (day of the year), and isdst (daylight saving flag, a boolean).

    If format is not "*t", then date returns the date as a string, formatted according to the same rules as the C function strftime.

    When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")).


    os.difftime (t2, t1)

    Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1.


    os.execute ([command])

    This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise.


    os.exit ([code])

    Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code.


    os.getenv (varname)

    Returns the value of the process environment variable varname, or nil if the variable is not defined.


    os.remove (filename)

    Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error.


    os.rename (oldname, newname)

    Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error.


    os.setlocale (locale [, category])

    Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored.

    If locale is the empty string, the current locate is set to an implementation-defined native locale. If locate is the string "C", the current locate is set to the standard C locale.

    When called with nil as the first argument, this function only returns the name of the current locale for the given category.


    os.time ([table])

    Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function).

    The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime.


    os.tmpname ()

    Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed.

    5.9 - The Debug Library

    This library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: they can be very slow. Moreover, several of its functions violate some assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside or that userdata metatables cannot be changed by Lua code) and therefore can compromise otherwise secure code.

    All functions in this library are provided inside the debug table. All functions that operate over a thread have an optional first argument which is the thread to operate over. The default is always the current thread.


    debug.debug ()

    Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.

    Note that commands for debug.debug are not lexically nested within any function, and so have no direct access to local variables.


    debug.getfenv (o)

    Returns the environment of object o.


    debug.gethook ([thread])

    Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).


    debug.getinfo ([thread,] function [, what])

    Returns a table with information about a function. You can give the function directly, or you can give a number as the value of function, which means the function running at level function of the call stack of the given thread: level 0 is the current function (getinfo itself); level 1 is the function that called getinfo; and so on. If function is a number larger than the number of active functions, then getinfo returns nil.

    The returned table may contain all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available, except the table of valid lines. If present, the option 'f' adds a field named func with the function itself. If present, the option 'L' adds a field named activelines with the table of valid lines.

    For instance, the expression debug.getinfo(1,"n").name returns a name of the current function, if a reasonable name can be found, and the expression debug.getinfo(print) returns a table with all available information about the print function.


    debug.getlocal ([thread,] level, local)

    This function returns the name and the value of the local variable with index local of the function at level level of the stack. (The first parameter or local variable has index 1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)

    Variable names starting with '(' (open parentheses) represent internal variables (loop control variables, temporaries, and C function locals).


    debug.getmetatable (object)

    Returns the metatable of the given object or nil if it does not have a metatable.


    debug.getregistry ()

    Returns the registry table (see §3.5).


    debug.getupvalue (func, up)

    This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index.


    debug.setfenv (object, table)

    Sets the environment of the given object to the given table. Returns object.


    debug.sethook ([thread,] hook, mask [, count])

    Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning:

    • "c": The hook is called every time Lua calls a function;
    • "r": The hook is called every time Lua returns from a function;
    • "l": The hook is called every time Lua enters a new line of code.

    With a count different from zero, the hook is called after every count instructions.

    When called without arguments, debug.sethook turns off the hook.

    When the hook is called, its first parameter is a string describing the event that has triggered its call: "call", "return" (or "tail return"), "line", and "count". For line events, the hook also gets the new line number as its second parameter. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level 0 is the getinfo function, and level 1 is the hook function), unless the event is "tail return". In this case, Lua is only simulating the return, and a call to getinfo will return invalid data.


    debug.setlocal ([thread,] level, local, value)

    This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.) Otherwise, it returns the name of the local variable.


    debug.setmetatable (object, table)

    Sets the metatable for the given object to the given table (which can be nil).


    debug.setupvalue (func, up, value)

    This function assigns the value value to the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue.


    debug.traceback ([thread,] [message] [, level])

    Returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. An optional level number tells at which level to start the traceback (default is 1, the function calling traceback).

    6 - Lua Stand-alone

    Although Lua has been designed as an extension language, to be embedded in a host C program, it is also frequently used as a stand-alone language. An interpreter for Lua as a stand-alone language, called simply lua, is provided with the standard distribution. The stand-alone interpreter includes all standard libraries, including the debug library. Its usage is:

         lua [options] [script [args]]
    

    The options are:

    • -e stat: executes string stat;
    • -l mod: "requires" mod;
    • -i: enters interactive mode after running script;
    • -v: prints version information;
    • --: stops handling options;
    • -: executes stdin as a file and stops handling options.

    After handling its options, lua runs the given script, passing to it the given args as string arguments. When called without arguments, lua behaves as lua -v -i when the standard input (stdin) is a terminal, and as lua - otherwise.

    Before running any argument, the interpreter checks for an environment variable LUA_INIT. If its format is @filename, then lua executes the file. Otherwise, lua executes the string itself.

    All options are handled in order, except -i. For instance, an invocation like

         $ lua -e'a=1' -e 'print(a)' script.lua
    

    will first set a to 1, then print the value of a (which is '1'), and finally run the file script.lua with no arguments. (Here $ is the shell prompt. Your prompt may be different.)

    Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored at index 0, the first argument after the script name goes to index 1, and so on. Any arguments before the script name (that is, the interpreter name plus the options) go to negative indices. For instance, in the call

         $ lua -la b.lua t1 t2
    

    the interpreter first runs the file a.lua, then creates a table

         arg = { [-2] = "lua", [-1] = "-la",
                 [0] = "b.lua",
                 [1] = "t1", [2] = "t2" }
    

    and finally runs the file b.lua. The script is called with arg[1], arg[2], ··· as arguments; it can also access these arguments with the vararg expression '...'.

    In interactive mode, if you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt.

    If the global variable _PROMPT contains a string, then its value is used as the prompt. Similarly, if the global variable _PROMPT2 contains a string, its value is used as the secondary prompt (issued during incomplete statements). Therefore, both prompts can be changed directly on the command line. For instance,

         $ lua -e"_PROMPT='myprompt> '" -i
    

    (the outer pair of quotes is for the shell, the inner pair is for Lua), or in any Lua programs by assigning to _PROMPT. Note the use of -i to enter interactive mode; otherwise, the program would just end silently right after the assignment to _PROMPT.

    To allow the use of Lua as a script interpreter in Unix systems, the stand-alone interpreter skips the first line of a chunk if it starts with #. Therefore, Lua scripts can be made into executable programs by using chmod +x and the #! form, as in

         #!/usr/local/bin/lua
    

    (Of course, the location of the Lua interpreter may be different in your machine. If lua is in your PATH, then

         #!/usr/bin/env lua
    

    is a more portable solution.)

    7 - Incompatibilities with the Previous Version

    Here we list the incompatibilities that you may found when moving a program from Lua 5.0 to Lua 5.1. You can avoid most of the incompatibilities compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua.

    7.1 - Changes in the Language

    • The vararg system changed from the pseudo-argument arg with a table with the extra arguments to the vararg expression. (See compile-time option LUA_COMPAT_VARARG in luaconf.h.)
    • There was a subtle change in the scope of the implicit variables of the for statement and for the repeat statement.
    • The long string/long comment syntax ([[string]]) does not allow nesting. You can use the new syntax ([=[string]=]) in these cases. (See compile-time option LUA_COMPAT_LSTR in luaconf.h.)

    7.2 - Changes in the Libraries

    • Function string.gfind was renamed string.gmatch. (See compile-time option LUA_COMPAT_GFIND in luaconf.h.)
    • When string.gsub is called with a function as its third argument, whenever this function returns nil or false the replacement string is the whole match, instead of the empty string.
    • Function table.setn was deprecated. Function table.getn corresponds to the new length operator (#); use the operator instead of the function. (See compile-time option LUA_COMPAT_GETN in luaconf.h.)
    • Function loadlib was renamed package.loadlib. (See compile-time option LUA_COMPAT_LOADLIB in luaconf.h.)
    • Function math.mod was renamed math.fmod. (See compile-time option LUA_COMPAT_MOD in luaconf.h.)
    • Functions table.foreach and table.foreachi are deprecated. You can use a for loop with pairs or ipairs instead.
    • There were substantial changes in function require due to the new module system. However, the new behavior is mostly compatible with the old, but require gets the path from package.path instead of from LUA_PATH.
    • Function collectgarbage has different arguments. Function gcinfo is deprecated; use collectgarbage("count") instead.

    7.3 - Changes in the API

    • The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function.
    • Function lua_open was replaced by lua_newstate to allow the user to set a memory-allocation function. You can use luaL_newstate from the standard library to create a state with a standard allocation function (based on realloc).
    • Functions luaL_getn and luaL_setn (from the auxiliary library) are deprecated. Use lua_objlen instead of luaL_getn and nothing instead of luaL_setn.
    • Function luaL_openlib was replaced by luaL_register.
    • Function luaL_checkudata now throws an error when the given value is not a userdata of the expected type. (In Lua 5.0 it returned NULL.)

    8 - The Complete Syntax of Lua

    Here is the complete syntax of Lua in extended BNF. (It does not describe operator precedences.)

    
    	chunk ::= {stat [`;´]} [laststat [`;´]]
    
    	block ::= chunk
    
    	stat ::=  varlist1 `=´ explist1 | 
    		 functioncall | 
    		 do block end | 
    		 while exp do block end | 
    		 repeat block until exp | 
    		 if exp then block {elseif exp then block} [else block] end | 
    		 for Name `=´ exp `,´ exp [`,´ exp] do block end | 
    		 for namelist in explist1 do block end | 
    		 function funcname funcbody | 
    		 local function Name funcbody | 
    		 local namelist [`=´ explist1] 
    
    	laststat ::= return [explist1] | break
    
    	funcname ::= Name {`.´ Name} [`:´ Name]
    
    	varlist1 ::= var {`,´ var}
    
    	var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 
    
    	namelist ::= Name {`,´ Name}
    
    	explist1 ::= {exp `,´} exp
    
    	exp ::=  nil | false | true | Number | String | `...´ | function | 
    		 prefixexp | tableconstructor | exp binop exp | unop exp 
    
    	prefixexp ::= var | functioncall | `(´ exp `)´
    
    	functioncall ::=  prefixexp args | prefixexp `:´ Name args 
    
    	args ::=  `(´ [explist1] `)´ | tableconstructor | String 
    
    	function ::= function funcbody
    
    	funcbody ::= `(´ [parlist1] `)´ block end
    
    	parlist1 ::= namelist [`,´ `...´] | `...´
    
    	tableconstructor ::= `{´ [fieldlist] `}´
    
    	fieldlist ::= field {fieldsep field} [fieldsep]
    
    	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
    
    	fieldsep ::= `,´ | `;´
    
    	binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
    		 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
    		 and | or
    
    	unop ::= `-´ | not | `#´
    
    


    Last update: Mon Mar 26 12:59:26 BRT 2007 infon/lua-5.1.2/doc/readme.html0000644000076400001440000000150110603200764016045 0ustar dividuumusers Lua documentation

    Lua Documentation

    This is the documentation included in the source distribution of Lua 5.1.2. Lua's official web site contains updated documentation, especially the reference manual.


    Last update: Fri Mar 23 14:19:36 BRT 2007 infon/lua-5.1.2/doc/cover.png0000644000076400001440000000635110603200764015556 0ustar dividuumusersPNG  IHDRE^N&gAMA a8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IIDATxKpy3,xc$@IQ/ 9r|MG_t%/TT"ǩr$Ŋh*IR$$žgb"¿pt)B[c>+Hh Cfm8.E]0~;dlz9RD^S,dqҕt יOhRV}]绢-;d$s3.Z %R;J>ɢOV)a)e@q= RǢt!eiҸ0A8Re _PLh iz(ƥQz;z= "aLT\V#(h O)LclCk&!AJv쎓LA%ƶh 5mQ:[ioC2ƶE5xxՠ2wp>bfRV*/5˟jljH4Oؔca dJQZQ6St:m3 eZssI^:J$R$R\u&Y($$Ρ! LLL"B5ÆI*/m0J1=o?t[$_$>!^y8Ado?w &?rzY&C%>KGgů߼r4O ۱LL2Ϳ?!_]F'q>:|9+wo2г5Mk\4&s)=Fn0RS{#۳gޘ6+Ϯp.R0Ǔ5"lOs2xottH)ǽx֛owigP!XȐkڸ_ntѾgǯNpzO^62 CGy; rH!j_o6Gl͎>|x?sBmqyΠ9H}s5P(㜾L:[_tkh%)iCC"h}>ՇZSFM H$ou%]?K7Wcߜ"[!^ JJZ۷g~_COq|nkؑZy`D#(Ksk{R?ٿӹv)e>_<}ڛosefal\T3/>Q.ҚuX|Ç"DbddR MY:[}>bfگg?*}=6C}~Utj,YLI,U9i;#{|s-Oomç 叆92\B3CowC,w#G@8Ӈ* \AJ^|OX;.=S[ܹWr]<}SN3˓|mL`ZUl瓋~(bH< ڼvpڛBy%|uP| oa؁RH W|Uk/h.}SQ16@wib>$өӄ|E^;N0NB6{⾺j(ik]F)^2yfk5|<(l ]yh?o\4Df1]<ϸ:bOu2y^=FthPz츌dg\!Q ORbHDn=;o29HD3Wy4-B6i EY)wxDuv5>dqh),WRȆdrܚh 84XX;|7vlo#̈,`qtIME7#IENDB`infon/lua-5.1.2/doc/luac.10000644000076400001440000000704110603200764014735 0ustar dividuumusers.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ .TH LUAC 1 "$Date: 2006/01/06 16:03:34 $" .SH NAME luac \- Lua compiler .SH SYNOPSIS .B luac [ .I options ] [ .I filenames ] .SH DESCRIPTION .B luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be later loaded and executed. .LP The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking. .LP Pre-compiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. .B luac simply allows those bytecodes to be saved in a file for later execution. .LP Pre-compiled chunks are not necessarily smaller than the corresponding source. The main goal in pre-compiling is faster loading. .LP The binary files created by .B luac are portable only among architectures with the same word size and byte order. .LP .B luac produces a single output file containing the bytecodes for all source files given. By default, the output file is named .BR luac.out , but you can change this with the .B \-o option. .LP In the command line, you can mix text files containing Lua source and binary files containing precompiled chunks. This is useful to combine several precompiled chunks, even from different (but compatible) platforms, into a single precompiled chunk. .LP You can use .B "'\-'" to indicate the standard input as a source file and .B "'\--'" to signal the end of options (that is, all remaining arguments will be treated as files even if they start with .BR "'\-'" ). .LP The internal format of the binary files produced by .B luac is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile. .LP .SH OPTIONS Options must be separate. .TP .B \-l produce a listing of the compiled bytecode for Lua's virtual machine. Listing bytecodes is useful to learn about Lua's virtual machine. If no files are given, then .B luac loads .B luac.out and lists its contents. .TP .BI \-o " file" output to .IR file , instead of the default .BR luac.out . (You can use .B "'\-'" for standard output, but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files. .TP .B \-p load files but do not generate any output file. Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. Lua always performs a thorough integrity test on precompiled chunks. Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. (None can be given, because the halting problem is unsolvable.) If no files are given, then .B luac loads .B luac.out and tests its contents. No messages are displayed if the file passes the integrity test. .TP .B \-s strip debug information before writing the output file. This saves some space in very large chunks, but if errors occur when running a stripped chunk, then the error messages may not contain the full information they usually do. For instance, line numbers and names of local variables are lost. .TP .B \-v show version information. .SH FILES .TP 15 .B luac.out default output file .SH "SEE ALSO" .BR lua (1) .br http://www.lua.org/ .SH DIAGNOSTICS Error messages should be self explanatory. .SH AUTHORS L. H. de Figueiredo, R. Ierusalimschy and W. Celes .\" EOF infon/lua-5.1.2/doc/logo.gif0000644000076400001440000001021010603200764015346 0ustar dividuumusersGIF87arvz}~ oooqqqvvvzzz !!%%""%%)),,55115511::::??BBDDBBEEJJHHLLMMPPTTQQWWYYZZ\\^^``ccggiijjoollqqvvttyy{{~~‰ËŎƐǒȕʙ˙̟ϡϢѥҩөԭ֯ױױصڻݼ,' H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIpִQ:(RJI;HGSSFAPȑA!rC+j D#:S Y:A mSNF1Rg.=2 @ ;5A)s.:)v 0`ϟlnp#rdDD#xЙ 643#LTFyPE+]s2Qk( ;gGΗPfh ( oNr,NiHG0^s& *92;!lX_mwDGU7 DX qIRw5EA&9MdMDHM(އhcYC$#!~8@I$~! $pP |@ c11abRI!``a㠁Y2qkD;Pv}6jǍ0}F^ipZDE ph2+ar&C }t.GEbC |,s69 P( y0DpVft%Af.KH?,nb9"|/GAH"} A#w:p;x5$sE-I";[Xwu85!KV}[A]$ܩepG pYC@ڄkn:m VXf2 BYzD3 ,.zs9PBD\ lf4y",Bscdqf(6J袋@\[$z@@B ˦=5ɢE8H Dk8F{R= ~}Ν `g-1,RBHe-Ms (!{QHm ` AcRf!F &D `Dvd!B07 ,^lأRPIh~ @r)`$ hC@AG"yX mB4i Y(D8& F+1Rh KIH+ @EJ I* #RWDBhD ,6o| m#DxBЪV@$Y B yC$B*$} ZE @asPJoQ| Η?BYeJB8JH,iuJ&9a!r(#D|,9|D'yF)_st$ @2^o'ЯCh>@dz,F!QHB6I( E9E;C\oh2B5+$T}mHCه:VGjM0$8!mhApfBɏ@ m:O<6t}p<1@"t$H "BZ-6lgq,:@|P aF #Q!a'Qi];$}^V_xpmѳq8K`m[@(m`q! B /[mrg&^&qt$ 6g)l ];FpHA(]r Ƃb`QAFkq72-KMΧh xw=XvA@@m‡ƺXZO/ ?xă(+D,d9}Ev XԽIe 0]4y}'W!)] B|Fq D ͧ?s!#F3_ӣ738 N>@8lH q[ JƱ7(hE6,sI7)F0Vp`[%W25fc"8t.Aa!D@i_qeG#UT4PFxE vDa~ R t<"(WAl-[uf$P%~w9W@xwHv{9whV65P\ "ufoDd2g>6-c0(Y< 1"1O*p)ЊPj*25 0% (@BanS{ DN/%Jҍ  (3 b1$X]RP9Z*)~N-#r]NhGpl с^@FY4}b/M !0U|Me=dE$>pM ~rJ-&&@.\ 87{3`%0ds+1Hh22PK3 W0uE)*U))+ @50FtEOKHP@}^ jH0}U`10 k咹EcVUK$A_z`TEΑUɕ4A֓<RrfPGBza"gd62(ayImF"qc("gAyP0i@eESҘYO9b4"}"x@'Pupj`22,*&qٕf%E+]B%f0YJ3f?1,/p?;}XV5Q%H1Z4JmpOP7d=O y;!ӑpeq!F PP-eKfw.lzp`- j`o@EPOv*RzUP uS@Ĩ!IO*PEAO` p\ P 1{:LSPU@QzRʪ#4PG`Nڬ;infon/lua-5.1.2/doc/lua.html0000644000076400001440000000755710603200764015412 0ustar dividuumusers LUA man page

    NAME

    lua - Lua interpreter

    SYNOPSIS

    lua [ options ] [ script [ args ] ]

    DESCRIPTION

    lua is the stand-alone Lua interpreter. It loads and executes Lua programs, either in textual source form or in precompiled binary form. (Precompiled binaries are output by luac, the Lua compiler.) lua can be used as a batch interpreter and also interactively.

    The given options (see below) are executed and then the Lua program in file script is loaded and executed. The given args are available to script as strings in a global table named arg. If these arguments contain spaces or other characters special to the shell, then they should be quoted (but note that the quotes will be removed by the shell). The arguments in arg start at 0, which contains the string 'script'. The index of the last argument is stored in arg.n. The arguments given in the command line before script, including the name of the interpreter, are available in negative indices in arg.

    At the very start, before even handling the command line, lua executes the contents of the environment variable LUA_INIT, if it is defined. If the value of LUA_INIT is of the form '@filename', then filename is executed. Otherwise, the string is assumed to be a Lua statement and is executed.

    Options start with '-' and are described below. You can use '--' to signal the end of options.

    If no arguments are given, then "-v -i" is assumed when the standard input is a terminal; otherwise, "-" is assumed.

    In interactive mode, lua prompts the user, reads lines from the standard input, and executes them as they are read. If a line does not contain a complete statement, then a secondary prompt is displayed and lines are read until a complete statement is formed or a syntax error is found. So, one way to interrupt the reading of an incomplete statement is to force a syntax error: adding a ';' in the middle of a statement is a sure way of forcing a syntax error (except inside multiline strings and comments; these must be closed explicitly). If a line starts with '=', then lua displays the values of all the expressions in the remainder of the line. The expressions must be separated by commas. The primary prompt is the value of the global variable _PROMPT, if this value is a string; otherwise, the default prompt is used. Similarly, the secondary prompt is the value of the global variable _PROMPT2. So, to change the prompts, set the corresponding variable to a string of your choice. You can do that after calling the interpreter or on the command line (but in this case you have to be careful with quotes if the prompt string contains a space; otherwise you may confuse the shell.) The default prompts are "> " and ">> ".

    OPTIONS

    - load and execute the standard input as a file, that is, not interactively, even when the standard input is a terminal.

    -e stat execute statement stat. You need to quote stat if it contains spaces, quotes, or other characters special to the shell.

    -i enter interactive mode after script is executed.

    -l name call require('name') before executing script. Typically used to load libraries.

    -v show version information.

    SEE ALSO

    luac(1)
    http://www.lua.org/

    DIAGNOSTICS

    Error messages should be self explanatory.

    AUTHORS

    R. Ierusalimschy, L. H. de Figueiredo, and W. Celes infon/lua-5.1.2/doc/manual.css0000644000076400001440000000010010603200764015703 0ustar dividuumusersh3 code { font-family: inherit ; } pre { font-size: 105% ; } infon/lua-5.1.2/doc/luac.html0000644000076400001440000000747010603200764015547 0ustar dividuumusers LUAC man page

    NAME

    luac - Lua compiler

    SYNOPSIS

    luac [ options ] [ filenames ]

    DESCRIPTION

    luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be later loaded and executed.

    The main advantages of precompiling chunks are: faster loading, protecting source code from accidental user changes, and off-line syntax checking.

    Precompiling does not imply faster execution because in Lua chunks are always compiled into bytecodes before being executed. luac simply allows those bytecodes to be saved in a file for later execution.

    Precompiled chunks are not necessarily smaller than the corresponding source. The main goal in precompiling is faster loading.

    The binary files created by luac are portable only among architectures with the same word size and byte order.

    luac produces a single output file containing the bytecodes for all source files given. By default, the output file is named luac.out, but you can change this with the -o option.

    In the command line, you can mix text files containing Lua source and binary files containing precompiled chunks. This is useful because several precompiled chunks, even from different (but compatible) platforms, can be combined into a single precompiled chunk.

    You can use '-' to indicate the standard input as a source file and '--' to signal the end of options (that is, all remaining arguments will be treated as files even if they start with '-').

    The internal format of the binary files produced by luac is likely to change when a new version of Lua is released. So, save the source files of all Lua programs that you precompile.

    OPTIONS

    Options must be separate.

    -l produce a listing of the compiled bytecode for Lua's virtual machine. Listing bytecodes is useful to learn about Lua's virtual machine. If no files are given, then luac loads luac.out and lists its contents.

    -o file output to file, instead of the default luac.out. (You can use '-' for standard output, but not on platforms that open standard output in text mode.) The output file may be a source file because all files are loaded before the output file is written. Be careful not to overwrite precious files.

    -p load files but do not generate any output file. Used mainly for syntax checking and for testing precompiled chunks: corrupted files will probably generate errors when loaded. Lua always performs a thorough integrity test on precompiled chunks. Bytecode that passes this test is completely safe, in the sense that it will not break the interpreter. However, there is no guarantee that such code does anything sensible. (None can be given, because the halting problem is unsolvable.) If no files are given, then luac loads luac.out and tests its contents. No messages are displayed if the file passes the integrity test.

    -s strip debug information before writing the output file. This saves some space in very large chunks, but if errors occur when running a stripped chunk, then the error messages may not contain the full information they usually do. For instance, line numbers and names of local variables are lost.

    -v show version information.

    FILES

    luac.out default output file

    SEE ALSO

    lua(1)
    http://www.lua.org/

    DIAGNOSTICS

    Error messages should be self explanatory.

    AUTHORS

    L. H. de Figueiredo, R. Ierusalimschy and W. Celes infon/lua-5.1.2/doc/lua.css0000644000076400001440000000111410603200764015215 0ustar dividuumusersbody { color: #000000 ; background-color: #FFFFFF ; font-family: sans-serif ; text-align: justify ; margin-right: 20px ; margin-left: 20px ; } h1, h2, h3, h4 { font-weight: normal ; font-style: italic ; } a:link { color: #000080 ; background-color: inherit ; text-decoration: none ; } a:visited { background-color: inherit ; text-decoration: none ; } a:link:hover, a:visited:hover { color: #000080 ; background-color: #E0E0FF ; } a:link:active, a:visited:active { color: #FF0000 ; } hr { border: 0 ; height: 1px ; color: #a0a0a0 ; background-color: #a0a0a0 ; } infon/lua-5.1.2/doc/amazon.gif0000644000076400001440000000143510603200764015704 0ustar dividuumusersGIF89aZg >>5p̙oo_䯯޾;;ѲW~ .tłԞ!,Z&dihl;2L tmx<|2pH,ȤrpZجvzEAMzn|CB5A ,老dxz   p   yi{|  l {|} i ϡ i|l}|{LYk@ XĈ(? B&s  =eM=k~G ,R7qi@,M #include #include #include #include #include /* This file uses only the official API of Lua. ** Any function declared here could be written as an application function. */ #define lauxlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #define FREELIST_REF 0 /* free list of references */ /* convert a stack index to positive */ #define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ lua_gettop(L) + (i) + 1) /* ** {====================================================== ** Error-report functions ** ======================================================= */ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ return luaL_error(L, "calling " LUA_QS " on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = "?"; return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", narg, ar.name, extramsg); } LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg)); return luaL_argerror(L, narg, msg); } static void tag_error (lua_State *L, int narg, int tag) { luaL_typerror(L, narg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; } } lua_pushliteral(L, ""); /* else, no information available... */ } LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); luaL_where(L, 1); lua_pushvfstring(L, fmt, argp); va_end(argp); lua_concat(L, 2); return lua_error(L); } /* }====================================================== */ LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; return luaL_argerror(L, narg, lua_pushfstring(L, "invalid option " LUA_QS, name)); } LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ if (!lua_isnil(L, -1)) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_newtable(L); /* create metatable */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ lua_pop(L, 2); /* remove both metatables */ return p; } } } luaL_typerror(L, ud, tname); /* else error */ return NULL; /* to avoid warnings */ } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { if (!lua_checkstack(L, space)) luaL_error(L, "stack overflow (%s)", mes); } LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { if (lua_type(L, narg) != t) tag_error(L, narg, t); } LUALIB_API void luaL_checkany (lua_State *L, int narg) { if (lua_type(L, narg) == LUA_TNONE) luaL_argerror(L, narg, "value expected"); } LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { const char *s = lua_tolstring(L, narg, len); if (!s) tag_error(L, narg, LUA_TSTRING); return s; } LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, const char *def, size_t *len) { if (lua_isnoneornil(L, narg)) { if (len) *len = (def ? strlen(def) : 0); return def; } else return luaL_checklstring(L, narg, len); } LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { lua_Number d = lua_tonumber(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { return luaL_opt(L, luaL_checknumber, narg, def); } LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { lua_Integer d = lua_tointeger(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ tag_error(L, narg, LUA_TNUMBER); return d; } LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, lua_Integer def) { return luaL_opt(L, luaL_checkinteger, narg, def); } LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; lua_pushstring(L, event); lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 2); /* remove metatable and metafield */ return 0; } else { lua_remove(L, -2); /* remove only metatable */ return 1; } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = abs_index(L, obj); if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); return 1; } LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l) { luaI_openlib(L, libname, l, 0); } static int libsize (const luaL_Reg *l) { int size = 0; for (; l->name; l++) size++; return size; } LUALIB_API void luaI_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { if (libname) { int size = libsize(l); /* check whether lib already exists */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); lua_getfield(L, -1, libname); /* get _LOADED[libname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) luaL_error(L, "name conflict for module " LUA_QS, libname); lua_pushvalue(L, -1); lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ lua_insert(L, -(nup+1)); /* move library table to below upvalues */ } for (; l->name; l++) { int i; for (i=0; ifunc, nup); lua_setfield(L, -(nup+2), l->name); } lua_pop(L, nup); /* remove upvalues */ } /* ** {====================================================== ** getn-setn: size for arrays ** ======================================================= */ #if defined(LUA_COMPAT_GETN) static int checkint (lua_State *L, int topop) { int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1; lua_pop(L, topop); return n; } static void getsizes (lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); if (lua_isnil(L, -1)) { /* no `size' table? */ lua_pop(L, 1); /* remove nil */ lua_newtable(L); /* create it */ lua_pushvalue(L, -1); /* `size' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */ } } LUALIB_API void luaL_setn (lua_State *L, int t, int n) { t = abs_index(L, t); lua_pushliteral(L, "n"); lua_rawget(L, t); if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ lua_pushliteral(L, "n"); /* use it */ lua_pushinteger(L, n); lua_rawset(L, t); } else { /* use `sizes' */ getsizes(L); lua_pushvalue(L, t); lua_pushinteger(L, n); lua_rawset(L, -3); /* sizes[t] = n */ lua_pop(L, 1); /* remove `sizes' */ } } LUALIB_API int luaL_getn (lua_State *L, int t) { int n; t = abs_index(L, t); lua_pushliteral(L, "n"); /* try t.n */ lua_rawget(L, t); if ((n = checkint(L, 1)) >= 0) return n; getsizes(L); /* else try sizes[t] */ lua_pushvalue(L, t); lua_rawget(L, -2); if ((n = checkint(L, 2)) >= 0) return n; return (int)lua_objlen(L, t); } #endif /* }====================================================== */ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ s = wild + l; /* continue after `p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); return lua_tostring(L, -1); } LUALIB_API const char *luaL_findtable (lua_State *L, int idx, const char *fname, int szhint) { const char *e; lua_pushvalue(L, idx); do { e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); lua_rawget(L, -2); if (lua_isnil(L, -1)) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ } else if (!lua_istable(L, -1)) { /* field has a non-table value? */ lua_pop(L, 2); /* remove table and value */ return fname; /* return problematic part of the name */ } lua_remove(L, -2); /* remove previous table */ fname = e + 1; } while (*e == '.'); return NULL; } /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ #define bufflen(B) ((B)->p - (B)->buffer) #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) #define LIMIT (LUA_MINSTACK/2) static int emptybuffer (luaL_Buffer *B) { size_t l = bufflen(B); if (l == 0) return 0; /* put nothing on stack */ else { lua_pushlstring(B->L, B->buffer, l); B->p = B->buffer; B->lvl++; return 1; } } static void adjuststack (luaL_Buffer *B) { if (B->lvl > 1) { lua_State *L = B->L; int toget = 1; /* number of levels to concat */ size_t toplen = lua_strlen(L, -1); do { size_t l = lua_strlen(L, -(toget+1)); if (B->lvl - toget + 1 >= LIMIT || toplen > l) { toplen += l; toget++; } else break; } while (toget < B->lvl); lua_concat(L, toget); B->lvl = B->lvl - toget + 1; } } LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { if (emptybuffer(B)) adjuststack(B); return B->buffer; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { while (l--) luaL_addchar(B, *s++); } LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { luaL_addlstring(B, s, strlen(s)); } LUALIB_API void luaL_pushresult (luaL_Buffer *B) { emptybuffer(B); lua_concat(B->L, B->lvl); B->lvl = 1; } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; size_t vl; const char *s = lua_tolstring(L, -1, &vl); if (vl <= bufffree(B)) { /* fit into buffer? */ memcpy(B->p, s, vl); /* put it there */ B->p += vl; lua_pop(L, 1); /* remove from stack */ } else { if (emptybuffer(B)) lua_insert(L, -2); /* put buffer before new value */ B->lvl++; /* add new value into B stack */ adjuststack(B); } } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->L = L; B->p = B->buffer; B->lvl = 0; } /* }====================================================== */ LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; t = abs_index(L, t); if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ } else { /* no free elements */ ref = (int)lua_objlen(L, t); ref++; /* create new reference */ } lua_rawseti(L, t, ref); return ref; } LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = abs_index(L, t); lua_rawgeti(L, t, FREELIST_REF); lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ lua_pushinteger(L, ref); lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ } } /* ** {====================================================== ** Load functions ** ======================================================= */ typedef struct LoadF { int extraline; FILE *f; char buff[LUAL_BUFFERSIZE]; } LoadF; static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; if (lf->extraline) { lf->extraline = 0; *size = 1; return "\n"; } if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); return (*size > 0) ? lf->buff : NULL; } static int errfile (lua_State *L, const char *what, int fnameindex) { const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { LoadF lf; int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ lf.extraline = 0; if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; } else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } c = getc(lf.f); if (c == '#') { /* Unix exec. file? */ lf.extraline = 1; while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ if (c == '\n') c = getc(lf.f); } if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */ fclose(lf.f); lf.f = fopen(filename, "rb"); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); /* skip eventual `#!...' */ while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; lf.extraline = 0; } ungetc(c, lf.f); status = lua_load(L, getF, &lf, lua_tostring(L, -1)); readstatus = ferror(lf.f); if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from `lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; } typedef struct LoadS { const char *s; size_t size; } LoadS; static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; (void)L; if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; return ls->s; } LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, const char *name) { LoadS ls; ls.s = buff; ls.size = size; return lua_load(L, getS, &ls, name); } LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); } static int panic (lua_State *L) { (void)L; /* to avoid warnings */ fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; } LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); if (L) lua_atpanic(L, &panic); return L; } infon/lua-5.1.2/src/ldebug.c0000644000076400001440000003654010603200765015366 0ustar dividuumusers/* ** $Id: ldebug.c,v 2.29a 2005/12/22 16:19:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ #include #include #include #define ldebug_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ if (ci == L->ci) ci->ctx = L->ctx; return pcRel(cast(const Instruction *, ci->ctx), ci_func(ci)->l.p); } static int currentline (lua_State *L, CallInfo *ci) { int pc = currentpc(L, ci); if (pc < 0) return -1; /* only active lua functions have current-line information */ else return getline(ci_func(ci)->l.p, pc); } /* ** this function can be called asynchronous (e.g. during a signal) */ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; } L->hook = func; L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); return 1; } LUA_API lua_Hook lua_gethook (lua_State *L) { return L->hook; } LUA_API int lua_gethookmask (lua_State *L) { return L->hookmask; } LUA_API int lua_gethookcount (lua_State *L) { return L->basehookcount; } LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; lua_lock(L); for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { level--; if (f_isLua(ci)) /* Lua function? */ level -= ci->tailcalls; /* skip lost tail calls */ } if (level == 0 && ci > L->base_ci) { /* level found? */ status = 1; ar->i_ci = cast_int(ci - L->base_ci); } else if (level < 0) { /* level is of a lost tail call? */ status = 1; ar->i_ci = 0; } else status = 0; /* no such level */ lua_unlock(L); return status; } static Proto *getluaproto (CallInfo *ci) { return (isLua(ci) ? ci_func(ci)->l.p : NULL); } static const char *findlocal (lua_State *L, CallInfo *ci, int n) { const char *name; Proto *fp = getluaproto(ci); if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) return name; /* is a local variable in a Lua function */ else { StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ return "(*temporary)"; else return NULL; } } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { CallInfo *ci = L->base_ci + ar->i_ci; const char *name = findlocal(L, ci, n); lua_lock(L); if (name) luaA_pushobject(L, ci->base + (n - 1)); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { CallInfo *ci = L->base_ci + ar->i_ci; const char *name = findlocal(L, ci, n); lua_lock(L); if (name) setobjs2s(L, ci->base + (n - 1), L->top - 1); L->top--; /* pop value */ lua_unlock(L); return name; } static void funcinfo (lua_Debug *ar, Closure *cl) { if (cl->c.isC) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; ar->what = "C"; } else { ar->source = getstr(cl->l.p->source); ar->linedefined = cl->l.p->linedefined; ar->lastlinedefined = cl->l.p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } static void info_tailcall (lua_Debug *ar) { ar->name = ar->namewhat = ""; ar->what = "tail"; ar->lastlinedefined = ar->linedefined = ar->currentline = -1; ar->source = "=(tail call)"; luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); ar->nups = 0; } static void collectvalidlines (lua_State *L, Closure *f) { if (f == NULL || f->c.isC) { setnilvalue(L->top); } else { Table *t = luaH_new(L, 0, 0); int *lineinfo = f->l.p->lineinfo; int i; for (i=0; il.p->sizelineinfo; i++) setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); sethvalue(L, L->top, t); } incr_top(L); } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; if (f == NULL) { info_tailcall(ar); return status; } for (; *what; what++) { switch (*what) { case 'S': { funcinfo(ar, f); break; } case 'l': { ar->currentline = (ci) ? currentline(L, ci) : -1; break; } case 'u': { ar->nups = f->c.nupvalues; break; } case 'n': { ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; } break; } case 'L': case 'f': /* handled by lua_getinfo */ break; default: status = 0; /* invalid option */ } } return status; } LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *f = NULL; CallInfo *ci = NULL; lua_lock(L); if (*what == '>') { StkId func = L->top - 1; luai_apicheck(L, ttisfunction(func)); what++; /* skip the '>' */ f = clvalue(func); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ ci = L->base_ci + ar->i_ci; lua_assert(ttisfunction(ci->func)); f = clvalue(ci->func); } status = auxgetinfo(L, what, ar, f, ci); if (strchr(what, 'f')) { if (f == NULL) setnilvalue(L->top); else setclvalue(L, L->top, f); incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, f); lua_unlock(L); return status; } /* ** {====================================================== ** Symbolic Execution and code checker ** ======================================================= */ #define check(x) if (!(x)) return 0; #define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) #define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) static int precheck (const Proto *pt) { check(pt->maxstacksize <= MAXSTACK); lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || (pt->is_vararg & VARARG_HASARG)); check(pt->sizeupvalues <= pt->nups); check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); return 1; } #define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) int luaG_checkopenop (Instruction i) { switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: case OP_RETURN: case OP_SETLIST: { check(GETARG_B(i) == 0); return 1; } default: return 0; /* invalid instruction after an open call */ } } static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { switch (mode) { case OpArgN: check(r == 0); break; case OpArgU: break; case OpArgR: checkreg(pt, r); break; case OpArgK: check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); break; } return 1; } static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); check(checkArgMode(pt, b, getBMode(op))); check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); if (getBMode(op) == OpArgR) { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); if (dest > 0) { /* cannot jump to a setlist count */ Instruction d = pt->code[dest-1]; check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); } } break; } } if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } switch (op) { case OP_LOADBOOL: { check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ break; } case OP_LOADNIL: { if (a <= reg && reg <= b) last = pc; /* set registers from `a' to `b' */ break; } case OP_GETUPVAL: case OP_SETUPVAL: { check(b < pt->nups); break; } case OP_GETGLOBAL: case OP_SETGLOBAL: { check(ttisstring(&pt->k[b])); break; } case OP_SELF: { checkreg(pt, a+1); if (reg == a+1) last = pc; break; } case OP_CONCAT: { check(b < c); /* at least two operands */ break; } case OP_TFORLOOP: { check(c >= 1); /* at least one result (control variable) */ checkreg(pt, a+2+c); /* space for results */ if (reg >= a+2) last = pc; /* affect all regs above its base */ break; } case OP_FORLOOP: case OP_FORPREP: checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ break; } case OP_CALL: case OP_TAILCALL: { if (b != 0) { checkreg(pt, a+b-1); } c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) checkreg(pt, a+c-1); if (reg >= a) last = pc; /* affect all registers above base */ break; } case OP_RETURN: { b--; /* b = num. returns */ if (b > 0) checkreg(pt, a+b-1); break; } case OP_SETLIST: { if (b > 0) checkreg(pt, a + b); if (c == 0) pc++; break; } case OP_CLOSURE: { int nup, j; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); for (j = 1; j <= nup; j++) { OpCode op1 = GET_OPCODE(pt->code[pc + j]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } if (reg != NO_REG) /* tracing? */ pc += nup; /* do not 'execute' these pseudo-instructions */ break; } case OP_VARARG: { check((pt->is_vararg & VARARG_ISVARARG) && !(pt->is_vararg & VARARG_NEEDSARG)); b--; if (b == LUA_MULTRET) check(checkopenop(pt, pc)); checkreg(pt, a+b-1); break; } default: break; } } return pt->code[last]; } #undef check #undef checkjump #undef checkreg /* }====================================================== */ int luaG_checkcode (const Proto *pt) { return (symbexec(pt, pt->sizecode, NO_REG) != 0); } static const char *kname (Proto *p, int c) { if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) return svalue(&p->k[INDEXK(c)]); else return "?"; } static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, const char **name) { if (isLua(ci)) { /* a Lua function? */ Proto *p = ci_func(ci)->l.p; int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ return "local"; i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { int g = GETARG_Bx(i); /* global index */ lua_assert(ttisstring(&p->k[g])); *name = svalue(&p->k[g]); return "global"; } case OP_MOVE: { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "field"; } case OP_GETUPVAL: { int u = GETARG_B(i); /* upvalue index */ *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; return "upvalue"; } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "method"; } default: break; } } return NULL; /* no useful name found */ } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { Instruction i; if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ i = ci_func(ci)->l.p->code[currentpc(L, ci)]; if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_TFORLOOP) return getobjname(L, ci, GETARG_A(i), name); else return NULL; /* no useful name can be found */ } /* only ANSI way to check whether a pointer points to an array */ static int isinstack (CallInfo *ci, const TValue *o) { StkId p; for (p = ci->base; p < ci->top; p++) if (o == p) return 1; return 0; } void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *name = NULL; const char *t = luaT_typenames[ttype(o)]; const char *kind = (isinstack(L->ci, o)) ? getobjname(L, L->ci, cast_int(o - L->base), &name) : NULL; if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); } void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { if (ttisstring(p1)) p1 = p2; lua_assert(!ttisstring(p1)); luaG_typeerror(L, p1, "concatenate"); } void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { TValue temp; if (luaV_tonumber(p1, &temp) == NULL) p2 = p1; /* first operand is wrong */ luaG_typeerror(L, p2, "perform arithmetic on"); } int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = luaT_typenames[ttype(p1)]; const char *t2 = luaT_typenames[ttype(p2)]; if (t1[2] == t2[2]) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); return 0; } static void addinfo (lua_State *L, const char *msg) { CallInfo *ci = L->ci; if (isLua(ci)) { /* is Lua code? */ char buff[LUA_IDSIZE]; /* add file:line information */ int line = currentline(L, ci); luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } } void luaG_runerror (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); addinfo(L, luaO_pushvfstring(L, fmt, argp)); va_end(argp); luaD_throw(L, LUA_ERRRUN); } infon/lua-5.1.2/src/lauxlib.h0000644000076400001440000001321510603200765015563 0ustar dividuumusers/* ** $Id: lauxlib.h,v 1.88 2006/04/12 20:31:15 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #ifndef lauxlib_h #define lauxlib_h #include #include #include "lua.h" #if defined(LUA_COMPAT_GETN) LUALIB_API int (luaL_getn) (lua_State *L, int t); LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); #else #define luaL_getn(L,i) ((int)lua_objlen(L, i)) #define luaL_setn(L,i,j) ((void)0) /* no op! */ #endif #if defined(LUA_COMPAT_OPENLIB) #define luaI_openlib luaL_openlib #endif /* extra error code for `luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg; LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); LUALIB_API void (luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l); LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, const char *def, size_t *l); LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, lua_Integer def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int narg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, const char *const lst[]); LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, const char *fname, int szhint); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define luaL_argcheck(L, cond,numarg,extramsg) \ ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) #define luaL_dofile(L, fn) \ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_dostring(L, s) \ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ typedef struct luaL_Buffer { char *p; /* current position in buffer */ int lvl; /* number of strings in the stack (level) */ lua_State *L; char buffer[LUAL_BUFFERSIZE]; } luaL_Buffer; #define luaL_addchar(B,c) \ ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ (*(B)->p++ = (char)(c))) /* compatibility only */ #define luaL_putchar(B,c) luaL_addchar(B,c) #define luaL_addsize(B,n) ((B)->p += (n)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); /* }====================================================== */ /* compatibility with ref system */ /* pre-defined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) #define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) #define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) #define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) #define luaL_reg luaL_Reg #endif infon/lua-5.1.2/src/ldebug.h0000644000076400001440000000176410603200765015373 0ustar dividuumusers/* ** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ #ifndef ldebug_h #define ldebug_h #include "lstate.h" #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) #define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) #define resethookcount(L) (L->hookcount = L->basehookcount) LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o, const char *opname); LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2); LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC int luaG_checkcode (const Proto *pt); LUAI_FUNC int luaG_checkopenop (Instruction i); #endif infon/lua-5.1.2/src/ltablib.c0000644000076400001440000001621310603200765015530 0ustar dividuumusers/* ** $Id: ltablib.c,v 1.38 2005/10/23 17:38:15 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #include #define ltablib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) static int foreachi (lua_State *L) { int n; int i = lua_icontext(L); if (i) { n = lua_tointeger(L, 3); /* get cached n */ goto resume; } n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); lua_settop(L, 2); lua_pushinteger(L, n); /* cache n because aux_getn may be expensive */ for (i=1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ lua_icall(L, 2, 1, i); resume: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 1); /* remove nil result */ } return 0; } static int foreach (lua_State *L) { if (lua_vcontext(L)) goto resume; luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pushvalue(L, 2); /* function */ lua_pushvalue(L, -3); /* key */ lua_pushvalue(L, -3); /* value */ lua_icall(L, 2, 1, 1); resume: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ } return 0; } static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pop(L, 1); /* remove value */ if (lua_type(L, -1) == LUA_TNUMBER) { lua_Number v = lua_tonumber(L, -1); if (v > max) max = v; } } lua_pushnumber(L, max); return 1; } static int getn (lua_State *L) { lua_pushinteger(L, aux_getn(L, 1)); return 1; } static int setn (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); #ifndef luaL_setn luaL_setn(L, 1, luaL_checkint(L, 2)); #else luaL_error(L, LUA_QL("setn") " is obsolete"); #endif lua_pushvalue(L, 1); return 1; } static int tinsert (lua_State *L) { int e = aux_getn(L, 1) + 1; /* first empty element */ int pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ if (pos > e) e = pos; /* `grow' array if necessary */ for (i = e; i > pos; i--) { /* move up elements */ lua_rawgeti(L, 1, i-1); lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ } break; } default: { return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); } } luaL_setn(L, 1, e); /* new size */ lua_rawseti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { int e = aux_getn(L, 1); int pos = luaL_optint(L, 2, e); if (e == 0) return 0; /* table is `empty' */ luaL_setn(L, 1, e - 1); /* t.n = n-1 */ lua_rawgeti(L, 1, pos); /* result = t[pos] */ for ( ;pos= P */ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i>u) luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* repeat --j until a[j] <= P */ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { if (j #include #include #include #define liolib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define IO_INPUT 1 #define IO_OUTPUT 2 static const char *const fnames[] = {"input", "output"}; static int pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (filename) lua_pushfstring(L, "%s: %s", filename, strerror(en)); else lua_pushfstring(L, "%s", strerror(en)); lua_pushinteger(L, en); return 3; } } static void fileerror (lua_State *L, int arg, const char *filename) { lua_pushfstring(L, "%s: %s", filename, strerror(errno)); luaL_argerror(L, arg, lua_tostring(L, -1)); } #define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) static int io_type (lua_State *L) { void *ud; luaL_checkany(L, 1); ud = lua_touserdata(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) lua_pushnil(L); /* not a file */ else if (*((FILE **)ud) == NULL) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); return 1; } static FILE *tofile (lua_State *L) { FILE **f = topfile(L); if (*f == NULL) luaL_error(L, "attempt to use a closed file"); return *f; } /* ** When creating file handles, always creates a `closed' file handle ** before opening the actual file; so, if there is a memory error, the ** file is not left opened. */ static FILE **newfile (lua_State *L) { FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); *pf = NULL; /* file handle is currently `closed' */ luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); return pf; } /* ** this function has a separated environment, which defines the ** correct __close for 'popen' files */ static int io_pclose (lua_State *L) { FILE **p = topfile(L); int ok = lua_pclose(L, *p); *p = NULL; return pushresult(L, ok, NULL); } static int io_fclose (lua_State *L) { FILE **p = topfile(L); int ok = (fclose(*p) == 0); *p = NULL; return pushresult(L, ok, NULL); } static int aux_close (lua_State *L) { lua_getfenv(L, 1); lua_getfield(L, -1, "__close"); return (lua_tocfunction(L, -1))(L); } static int io_close (lua_State *L) { if (lua_isnone(L, 1)) lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); tofile(L); /* make sure argument is a file */ return aux_close(L); } static int io_gc (lua_State *L) { FILE *f = *topfile(L); /* ignore closed files and standard files */ if (f != NULL && f != stdin && f != stdout && f != stderr) aux_close(L); return 0; } static int io_tostring (lua_State *L) { FILE *f = *topfile(L); if (f == NULL) lua_pushstring(L, "file (closed)"); else lua_pushfstring(L, "file (%p)", f); return 1; } static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = fopen(filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); FILE **pf = newfile(L); *pf = lua_popen(L, filename, mode); return (*pf == NULL) ? pushresult(L, 0, filename) : 1; } static int io_tmpfile (lua_State *L) { FILE **pf = newfile(L); *pf = tmpfile(); return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; } static FILE *getiofile (lua_State *L, int findex) { FILE *f; lua_rawgeti(L, LUA_ENVIRONINDEX, findex); f = *(FILE **)lua_touserdata(L, -1); if (f == NULL) luaL_error(L, "standard %s file is closed", fnames[findex - 1]); return f; } static int g_iofile (lua_State *L, int f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); if (filename) { FILE **pf = newfile(L); *pf = fopen(filename, mode); if (*pf == NULL) fileerror(L, 1, filename); } else { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } lua_rawseti(L, LUA_ENVIRONINDEX, f); } /* return current value */ lua_rawgeti(L, LUA_ENVIRONINDEX, f); return 1; } static int io_input (lua_State *L) { return g_iofile(L, IO_INPUT, "r"); } static int io_output (lua_State *L) { return g_iofile(L, IO_OUTPUT, "w"); } static int io_readline (lua_State *L); static void aux_lines (lua_State *L, int idx, int toclose) { lua_pushvalue(L, idx); lua_pushboolean(L, toclose); /* close/not close file when finished */ lua_pushcclosure(L, io_readline, 2); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ aux_lines(L, 1, 0); return 1; } static int io_lines (lua_State *L) { if (lua_isnoneornil(L, 1)) { /* no arguments? */ /* will iterate over default input */ lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); return f_lines(L); } else { const char *filename = luaL_checkstring(L, 1); FILE **pf = newfile(L); *pf = fopen(filename, "r"); if (*pf == NULL) fileerror(L, 1, filename); aux_lines(L, lua_gettop(L), 1); return 1; } } /* ** {====================================================== ** READ ** ======================================================= */ static int read_number (lua_State *L, FILE *f) { lua_Number d; if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { lua_pushnumber(L, d); return 1; } else return 0; /* read fails */ } static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); lua_pushlstring(L, NULL, 0); return (c != EOF); } static int read_line (lua_State *L, FILE *f) { luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { size_t l; char *p = luaL_prepbuffer(&b); if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ luaL_pushresult(&b); /* close buffer */ return (lua_strlen(L, -1) > 0); /* check whether read something */ } l = strlen(p); if (l == 0 || p[l-1] != '\n') luaL_addsize(&b, l); else { luaL_addsize(&b, l - 1); /* do not include `eol' */ luaL_pushresult(&b); /* close buffer */ return 1; /* read at least an `eol' */ } } } static int read_chars (lua_State *L, FILE *f, size_t n) { size_t rlen; /* how much to read */ size_t nr; /* number of chars actually read */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); if (rlen > n) rlen = n; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); n -= nr; /* still have to read `n' chars */ } while (n > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ return (n == 0 || lua_strlen(L, -1) > 0); } static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* number */ success = read_number(L, f); break; case 'l': /* line */ success = read_line(L, f); break; case 'a': /* file */ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (ferror(f)) return pushresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - first; } static int io_read (lua_State *L) { return g_read(L, getiofile(L, IO_INPUT), 1); } static int f_read (lua_State *L) { return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); int sucess; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); sucess = read_line(L, f); if (ferror(f)) return luaL_error(L, "%s", strerror(errno)); if (sucess) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; } } /* }====================================================== */ static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - 1; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; } else { size_t l; const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } return pushresult(L, status, NULL); } static int io_write (lua_State *L) { return g_write(L, getiofile(L, IO_OUTPUT), 1); } static int f_write (lua_State *L) { return g_write(L, tofile(L), 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); long offset = luaL_optlong(L, 3, 0); op = fseek(f, offset, mode[op]); if (op) return pushresult(L, 0, NULL); /* error */ else { lua_pushinteger(L, ftell(f)); return 1; } } static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], sz); return pushresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { return pushresult(L, fflush(tofile(L)) == 0, NULL); } static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, {"input", io_input}, {"lines", io_lines}, {"open", io_open}, {"output", io_output}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, {"write", io_write}, {NULL, NULL} }; static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, {"__gc", io_gc}, {"__tostring", io_tostring}, {NULL, NULL} }; static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_register(L, NULL, flib); /* file methods */ } static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { *newfile(L) = f; if (k > 0) { lua_pushvalue(L, -1); lua_rawseti(L, LUA_ENVIRONINDEX, k); } lua_setfield(L, -2, fname); } LUALIB_API int luaopen_io (lua_State *L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ lua_createtable(L, 2, 1); lua_replace(L, LUA_ENVIRONINDEX); /* open library */ luaL_register(L, LUA_IOLIBNAME, iolib); /* create (and set) default files */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); /* create environment for 'popen' */ lua_getfield(L, -1, "popen"); lua_createtable(L, 0, 1); lua_pushcfunction(L, io_pclose); lua_setfield(L, -2, "__close"); lua_setfenv(L, -2); lua_pop(L, 1); /* pop 'popen' */ /* set default close function */ lua_pushcfunction(L, io_fclose); lua_setfield(L, LUA_ENVIRONINDEX, "__close"); return 1; } infon/lua-5.1.2/src/lstrlib.c0000644000076400001440000005545510603200765015605 0ustar dividuumusers/* ** $Id: lstrlib.c,v 1.132a 2006/04/26 20:41:19 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lstrlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* macro to `unsign' a character */ #define uchar(c) ((unsigned char)(c)) static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushinteger(L, l); return 1; } static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { /* relative string position: negative means back from end */ return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; if (start <= end) lua_pushlstring(L, s+start-1, end-start+1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { size_t l; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); while (l--) luaL_addchar(&b, s[l]); luaL_pushresult(&b); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); luaL_buffinit(L, &b); for (i=0; i 0) luaL_addlstring(&b, s, l); luaL_pushresult(&b); return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi <= 0) posi = 1; if ((size_t)pose > l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ n = (int)(pose - posi + 1); if (posi + n <= pose) /* overflow? */ luaL_error(L, "string slice too long"); luaL_checkstack(L, n, "string slice too long"); for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index"); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { if (*p == '\0') luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a `]' */ if (*p == '\0') luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); if (*(p++) == L_ESC && *p != '\0') p++; /* skip escapes (e.g. `%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; case 'z' : res = (c == 0); break; default: return (cl == c); } return (islower(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the `^' */ } while (++p < ec) { if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int singlematch (int c, const char *p, const char *ep) { switch (*p) { case '.': return 1; /* matches any char */ case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } static const char *match (MatchState *ms, const char *s, const char *p); static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (*p == 0 || *(p+1) == 0) luaL_error(ms->L, "unbalanced pattern"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (ssrc_end && singlematch(uchar(*s), p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { init: /* using goto's to optimize tail recursion */ switch (*p) { case '(': { /* start capture */ if (*(p+1) == ')') /* position capture? */ return start_capture(ms, s, p+2, CAP_POSITION); else return start_capture(ms, s, p+1, CAP_UNFINISHED); } case ')': { /* end capture */ return end_capture(ms, s, p+1); } case L_ESC: { switch (*(p+1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p+2); if (s == NULL) return NULL; p+=4; goto init; /* else return match(ms, s, p+4); */ } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing " LUA_QL("[") " after " LUA_QL("%%f") " in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s-1); if (matchbracketclass(uchar(previous), p, ep-1) || !matchbracketclass(uchar(*s), p, ep-1)) return NULL; p=ep; goto init; /* else return match(ms, s, ep); */ } default: { if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p+1))); if (s == NULL) return NULL; p+=2; goto init; /* else return match(ms, s, p+2) */ } goto dflt; /* case default */ } } } case '\0': { /* end of pattern */ return s; /* match succeeded */ } case '$': { if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ return (s == ms->src_end) ? s : NULL; /* check end of string */ else goto dflt; } default: dflt: { /* it is a pattern item */ const char *ep = classend(ms, p); /* points to what is next */ int m = ssrc_end && singlematch(uchar(*s), p, ep); switch (*ep) { case '?': { /* optional */ const char *res; if (m && ((res=match(ms, s+1, ep+1)) != NULL)) return res; p=ep+1; goto init; /* else return match(ms, s, ep+1); */ } case '*': { /* 0 or more repetitions */ return max_expand(ms, s, p, ep); } case '+': { /* 1 or more repetitions */ return (m ? max_expand(ms, s+1, p, ep) : NULL); } case '-': { /* 0 or more repetitions (minimum) */ return min_expand(ms, s, p, ep); } default: { if (!m) return NULL; s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ } } } } } static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative `l1' */ else { const char *init; /* to search for a `*s2' inside `s1' */ l2--; /* 1st char will be checked by `memchr' */ l1 = l1-l2; /* `s2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; else { /* correct `l1' and `s1' to try again */ l1 -= init-s1; s1 = init; } } return NULL; /* not found */ } } static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else luaL_error(ms->L, "invalid capture index"); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ } static int str_find_aux (lua_State *L, int find) { size_t l1, l2; const char *s = luaL_checklstring(L, 1, &l1); const char *p = luaL_checklstring(L, 2, &l2); ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; if (init < 0) init = 0; else if ((size_t)(init) > l1) init = (ptrdiff_t)l1; if (find && (lua_toboolean(L, 4) || /* explicit request? */ strpbrk(p, SPECIALS) == NULL)) { /* or no special characters? */ /* do a plain search */ const char *s2 = lmemfind(s+init, l1-init, p, l2); if (s2) { lua_pushinteger(L, s2-s+1); lua_pushinteger(L, s2-s+l2); return 2; } } else { MatchState ms; int anchor = (*p == '^') ? (p++, 1) : 0; const char *s1=s+init; ms.L = L; ms.src_init = s; ms.src_end = s+l1; do { const char *res; ms.level = 0; if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, s1-s+1); /* start */ lua_pushinteger(L, res-s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else return push_captures(&ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int str_find (lua_State *L) { return str_find_aux(L, 1); } static int str_match (lua_State *L) { return str_find_aux(L, 0); } static int gmatch_aux (lua_State *L) { MatchState ms; size_t ls; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); const char *p = lua_tostring(L, lua_upvalueindex(2)); const char *src; ms.L = L; ms.src_init = s; ms.src_end = s+ls; for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); src <= ms.src_end; src++) { const char *e; ms.level = 0; if ((e = match(&ms, src, p)) != NULL) { lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ lua_pushinteger(L, newstart); lua_replace(L, lua_upvalueindex(3)); return push_captures(&ms, src, e); } } return 0; /* not found */ } static int gmatch (lua_State *L) { luaL_checkstring(L, 1); luaL_checkstring(L, 2); lua_settop(L, 2); lua_pushinteger(L, 0); lua_pushcclosure(L, gmatch_aux, 3); return 1; } static int gfind_nodef (lua_State *L) { return luaL_error(L, LUA_QL("string.gfind") " was renamed to " LUA_QL("string.gmatch")); } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; const char *news = lua_tolstring(ms->L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) luaL_addchar(b, news[i]); else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); luaL_addvalue(b); /* add capture to accumulated result */ } } } } static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { lua_State *L = ms->L; switch (lua_type(L, 3)) { case LUA_TNUMBER: case LUA_TSTRING: { add_s(ms, b, s, e); return; } case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(L, n, 1); break; } case LUA_TTABLE: { push_onecapture(ms, 0, s, e); lua_gettable(L, 3); break; } default: { luaL_argerror(L, 3, "string/function/table expected"); return; } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { size_t srcl; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checkstring(L, 2); int max_s = luaL_optint(L, 4, srcl+1); int anchor = (*p == '^') ? (p++, 1) : 0; int n = 0; MatchState ms; luaL_Buffer b; luaL_buffinit(L, &b); ms.L = L; ms.src_init = src; ms.src_end = src+srcl; while (n < max_s) { const char *e; ms.level = 0; e = match(&ms, src, p); if (e) { n++; add_value(&ms, &b, src, e); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushinteger(L, n); /* number of substitutions */ return 2; } /* }====================================================== */ /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ #define MAX_ITEM 512 /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as '%-099.99d') ** (+10 accounts for %99.99x plus margin of error) */ #define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { switch (*s) { case '"': case '\\': case '\n': { luaL_addchar(b, '\\'); luaL_addchar(b, *s); break; } case '\r': { luaL_addlstring(b, "\\r", 2); break; } case '\0': { luaL_addlstring(b, "\\000", 4); break; } default: { luaL_addchar(b, *s); break; } } s++; } luaL_addchar(b, '"'); } static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; strncpy(form, strfrmt, p - strfrmt + 1); form += p - strfrmt + 1; *form = '\0'; return p; } static void addintlen (char *form) { size_t l = strlen(form); char spec = form[l - 1]; strcpy(form + l - 1, LUA_INTFRMLEN); form[l + sizeof(LUA_INTFRMLEN) - 2] = spec; form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0'; } static int str_format (lua_State *L) { int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ char buff[MAX_ITEM]; /* to store the formatted item */ arg++; strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { sprintf(buff, form, (int)luaL_checknumber(L, arg)); break; } case 'd': case 'i': { addintlen(form); sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'o': case 'u': case 'x': case 'X': { addintlen(form); sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg)); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); continue; /* skip the 'addsize' at the end */ } case 's': { size_t l; const char *s = luaL_checklstring(L, arg, &l); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted; keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); continue; /* skip the `addsize' at the end */ } else { sprintf(buff, form, s); break; } } default: { /* also treat cases `pnLlh' */ return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " LUA_QL("format"), *(strfrmt - 1)); } } luaL_addlstring(&b, buff, strlen(buff)); } } luaL_pushresult(&b); return 1; } static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, {"dump", str_dump}, {"find", str_find}, {"format", str_format}, {"gfind", gfind_nodef}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, {"lower", str_lower}, {"match", str_match}, {"rep", str_rep}, {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, {NULL, NULL} }; static void createmetatable (lua_State *L) { lua_createtable(L, 0, 1); /* create metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); lua_setmetatable(L, -2); /* set string metatable */ lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* string library... */ lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ LUALIB_API int luaopen_string (lua_State *L) { luaL_register(L, LUA_STRLIBNAME, strlib); #if defined(LUA_COMPAT_GFIND) lua_getfield(L, -1, "gmatch"); lua_setfield(L, -2, "gfind"); #endif createmetatable(L); return 1; } infon/lua-5.1.2/src/lualib.h0000644000076400001440000000177610603200765015404 0ustar dividuumusers/* ** $Id: lualib.h,v 1.36 2005/12/27 17:12:00 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ #ifndef lualib_h #define lualib_h #include "lua.h" /* Key to file-handle type */ #define LUA_FILEHANDLE "FILE*" #define LUA_COLIBNAME "coroutine" LUALIB_API int (luaopen_base) (lua_State *L); #define LUA_TABLIBNAME "table" LUALIB_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUALIB_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" LUALIB_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUALIB_API int (luaopen_string) (lua_State *L); #define LUA_MATHLIBNAME "math" LUALIB_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUALIB_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" LUALIB_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); #ifndef lua_assert #define lua_assert(x) ((void)0) #endif #endif infon/lua-5.1.2/src/ldo.c0000644000076400001440000004324110603200765014676 0ustar dividuumusers/* ** $Id: ldo.c,v 2.38 2006/06/05 19:36:14 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #include #include #include #define ldo_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" #include "lzio.h" /* ** {====================================================== ** Error-recovery functions ** ======================================================= */ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; luai_jmpbuf b; volatile int status; /* error code */ }; void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); break; } case LUA_ERRERR: { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } case LUA_ERREXC: { setsvalue2s(L, oldtop, luaS_newliteral(L, "unhandled C++ exception")); break; } case LUA_ERRSYNTAX: case LUA_ERRRUN: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } L->top = oldtop + 1; } static void restore_stack_limit (lua_State *L) { lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ int inuse = cast_int(L->ci - L->base_ci); if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ luaD_reallocCI(L, LUAI_MAXCALLS); } } static void resetstack (lua_State *L, int status) { L->ci = L->base_ci; L->base = L->ci->base; luaF_close(L, L->base); /* close eventual pending closures */ luaD_seterrorobj(L, status, L->base); L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; restore_stack_limit(L); L->errorJmp = NULL; } /* search for an error handler in the frame stack and call it */ static int call_errfunc (lua_State *L) { CallInfo *ci; for (ci = L->ci; ci > L->base_ci && ci->errfunc == 0; ci--) ; if (ci->errfunc >= 2) { StkId errfunc = ci->base + (ci->errfunc - 2); if (!ttisfunction(errfunc)) return LUA_ERRERR; setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1, LUA_NOYIELD | LUA_NOVPCALL); /* call it */ } return LUA_ERRRUN; } void luaD_throw (lua_State *L, int errcode) { struct lua_longjmp *lj = L->errorJmp; if (lj) { if (errcode == LUA_ERRRUN) errcode = call_errfunc(L); lj->status = errcode; LUAI_THROW(L, lj); } else { L->status = cast_byte(errcode); if (G(L)->panic) { resetstack(L, errcode); lua_unlock(L); G(L)->panic(L); } exit(EXIT_FAILURE); } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { struct lua_longjmp lj; lj.status = 0; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, lj.status = (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } static int f_continue (lua_State *L, void *ud) { ptrdiff_t stop_ci = (ptrdiff_t)ud; while (L->ci > restoreci(L, stop_ci)) { /* continue frames, top to bottom */ CClosure *cc = &ci_func(L->ci)->c; L->ci->errfunc = 0; if (cc->isC) { /* continue C function */ int n; lua_assert(L->ctx != NULL); if (L->top > L->ci->top) L->ci->top = L->top; lua_unlock(L); n = (*cc->f)(L); /* (re-)call it */ lua_lock(L); if (n < 0) return LUA_YIELD; lua_assert(L->base + n <= L->top); luaD_poscall(L, L->top - n); } else { /* continue Lua function */ luaV_resume(L); if (luaV_execute(L)) return LUA_YIELD; } } return 0; } static int unwind_frames (lua_State *L, CallInfo *stop, ptrdiff_t old_top, int status) { CallInfo *ci; StkId otop; for (ci = L->ci; ci > stop; ci--) if (ci->errfunc) { /* found vpcall catch frame */ L->ctx = (void *)(ptrdiff_t)status; otop = L->ci > ci ? (ci+1)->func : L->top - 1; goto found; } if (old_top == 0) return -1; /* no unwind? */ otop = restorestack(L, old_top); found: luaF_close(L, otop); /* close eventual pending closures */ luaD_seterrorobj(L, status, otop); /* sets L->top, too */ L->ci = ci; L->base = ci->base; L->hookmask = ci->hookmask; restore_stack_limit(L); return ci == stop; } int luaD_pcall (lua_State *L, Pfunc func, void *ud, ptrdiff_t old_top, int ef, unsigned int flagmask) { int status; ptrdiff_t stop_ci = saveci(L, L->ci); unsigned int old_nCcalls = L->nCcalls; luaD_catch(L, ef); for (;;) { L->nCcalls = old_nCcalls & flagmask; status = luaD_rawrunprotected(L, func, ud); if (status == 0) break; if (unwind_frames(L, restoreci(L, stop_ci), old_top, status)) break; func = f_continue; ud = (void *)stop_ci; } lua_assert(L->ci == restoreci(L, stop_ci)); L->ci->errfunc = 0; L->nCcalls = old_nCcalls; return status; } /* }====================================================== */ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; GCObject *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->gch.next) gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->top = (ci->top - oldstack) + L->stack; ci->base = (ci->base - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; } L->base = (L->base - oldstack) + L->stack; } void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; int realsize = newsize + 1 + EXTRA_STACK; lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); L->stacksize = realsize; L->stack_last = L->stack+newsize; correctstack(L, oldstack); } void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); L->size_ci = newsize; L->ci = (L->ci - oldci) + L->base_ci; L->end_ci = L->base_ci + L->size_ci - 1; } void luaD_growstack (lua_State *L, int n) { if (n <= L->stacksize) /* double size is enough? */ luaD_reallocstack(L, 2*L->stacksize); else luaD_reallocstack(L, L->stacksize + n); } static CallInfo *growCI (lua_State *L) { if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ luaD_throw(L, LUA_ERRERR); else { luaD_reallocCI(L, 2*L->size_ci); if (L->size_ci > LUAI_MAXCALLS) luaG_runerror(L, "stack overflow"); } return ++L->ci; } void luaD_callhook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && !nohooks(L)) { ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, L->ci->top); lua_Debug ar; unsigned short old_nCcalls; ar.event = event; ar.currentline = line; if (event == LUA_HOOKTAILRET) ar.i_ci = 0; /* tail call; no debug information about it */ else ar.i_ci = cast_int(L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); old_nCcalls = L->nCcalls; L->nCcalls = old_nCcalls | (event >= LUA_HOOKLINE ? (LUA_NOVPCALL | LUA_NOHOOKS) : /* line+count hook can yield */ (LUA_NOVPCALL | LUA_NOHOOKS | LUA_NOYIELD)); lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(nohooks(L)); L->nCcalls = old_nCcalls; /* restore call flags */ L->ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); if (L->status == LUA_YIELD) { /* handle hook yield here, after restore */ L->base = L->top; /* protect Lua frame, undo this in f_coresume */ SAVEPC(L, GETPC(L) - 1); /* correct pc */ luaD_throw(L, LUA_YIELD); } } } static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; Table *htab = NULL; StkId base, fixed; for (; actual < nfixargs; ++actual) setnilvalue(L->top++); #if defined(LUA_COMPAT_VARARG) if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ int nvar = actual - nfixargs; /* number of extra arguments */ lua_assert(p->is_vararg & VARARG_HASARG); luaC_checkGC(L); htab = luaH_new(L, nvar, 1); /* create `arg' table */ for (i=0; itop - nvar + i); /* store counter in field `n' */ setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); } #endif /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i=0; itop++, fixed+i); setnilvalue(fixed+i); } /* add `arg' parameter */ if (htab) { sethvalue(L, L->top++, htab); lua_assert(iswhite(obj2gco(htab))); } return base; } static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); incr_top(L); func = restorestack(L, funcr); /* previous call may change stack */ setobj2s(L, func, tm); /* tag method is the new function to be called */ return func; } #define inc_ci(L) \ ((L->ci == L->end_ci) ? growCI(L) : \ (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) int luaD_precall (lua_State *L, StkId func, int nresults) { Closure *cl; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); cl = clvalue(func); L->ci->ctx = L->ctx; if (!cl->l.isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; Proto *p = cl->l.p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); if (!p->is_vararg) { /* no varargs? */ base = func + 1; if (L->top > base + p->numparams) L->top = base + p->numparams; } else { /* vararg function */ int nargs = cast_int(L->top - func) - 1; base = adjust_varargs(L, p, nargs); func = restorestack(L, funcr); /* previous call may change the stack */ } ci = inc_ci(L); /* now `enter' new function */ ci->func = func; L->base = ci->base = base; ci->top = L->base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); SAVEPC(L, p->code); /* starting point */ ci->tailcalls = 0; ci->nresults = cast(short, nresults); ci->errfunc = 0; for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; if (L->hookmask & LUA_MASKCALL) { const Instruction* pc = GETPC(L); SAVEPC(L, pc+1); /* hooks assume 'pc' is already incremented */ luaD_callhook(L, LUA_HOOKCALL, -1); SAVEPC(L, pc); /* correct 'pc' */ } return PCRLUA; } else { /* if is a C function, call it */ CallInfo *ci; int n; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci = inc_ci(L); /* now `enter' new function */ ci->func = restorestack(L, funcr); L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); L->ctx = NULL; /* initial vcontext */ ci->nresults = cast(short, nresults); ci->errfunc = 0; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*cl->c.f)(L); /* do the actual call */ lua_lock(L); if (n < 0) /* yielding? */ return PCRYIELD; else { luaD_poscall(L, L->top - n); return PCRC; } } } static StkId callrethooks (lua_State *L, StkId firstResult) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ luaD_callhook(L, LUA_HOOKRET, -1); if (f_isLua(L->ci)) { /* Lua function? */ while (L->ci->tailcalls--) /* call hook for eventual tail calls */ luaD_callhook(L, LUA_HOOKTAILRET, -1); } return restorestack(L, fr); } int luaD_poscall (lua_State *L, StkId firstResult) { StkId res; int wanted, i; CallInfo *ci; if (L->hookmask & LUA_MASKRET) firstResult = callrethooks(L, firstResult); ci = L->ci--; res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; L->base = (ci - 1)->base; /* restore base */ L->ctx = (ci - 1)->ctx; /* restore ctx */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); while (i-- > 0) setnilvalue(res++); L->top = res; return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ } /* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. */ void luaD_call (lua_State *L, StkId func, int nresults, int callflags) { unsigned short old_nCcalls = L->nCcalls; int pcr; G(L)->cycles -= 100; L->nCcalls = (old_nCcalls + 8) | callflags; if (L->nCcalls >= LUAI_MAXCCALLS*8) { if (L->nCcalls < (LUAI_MAXCCALLS+1)*8) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))*8) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } pcr = luaD_precall(L, func, nresults); if ((pcr == PCRLUA && luaV_execute(L)) || pcr == PCRYIELD) luaD_throw(L, LUA_YIELD); /* need to break C call boundary */ luaC_checkGC(L); L->nCcalls = old_nCcalls; } static int f_coresume (lua_State *L, void *ud) { StkId base = cast(StkId, ud); if (L->ctx == NULL) /* tail yield from C */ luaD_poscall(L, base); /* finish C call */ else if (f_isLua(L->ci)) { /* yield from Lua hook */ L->base = L->ci->base; /* restore invariant */ if (luaV_execute(L)) return LUA_YIELD; } else { /* resumable yield from C */ StkId rbase = L->base; if (rbase < base) { while (base < L->top) setobjs2s(L, rbase++, base++); /* move results down */ L->top = rbase; } L->base = L->ci->base; /* restore invariant */ } return f_continue(L, (void *)(ptrdiff_t)0); /* resume remaining frames */ } static int f_costart (lua_State *L, void *ud) { int pcr = luaD_precall(L, cast(StkId, ud), LUA_MULTRET); if ((pcr == PCRLUA && luaV_execute(L)) || pcr == PCRYIELD) return LUA_YIELD; else return 0; } static int resume_error (lua_State *L, const char *msg) { L->top = L->ci->base; setsvalue2s(L, L->top, luaS_new(L, msg)); incr_top(L); lua_unlock(L); return LUA_ERRRUN; } LUA_API int lua_resume (lua_State *L, int nargs) { Pfunc pf; void *ud; int status; lua_lock(L); switch (L->status) { case LUA_YIELD: pf = f_coresume; ud = L->top - nargs; L->status = 0; break; case 0: if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); pf = f_costart; ud = L->top - (nargs + 1); break; default: return resume_error(L, "cannot resume dead coroutine"); } lua_assert(cast(StkId, ud) >= L->base); for (;;) { L->nCcalls = 0; status = luaD_rawrunprotected(L, pf, ud); if (status <= LUA_YIELD) break; if (unwind_frames(L, L->base_ci, 0, status)) { /* fallthrough? */ /* keep frames for traceback, but mark coroutine as `dead' */ luaD_seterrorobj(L, status, L->top); break; } pf = f_continue; ud = (void *)(ptrdiff_t)0; /* (void *)saveci(L, L->base_ci); */ } L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; L->status = status; lua_unlock(L); return status; } LUA_API int lua_vyield (lua_State *L, int nresults, void *ctx) { lua_lock(L); if (noyield(L)) luaG_runerror(L, "attempt to yield across non-resumable call boundary"); lua_assert(L->ci > L->base_ci); if (!f_isLua(L->ci)) { /* usual yield */ L->ctx = ctx; L->base = L->top - nresults; /* no longer in sync with L->ci->base */ } L->status = LUA_YIELD; /* marker for luaD_callhook */ lua_unlock(L); return -1; } /* ** Execute a protected parser. */ struct SParser { /* data to `f_parser' */ ZIO *z; Mbuffer buff; /* buffer to be used by the scanner */ const char *name; }; static int f_parser (lua_State *L, void *ud) { int i; Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); L->nCcalls |= (LUA_NOYIELD | LUA_NOVPCALL); /* parser is not resumable */ luaC_checkGC(L); tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, &p->buff, p->name); cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); setclvalue(L, L->top, cl); incr_top(L); return 0; } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { struct SParser p; int status; p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), -1, ~0); /* -1 = inherit errfunc */ luaZ_freebuffer(L, &p.buff); return status; } infon/lua-5.1.2/src/ldump.c0000644000076400001440000000604310603200765015240 0ustar dividuumusers/* ** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define ldump_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" typedef struct { lua_State* L; lua_Writer writer; void* data; int strip; int status; } DumpState; #define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) #define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) static void DumpBlock(const void* b, size_t size, DumpState* D) { if (D->status==0) { lua_unlock(D->L); D->status=(*D->writer)(D->L,b,size,D->data); lua_lock(D->L); } } static void DumpChar(int y, DumpState* D) { char x=(char)y; DumpVar(x,D); } static void DumpInt(int x, DumpState* D) { DumpVar(x,D); } static void DumpNumber(lua_Number x, DumpState* D) { DumpVar(x,D); } static void DumpVector(const void* b, int n, size_t size, DumpState* D) { DumpInt(n,D); DumpMem(b,n,size,D); } static void DumpString(const TString* s, DumpState* D) { if (s==NULL || getstr(s)==NULL) { size_t size=0; DumpVar(size,D); } else { size_t size=s->tsv.len+1; /* include trailing '\0' */ DumpVar(size,D); DumpBlock(getstr(s),size,D); } } #define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) static void DumpFunction(const Proto* f, const TString* p, DumpState* D); static void DumpConstants(const Proto* f, DumpState* D) { int i,n=f->sizek; DumpInt(n,D); for (i=0; ik[i]; DumpChar(ttype(o),D); switch (ttype(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: DumpChar(bvalue(o),D); break; case LUA_TNUMBER: DumpNumber(nvalue(o),D); break; case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; default: lua_assert(0); /* cannot happen */ break; } } n=f->sizep; DumpInt(n,D); for (i=0; ip[i],f->source,D); } static void DumpDebug(const Proto* f, DumpState* D) { int i,n; n= (D->strip) ? 0 : f->sizelineinfo; DumpVector(f->lineinfo,n,sizeof(int),D); n= (D->strip) ? 0 : f->sizelocvars; DumpInt(n,D); for (i=0; ilocvars[i].varname,D); DumpInt(f->locvars[i].startpc,D); DumpInt(f->locvars[i].endpc,D); } n= (D->strip) ? 0 : f->sizeupvalues; DumpInt(n,D); for (i=0; iupvalues[i],D); } static void DumpFunction(const Proto* f, const TString* p, DumpState* D) { DumpString((f->source==p || D->strip) ? NULL : f->source,D); DumpInt(f->linedefined,D); DumpInt(f->lastlinedefined,D); DumpChar(f->nups,D); DumpChar(f->numparams,D); DumpChar(f->is_vararg,D); DumpChar(f->maxstacksize,D); DumpCode(f,D); DumpConstants(f,D); DumpDebug(f,D); } static void DumpHeader(DumpState* D) { char h[LUAC_HEADERSIZE]; luaU_header(h); DumpBlock(h,LUAC_HEADERSIZE,D); } /* ** dump Lua function as precompiled chunk */ int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { DumpState D; D.L=L; D.writer=w; D.data=data; D.strip=strip; D.status=0; DumpHeader(&D); DumpFunction(f,NULL,&D); return D.status; } infon/lua-5.1.2/src/ldo.h0000644000076400001440000000472610603200765014710 0ustar dividuumusers/* ** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #ifndef ldo_h #define ldo_h #include "lobject.h" #include "lstate.h" #include "lzio.h" #define luaD_checkstack(L,n) \ if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ luaD_growstack(L, n); \ else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); #define incr_top(L) {luaD_checkstack(L,1); L->top++;} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) #define saveci(L,p) ((char *)(p) - (char *)L->base_ci) #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) /* results from luaD_precall */ #define PCRLUA 0 /* initiated a call to a Lua function */ #define PCRC 1 /* did a call to a C function */ #define PCRYIELD 2 /* C function yielded */ /* call flags for luaD_call, stored in least significant bits of nCcalls */ #define LUA_NOHOOKS 1 #define LUA_NOVPCALL 2 #define LUA_NOYIELD 4 #define nohooks(L) (L->nCcalls & LUA_NOHOOKS) #define novpcall(L) (L->nCcalls & LUA_NOVPCALL) #define noyield(L) (L->nCcalls & LUA_NOYIELD) #define notresumable(L, stmt) \ { unsigned short save_ncc = L->nCcalls; \ L->nCcalls = save_ncc | (LUA_NOYIELD | LUA_NOVPCALL); \ stmt \ L->nCcalls = save_ncc; } /* type of protected functions, to be run by `runprotected' */ typedef int (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nresults, int callflags); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *ud, ptrdiff_t old_top, int ef, unsigned int flagmask); #define luaD_catch(L, ef) \ { lua_assert((ef) + 1 >= 0 && (ef) + 1 <= 255); \ L->ci->hookmask = L->hookmask; \ L->ci->errfunc = (ef) + 1; } LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); #endif infon/lua-5.1.2/src/loslib.c0000644000076400001440000001361110603200765015402 0ustar dividuumusers/* ** $Id: loslib.c,v 1.20 2006/09/19 13:57:08 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ #include #include #include #include #include #define loslib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int os_pushresult (lua_State *L, int i, const char *filename) { int en = errno; /* calls to Lua API may change this value */ if (i) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); lua_pushfstring(L, "%s: %s", filename, strerror(en)); lua_pushinteger(L, en); return 3; } } static int os_execute (lua_State *L) { lua_pushinteger(L, system(luaL_optstring(L, 1, NULL))); return 1; } static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return os_pushresult(L, remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return os_pushresult(L, rename(fromname, toname) == 0, fromname); } static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); if (err) return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; } static int os_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int os_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } static int getboolfield (lua_State *L, const char *key) { int res; lua_getfield(L, -1, key); res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } static int getfield (lua_State *L, const char *key, int d) { int res; lua_getfield(L, -1, key); if (lua_isnumber(L, -1)) res = (int)lua_tointeger(L, -1); else { if (d < 0) return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; } lua_pop(L, 1); return res; } static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); struct tm *stm; if (*s == '!') { /* UTC? */ stm = gmtime(&t); s++; /* skip `!' */ } else stm = localtime(&t); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char cc[3]; luaL_Buffer b; cc[0] = '%'; cc[2] = '\0'; luaL_buffinit(L, &b); for (; *s; s++) { if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ luaL_addchar(&b, *s); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ cc[1] = *(++s); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } } luaL_pushresult(&b); } return 1; } static int os_time (lua_State *L) { time_t t; if (lua_isnoneornil(L, 1)) /* called without args? */ t = time(NULL); /* get current time */ else { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); ts.tm_mday = getfield(L, "day", -1); ts.tm_mon = getfield(L, "month", -1) - 1; ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); } if (t == (time_t)(-1)) lua_pushnil(L); else lua_pushnumber(L, (lua_Number)t); return 1; } static int os_difftime (lua_State *L) { lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), (time_t)(luaL_optnumber(L, 2, 0)))); return 1; } /* }====================================================== */ static int os_setlocale (lua_State *L) { static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = luaL_optstring(L, 1, NULL); int op = luaL_checkoption(L, 2, "all", catnames); lua_pushstring(L, setlocale(cat[op], l)); return 1; } static int os_exit (lua_State *L) { exit(luaL_optint(L, 1, EXIT_SUCCESS)); return 0; /* to avoid warnings */ } static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, {"difftime", os_difftime}, {"execute", os_execute}, {"exit", os_exit}, {"getenv", os_getenv}, {"remove", os_remove}, {"rename", os_rename}, {"setlocale", os_setlocale}, {"time", os_time}, {"tmpname", os_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUALIB_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; } infon/lua-5.1.2/src/luac.c0000644000076400001440000001106510603200765015043 0ustar dividuumusers/* ** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $ ** Lua compiler (saves bytecodes to files; also list bytecodes) ** See Copyright Notice in lua.h */ #include #include #include #include #define luac_c #define LUA_CORE #include "lua.h" #include "lauxlib.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lstring.h" #include "lundump.h" #define PROGNAME "luac" /* default program name */ #define OUTPUT PROGNAME ".out" /* default output file */ static int listing=0; /* list bytecodes? */ static int dumping=1; /* dump bytecodes? */ static int stripping=0; /* strip debug information? */ static char Output[]={ OUTPUT }; /* default output file name */ static const char* output=Output; /* actual output file name */ static const char* progname=PROGNAME; /* actual program name */ static void fatal(const char* message) { fprintf(stderr,"%s: %s\n",progname,message); exit(EXIT_FAILURE); } static void cannot(const char* what) { fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno)); exit(EXIT_FAILURE); } static void usage(const char* message) { if (*message=='-') fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames].\n" "Available options are:\n" " - process stdin\n" " -l list\n" " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" " -- stop handling options\n", progname,Output); exit(EXIT_FAILURE); } #define IS(s) (strcmp(argv[i],s)==0) static int doargs(int argc, char* argv[]) { int i; int version=0; if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0]; for (i=1; itop+(i))->l.p) static const Proto* combine(lua_State* L, int n) { if (n==1) return toproto(L,-1); else { int i,pc; Proto* f=luaF_newproto(L); setptvalue2s(L,L->top,f); incr_top(L); f->source=luaS_newliteral(L,"=(" PROGNAME ")"); f->maxstacksize=1; pc=2*n+1; f->code=luaM_newvector(L,pc,Instruction); f->sizecode=pc; f->p=luaM_newvector(L,n,Proto*); f->sizep=n; pc=0; for (i=0; ip[i]=toproto(L,i-n-1); f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i); f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1); } f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0); return f; } } static int writer(lua_State* L, const void* p, size_t size, void* u) { UNUSED(L); return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0); } struct Smain { int argc; char** argv; }; static int pmain(lua_State* L) { struct Smain* s = (struct Smain*)lua_touserdata(L, 1); int argc=s->argc; char** argv=s->argv; const Proto* f; int i; if (!lua_checkstack(L,argc)) fatal("too many input files"); for (i=0; i1); if (dumping) { FILE* D= (output==NULL) ? stdout : fopen(output,"wb"); if (D==NULL) cannot("open"); lua_lock(L); luaU_dump(L,f,writer,D,stripping); lua_unlock(L); if (ferror(D)) cannot("write"); if (fclose(D)) cannot("close"); } return 0; } int main(int argc, char* argv[]) { lua_State* L; struct Smain s; int i=doargs(argc,argv); argc-=i; argv+=i; if (argc<=0) usage("no input files given"); L=lua_open(); if (L==NULL) fatal("not enough memory for state"); s.argc=argc; s.argv=argv; if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1)); lua_close(L); return EXIT_SUCCESS; } infon/lua-5.1.2/src/lundump.c0000644000076400001440000001064010603200765015601 0ustar dividuumusers/* ** $Id: lundump.c,v 1.60 2006/02/16 15:53:49 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #include #define lundump_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" typedef struct { lua_State* L; ZIO* Z; Mbuffer* b; const char* name; } LoadState; #ifdef LUAC_TRUST_BINARIES #define IF(c,s) #else #define IF(c,s) if (c) error(S,s) static void error(LoadState* S, const char* why) { luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); } #endif #define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) #define LoadByte(S) (lu_byte)LoadChar(S) #define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) static void LoadBlock(LoadState* S, void* b, size_t size) { size_t r=luaZ_read(S->Z,b,size); IF (r!=0, "unexpected end"); } static int LoadChar(LoadState* S) { char x; LoadVar(S,x); return x; } static int LoadInt(LoadState* S) { int x; LoadVar(S,x); IF (x<0, "bad integer"); return x; } static lua_Number LoadNumber(LoadState* S) { lua_Number x; LoadVar(S,x); return x; } static TString* LoadString(LoadState* S) { size_t size; LoadVar(S,size); if (size==0) return NULL; else { char* s=luaZ_openspace(S->L,S->b,size); LoadBlock(S,s,size); return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ } } static void LoadCode(LoadState* S, Proto* f) { int n=LoadInt(S); f->code=luaM_newvector(S->L,n,Instruction); f->sizecode=n; LoadVector(S,f->code,n,sizeof(Instruction)); } static Proto* LoadFunction(LoadState* S, TString* p); static void LoadConstants(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->k=luaM_newvector(S->L,n,TValue); f->sizek=n; for (i=0; ik[i]); for (i=0; ik[i]; int t=LoadChar(S); switch (t) { case LUA_TNIL: setnilvalue(o); break; case LUA_TBOOLEAN: setbvalue(o,LoadChar(S)); break; case LUA_TNUMBER: setnvalue(o,LoadNumber(S)); break; case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; default: IF (1, "bad constant"); break; } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; for (i=0; ip[i]=LoadFunction(S,f->source); } static void LoadDebug(LoadState* S, Proto* f) { int i,n; n=LoadInt(S); f->lineinfo=luaM_newvector(S->L,n,int); f->sizelineinfo=n; LoadVector(S,f->lineinfo,n,sizeof(int)); n=LoadInt(S); f->locvars=luaM_newvector(S->L,n,LocVar); f->sizelocvars=n; for (i=0; ilocvars[i].varname=NULL; for (i=0; ilocvars[i].varname=LoadString(S); f->locvars[i].startpc=LoadInt(S); f->locvars[i].endpc=LoadInt(S); } n=LoadInt(S); f->upvalues=luaM_newvector(S->L,n,TString*); f->sizeupvalues=n; for (i=0; iupvalues[i]=NULL; for (i=0; iupvalues[i]=LoadString(S); } static Proto* LoadFunction(LoadState* S, TString* p) { Proto* f=luaF_newproto(S->L); setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->source=LoadString(S); if (f->source==NULL) f->source=p; f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->nups=LoadByte(S); f->numparams=LoadByte(S); f->is_vararg=LoadByte(S); f->maxstacksize=LoadByte(S); LoadCode(S,f); LoadConstants(S,f); LoadDebug(S,f); IF (!luaG_checkcode(f), "bad code"); S->L->top--; return f; } static void LoadHeader(LoadState* S) { char h[LUAC_HEADERSIZE]; char s[LUAC_HEADERSIZE]; luaU_header(h); LoadBlock(S,s,LUAC_HEADERSIZE); IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header"); } /* ** load precompiled chunk */ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; if (*name=='@' || *name=='=') S.name=name+1; else if (*name==LUA_SIGNATURE[0]) S.name="binary string"; else S.name=name; S.L=L; S.Z=Z; S.b=buff; LoadHeader(&S); return LoadFunction(&S,luaS_newliteral(L,"=?")); } /* * make header */ void luaU_header (char* h) { int x=1; memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1); h+=sizeof(LUA_SIGNATURE)-1; *h++=(char)LUAC_VERSION; *h++=(char)LUAC_FORMAT; *h++=(char)*(char*)&x; /* endianness */ *h++=(char)sizeof(int); *h++=(char)sizeof(size_t); *h++=(char)sizeof(Instruction); *h++=(char)sizeof(lua_Number); *h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */ } infon/lua-5.1.2/src/ldblib.c0000644000076400001440000002374510603200765015357 0ustar dividuumusers/* ** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #include #include #include #define ldblib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; } static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); /* no metatable */ } return 1; } static int db_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); lua_pushboolean(L, lua_setmetatable(L, 1)); return 1; } static int db_getfenv (lua_State *L) { lua_getfenv(L, 1); return 1; } static int db_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); lua_settop(L, 2); if (lua_setfenv(L, 1) == 0) luaL_error(L, LUA_QL("setfenv") " cannot change environment of given object"); return 1; } static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, v); lua_setfield(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushinteger(L, v); lua_setfield(L, -2, i); } static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; return lua_tothread(L, 1); } else { *arg = 0; return L; } } static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { if (L == L1) { lua_pushvalue(L, -2); lua_remove(L, -3); } else lua_xmove(L1, L, 1); lua_setfield(L, -2, fname); } static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnSu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); } else return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) settabsi(L, "nups", ar.nups); if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } static int db_getlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); if (name) { lua_xmove(L1, L, 1); lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; } else { lua_pushnil(L); return 1; } } static int db_setlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); lua_xmove(L, L1, 1); lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); return 1; } static int auxupvalue (lua_State *L, int get) { const char *name; int n = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); return get + 1; } static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } static const char KEY_HOOK = 'h'; static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail return"}; lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushlightuserdata(L, L); lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) lua_pushinteger(L, ar->currentline); else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); } } static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (count > 0) mask |= LUA_MASKCOUNT; return mask; } static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; if (mask & LUA_MASKRET) smask[i++] = 'r'; if (mask & LUA_MASKLINE) smask[i++] = 'l'; smask[i] = '\0'; return smask; } static void gethooktable (lua_State *L) { lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); if (!lua_istable(L, -1)) { lua_pop(L, 1); lua_createtable(L, 0, 1); lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); } } static int db_sethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); if (lua_isnoneornil(L, arg+1)) { lua_settop(L, arg+1); lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); int count = luaL_optint(L, arg+3, 0); luaL_checktype(L, arg+1, LUA_TFUNCTION); lua_sethook(L1, hookf, makemask(smask, count), count); } gethooktable(L1); lua_pushlightuserdata(L1, L1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); lua_rawset(L1, -3); /* set new hook */ lua_pop(L1, 1); /* remove hook table */ return 0; } static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); if (hook != NULL && hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { gethooktable(L1); lua_pushlightuserdata(L1, L1); lua_rawget(L1, -2); /* get hook */ lua_remove(L1, -2); /* remove hook table */ lua_xmove(L1, L, 1); } lua_pushstring(L, unmakemask(mask, buff)); lua_pushinteger(L, lua_gethookcount(L1)); return 3; } static int db_debug (lua_State *L) { for (;;) { char buffer[250]; fputs("lua_debug> ", stderr); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) { fputs(lua_tostring(L, -1), stderr); fputs("\n", stderr); } lua_settop(L, 0); /* remove eventual returns */ } } #define LEVELS1 12 /* size of the first part of the stack */ #define LEVELS2 10 /* size of the second part of the stack */ static int db_errorfb (lua_State *L) { int level; int firstpart = 1; /* still before eventual `...' */ int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; if (lua_isnumber(L, arg+2)) { level = (int)lua_tointeger(L, arg+2); luaL_argcheck(L, level >= 0, arg+2, "level must be non-negative"); lua_pop(L, 1); } else level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ if (lua_gettop(L) == arg) lua_pushliteral(L, ""); else if (lua_isnil(L, arg+1)) { lua_pushliteral(L, ""); lua_replace(L, arg+1); } else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ else lua_pushliteral(L, "\r\n"); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ if (!lua_getstack(L1, level+LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\r\n\t..."); /* too many levels */ while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_pushliteral(L, "\r\n\t"); lua_getinfo(L1, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); if (*ar.namewhat != '\0') /* is there a name? */ lua_pushfstring(L, " in function " LUA_QS, ar.name); else { if (*ar.what == 'm') /* main? */ lua_pushfstring(L, " in main chunk"); else if (*ar.what == 'C' || *ar.what == 't') lua_pushliteral(L, " ?"); /* C function or tail call */ else lua_pushfstring(L, " in function <%s:%d>", ar.short_src, ar.linedefined); } lua_concat(L, lua_gettop(L) - arg); } lua_concat(L, lua_gettop(L) - arg); return 1; } static const luaL_Reg dblib[] = { {"debug", db_debug}, {"getfenv", db_getfenv}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, {"setfenv", db_setfenv}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, {"traceback", db_errorfb}, {NULL, NULL} }; LUALIB_API int luaopen_debug (lua_State *L) { luaL_register(L, LUA_DBLIBNAME, dblib); return 1; } infon/lua-5.1.2/src/lundump.h0000644000076400001440000000156210603200765015611 0ustar dividuumusers/* ** $Id: lundump.h,v 1.40 2005/11/11 14:03:13 lhf Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #ifndef lundump_h #define lundump_h #include "lobject.h" #include "lzio.h" /* load one chunk; from lundump.c */ LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ LUAI_FUNC void luaU_header (char* h); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); #ifdef luac_c /* print one chunk; from print.c */ LUAI_FUNC void luaU_print (const Proto* f, int full); #endif /* for header of binary files -- this is Lua 5.1 */ #define LUAC_VERSION 0x51 /* for header of binary files -- this is the official format */ #define LUAC_FORMAT 0 /* size of header of binary files */ #define LUAC_HEADERSIZE 12 #endif infon/lua-5.1.2/src/lmem.c0000644000076400001440000000417010603200765015050 0ustar dividuumusers/* ** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #include #define lmem_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** (`osize' is the old size, `nsize' is the new size) ** ** Lua ensures that (ptr == NULL) iff (osize == 0). ** ** * frealloc(ud, NULL, 0, x) creates a new block of size `x' ** ** * frealloc(ud, p, x, 0) frees the block `p' ** (in this specific case, frealloc must return NULL). ** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ANSI C) ** ** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) */ #define MINSIZEARRAY 4 void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, int limit, const char *errormsg) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ if (*size >= limit) /* cannot grow even a little? */ luaG_runerror(L, errormsg); newsize = limit; /* still have at least one free place */ } else { newsize = (*size)*2; if (newsize < MINSIZEARRAY) newsize = MINSIZEARRAY; /* minimum size */ } newblock = luaM_reallocv(L, block, *size, newsize, size_elems); *size = newsize; /* update only when everything else is OK */ return newblock; } void *luaM_toobig (lua_State *L) { luaG_runerror(L, "memory allocation error: block too big"); return NULL; /* to avoid warnings */ } /* ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); block = (*g->frealloc)(g->ud, block, osize, nsize); if (block == NULL && nsize > 0) luaD_throw(L, LUA_ERRMEM); lua_assert((nsize == 0) == (block == NULL)); g->totalbytes = (g->totalbytes - osize) + nsize; return block; } infon/lua-5.1.2/src/lmathlib.c0000644000076400001440000001330310603200765015710 0ustar dividuumusers/* ** $Id: lmathlib.c,v 1.67 2005/08/26 17:36:32 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ #include #include #define lmathlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" #undef PI #define PI (3.14159265358979323846) #define RADIANS_PER_DEGREE (PI/180.0) static int math_abs (lua_State *L) { lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { lua_pushnumber(L, sin(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { lua_pushnumber(L, sinh(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { lua_pushnumber(L, cos(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { lua_pushnumber(L, cosh(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { lua_pushnumber(L, tan(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { lua_pushnumber(L, tanh(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { lua_pushnumber(L, asin(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { lua_pushnumber(L, acos(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { lua_pushnumber(L, atan(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { lua_pushnumber(L, floor(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { double ip; double fp = modf(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_log (lua_State *L) { lua_pushnumber(L, log(luaL_checknumber(L, 1))); return 1; } static int math_log10 (lua_State *L) { lua_pushnumber(L, log10(luaL_checknumber(L, 1))); return 1; } static int math_exp (lua_State *L) { lua_pushnumber(L, exp(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); return 1; } static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); return 1; } static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); return 1; } static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmin = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d < dmin) dmin = d; } lua_pushnumber(L, dmin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number dmax = luaL_checknumber(L, 1); int i; for (i=2; i<=n; i++) { lua_Number d = luaL_checknumber(L, i); if (d > dmax) dmax = d; } lua_pushnumber(L, dmax); return 1; } static int math_random (lua_State *L) { /* the `%' avoids the (rare) case of r==1, and is needed also because on some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, r); /* Number between 0 and 1 */ break; } case 1: { /* only upper limit */ int u = luaL_checkint(L, 1); luaL_argcheck(L, 1<=u, 1, "interval is empty"); lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */ break; } case 2: { /* lower and upper limits */ int l = luaL_checkint(L, 1); int u = luaL_checkint(L, 2); luaL_argcheck(L, l<=u, 2, "interval is empty"); lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ break; } default: return luaL_error(L, "wrong number of arguments"); } return 1; } static int math_randomseed (lua_State *L) { srand(luaL_checkint(L, 1)); return 0; } static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, {"atan2", math_atan2}, {"atan", math_atan}, {"ceil", math_ceil}, {"cosh", math_cosh}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, {"floor", math_floor}, {"fmod", math_fmod}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, {"log10", math_log10}, {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, {"sinh", math_sinh}, {"sin", math_sin}, {"sqrt", math_sqrt}, {"tanh", math_tanh}, {"tan", math_tan}, {NULL, NULL} }; /* ** Open math library */ LUALIB_API int luaopen_math (lua_State *L) { luaL_register(L, LUA_MATHLIBNAME, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, HUGE_VAL); lua_setfield(L, -2, "huge"); #if defined(LUA_COMPAT_MOD) lua_getfield(L, -1, "fmod"); lua_setfield(L, -2, "mod"); #endif return 1; } infon/lua-5.1.2/src/Makefile0000644000076400001440000001425310603200765015415 0ustar dividuumusers# makefile for building Lua # see ../INSTALL for installation instructions # see ../Makefile and luaconf.h for further customization # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= # Your platform. See PLATS for possible values. PLAT= none CC?= gcc CFLAGS= -O2 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f LIBS= -lm $(MYLIBS) MYCFLAGS= MYLDFLAGS= MYLIBS= # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris debug optimize LUA_A= liblua.a CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ lstrlib.o loadlib.o linit.o LUA_T= lua LUA_O= lua.o LUAC_T= luac LUAC_O= luac.o print.o ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O) ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) ALL_A= $(LUA_A) default: $(PLAT) all: $(ALL_T) o: $(ALL_O) a: $(ALL_A) $(LUA_A): $(CORE_O) $(LIB_O) $(AR) $@ $? $(RANLIB) $@ $(LUA_T): $(LUA_O) $(LUA_A) $(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS) $(LUAC_T): $(LUAC_O) $(LUA_A) $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) clean: $(RM) $(ALL_T) $(ALL_O) depend: @$(CC) $(CFLAGS) -MM l*.c print.c echo: @echo "PLAT = $(PLAT)" @echo "CC = $(CC)" @echo "CFLAGS = $(CFLAGS)" @echo "AR = $(AR)" @echo "RANLIB = $(RANLIB)" @echo "RM = $(RM)" @echo "MYCFLAGS = $(MYCFLAGS)" @echo "MYLDFLAGS = $(MYLDFLAGS)" @echo "MYLIBS = $(MYLIBS)" # convenience targets for popular platforms none: @echo "Please choose a platform:" @echo " $(PLATS)" aix: $(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall" ansi: $(MAKE) all MYCFLAGS=-DLUA_ANSI bsd: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E" generic: $(MAKE) all MYCFLAGS= debug: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -ggdb -DLUA_USE_APICHECK" MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" optimize: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -fexpensive-optimizations -finline-functions -fomit-frame-pointer" linux: $(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses" macosx: $(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX # use this on Mac OS X 10.4 # $(MAKE) all MYCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" MYLIBS="-lreadline" mingw: $(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe $(MAKE) "LUAC_T=luac.exe" luac.exe posix: $(MAKE) all MYCFLAGS=-DLUA_USE_POSIX solaris: $(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \ lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \ lundump.h lvm.h lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ ltable.h ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \ llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lvm.h ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \ ltable.h lundump.h lvm.h ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h lundump.h lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \ lstate.h ltm.h lzio.h lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \ lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h loadlib.o: loadlib.c lauxlib.h lua.h luaconf.h lobject.h llimits.h \ lualib.h lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \ ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \ lfunc.h lstring.h lgc.h ltable.h lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ ltm.h lzio.h lstring.h lgc.h lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ lmem.h lstring.h lgc.h ltable.h lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \ lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \ lundump.h lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ lzio.h print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \ ltm.h lzio.h lmem.h lopcodes.h lundump.h # (end of Makefile) infon/lua-5.1.2/src/lstate.c0000644000076400001440000001315610603200765015416 0ustar dividuumusers/* ** $Id: lstate.c,v 2.36 2006/05/24 14:15:50 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #include #define lstate_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #define state_size(x) (sizeof(x) + LUAI_EXTRASPACE) #define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE) #define tostate(l) (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE)) /* ** Main thread combines a thread state and the global state */ typedef struct LG { lua_State l; global_State g; } LG; static void stack_init (lua_State *L1, lua_State *L) { /* initialize CallInfo array */ L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); L1->ci = L1->base_ci; L1->size_ci = BASIC_CI_SIZE; L1->end_ci = L1->base_ci + L1->size_ci - 1; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue); L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L1->top = L1->stack; L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; /* initialize first ci */ L1->ci->func = L1->top; setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; L1->ci->errfunc = 0; } static void freestack (lua_State *L, lua_State *L1) { luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); luaM_freearray(L, L1->stack, L1->stacksize, TValue); } /* ** open parts that may cause memory-allocation errors */ static int f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ luaT_init(L); luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); g->GCthreshold = 4*g->totalbytes; return 0; } static void preinit_state (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; L->status = 0; L->base_ci = L->ci = NULL; L->ctx = NULL; setnilvalue(gt(L)); } static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeall(L); /* collect all objects */ lua_assert(g->rootgc == obj2gco(L)); lua_assert(g->strt.nuse == 0); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); luaZ_freebuffer(L, &g->buff); freestack(L, L); lua_assert(g->totalbytes == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); } lua_State *luaE_newthread (lua_State *L) { lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); luaC_link(L, obj2gco(L1), LUA_TTHREAD); preinit_state(L1, G(L)); stack_init(L1, L); /* init stack */ setobj2n(L, gt(L1), gt(L)); /* share table of globals */ L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); lua_assert(iswhite(obj2gco(L1))); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L1); freestack(L, L1); luaM_freemem(L, fromstate(L1), state_size(lua_State)); } LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; void *l = (*f)(ud, NULL, 0, state_size(LG)); if (l == NULL) return NULL; L = tostate(l); g = &((LG *)L)->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); L->marked = luaC_white(g); set2bits(L->marked, FIXEDBIT, SFIXEDBIT); preinit_state(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; g->GCthreshold = 0; /* mark it as unfinished state */ g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(registry(L)); luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->gcstate = GCSpause; g->rootgc = obj2gco(L); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gray = NULL; g->grayagain = NULL; g->weak = NULL; g->tmudata = NULL; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; g->gcdept = 0; g->cpu_exceeded = NULL; g->cycles = 0xFFFFFF; // XXX: maximalwert for (i=0; imt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); L = NULL; } else luai_userstateopen(L); return L; } static int callallgcTM (lua_State *L, void *ud) { UNUSED(ud); luaC_callGCTM(L); /* call GC metamethods for all udata */ return 0; } LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; L->ci->errfunc = 0; /* no error function during GC metamethods */ L->base = L->top = L->ci->base; L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); luai_userstateclose(L); close_state(L); } infon/lua-5.1.2/src/ltm.c0000644000076400001440000000315610603200765014715 0ustar dividuumusers/* ** $Id: ltm.c,v 2.8 2006/01/10 12:50:00 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #include #define ltm_c #define LUA_CORE #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", "string", "table", "function", "userdata", "thread", "proto", "upval" }; void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__eq", "__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__len", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); luaS_fix(G(L)->tmname[i]); /* never collect these names */ } } /* ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<metatable; break; case LUA_TUSERDATA: mt = uvalue(o)->metatable; break; default: mt = G(L)->mt[ttype(o)]; } return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); } infon/lua-5.1.2/src/lvm.c0000644000076400001440000006203510603200765014720 0ustar dividuumusers/* ** $Id: lvm.c,v 2.63a 2006/06/05 15:58:59 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #include #include #include #define lvm_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" /* limit for table tag-method chains (to avoid loops) */ #define MAXTAGLOOP 100 const TValue *luaV_tonumber (const TValue *obj, TValue *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { setnvalue(n, num); return n; } else return NULL; } int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { char s[LUAI_MAXNUMBER2STR]; lua_Number n = nvalue(obj); lua_number2str(s, n); setsvalue2s(L, obj, luaS_new(L, s)); return 1; } } static StkId traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; const Instruction *oldpc = GETPC(L); SAVEPC(L, pc); if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); } } if (mask & LUA_MASKLINE) { Proto *p = ci_func(L->ci)->l.p; int npc = pcRel(pc, p); int newline = getline(p, npc); /* call linehook when enter a new function, when jump back (loop), or when enter a new line */ if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); } return L->base; } static void callTMres (lua_State *L, StkId res, const TValue *f, const TValue *p1, const TValue *p2) { ptrdiff_t result = savestack(L, res); setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ luaD_checkstack(L, 3); L->top += 3; luaD_call(L, L->top - 3, 1, 0); res = restorestack(L, result); L->top--; setobjs2s(L, res, L->top); } static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, const TValue *p3) { setobj2s(L, L->top, f); /* push function */ setobj2s(L, L->top+1, p1); /* 1st argument */ setobj2s(L, L->top+2, p2); /* 2nd argument */ setobj2s(L, L->top+3, p3); /* 3th argument */ luaD_checkstack(L, 4); L->top += 4; luaD_call(L, L->top - 4, 0, 0); } void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); } void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); } static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; callTMres(L, res, tm, p1, p2); return 1; } static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); if (tm2 == NULL) return NULL; /* no metamethod */ if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ return tm1; return NULL; } static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { const TValue *tm1 = luaT_gettmbyobj(L, p1, event); const TValue *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); } static int l_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = ls->tsv.len; const char *r = getstr(rs); size_t lr = rs->tsv.len; for (;;) { int temp = strcoll(l, r); if (temp != 0) return temp; else { /* strings are equal up to a `\0' */ size_t len = strlen(l); /* index of first `\0' in both strings */ if (len == lr) /* r is finished? */ return (len == ll) ? 0 : 1; else if (len == ll) /* l is finished? */ return -1; /* l is smaller than r (because r is not finished) */ /* both strings longer than `len'; go on comparing (after the `\0') */ len++; l += len; ll -= len; r += len; lr -= len; } } } int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return luai_numlt(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r); } static int lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return luai_numle(nvalue(l), nvalue(r)); else if (ttisstring(l)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ return !res; return luaG_ordererror(L, l, r); } int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ callTMres(L, L->top, tm, t1, t2); /* call TM */ return !l_isfalse(L->top); } void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { setpvalue(L->top, (void *)(ptrdiff_t)(last - 1)); /* for luaV_resume */ L->top++; if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); L->top--; } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ (void)tostring(L, top - 2); /* result is first op (as string) */ else { /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ } static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); } /* ** some macros for common tasks in `luaV_execute' */ #define runtime_check(L, c) { if (!(c)) break; } #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} #define Protect(x) { SAVEPC(L, pc); {x;}; base = L->base; } #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(nb, nc)); \ } \ else \ Protect(Arith(L, ra, rb, rc, tm)); \ } #define cpu_exceeded_grace_cycles 16 static void cpu_limit_exceeded(lua_State *L) { luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); lua_unlock(L); lua_set_cycles(L, 0xFFFFFF); if (G(L)->cpu_exceeded) G(L)->cpu_exceeded(L); else lua_pushliteral(L, "cycles exceeded"); lua_set_cycles(L, cpu_exceeded_grace_cycles); lua_error(L); } int luaV_execute (lua_State *L) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; int nexeccalls = 1; reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = GETPC(L); cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if (--G(L)->cycles <= 0) { SAVEPC(L, pc); cpu_limit_exceeded(L); // never returns } if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) base = traceexec(L, pc); /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } case OP_GETGLOBAL: { TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); Protect(luaV_gettable(L, &g, rb, ra)); continue; } case OP_GETTABLE: { Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); Protect(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } } continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { dojump(L, pc, GETARG_sBx(i)); continue; } case OP_EQ: { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LE: { Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_TEST: { if (l_isfalse(ra) != GETARG_C(i)) dojump(L, pc, GETARG_sBx(*pc)); pc++; continue; } case OP_TESTSET: { TValue *rb = RB(i); if (l_isfalse(rb) != GETARG_C(i)) { setobjs2s(L, ra, rb); dojump(L, pc, GETARG_sBx(*pc)); } pc++; continue; } case OP_CALL: if (G(L)->cycles < cpu_exceeded_grace_cycles) { luaG_runerror(L, "too few cpu cycles left for function call"); } else { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ SAVEPC(L, pc); switch (luaD_precall(L, ra, nresults)) { case PCRLUA: { nexeccalls++; goto reentry; /* restart luaV_execute over new Lua function */ } case PCRC: { /* it was a C function (`precall' called it); adjust results */ if (nresults >= 0) L->top = L->ci->top; base = L->base; continue; } default: { return LUA_YIELD; /* yield */ } } } case OP_TAILCALL: if (G(L)->cycles < cpu_exceeded_grace_cycles) { luaG_runerror(L, "too few cpu cycles left for function call"); } else { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ SAVEPC(L, pc); lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); switch (luaD_precall(L, ra, LUA_MULTRET)) { case PCRLUA: { /* tail call: put new frame in place of previous one */ CallInfo *ci = L->ci - 1; /* previous frame */ int aux; StkId func = ci->func; StkId pfunc = (ci+1)->func; /* previous function index */ if (L->openupval) luaF_close(L, ci->base); L->base = ci->base = ci->func + ((ci+1)->base - pfunc); for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ setobjs2s(L, func+aux, pfunc+aux); ci->top = L->top = func+aux; /* correct top */ lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); ci->ctx = L->ctx; ci->tailcalls++; /* one more call lost */ L->ci--; /* remove new frame */ goto reentry; } case PCRC: { /* it was a C function (`precall' called it) */ base = L->base; continue; } default: { return LUA_YIELD; } } } case OP_RETURN: { int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); SAVEPC(L, pc); b = luaD_poscall(L, ra); if (--nexeccalls == 0) /* was previous function running `here'? */ return 0; /* no: return */ else { /* yes: continue its execution */ if (b) L->top = L->ci->top; lua_assert(isLua(L->ci) && GET_OPCODE(*(GETPC(L)-1)) == OP_CALL); goto reentry; } } case OP_FORLOOP: { lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); if (luai_numlt(0, step) ? luai_numle(idx, limit) : luai_numle(limit, idx)) { dojump(L, pc, GETARG_sBx(i)); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } continue; } case OP_FORPREP: { const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; SAVEPC(L, pc); /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) luaG_runerror(L, LUA_QL("for") " limit must be a number"); else if (!tonumber(pstep, ra+2)) luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); dojump(L, pc, GETARG_sBx(i)); continue; } case OP_TFORLOOP: { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ Protect(luaD_call(L, cb, GETARG_C(i), 0)); L->top = L->ci->top; cb = RA(i) + 3; /* previous call may change the stack */ if (!ttisnil(cb)) { /* continue loop? */ setobjs2s(L, cb-1, cb); /* save control variable */ dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ } pc++; continue; } case OP_SETLIST: { int n = GETARG_B(i); int c = GETARG_C(i); int last; Table *h; if (n == 0) { n = cast_int(L->top - ra) - 1; L->top = L->ci->top; } if (c == 0) c = cast_int(*pc++); runtime_check(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* pre-alloc it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setnum(L, h, last--), val); luaC_barriert(L, h, val); } continue; } case OP_CLOSE: { luaF_close(L, ra); continue; } case OP_CLOSURE: { Proto *p; Closure *ncl; int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; ncl = luaF_newLclosure(L, nup, cl->env); ncl->l.p = p; for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; else { lua_assert(GET_OPCODE(*pc) == OP_MOVE); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } setclvalue(L, ra, ncl); Protect(luaC_checkGC(L)); continue; } case OP_VARARG: { int b = GETARG_B(i) - 1; int j; CallInfo *ci = L->ci; int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; if (b == LUA_MULTRET) { Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ b = n; L->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { setobjs2s(L, ra + j, ci->base - n + j); } else { setnilvalue(ra + j); } } continue; } } } } void luaV_resume (lua_State *L) { const Instruction *pc = GETPC(L); const Instruction i = *(pc - 1); switch (GET_OPCODE(i)) { /* finish opcodes */ case OP_CALL: if (i & MASK1(SIZE_C,POS_C)) L->top = L->ci->top; break; case OP_SETGLOBAL: case OP_SETTABLE: case OP_TAILCALL: break; /* ok, but nothing to do */ case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: L->top--; setobjs2s(L, L->base + GETARG_A(i), L->top); break; case OP_LT: case OP_LE: case OP_EQ: L->top--; if (!l_isfalse(L->top) != GETARG_A(i)) pc++; else dojump(L, pc, GETARG_sBx(*pc) + 1); SAVEPC(L, pc); break; case OP_TFORLOOP: { StkId cb; /* call base */ L->top = L->ci->top; cb = L->base + GETARG_A(i) + 3; if (ttisnil(cb)) /* break loop? */ pc++; /* skip jump (break loop) */ else { setobjs2s(L, cb-1, cb); /* save control variable */ dojump(L, pc, GETARG_sBx(*pc) + 1); /* jump back */ } SAVEPC(L, pc); break; } case OP_CONCAT: { int b = GETARG_B(i); int c; L->top -= 2; c = (int)(ptrdiff_t)pvalue(L->top); setobjs2s(L, L->base + c, L->top + 1); if (c > b) luaV_concat(L, c-b+1, c); luaC_checkGC(L); /***/ setobjs2s(L, L->base + GETARG_A(i), L->base + b); break; } default: luaG_runerror(L, "return to non-resumable opcode %d", GET_OPCODE(i)); break; } lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL); } infon/lua-5.1.2/src/lmem.h0000644000076400001440000000272210603200765015056 0ustar dividuumusers/* ** $Id: lmem.h,v 1.31 2005/04/25 19:24:10 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #ifndef lmem_h #define lmem_h #include #include "llimits.h" #include "lua.h" #define MEMERRMSG "not enough memory" #define luaM_reallocv(L,b,on,n,e) \ ((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \ luaM_toobig(L)) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) #define luaM_freearray(L, b, n, t) luaM_reallocv(L, (b), n, 0, sizeof(t)) #define luaM_malloc(L,t) luaM_realloc_(L, NULL, 0, (t)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) #define luaM_newvector(L,n,t) \ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) #define luaM_growvector(L,v,nelems,size,t,limit,e) \ if ((nelems)+1 > (size)) \ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); LUAI_FUNC void *luaM_toobig (lua_State *L); LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, int limit, const char *errormsg); #endif infon/lua-5.1.2/src/lstate.h0000644000076400001440000001173710603200765015426 0ustar dividuumusers/* ** $Id: lstate.h,v 2.24 2006/02/06 18:27:59 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #ifndef lstate_h #define lstate_h #include "lua.h" #include "lobject.h" #include "ltm.h" #include "lzio.h" struct lua_longjmp; /* defined in ldo.c */ /* table of globals */ #define gt(L) (&L->l_gt) /* registry */ #define registry(L) (&G(L)->l_registry) /* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 #define BASIC_CI_SIZE 8 #define BASIC_STACK_SIZE (2*LUA_MINSTACK) typedef struct stringtable { GCObject **hash; lu_int32 nuse; /* number of elements */ int size; } stringtable; /* ** informations about a call */ typedef struct CallInfo { StkId base; /* base for this function */ StkId func; /* function index in the stack */ StkId top; /* top for this function */ void *ctx; /* saved pc for Lua functions or vcontext for C functions */ int tailcalls; /* number of tail calls lost under this entry */ short nresults; /* expected number of results from this function */ lu_byte hookmask; /* restore on catch: hookmask */ lu_byte errfunc; /* 0: no catch, 1: catch, >=2: catch with errfunc */ } CallInfo; #define curr_func(L) (clvalue(L->ci->func)) #define ci_func(ci) (clvalue((ci)->func)) #define f_isLua(ci) (!ci_func(ci)->c.isC) #define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) /* ** `global state', shared by all threads of this state */ typedef struct global_State { stringtable strt; /* hash table for strings */ lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to `frealloc' */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ int sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ GCObject **sweepgc; /* position of sweep in `rootgc' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* last element of list of userdata to be GC */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem totalbytes; /* number of bytes currently allocated */ lu_mem estimate; /* an estimate of number of bytes actually in use */ lu_mem gcdept; /* how much GC is `behind schedule' */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ lua_CFunction cpu_exceeded; /* to be called if cpu usage exceeded */ TValue l_registry; struct lua_State *mainthread; UpVal uvhead; /* head of double-linked list of all open upvalues */ struct Table *mt[NUM_TAGS]; /* metatables for basic types */ TString *tmname[TM_N]; /* array with tag-method names */ int cycles; } global_State; /* ** `per thread' state */ struct lua_State { CommonHeader; lu_byte status; lu_byte hookmask; int stacksize; StkId top; /* first free slot in the stack */ StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ void *ctx; /* ctx for current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ int size_ci; /* size of array `base_ci' */ unsigned short nCcalls; /* number of nested C calls + callflags */ int hookcount; lua_Hook hook; TValue l_gt; /* table of globals */ TValue env; /* temporary place for environments */ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ int basehookcount; }; #define G(L) (L->l_G) /* ** Union of all collectable objects */ union GCObject { GCheader gch; union TString ts; union Udata u; union Closure cl; struct Table h; struct Proto p; struct UpVal uv; struct lua_State th; /* thread */ }; /* macros to convert a GCObject into a specific value */ #define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) #define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) #define gco2u(o) (&rawgco2u(o)->uv) #define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) #define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define ngcotouv(o) \ check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) #define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) /* macro to convert any Lua object into a GCObject */ #define obj2gco(v) (cast(GCObject *, (v))) LUAI_FUNC lua_State *luaE_newthread (lua_State *L); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); #endif infon/lua-5.1.2/src/ltm.h0000644000076400001440000000176610603200765014727 0ustar dividuumusers/* ** $Id: ltm.h,v 2.6 2005/06/06 13:30:25 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #ifndef ltm_h #define ltm_h #include "lobject.h" /* * WARNING: if you change the order of this enumeration, * grep "ORDER TM" */ typedef enum { TM_INDEX, TM_NEWINDEX, TM_GC, TM_MODE, TM_EQ, /* last tag method with `fast' access */ TM_ADD, TM_SUB, TM_MUL, TM_DIV, TM_MOD, TM_POW, TM_UNM, TM_LEN, TM_LT, TM_LE, TM_CONCAT, TM_CALL, TM_N /* number of elements in the enum */ } TMS; #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) LUAI_DATA const char *const luaT_typenames[]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); #endif infon/lua-5.1.2/src/ltable.c0000644000076400001440000003761010603200765015366 0ustar dividuumusers/* ** $Id: ltable.c,v 2.32 2006/01/18 11:49:02 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array ** part. The actual size of the array is the largest `n' such that at ** least half the slots between 0 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the `original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ #include #include #define ltable_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "ltable.h" /* ** max size of array part is 2^MAXBITS */ #if LUAI_BITSINT > 26 #define MAXBITS 26 #else #define MAXBITS (LUAI_BITSINT-2) #endif #define MAXASIZE (1 << MAXBITS) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->tsv.hash) #define hashboolean(t,p) hashpow2(t, p) /* ** for some types, it is better to avoid modulus by power of 2, as ** they tend to have many 2 factors. */ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, IntPoint(p)) /* ** number of ints inside a lua_Number */ #define numints cast_int(sizeof(lua_Number)/sizeof(int)) #define dummynode (&dummynode_) static const Node dummynode_ = { {{NULL}, LUA_TNIL}, /* value */ {{{NULL}, LUA_TNIL, NULL}} /* key */ }; /* ** hash for lua_Numbers */ static Node *hashnum (const Table *t, lua_Number n) { unsigned int a[numints]; int i; n += 1; /* normalize number (avoid -0) */ lua_assert(sizeof(a) <= sizeof(n)); memcpy(a, &n, sizeof(a)); for (i = 1; i < numints; i++) a[0] += a[i]; return hashmod(t, a[0]); } /* ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); case LUA_TSTRING: return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); default: return hashpointer(t, gcvalue(key)); } } /* ** returns the index for `key' if `key' is an appropriate key to live in ** the array part of the table, -1 otherwise. */ static int arrayindex (const TValue *key) { if (ttisnumber(key)) { lua_Number n = nvalue(key); int k; lua_number2int(k, n); if (luai_numeq(cast_num(k), n)) return k; } return -1; /* `key' did not match some condition */ } /* ** returns the index of a `key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signalled by -1. */ static int findindex (lua_State *L, Table *t, StkId key) { int i; if (ttisnil(key)) return -1; /* first iteration */ i = arrayindex(key); if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ return i-1; /* yes; that's the index (corrected to C) */ else { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in `next' */ if (luaO_rawequalObj(key2tval(n), key) || (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && gcvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return i + t->sizearray; } else n = gnext(n); } while (n); luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ return 0; /* to avoid warnings */ } } int luaH_next (lua_State *L, Table *t, StkId key) { int i = findindex(L, t, key); /* find original element */ for (i++; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setnvalue(key, cast_num(i+1)); setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, key2tval(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } return 0; /* no more elements */ } /* ** {============================================================= ** Rehash ** ============================================================== */ static int computesizes (int nums[], int *narray) { int i; int twotoi; /* 2^i */ int a = 0; /* number of elements smaller than 2^i */ int na = 0; /* number of elements to go to array part */ int n = 0; /* optimal size for array part */ for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ n = twotoi; /* optimal size (till now) */ na = a; /* all elements smaller than n will go to array part */ } } if (a == *narray) break; /* all elements already counted */ } *narray = n; lua_assert(*narray/2 <= na && na <= *narray); return na; } static int countint (const TValue *key, int *nums) { int k = arrayindex(key); if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ nums[ceillog2(k)]++; /* count as such */ return 1; } else return 0; } static int numusearray (const Table *t, int *nums) { int lg; int ttlg; /* 2^lg */ int ause = 0; /* summation of `nums' */ int i = 1; /* count to traverse all array keys */ for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ int lc = 0; /* counter */ int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } /* count elements in range (2^(lg-1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; } nums[lg] += lc; ause += lc; } return ause; } static int numusehash (const Table *t, int *nums, int *pnasize) { int totaluse = 0; /* total number of elements */ int ause = 0; /* summation of `nums' */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(key2tval(n), nums); totaluse++; } } *pnasize += ause; return totaluse; } static void setarrayvector (lua_State *L, Table *t, int size) { int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); t->sizearray = size; } static void setnodevector (lua_State *L, Table *t, int size) { int lsize; if (size == 0) { /* no elements to hash part? */ t->node = cast(Node *, dummynode); /* use common `dummynode' */ lsize = 0; } else { int i; lsize = ceillog2(size); if (lsize > MAXBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i=0; ilsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ } static void resize (lua_State *L, Table *t, int nasize, int nhsize) { int i; int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; iarray[i])) setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ for (i = twoto(oldhsize) - 1; i >= 0; i--) { Node *old = nold+i; if (!ttisnil(gval(old))) setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); } if (nold != dummynode) luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ } void luaH_resizearray (lua_State *L, Table *t, int nasize) { int nsize = (t->node == dummynode) ? 0 : sizenode(t); resize(L, t, nasize, nsize); } static void rehash (lua_State *L, Table *t, const TValue *ek) { int nasize, na; int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ int i; int totaluse; for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ nasize = numusearray(t, nums); /* count keys in array part */ totaluse = nasize; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ /* count extra key */ nasize += countint(ek, nums); totaluse++; /* compute new size for array part */ na = computesizes(nums, &nasize); /* resize the table to new computed sizes */ resize(L, t, nasize, totaluse - na); } /* ** }============================================================= */ Table *luaH_new (lua_State *L, int narray, int nhash) { Table *t = luaM_new(L, Table); luaC_link(L, obj2gco(t), LUA_TTABLE); t->metatable = NULL; t->flags = cast_byte(~0); /* temporary values (kept only if some malloc fails) */ t->array = NULL; t->sizearray = 0; t->lsizenode = 0; t->node = cast(Node *, dummynode); setarrayvector(L, t, narray); setnodevector(L, t, nhash); return t; } void luaH_free (lua_State *L, Table *t) { if (t->node != dummynode) luaM_freearray(L, t->node, sizenode(t), Node); luaM_freearray(L, t->array, t->sizearray, TValue); luaM_free(L, t); } static Node *getfreepos (Table *t) { while (t->lastfree-- > t->node) { if (ttisnil(gkey(t->lastfree))) return t->lastfree; } return NULL; /* could not find a free place */ } /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main ** position or not: if it is not, move colliding node to an empty place and ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ static TValue *newkey (lua_State *L, Table *t, const TValue *key) { Node *mp = mainposition(t, key); if (!ttisnil(gval(mp)) || mp == dummynode) { Node *othern; Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } lua_assert(n != dummynode); othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ gnext(n) = gnext(mp); /* chain new position */ gnext(mp) = n; mp = n; } } gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); } /* ** search function for integers */ const TValue *luaH_getnum (Table *t, int key) { /* (1 <= key && key <= t->sizearray) */ if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) return &t->array[key-1]; else { lua_Number nk = cast_num(key); Node *n = hashnum(t, nk); do { /* check whether `key' is somewhere in the chain */ if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } /* ** search function for strings */ const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); do { /* check whether `key' is somewhere in the chain */ if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } /* ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNIL: return luaO_nilobject; case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ return luaH_getnum(t, k); /* use specialized version */ /* else go through */ } default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ if (luaO_rawequalObj(key2tval(n), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); return luaO_nilobject; } } } TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); t->flags = 0; if (p != luaO_nilobject) return cast(TValue *, p); else { if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisnumber(key) && luai_numisnan(nvalue(key))) luaG_runerror(L, "table index is NaN"); return newkey(L, t, key); } } TValue *luaH_setnum (lua_State *L, Table *t, int key) { const TValue *p = luaH_getnum(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; setnvalue(&k, cast_num(key)); return newkey(L, t, &k); } } TValue *luaH_setstr (lua_State *L, Table *t, TString *key) { const TValue *p = luaH_getstr(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else { TValue k; setsvalue(L, &k, key); return newkey(L, t, &k); } } static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find `i' and `j' such that i is present and j is not */ while (!ttisnil(luaH_getnum(t, j))) { i = j; j *= 2; if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getnum(t, i))) i++; return i - 1; } } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(luaH_getnum(t, m))) j = m; else i = m; } return i; } /* ** Try to find a boundary in table `t'. A `boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ else if (t->node == dummynode) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } #if defined(LUA_DEBUG) Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } int luaH_isdummy (Node *n) { return n == dummynode; } #endif infon/lua-5.1.2/src/lvm.h0000644000076400001440000000240510603200765014720 0ustar dividuumusers/* ** $Id: lvm.h,v 2.5 2005/08/22 18:54:49 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lvm_h #define lvm_h #include "ldo.h" #include "lobject.h" #include "ltm.h" #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o))) #define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \ (((o) = luaV_tonumber(o,n)) != NULL)) #define equalobj(L,o1,o2) \ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) #define GETPC(L) (cast(const Instruction *, L->ctx)) #define SAVEPC(L, pc) L->ctx = cast(void *, (pc)) LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); LUAI_FUNC int luaV_execute (lua_State *L); LUAI_FUNC void luaV_resume (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); #endif infon/lua-5.1.2/src/llex.c0000644000076400001440000003026610603200765015067 0ustar dividuumusers/* ** $Id: llex.c,v 2.20 2006/03/09 18:14:31 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #include #include #include #define llex_c #define LUA_CORE #include "lua.h" #include "ldo.h" #include "llex.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lzio.h" #define next(ls) (ls->current = zgetc(ls->z)) #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "..", "...", "==", ">=", "<=", "~=", "", "", "", "", NULL }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (b->n + 1 > b->buffsize) { size_t newsize; if (b->buffsize >= MAX_SIZET/2) luaX_lexerror(ls, "lexical element too long", 0); newsize = b->buffsize * 2; luaZ_resizebuffer(ls->L, b, newsize); } b->buffer[b->n++] = cast(char, c); } void luaX_init (lua_State *L) { int i; for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ } } #define MAXSRC 80 const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { lua_assert(token == cast(unsigned char, token)); return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : luaO_pushfstring(ls->L, "%c", token); } else return luaX_tokens[token-FIRST_RESERVED]; } static const char *txtToken (LexState *ls, int token) { switch (token) { case TK_NAME: case TK_STRING: case TK_NUMBER: save(ls, '\0'); return luaZ_buffer(ls->buff); default: return luaX_token2str(ls, token); } } void luaX_lexerror (LexState *ls, const char *msg, int token) { char buff[MAXSRC]; luaO_chunkid(buff, getstr(ls->source), MAXSRC); msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); if (token) luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } void luaX_syntaxerror (LexState *ls, const char *msg) { luaX_lexerror(ls, msg, ls->t.token); } TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TString *ts = luaS_newlstr(L, str, l); TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ if (ttisnil(o)) setbvalue(o, 1); /* make sure `str' will not be collected */ return ts; } static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); next(ls); /* skip `\n' or `\r' */ if (currIsNewline(ls) && ls->current != old) next(ls); /* skip `\n\r' or `\r\n' */ if (++ls->linenumber >= MAX_INT) luaX_syntaxerror(ls, "chunk has too many lines"); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { ls->decpoint = '.'; ls->L = L; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; ls->fs = NULL; ls->linenumber = 1; ls->lastline = 1; ls->source = source; luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ next(ls); /* read first char */ } /* ** ======================================================= ** LEXICAL ANALYZER ** ======================================================= */ static int check_next (LexState *ls, const char *set) { if (!strchr(set, ls->current)) return 0; save_and_next(ls); return 1; } static void buffreplace (LexState *ls, char from, char to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); while (n--) if (p[n] == from) p[n] = to; } static void trydecpoint (LexState *ls, SemInfo *seminfo) { /* format error: try to update decimal point separator */ struct lconv *cv = localeconv(); char old = ls->decpoint; ls->decpoint = (cv ? cv->decimal_point[0] : '.'); buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ luaX_lexerror(ls, "malformed number", TK_NUMBER); } } /* LUA_NUMBER */ static void read_numeral (LexState *ls, SemInfo *seminfo) { lua_assert(isdigit(ls->current)); do { save_and_next(ls); } while (isdigit(ls->current) || ls->current == '.'); if (check_next(ls, "Ee")) /* `E'? */ check_next(ls, "+-"); /* optional exponent sign */ while (isalnum(ls->current) || ls->current == '_') save_and_next(ls); save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ trydecpoint(ls, seminfo); /* try to update decimal point separator */ } static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); while (ls->current == '=') { save_and_next(ls); count++; } return (ls->current == s) ? count : (-count) - 1; } static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int cont = 0; (void)(cont); /* avoid warnings when `cont' is not used */ save_and_next(ls); /* skip 2nd `[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: luaX_lexerror(ls, (seminfo) ? "unfinished long string" : "unfinished long comment", TK_EOS); break; /* to avoid warnings */ #if defined(LUA_COMPAT_LSTR) case '[': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `[' */ cont++; #if LUA_COMPAT_LSTR == 1 if (sep == 0) luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); #endif } break; } #endif case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd `]' */ #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 cont--; if (sep == 0 && cont >= 0) break; #endif goto endloop; } break; } case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ break; } default: { if (seminfo) save_and_next(ls); else next(ls); } } } endloop: if (seminfo) seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), luaZ_bufflen(ls->buff) - 2*(2 + sep)); } static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); while (ls->current != del) { switch (ls->current) { case EOZ: luaX_lexerror(ls, "unfinished string", TK_EOS); continue; /* to avoid warnings */ case '\n': case '\r': luaX_lexerror(ls, "unfinished string", TK_STRING); continue; /* to avoid warnings */ case '\\': { int c; next(ls); /* do not save the `\' */ switch (ls->current) { case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\n': /* go through */ case '\r': save(ls, '\n'); inclinenumber(ls); continue; case EOZ: continue; /* will raise an error next loop */ default: { if (!isdigit(ls->current)) save_and_next(ls); /* handles \\, \", \', and \? */ else { /* \xxx */ int i = 0; c = 0; do { c = 10*c + (ls->current-'0'); next(ls); } while (++i<3 && isdigit(ls->current)); if (c > UCHAR_MAX) luaX_lexerror(ls, "escape sequence too large", TK_STRING); save(ls, c); } continue; } } save(ls, c); next(ls); continue; } default: save_and_next(ls); } } save_and_next(ls); /* skip delimiter */ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, luaZ_bufflen(ls->buff) - 2); } static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { case '\n': case '\r': { inclinenumber(ls); continue; } case '-': { next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); if (ls->current == '[') { int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* long comment */ luaZ_resetbuffer(ls->buff); continue; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) next(ls); continue; } case '[': { int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return TK_STRING; } else if (sep == -1) return '['; else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); } case '=': { next(ls); if (ls->current != '=') return '='; else { next(ls); return TK_EQ; } } case '<': { next(ls); if (ls->current != '=') return '<'; else { next(ls); return TK_LE; } } case '>': { next(ls); if (ls->current != '=') return '>'; else { next(ls); return TK_GE; } } case '~': { next(ls); if (ls->current != '=') return '~'; else { next(ls); return TK_NE; } } case '"': case '\'': { read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { save_and_next(ls); if (check_next(ls, ".")) { if (check_next(ls, ".")) return TK_DOTS; /* ... */ else return TK_CONCAT; /* .. */ } else if (!isdigit(ls->current)) return '.'; else { read_numeral(ls, seminfo); return TK_NUMBER; } } case EOZ: { return TK_EOS; } default: { if (isspace(ls->current)) { lua_assert(!currIsNewline(ls)); next(ls); continue; } else if (isdigit(ls->current)) { read_numeral(ls, seminfo); return TK_NUMBER; } else if (isalpha(ls->current) || ls->current == '_') { /* identifier or reserved word */ TString *ts; do { save_and_next(ls); } while (isalnum(ls->current) || ls->current == '_'); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); if (ts->tsv.reserved > 0) /* reserved word? */ return ts->tsv.reserved - 1 + FIRST_RESERVED; else { seminfo->ts = ts; return TK_NAME; } } else { int c = ls->current; next(ls); return c; /* single-char tokens (+ - / ...) */ } } } } } void luaX_next (LexState *ls) { ls->lastline = ls->linenumber; if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ ls->t = ls->lookahead; /* use this one */ ls->lookahead.token = TK_EOS; /* and discharge it */ } else ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ } void luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); } infon/lua-5.1.2/src/lgc.c0000644000076400001440000004702510603200765014671 0ustar dividuumusers/* ** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #include #define lgc_c #define LUA_CORE #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #define GCSTEPSIZE 1024u #define GCSWEEPMAX 40 #define GCSWEEPCOST 10 #define GCFINALIZECOST 100 #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) #define makewhite(g,x) \ ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) #define KEYWEAK bitmask(KEYWEAKBIT) #define VALUEWEAK bitmask(VALUEWEAKBIT) #define markvalue(g,o) { checkconsistency(o); \ if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } #define markobject(g,t) { if (iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (iscollectable(gkey(n))) setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ } static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); white2gray(o); switch (o->gch.tt) { case LUA_TSTRING: { return; } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; gray2black(o); /* udata are never gray */ if (mt) markobject(g, mt); markobject(g, gco2u(o)->env); return; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); if (uv->v == &uv->u.value) /* closed? */ gray2black(o); /* open upvalues are never black */ return; } case LUA_TFUNCTION: { gco2cl(o)->c.gclist = g->gray; g->gray = o; break; } case LUA_TTABLE: { gco2h(o)->gclist = g->gray; g->gray = o; break; } case LUA_TTHREAD: { gco2th(o)->gclist = g->gray; g->gray = o; break; } case LUA_TPROTO: { gco2p(o)->gclist = g->gray; g->gray = o; break; } default: lua_assert(0); } } static void marktmu (global_State *g) { GCObject *u = g->tmudata; if (u) { do { u = u->gch.next; makewhite(g, u); /* may be marked, if left from previous GC */ reallymarkobject(g, u); } while (u != g->tmudata); } } /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); size_t deadmem = 0; GCObject **p = &g->mainthread->next; GCObject *curr; while ((curr = *p) != NULL) { if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gco2u(curr)); markfinalized(gco2u(curr)); *p = curr->gch.next; /* link `curr' at the end of `tmudata' list */ if (g->tmudata == NULL) /* list is empty? */ g->tmudata = curr->gch.next = curr; /* creates a circular list */ else { curr->gch.next = g->tmudata->gch.next; g->tmudata->gch.next = curr; g->tmudata = curr; } } } return deadmem; } static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; int weakvalue = 0; const TValue *mode; if (h->metatable) markobject(g, h->metatable); mode = gfasttm(g, h->metatable, TM_MODE); if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); if (weakkey || weakvalue) { /* is really weak? */ h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); h->gclist = g->weak; /* must be cleared after GC, ... */ g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } if (weakkey && weakvalue) return 1; if (!weakvalue) { i = h->sizearray; while (i--) markvalue(g, &h->array[i]); } i = sizenode(h); while (i--) { Node *n = gnode(h, i); lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); if (ttisnil(gval(n))) removeentry(n); /* remove empty entries */ else { lua_assert(!ttisnil(gkey(n))); if (!weakkey) markvalue(g, gkey(n)); if (!weakvalue) markvalue(g, gval(n)); } } return weakkey || weakvalue; } /* ** All marks are conditional because a GC may happen while the ** prototype is still being created */ static void traverseproto (global_State *g, Proto *f) { int i; if (f->source) stringmark(f->source); for (i=0; isizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i=0; isizeupvalues; i++) { /* mark upvalue names */ if (f->upvalues[i]) stringmark(f->upvalues[i]); } for (i=0; isizep; i++) { /* mark nested protos */ if (f->p[i]) markobject(g, f->p[i]); } for (i=0; isizelocvars; i++) { /* mark local-variable names */ if (f->locvars[i].varname) stringmark(f->locvars[i].varname); } } static void traverseclosure (global_State *g, Closure *cl) { markobject(g, cl->c.env); if (cl->c.isC) { int i; for (i=0; ic.nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->c.upvalue[i]); } else { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); markobject(g, cl->l.p); for (i=0; il.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); } } static void checkstacksizes (lua_State *L, StkId max) { int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ int s_used = cast_int(max - L->stack); /* part of stack in use */ if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ return; /* do not touch the stacks */ if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ condhardstacktests(luaD_reallocCI(L, ci_used + 1)); if (4*s_used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ condhardstacktests(luaD_reallocstack(L, s_used)); } static void traversestack (global_State *g, lua_State *l) { StkId o, lim; CallInfo *ci; markvalue(g, gt(l)); lim = l->top; for (ci = l->base_ci; ci <= l->ci; ci++) { lua_assert(ci->top <= l->stack_last); if (lim < ci->top) lim = ci->top; } for (o = l->stack; o < l->top; o++) markvalue(g, o); for (; o <= lim; o++) setnilvalue(o); checkstacksizes(l, lim); } /* ** traverse one gray object, turning it to black. ** Returns `quantity' traversed. */ static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (o->gch.tt) { case LUA_TTABLE: { Table *h = gco2h(o); g->gray = h->gclist; if (traversetable(g, h)) /* table is weak? */ black2gray(o); /* keep it gray */ return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } case LUA_TFUNCTION: { Closure *cl = gco2cl(o); g->gray = cl->c.gclist; traverseclosure(g, cl); return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); } case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; th->gclist = g->grayagain; g->grayagain = o; black2gray(o); traversestack(g, th); return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci; } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; traverseproto(g, p); return sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; } default: lua_assert(0); return 0; } } static size_t propagateall (global_State *g) { size_t m = 0; while (g->gray) m += propagatemark(g); return m; } /* ** The next function tells whether a key or value can be cleared from ** a weak table. Non-collectable objects are never removed from weak ** tables. Strings behave as `values', so are never removed too. for ** other objects: if really collected, cannot keep them; for userdata ** being finalized, keep them in keys, but not in values */ static int iscleared (const TValue *o, int iskey) { if (!iscollectable(o)) return 0; if (ttisstring(o)) { stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } return iswhite(gcvalue(o)) || (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); } /* ** clear collected entries from weaktables */ static void cleartable (GCObject *l) { while (l) { Table *h = gco2h(l); int i = h->sizearray; lua_assert(testbit(h->marked, VALUEWEAKBIT) || testbit(h->marked, KEYWEAKBIT)); if (testbit(h->marked, VALUEWEAKBIT)) { while (i--) { TValue *o = &h->array[i]; if (iscleared(o, 0)) /* value was collected? */ setnilvalue(o); /* remove value */ } } i = sizenode(h); while (i--) { Node *n = gnode(h, i); if (!ttisnil(gval(n)) && /* non-empty entry? */ (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* remove entry from table */ } } l = h->gclist; } } static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2h(o)); break; case LUA_TTHREAD: { lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); luaE_freethread(L, gco2th(o)); break; } case LUA_TSTRING: { G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } case LUA_TUSERDATA: { luaM_freemem(L, o, sizeudata(gco2u(o))); break; } default: lua_assert(0); } } #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; global_State *g = G(L); int deadmask = otherwhite(g); while ((curr = *p) != NULL && count-- > 0) { if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ sweepwholelist(L, &gco2th(curr)->openupval); if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); makewhite(g, curr); /* make it white (for next cycle) */ p = &curr->gch.next; } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); } } return p; } static void checkSizes (lua_State *L) { global_State *g = G(L); /* check size of string hash */ if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ size_t newsize = luaZ_sizebuffer(&g->buff) / 2; luaZ_resizebuffer(L, &g->buff, newsize); } } static void GCTM (lua_State *L) { global_State *g = G(L); GCObject *o = g->tmudata->gch.next; /* get first element */ Udata *udata = rawgco2u(o); const TValue *tm; /* remove udata from `tmudata' */ if (o == g->tmudata) /* last element? */ g->tmudata = NULL; else g->tmudata->gch.next = udata->uv.next; udata->uv.next = g->mainthread->next; /* return it to `root' list */ g->mainthread->next = o; makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_mem oldt = g->GCthreshold; g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; luaD_call(L, L->top - 2, 0, LUA_NOYIELD | LUA_NOVPCALL | LUA_NOHOOKS); g->GCthreshold = oldt; /* restore threshold */ } } /* ** Call all GC tag methods */ void luaC_callGCTM (lua_State *L) { while (G(L)->tmudata) GCTM(L); } void luaC_freeall (lua_State *L) { global_State *g = G(L); int i; g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ sweepwholelist(L, &g->rootgc); for (i = 0; i < g->strt.size; i++) /* free all string lists */ sweepwholelist(L, &g->strt.hash[i]); } static void markmt (global_State *g) { int i; for (i=0; imt[i]) markobject(g, g->mt[i]); } /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); g->gray = NULL; g->grayagain = NULL; g->weak = NULL; markobject(g, g->mainthread); /* make global table be traversed before main stack */ markvalue(g, gt(g->mainthread)); markvalue(g, registry(L)); markmt(g); g->gcstate = GCSpropagate; } static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); if (isgray(obj2gco(uv))) markvalue(g, uv->v); } } static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); /* traverse objects cautch by write barrier and by 'remarkupvals' */ propagateall(g); /* remark weak tables */ g->gray = g->weak; g->weak = NULL; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ markmt(g); /* mark basic metatables (again) */ propagateall(g); /* remark gray again */ g->gray = g->grayagain; g->grayagain = NULL; propagateall(g); udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ marktmu(g); /* mark `preserved' userdata */ udsize += propagateall(g); /* remark, to propagate `preserveness' */ cleartable(g->weak); /* remove collected objects from weak tables */ /* flip current white */ g->currentwhite = cast_byte(otherwhite(g)); g->sweepstrgc = 0; g->sweepgc = &g->rootgc; g->gcstate = GCSsweepstring; g->estimate = g->totalbytes - udsize; /* first estimate */ } static l_mem singlestep (lua_State *L) { global_State *g = G(L); /*lua_checkmemory(L);*/ switch (g->gcstate) { case GCSpause: { markroot(L); /* start a new collection */ return 0; } case GCSpropagate: { if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ atomic(L); /* finish mark phase */ return 0; } } case GCSsweepstring: { lu_mem old = g->totalbytes; sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ g->gcstate = GCSsweep; /* end sweep-string phase */ lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } case GCSsweep: { lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); if (*g->sweepgc == NULL) { /* nothing more to sweep? */ checkSizes(L); g->gcstate = GCSfinalize; /* end sweep phase */ } lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } case GCSfinalize: { if (g->tmudata) { GCTM(L); if (g->estimate > GCFINALIZECOST) g->estimate -= GCFINALIZECOST; return GCFINALIZECOST; } else { g->gcstate = GCSpause; /* end collection */ g->gcdept = 0; return 0; } } default: lua_assert(0); return 0; } } void luaC_step (lua_State *L) { global_State *g = G(L); l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; if (lim == 0) lim = (MAX_LUMEM-1)/2; /* no limit */ g->gcdept += g->totalbytes - g->GCthreshold; do { lim -= singlestep(L); if (g->gcstate == GCSpause) break; } while (lim > 0); if (g->gcstate != GCSpause) { if (g->gcdept < GCSTEPSIZE) g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ else { g->gcdept -= GCSTEPSIZE; g->GCthreshold = g->totalbytes; } } else { lua_assert(g->totalbytes >= g->estimate); setthreshold(g); } } void luaC_fullgc (lua_State *L) { global_State *g = G(L); if (g->gcstate <= GCSpropagate) { /* reset sweep marks to sweep all elements (returning them to white) */ g->sweepstrgc = 0; g->sweepgc = &g->rootgc; /* reset other collector lists */ g->gray = NULL; g->grayagain = NULL; g->weak = NULL; g->gcstate = GCSsweepstring; } lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); /* finish any pending sweep phase */ while (g->gcstate != GCSfinalize) { lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); singlestep(L); } markroot(L); while (g->gcstate != GCSpause) { singlestep(L); } setthreshold(g); } void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); lua_assert(ttype(&o->gch) != LUA_TTABLE); /* must keep invariant? */ if (g->gcstate == GCSpropagate) reallymarkobject(g, v); /* restore invariant */ else /* don't mind */ makewhite(g, o); /* mark as white just to avoid other barriers */ } void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); GCObject *o = obj2gco(t); lua_assert(isblack(o) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ t->gclist = g->grayagain; g->grayagain = o; } void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { global_State *g = G(L); o->gch.next = g->rootgc; g->rootgc = o; o->gch.marked = luaC_white(g); o->gch.tt = tt; } void luaC_linkupval (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = obj2gco(uv); o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; if (isgray(o)) { if (g->gcstate == GCSpropagate) { gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } else { /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } } } infon/lua-5.1.2/src/loadlib.c0000644000076400001440000004516610603200765015536 0ustar dividuumusers/* ** $Id: loadlib.c,v 1.54a 2006/07/03 20:16:49 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** ** This module contains an implementation of loadlib for Unix systems ** that have dlfcn, an implementation for Darwin (Mac OS X), an ** implementation for Windows, and a stub for other systems. */ #include #include #define loadlib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" /* separator for open functions in C libraries */ #define LUA_OFSEP "_" #define LIBPREFIX "LOADLIB: " #define POF LUA_POF #define LIB_FAIL "open" /* error codes for ll_loadfunc */ #define ERRLIB 1 #define ERRFUNC 2 #define setprogdir(L) ((void)0) static void ll_unloadlib (void *lib); static void *ll_load (lua_State *L, const char *path); static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); #if defined(LUA_DL_DLOPEN) /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least ** as an emulation layer on top of native functions. ** ========================================================================= */ #include static void ll_unloadlib (void *lib) { dlclose(lib); } static void *ll_load (lua_State *L, const char *path) { void *lib = dlopen(path, RTLD_NOW); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)dlsym(lib, sym); if (f == NULL) lua_pushstring(L, dlerror()); return f; } /* }====================================================== */ #elif defined(LUA_DL_DLL) /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. ** ======================================================================= */ #include #undef setprogdir static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); DWORD n = GetModuleFileNameA(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { *lb = '\0'; luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); lua_remove(L, -2); /* remove original string */ } } static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer), NULL)) lua_pushstring(L, buffer); else lua_pushfstring(L, "system error %d\n", error); } static void ll_unloadlib (void *lib) { FreeLibrary((HINSTANCE)lib); } static void *ll_load (lua_State *L, const char *path) { HINSTANCE lib = LoadLibraryA(path); if (lib == NULL) pusherror(L); return lib; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); if (f == NULL) pusherror(L); return f; } /* }====================================================== */ #elif defined(LUA_DL_DYLD) /* ** {====================================================================== ** Native Mac OS X / Darwin Implementation ** ======================================================================= */ #include /* Mac appends a `_' before C function names */ #undef POF #define POF "_" LUA_POF static void pusherror (lua_State *L) { const char *err_str; const char *err_file; NSLinkEditErrors err; int err_num; NSLinkEditError(&err, &err_num, &err_file, &err_str); lua_pushstring(L, err_str); } static const char *errorfromcode (NSObjectFileImageReturnCode ret) { switch (ret) { case NSObjectFileImageInappropriateFile: return "file is not a bundle"; case NSObjectFileImageArch: return "library is for wrong CPU type"; case NSObjectFileImageFormat: return "bad format"; case NSObjectFileImageAccess: return "cannot access file"; case NSObjectFileImageFailure: default: return "unable to load library"; } } static void ll_unloadlib (void *lib) { NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); } static void *ll_load (lua_State *L, const char *path) { NSObjectFileImage img; NSObjectFileImageReturnCode ret; /* this would be a rare case, but prevents crashing if it happens */ if(!_dyld_present()) { lua_pushliteral(L, "dyld not present"); return NULL; } ret = NSCreateObjectFileImageFromFile(path, &img); if (ret == NSObjectFileImageSuccess) { NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(img); if (mod == NULL) pusherror(L); return mod; } lua_pushstring(L, errorfromcode(ret)); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); if (nss == NULL) { lua_pushfstring(L, "symbol " LUA_QS " not found", sym); return NULL; } return (lua_CFunction)NSAddressOfSymbol(nss); } /* }====================================================== */ #else /* ** {====================================================== ** Fallback for other systems ** ======================================================= */ #undef LIB_FAIL #define LIB_FAIL "absent" #define DLMSG "dynamic libraries not enabled; check your Lua installation" static void ll_unloadlib (void *lib) { (void)lib; /* to avoid warnings */ } static void *ll_load (lua_State *L, const char *path) { (void)path; /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { (void)lib; (void)sym; /* to avoid warnings */ lua_pushliteral(L, DLMSG); return NULL; } /* }====================================================== */ #endif static void **ll_register (lua_State *L, const char *path) { void **plib; lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ if (!lua_isnil(L, -1)) /* is there an entry? */ plib = (void **)lua_touserdata(L, -1); else { /* no entry yet; create one */ lua_pop(L, 1); plib = (void **)lua_newuserdata(L, sizeof(const void *)); *plib = NULL; luaL_getmetatable(L, "_LOADLIB"); lua_setmetatable(L, -2); lua_pushfstring(L, "%s%s", LIBPREFIX, path); lua_pushvalue(L, -2); lua_settable(L, LUA_REGISTRYINDEX); } return plib; } /* ** __gc tag method: calls library's `ll_unloadlib' function with the lib ** handle */ static int gctm (lua_State *L) { void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); if (*lib) ll_unloadlib(*lib); *lib = NULL; /* mark library as closed */ return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { void **reg = ll_register(L, path); if (*reg == NULL) *reg = ll_load(L, path); if (*reg == NULL) return ERRLIB; /* unable to load library */ else { lua_CFunction f = ll_sym(L, *reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); return 0; /* return function */ } } static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); int stat = ll_loadfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ lua_pushnil(L); lua_insert(L, -2); lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); return 3; /* return nil, error message, and where */ } } /* ** {====================================================== ** 'require' function ** ======================================================= */ static int readable (const char *filename) { FILE *f = fopen(filename, "r"); /* try to open file */ if (f == NULL) return 0; /* open failed */ fclose(f); return 1; } static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; while (*path == *LUA_PATHSEP) path++; /* skip separators */ if (*path == '\0') return NULL; /* no more templates */ l = strchr(path, *LUA_PATHSEP); /* find next separator */ if (l == NULL) l = path + strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; } static const char *findfile (lua_State *L, const char *name, const char *pname) { const char *path; name = luaL_gsub(L, name, ".", LUA_DIRSEP); lua_getfield(L, LUA_ENVIRONINDEX, pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); lua_pushliteral(L, ""); /* error accumulator */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename; filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ lua_pushfstring(L, "\n\tno file " LUA_QS, filename); lua_remove(L, -2); /* remove file name */ lua_concat(L, 2); /* add entry to possible error message */ } return NULL; /* not found */ } static void loaderror (lua_State *L, const char *filename) { luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); } static int loader_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path"); if (filename == NULL) return 1; /* library not found in this path */ if (luaL_loadfile(L, filename) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static const char *mkfuncname (lua_State *L, const char *modname) { const char *funcname; const char *mark = strchr(modname, *LUA_IGMARK); if (mark) modname = mark + 1; funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); funcname = lua_pushfstring(L, POF"%s", funcname); lua_remove(L, -2); /* remove 'gsub' result */ return funcname; } static int loader_C (lua_State *L) { const char *funcname; const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath"); if (filename == NULL) return 1; /* library not found in this path */ funcname = mkfuncname(L, name); if (ll_loadfunc(L, filename, funcname) != 0) loaderror(L, filename); return 1; /* library loaded successfully */ } static int loader_Croot (lua_State *L) { const char *funcname; const char *filename; const char *name = luaL_checkstring(L, 1); const char *p = strchr(name, '.'); int stat; if (p == NULL) return 0; /* is root */ lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath"); if (filename == NULL) return 1; /* root not found */ funcname = mkfuncname(L, name); if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, name, filename); return 1; /* function not found */ } return 1; } static int loader_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.preload") " must be a table"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } static const int sentinel_ = 0; #define sentinel ((void *)&sentinel_) static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); int i; lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); if (lua_toboolean(L, -1)) { /* is it there? */ if (lua_touserdata(L, -1) == sentinel) /* check loops */ luaL_error(L, "loop or previous error loading module " LUA_QS, name); return 1; /* package is already loaded */ } /* else must load it; iterate over available loaders */ lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); if (!lua_istable(L, -1)) luaL_error(L, LUA_QL("package.loaders") " must be a table"); lua_pushliteral(L, ""); /* error message accumulator */ for (i=1; ; i++) { lua_rawgeti(L, -2, i); /* get a loader */ if (lua_isnil(L, -1)) luaL_error(L, "module " LUA_QS " not found:%s", name, lua_tostring(L, -2)); lua_pushstring(L, name); lua_call(L, 1, 1); /* call it */ if (lua_isfunction(L, -1)) /* did it find module? */ break; /* module loaded successfully */ else if (lua_isstring(L, -1)) /* loader returned error message? */ lua_concat(L, 2); /* accumulate it */ else lua_pop(L, 1); } lua_pushlightuserdata(L, sentinel); lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ } return 1; } /* }====================================================== */ /* ** {====================================================== ** 'module' function ** ======================================================= */ static void setfenv (lua_State *L) { lua_Debug ar; lua_getstack(L, 1, &ar); lua_getinfo(L, "f", &ar); lua_pushvalue(L, -2); lua_setfenv(L, -2); lua_pop(L, 1); } static void dooptions (lua_State *L, int n) { int i; for (i = 2; i <= n; i++) { lua_pushvalue(L, i); /* get option (a function) */ lua_pushvalue(L, -2); /* module */ lua_call(L, 1, 0); } } static void modinit (lua_State *L, const char *modname) { const char *dot; lua_pushvalue(L, -1); lua_setfield(L, -2, "_M"); /* module._M = module */ lua_pushstring(L, modname); lua_setfield(L, -2, "_NAME"); dot = strrchr(modname, '.'); /* look for last dot in module name */ if (dot == NULL) dot = modname; else dot++; /* set _PACKAGE as package name (full module name minus last part) */ lua_pushlstring(L, modname, dot - modname); lua_setfield(L, -2, "_PACKAGE"); } static int ll_module (lua_State *L) { const char *modname = luaL_checkstring(L, 1); int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ if (!lua_istable(L, -1)) { /* not found? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) return luaL_error(L, "name conflict for module " LUA_QS, modname); lua_pushvalue(L, -1); lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ } /* check whether table already has a _NAME field */ lua_getfield(L, -1, "_NAME"); if (!lua_isnil(L, -1)) /* is table an initialized module? */ lua_pop(L, 1); else { /* no; initialize it */ lua_pop(L, 1); modinit(L, modname); } lua_pushvalue(L, -1); setfenv(L); dooptions(L, loaded - 1); return 0; } static int ll_seeall (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); if (!lua_getmetatable(L, 1)) { lua_createtable(L, 0, 1); /* create new metatable */ lua_pushvalue(L, -1); lua_setmetatable(L, 1); } lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } /* }====================================================== */ /* auxiliary mark (for internal use) */ #define AUXMARK "\1" static void setpath (lua_State *L, const char *fieldname, const char *envname, const char *def) { const char *path = getenv(envname); if (path == NULL) /* no environment variable? */ lua_pushstring(L, def); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, LUA_PATHSEP AUXMARK LUA_PATHSEP); luaL_gsub(L, path, AUXMARK, def); lua_remove(L, -2); } setprogdir(L); lua_setfield(L, -2, fieldname); } static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, {"seeall", ll_seeall}, {NULL, NULL} }; static const luaL_Reg ll_funcs[] = { {"module", ll_module}, {"require", ll_require}, {NULL, NULL} }; static const lua_CFunction loaders[] = {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; LUALIB_API int luaopen_package (lua_State *L) { int i; /* create new type _LOADLIB */ luaL_newmetatable(L, "_LOADLIB"); lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* create `package' table */ luaL_register(L, LUA_LOADLIBNAME, pk_funcs); #if defined(LUA_COMPAT_LOADLIB) lua_getfield(L, -1, "loadlib"); lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); #endif lua_pushvalue(L, -1); lua_replace(L, LUA_ENVIRONINDEX); /* create `loaders' table */ lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); /* fill it with pre-defined loaders */ for (i=0; loaders[i] != NULL; i++) { lua_pushcfunction(L, loaders[i]); lua_rawseti(L, -2, i+1); } lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" LUA_EXECDIR "\n" LUA_IGMARK); lua_setfield(L, -2, "config"); /* set field `loaded' */ luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); lua_setfield(L, -2, "loaded"); /* set field `preload' */ lua_newtable(L); lua_setfield(L, -2, "preload"); lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_register(L, NULL, ll_funcs); /* open lib into global table */ lua_pop(L, 1); return 1; /* return 'package' table */ } infon/lua-5.1.2/src/lfunc.c0000644000076400001440000001100710603200765015222 0ustar dividuumusers/* ** $Id: lfunc.c,v 2.12a 2005/12/22 16:19:56 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #include #define lfunc_c #define LUA_CORE #include "lua.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->c.isC = 1; c->c.env = e; c->c.nupvalues = cast_byte(nelems); return c; } Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) { Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); luaC_link(L, obj2gco(c), LUA_TFUNCTION); c->l.isC = 0; c->l.env = e; c->l.nupvalues = cast_byte(nelems); while (nelems--) c->l.upvals[nelems] = NULL; return c; } UpVal *luaF_newupval (lua_State *L) { UpVal *uv = luaM_new(L, UpVal); luaC_link(L, obj2gco(uv), LUA_TUPVAL); uv->v = &uv->u.value; setnilvalue(uv->v); return uv; } UpVal *luaF_findupval (lua_State *L, StkId level) { global_State *g = G(L); GCObject **pp = &L->openupval; UpVal *p; UpVal *uv; while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) { lua_assert(p->v != &p->u.value); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, obj2gco(p))) /* is it dead? */ changewhite(obj2gco(p)); /* ressurect it */ return p; } pp = &p->next; } uv = luaM_new(L, UpVal); /* not found: create a new one */ uv->tt = LUA_TUPVAL; uv->marked = luaC_white(g); uv->v = level; /* current value lives in the stack */ uv->next = *pp; /* chain it in the proper position */ *pp = obj2gco(uv); uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ uv->u.l.next = g->uvhead.u.l.next; uv->u.l.next->u.l.prev = uv; g->uvhead.u.l.next = uv; lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); return uv; } static void unlinkupval (UpVal *uv) { lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ uv->u.l.prev->u.l.next = uv->u.l.next; } void luaF_freeupval (lua_State *L, UpVal *uv) { if (uv->v != &uv->u.value) /* is it open? */ unlinkupval(uv); /* remove from open list */ luaM_free(L, uv); /* free upvalue */ } void luaF_close (lua_State *L, StkId level) { UpVal *uv; global_State *g = G(L); while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) { GCObject *o = obj2gco(uv); lua_assert(!isblack(o) && uv->v != &uv->u.value); L->openupval = uv->next; /* remove from `open' list */ if (isdead(g, o)) luaF_freeupval(L, uv); /* free upvalue */ else { unlinkupval(uv); setobj(L, &uv->u.value, uv->v); uv->v = &uv->u.value; /* now current value lives here */ luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ } } } Proto *luaF_newproto (lua_State *L) { Proto *f = luaM_new(L, Proto); luaC_link(L, obj2gco(f), LUA_TPROTO); f->k = NULL; f->sizek = 0; f->p = NULL; f->sizep = 0; f->code = NULL; f->sizecode = 0; f->sizelineinfo = 0; f->sizeupvalues = 0; f->nups = 0; f->upvalues = NULL; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; f->lineinfo = NULL; f->sizelocvars = 0; f->locvars = NULL; f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; return f; } void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->p, f->sizep, Proto *); luaM_freearray(L, f->k, f->sizek, TValue); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); luaM_free(L, f); } void luaF_freeclosure (lua_State *L, Closure *c) { int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : sizeLclosure(c->l.nupvalues); luaM_freemem(L, c, size); } /* ** Look for n-th local variable at line `line' in function `func'. ** Returns NULL if not found. */ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { int i; for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ local_number--; if (local_number == 0) return getstr(f->locvars[i].varname); } } return NULL; /* not found */ } infon/lua-5.1.2/src/lopcodes.c0000644000076400001440000000550010603200765015724 0ustar dividuumusers/* ** $Id: lopcodes.c,v 1.37 2005/11/08 19:45:36 roberto Exp $ ** See Copyright Notice in lua.h */ #define lopcodes_c #define LUA_CORE #include "lopcodes.h" /* ORDER OP */ const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETGLOBAL", "GETTABLE", "SETGLOBAL", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD", "POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", "FORPREP", "TFORLOOP", "SETLIST", "CLOSE", "CLOSURE", "VARARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_GETGLOBAL */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ ,opmode(0, 0, OpArgK, OpArgN, iABx) /* OP_SETGLOBAL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ }; infon/lua-5.1.2/src/lparser.c0000644000076400001440000010734110603200765015572 0ustar dividuumusers/* ** $Id: lparser.c,v 2.42a 2006/06/05 15:57:59 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #include #define lparser_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) #define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) #define luaY_checklimit(fs,v,l,m) if ((v)>(l)) errorlimit(fs,l,m) /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int breaklist; /* list of jumps out of this loop */ lu_byte nactvar; /* # active locals outside the breakable structure */ lu_byte upval; /* true if some variable in the block is an upvalue */ lu_byte isbreakable; /* true if `block' is a loop */ } BlockCnt; /* ** prototypes for recursive non-terminal functions */ static void chunk (LexState *ls); static void expr (LexState *ls, expdesc *v); static void anchor_token (LexState *ls) { if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { TString *ts = ls->t.seminfo.ts; luaX_newstring(ls, getstr(ts), ts->tsv.len); } } static void error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token))); } static void errorlimit (FuncState *fs, int limit, const char *what) { const char *msg = (fs->f->linedefined == 0) ? luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) : luaO_pushfstring(fs->L, "function at line %d has more than %d %s", fs->f->linedefined, limit, what); luaX_lexerror(fs->ls, msg, 0); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { luaX_next(ls); return 1; } else return 0; } static void check (LexState *ls, int c) { if (ls->t.token != c) error_expected(ls, c); } static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); } #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } static void check_match (LexState *ls, int what, int who, int where) { if (!testnext(ls, what)) { if (where == ls->linenumber) error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, LUA_QS " expected (to close " LUA_QS " at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } } static TString *str_checkname (LexState *ls) { TString *ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; luaX_next(ls); return ts; } static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; e->u.s.info = i; } static void codestring (LexState *ls, expdesc *e, TString *s) { init_exp(e, VK, luaK_stringK(ls->fs, s)); } static void checkname(LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, LocVar, SHRT_MAX, "too many local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } #define new_localvarliteral(ls,v,n) \ new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n) static void new_localvar (LexState *ls, TString *name, int n) { FuncState *fs = ls->fs; luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables"); fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name)); } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; } } static void removevars (LexState *ls, int tolevel) { FuncState *fs = ls->fs; while (fs->nactvar > tolevel) getlocvar(fs, --fs->nactvar).endpc = fs->pc; } static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { int i; Proto *f = fs->f; int oldsize = f->sizeupvalues; for (i=0; inups; i++) { if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) { lua_assert(f->upvalues[i] == name); return i; } } /* new one */ luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues"); luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues, TString *, MAX_INT, ""); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL; f->upvalues[f->nups] = name; luaC_objbarrier(fs->L, f, name); lua_assert(v->k == VLOCAL || v->k == VUPVAL); fs->upvalues[f->nups].k = cast_byte(v->k); fs->upvalues[f->nups].info = cast_byte(v->u.s.info); return f->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i=fs->nactvar-1; i >= 0; i--) { if (n == getlocvar(fs, i).varname) return i; } return -1; /* not found */ } static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl && bl->nactvar > level) bl = bl->previous; if (bl) bl->upval = 1; } static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) { /* no more levels? */ init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ return VGLOBAL; } else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { init_exp(var, VLOCAL, v); if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } else { /* not found at current level; try upper one */ if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL) return VGLOBAL; var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ var->k = VUPVAL; /* upvalue in this level */ return VUPVAL; } } } static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VGLOBAL) var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */ } static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } } } static void enterlevel (LexState *ls) { if (++ls->L->nCcalls > LUAI_MAXCCALLS) luaX_lexerror(ls, "chunk has too many syntax levels", 0); } #define leavelevel(ls) ((ls)->L->nCcalls--) static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { bl->breaklist = NO_JUMP; bl->isbreakable = isbreakable; bl->nactvar = fs->nactvar; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; lua_assert(fs->freereg == fs->nactvar); } static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; fs->bl = bl->previous; removevars(fs->ls, bl->nactvar); if (bl->upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); /* a block either controls scope or breaks (never both) */ lua_assert(!bl->isbreakable || !bl->upval); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ luaK_patchtohere(fs, bl->breaklist); } static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizep; int i; luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; f->p[fs->np++] = func->f; luaC_objbarrier(ls->L, f, func->f); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); for (i=0; if->nups; i++) { OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); } } static void open_func (LexState *ls, FuncState *fs) { lua_State *L = ls->L; Proto *f = luaF_newproto(L); fs->f = f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; fs->L = L; ls->fs = fs; fs->pc = 0; fs->lasttarget = -1; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->bl = NULL; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ fs->h = luaH_new(L, 0, 0); /* anchor table of constants and prototype (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); incr_top(L); setptvalue2s(L, L->top, f); incr_top(L); } static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; removevars(ls, 0); luaK_ret(fs, 0, 0); /* final return */ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); f->sizeupvalues = f->nups; lua_assert(luaG_checkcode(f)); lua_assert(fs->bl == NULL); ls->fs = fs->prev; L->top -= 2; /* remove table and prototype from the stack */ /* last token read was anchored in defunct function; must reanchor it */ if (fs) anchor_token(ls); } Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; lexstate.buff = buff; luaX_setinput(L, &lexstate, z, luaS_new(L, name)); open_func(&lexstate, &funcstate); funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); check(&lexstate, TK_EOS); close_func(&lexstate); lua_assert(funcstate.prev == NULL); lua_assert(funcstate.f->nups == 0); lua_assert(lexstate.fs == NULL); return funcstate.f; } /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ static void field (LexState *ls, expdesc *v) { /* field -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyreg(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); } /* ** {====================================================================== ** Rules for Constructors ** ======================================================================= */ struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of `record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { /* recfield -> (NAME | `['exp1`]') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ yindex(ls, &key); cc->nh++; checknext(ls, '='); rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } static void closelistfield (FuncState *fs, struct ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } } static void listfield (LexState *ls, struct ConsControl *cc) { expr(ls, &cc->v); luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } static void constructor (LexState *ls, expdesc *t) { /* constructor -> ?? */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); switch(ls->t.token) { case TK_NAME: { /* may be listfields or recfields */ luaX_lookahead(ls); if (ls->lookahead.token != '=') /* expression? */ listfield(ls, &cc); else recfield(ls, &cc); break; } case '[': { /* constructor_item -> recfield */ recfield(ls, &cc); break; } default: { /* constructor_part -> listfield */ listfield(ls, &cc); break; } } } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ static void parlist (LexState *ls) { /* parlist -> [ param { `,' param } ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') { /* is `parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls), nparams++); break; } case TK_DOTS: { /* param -> `...' */ luaX_next(ls); #if defined(LUA_COMPAT_VARARG) /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG; #endif f->is_vararg |= VARARG_ISVARARG; break; } default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG)); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); } static int explist1 (LexState *ls, expdesc *v) { /* explist1 -> expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++; } return n; } static void funcargs (LexState *ls, expdesc *f) { FuncState *fs = ls->fs; expdesc args; int base, nparams; int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> `(' [ explist1 ] `)' */ if (line != ls->lastline) luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); return; } } lua_assert(f->k == VNONRELOC); base = f->u.s.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ } /* ** {====================================================================== ** Expression parsing ** ======================================================================= */ static void prefixexp (LexState *ls, expdesc *v) { /* prefixexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v); return; } default: { luaX_syntaxerror(ls, "unexpected symbol"); return; } } } static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; prefixexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* field */ field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key; luaK_exp2anyreg(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* `:' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use " LUA_QL("...") " outside a vararg function"); fs->f->is_vararg &= ~VARARG_NEEDSARG; /* don't need 'arg' */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { primaryexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ {10, 9}, {5, 4}, /* power and concat (right associative) */ {3, 3}, {3, 3}, /* equality and inequality */ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ {2, 2}, {1, 1} /* logical (and/or) */ }; #define UNARY_PRIORITY 8 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ } static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); } /* }==================================================================== */ /* ** {====================================================================== ** Rules for Statements ** ======================================================================= */ static int block_follow (int token) { switch (token) { case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_UNTIL: case TK_EOS: return 1; default: return 0; } } static void block (LexState *ls) { /* block -> chunk */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); chunk(ls); lua_assert(bl.breaklist == NO_JUMP); leaveblock(fs); } /* ** structure to chain all variables in the left-hand side of an ** assignment */ struct LHS_assign { struct LHS_assign *prev; expdesc v; /* variable (global, local, upvalue, or indexed) */ }; /* ** check whether, in an assignment to a local variable, the local variable ** is needed in a previous assignment (to a table). If so, save original ** local value in a safe place and use this safe copy in the previous ** assignment. */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { if (lh->v.k == VINDEXED) { if (lh->v.u.s.info == v->u.s.info) { /* conflict? */ conflict = 1; lh->v.u.s.info = extra; /* previous assignment will use safe copy */ } if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */ conflict = 1; lh->v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict) { luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */ luaK_reserveregs(fs, 1); } } static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, "syntax error"); if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ struct LHS_assign nv; nv.prev = lh; primaryexp(ls, &nv.v); if (nv.v.k == VLOCAL) check_conflict(ls, lh, &nv.v); assignment(ls, &nv, nvars+1); } else { /* assignment -> `=' explist1 */ int nexps; checknext(ls, '='); nexps = explist1(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e); } static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } static void breakstat (LexState *ls) { FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; int upval = 0; while (bl && !bl->isbreakable) { upval |= bl->upval; bl = bl->previous; } if (!bl) luaX_syntaxerror(ls, "no loop to break"); if (upval) luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); } static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_patchlist(fs, luaK_jump(fs), whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ chunk(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (!bl2.upval) { /* no upvalues? */ leaveblock(fs); /* finish scope */ luaK_patchlist(ls->fs, condexit, repeat_init); /* close the loop */ } else { /* complete semantics when there are upvalues */ breakstat(ls); /* if condition then break */ luaK_patchtohere(ls->fs, condexit); /* else... */ leaveblock(fs); /* finish scope... */ luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init); /* and repeat */ } leaveblock(fs); /* finish loop */ } static int exp1 (LexState *ls) { expdesc e; int k; expr(ls, &e); k = e.k; luaK_exp2nextreg(ls->fs, &e); return k; } static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars); luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1); } static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; new_localvarliteral(ls, "(for index)", 0); new_localvarliteral(ls, "(for limit)", 1); new_localvarliteral(ls, "(for step)", 2); new_localvar(ls, varname, 3); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist1 forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 0; int line; int base = fs->freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)", nvars++); new_localvarliteral(ls, "(for state)", nvars++); new_localvarliteral(ls, "(for control)", nvars++); /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',')) new_localvar(ls, str_checkname(ls), nvars++); checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist1(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ luaX_next(ls); /* skip `for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope (`break' jumps to this point) */ } static int test_then_block (LexState *ls) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ int condexit; luaX_next(ls); /* skip IF or ELSEIF */ condexit = cond(ls); checknext(ls, TK_THEN); block(ls); /* `then' part */ return condexit; } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int flist; int escapelist = NO_JUMP; flist = test_then_block(ls); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); flist = test_then_block(ls); /* ELSEIF cond THEN block */ } if (ls->t.token == TK_ELSE) { luaK_concat(fs, &escapelist, luaK_jump(fs)); luaK_patchtohere(fs, flist); luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ block(ls); /* `else' part */ } else luaK_concat(fs, &escapelist, flist); luaK_patchtohere(fs, escapelist); check_match(ls, TK_END, TK_IF, line); } static void localfunc (LexState *ls) { expdesc v, b; FuncState *fs = ls->fs; new_localvar(ls, str_checkname(ls), 0); init_exp(&v, VLOCAL, fs->freereg); luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, &b, 0, ls->linenumber); luaK_storevar(fs, &v, &b); /* debug information will only see the variable after this point! */ getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; } static void localstat (LexState *ls) { /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ int nvars = 0; int nexps; expdesc e; do { new_localvar(ls, str_checkname(ls), nvars++); } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist1(ls, &e); else { e.k = VVOID; nexps = 0; } adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {field} [`:' NAME] */ int needself = 0; singlevar(ls, v); while (ls->t.token == '.') field(ls, v); if (ls->t.token == ':') { needself = 1; field(ls, v); } return needself; } static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int needself; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, &v); body(ls, &b, needself, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ } static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; primaryexp(ls, &v.v); if (v.v.k == VCALL) /* stat -> func */ SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ else { /* stat -> assignment */ v.prev = NULL; assignment(ls, &v, 1); } } static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); } static int statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ switch (ls->t.token) { case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); return 0; } case TK_WHILE: { /* stat -> whilestat */ whilestat(ls, line); return 0; } case TK_DO: { /* stat -> DO block END */ luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); return 0; } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); return 0; } case TK_REPEAT: { /* stat -> repeatstat */ repeatstat(ls, line); return 0; } case TK_FUNCTION: { funcstat(ls, line); /* stat -> funcstat */ return 0; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else localstat(ls); return 0; } case TK_RETURN: { /* stat -> retstat */ retstat(ls); return 1; /* must be last statement */ } case TK_BREAK: { /* stat -> breakstat */ luaX_next(ls); /* skip BREAK */ breakstat(ls); return 1; /* must be last statement */ } default: { exprstat(ls); return 0; /* to avoid warnings */ } } } static void chunk (LexState *ls) { /* chunk -> { stat [`;'] } */ int islast = 0; enterlevel(ls); while (!islast && !block_follow(ls->t.token)) { islast = statement(ls); testnext(ls, ';'); lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ } leavelevel(ls); } /* }====================================================================== */ infon/lua-5.1.2/src/ltable.h0000644000076400001440000000223410603200765015365 0ustar dividuumusers/* ** $Id: ltable.h,v 2.10 2006/01/10 13:13:06 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ #ifndef ltable_h #define ltable_h #include "lobject.h" #define gnode(t,i) (&(t)->node[i]) #define gkey(n) (&(n)->i_key.nk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) #define key2tval(n) (&(n)->i_key.tvk) LUAI_FUNC const TValue *luaH_getnum (Table *t, int key); LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); #if defined(LUA_DEBUG) LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC int luaH_isdummy (Node *n); #endif #endif infon/lua-5.1.2/src/llex.h0000644000076400001440000000417510603200765015074 0ustar dividuumusers/* ** $Id: llex.h,v 1.58 2006/03/23 18:23:32 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #ifndef llex_h #define llex_h #include "lobject.h" #include "lzio.h" #define FIRST_RESERVED 257 /* maximum length of a reserved word */ #define TOKEN_LEN (sizeof("function")/sizeof(char)) /* * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" */ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, TK_NAME, TK_STRING, TK_EOS }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) /* array with token `names' */ LUAI_DATA const char *const luaX_tokens []; typedef union { lua_Number r; TString *ts; } SemInfo; /* semantics information */ typedef struct Token { int token; SemInfo seminfo; } Token; typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ int lastline; /* line of last token `consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* `FuncState' is private to the parser */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ TString *source; /* current source name */ char decpoint; /* locale decimal point */ } LexState; LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC void luaX_lookahead (LexState *ls); LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token); LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); #endif infon/lua-5.1.2/src/lgc.h0000644000076400001440000000612310603200765014670 0ustar dividuumusers/* ** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #ifndef lgc_h #define lgc_h #include "lobject.h" /* ** Possible states of the Garbage Collector */ #define GCSpause 0 #define GCSpropagate 1 #define GCSsweepstring 2 #define GCSsweep 3 #define GCSfinalize 4 /* ** some userful bit tricks */ #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) #define setbits(x,m) ((x) |= (m)) #define testbits(x,m) ((x) & (m)) #define bitmask(b) (1<<(b)) #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) #define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) #define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) #define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) /* ** Layout for bit use in `marked' field: ** bit 0 - object is white (type 0) ** bit 1 - object is white (type 1) ** bit 2 - object is black ** bit 3 - for userdata: has been finalized ** bit 3 - for tables: has weak keys ** bit 4 - for tables: has weak values ** bit 5 - object is fixed (should not be collected) ** bit 6 - object is "super" fixed (only the main thread) */ #define WHITE0BIT 0 #define WHITE1BIT 1 #define BLACKBIT 2 #define FINALIZEDBIT 3 #define KEYWEAKBIT 3 #define VALUEWEAKBIT 4 #define FIXEDBIT 5 #define SFIXEDBIT 6 #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) #define isblack(x) testbit((x)->gch.marked, BLACKBIT) #define isgray(x) (!isblack(x) && !iswhite(x)) #define otherwhite(g) (g->currentwhite ^ WHITEBITS) #define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) #define changewhite(x) ((x)->gch.marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #define luaC_checkGC(L) { \ condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ if (G(L)->totalbytes >= G(L)->GCthreshold) \ luaC_step(L); } #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),gcvalue(v)); } #define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ luaC_barrierback(L,t); } #define luaC_objbarrier(L,p,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ luaC_barrierf(L,obj2gco(p),obj2gco(o)); } #define luaC_objbarriert(L,t,o) \ { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); LUAI_FUNC void luaC_callGCTM (lua_State *L); LUAI_FUNC void luaC_freeall (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_fullgc (lua_State *L); LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); #endif infon/lua-5.1.2/src/lfunc.h0000644000076400001440000000214110603200765015226 0ustar dividuumusers/* ** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #ifndef lfunc_h #define lfunc_h #include "lobject.h" #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ cast(int, sizeof(TValue)*((n)-1))) #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ cast(int, sizeof(TValue *)*((n)-1))) LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); #endif infon/lua-5.1.2/src/lopcodes.h0000644000076400001440000001762210603200765015741 0ustar dividuumusers/* ** $Id: lopcodes.h,v 1.125 2006/03/14 19:04:44 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lopcodes_h #define lopcodes_h #include "llimits.h" /*=========================================================================== We assume that instructions are unsigned numbers. All instructions have an opcode in the first 6 bits. Instructions can have the following fields: `A' : 8 bits `B' : 9 bits `C' : 9 bits `Bx' : 18 bits (`B' and `C' together) `sBx' : signed Bx A signed argument is represented in excess K; that is, the number value is the unsigned value minus K. K is exactly the maximum value for that argument (so that -max is represented by 0, and +max is represented by 2*max), which is half the maximum for the corresponding unsigned argument. ===========================================================================*/ enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ /* ** size and position of opcode arguments. */ #define SIZE_C 9 #define SIZE_B 9 #define SIZE_Bx (SIZE_C + SIZE_B) #define SIZE_A 8 #define SIZE_OP 6 #define POS_OP 0 #define POS_A (POS_OP + SIZE_OP) #define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C /* ** limits for opcode arguments. ** we use (signed) int to manipulate most arguments, ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) */ #if SIZE_Bx < LUAI_BITSINT-1 #define MAXARG_Bx ((1<>1) /* `sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT #endif #define MAXARG_A ((1<>POS_OP) & MASK1(SIZE_OP,0))) #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ ((cast(Instruction, o)<>POS_A) & MASK1(SIZE_A,0))) #define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ ((cast(Instruction, u)<>POS_B) & MASK1(SIZE_B,0))) #define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ ((cast(Instruction, b)<>POS_C) & MASK1(SIZE_C,0))) #define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ ((cast(Instruction, b)<>POS_Bx) & MASK1(SIZE_Bx,0))) #define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ ((cast(Instruction, b)< C) then pc++ */ OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) =) R(A)*/ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ } OpCode; #define NUM_OPCODES (cast(int, OP_VARARG) + 1) /*=========================================================================== Notes: (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, and can be 0: OP_CALL then sets `top' to last_result+1, so next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). (*) In OP_RETURN, if (B == 0) then return up to `top' (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next `instruction' is real C (*) For comparisons, A specifies what condition the test should accept (true or false). (*) All `skips' (pc++) assume that next instruction is a jump ===========================================================================*/ /* ** masks for instruction properties. The format is: ** bits 0-1: op mode ** bits 2-3: C arg mode ** bits 4-5: B arg mode ** bit 6: instruction set register A ** bit 7: operator is a test */ enum OpArgMask { OpArgN, /* argument is not used */ OpArgU, /* argument is used */ OpArgR, /* argument is a register or a jump offset */ OpArgK /* argument is a constant or register/constant */ }; LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) #define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) #define testAMode(m) (luaP_opmodes[m] & (1 << 6)) #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ #define LFIELDS_PER_FLUSH 50 #endif infon/lua-5.1.2/src/lbaselib.c0000644000076400001440000004155210603200765015700 0ustar dividuumusers/* ** $Id: lbaselib.c,v 1.191a 2006/06/02 15:34:00 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ #include #include #include #include #define lbaselib_c #define LUA_LIB #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** If your system does not support `stdout', you can just remove this function. ** If you need, you can define your own `print' function, following this ** model but changing `fputs' to put the strings at a proper place ** (a console window or a log file, for instance). */ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i = lua_icontext(L); if (i) { n -= 2; /* compensate for tostring function and result */ goto resume; } lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_icall(L, 1, 1, i); resume: s = lua_tostring(L, -1); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); if (i>1) fputs("\t", stdout); fputs(s, stdout); lua_pop(L, 1); /* pop result */ } fputs("\n", stdout); return 0; } static int luaB_tonumber (lua_State *L) { int base = luaL_optint(L, 2, 10); if (base == 10) { /* standard conversion */ luaL_checkany(L, 1); if (lua_isnumber(L, 1)) { lua_pushnumber(L, lua_tonumber(L, 1)); return 1; } } else { const char *s1 = luaL_checkstring(L, 1); char *s2; unsigned long n; luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); n = strtoul(s1, &s2, base); if (s1 != s2) { /* at least one valid digit? */ while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ if (*s2 == '\0') { /* no invalid trailing characters? */ lua_pushnumber(L, (lua_Number)n); return 1; } } } lua_pushnil(L); /* else not a number */ return 1; } static int luaB_error (lua_State *L) { int level = luaL_optint(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); } return lua_error(L); } static int luaB_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); return 1; /* no metatable */ } luaL_getmetafield(L, 1, "__metatable"); return 1; /* returns either __metatable field (if present) or metatable */ } static int luaB_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable")) luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } static void getfunc (lua_State *L, int opt) { if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); else { lua_Debug ar; int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); if (lua_getstack(L, level, &ar) == 0) luaL_argerror(L, 1, "invalid level"); lua_getinfo(L, "f", &ar); if (lua_isnil(L, -1)) luaL_error(L, "no function environment for tail call at level %d", level); } } static int luaB_getfenv (lua_State *L) { getfunc(L, 1); if (lua_iscfunction(L, -1)) /* is a C function? */ lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ else lua_getfenv(L, -1); return 1; } static int luaB_setfenv (lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); getfunc(L, 0); lua_pushvalue(L, 2); if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) { /* change environment of current thread */ lua_pushthread(L); lua_insert(L, -2); lua_setfenv(L, -2); return 0; } else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) luaL_error(L, LUA_QL("setfenv") " cannot change environment of given object"); return 1; } static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); luaL_checkany(L, 2); lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; } static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); lua_settop(L, 2); lua_rawget(L, 1); return 1; } static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); lua_settop(L, 3); lua_rawset(L, 1); return 1; } static int luaB_gcinfo (lua_State *L) { lua_pushinteger(L, lua_getgccount(L)); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; int o = luaL_checkoption(L, 1, "collect", opts); int ex = luaL_optint(L, 2, 0); int res = lua_gc(L, optsnum[o], ex); switch (optsnum[o]) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, res + ((lua_Number)b/1024)); return 1; } case LUA_GCSTEP: { lua_pushboolean(L, res); return 1; } default: { lua_pushnumber(L, res); return 1; } } } static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, luaL_typename(L, 1)); return 1; } static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ if (lua_next(L, 1)) return 2; else { lua_pushnil(L); return 1; } } static int luaB_pairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushnil(L); /* and initial value */ return 3; } static int ipairsaux (lua_State *L) { int i = luaL_checkint(L, 2); luaL_checktype(L, 1, LUA_TTABLE); i++; /* next value */ lua_pushinteger(L, i); lua_rawgeti(L, 1, i); return (lua_isnil(L, -1)) ? 0 : 2; } static int luaB_ipairs (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ lua_pushvalue(L, 1); /* state, */ lua_pushinteger(L, 0); /* and initial value */ return 3; } static int load_aux (lua_State *L, int status) { if (status == 0) /* OK? */ return 1; else { lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ } } static int luaB_loadstring (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); const char *chunkname = luaL_optstring(L, 2, s); return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); } static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); return load_aux(L, luaL_loadfile(L, fname)); } /* ** Reader for generic `load' function: `lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { (void)ud; /* to avoid warnings */ luaL_checkstack(L, 2, "too many nested functions"); lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { *size = 0; return NULL; } else if (lua_isstring(L, -1)) { lua_replace(L, 3); /* save string in a reserved stack slot */ return lua_tolstring(L, 3, size); } else luaL_error(L, "reader function must return a string"); return NULL; /* to avoid warnings */ } static int luaB_load (lua_State *L) { int status; const char *cname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ status = lua_load(L, generic_reader, NULL, cname); return load_aux(L, status); } static int luaB_dofile (lua_State *L) { if (lua_icontext(L)) goto resume; lua_settop(L, 1); if (luaL_loadfile(L, luaL_optstring(L, 1, NULL)) != 0) lua_error(L); lua_icall(L, 0, LUA_MULTRET, 1); resume: return lua_gettop(L) - 1; } static int luaB_assert (lua_State *L) { luaL_checkany(L, 1); if (!lua_toboolean(L, 1)) return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); return lua_gettop(L); } static int luaB_unpack (lua_State *L) { int i, e, n; luaL_checktype(L, 1, LUA_TTABLE); i = luaL_optint(L, 2, 1); e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); n = e - i + 1; /* number of elements */ if (n <= 0) return 0; /* empty range */ luaL_checkstack(L, n, "table too big to unpack"); for (; i<=e; i++) /* push arg[i...e] */ lua_rawgeti(L, 1, i); return n; } static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { lua_pushinteger(L, n-1); return 1; } else { int i = luaL_checkint(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); return n - i; } } static int aux_pcall (lua_State *L, int ef) { int status = lua_icontext(L); if (status) goto resume; luaL_checkany(L, ef+1); status = lua_ipcall(L, lua_gettop(L) - ef - 1, LUA_MULTRET, ef, -1); resume: if (status > 0) { /* error */ lua_pushboolean(L, 0); lua_insert(L, -2); /* args may be left on stack with vpcall/ipcall */ return 2; /* return status + error */ } else { /* ok */ lua_pushboolean(L, 1); lua_insert(L, ef+1); return lua_gettop(L) - ef; /* return status + all results */ } } static int luaB_pcall (lua_State *L) { return aux_pcall(L, 0); } static int luaB_epcall (lua_State *L) { return aux_pcall(L, 1); } static int luaB_xpcall (lua_State *L) { /* for compatibility only */ if (lua_icontext(L) == 0) { luaL_checkany(L, 2); lua_settop(L, 2); lua_insert(L, 1); /* put error function under function to be called */ } return aux_pcall(L, 1); } static int luaB_tostring (lua_State *L) { if (lua_icontext(L)) return 1; luaL_checkany(L, 1); if (luaL_getmetafield(L, 1, "__tostring")) { lua_pushvalue(L, 1); lua_icall(L, 1, 1, 1); /* call metamethod */ return 1; } switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); break; case LUA_TSTRING: lua_pushvalue(L, 1); break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); break; case LUA_TNIL: lua_pushliteral(L, "nil"); break; default: lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); break; } return 1; } static int luaB_newproxy (lua_State *L) { lua_settop(L, 1); lua_newuserdata(L, 0); /* create proxy */ if (lua_toboolean(L, 1) == 0) return 1; /* no metatable */ else if (lua_isboolean(L, 1)) { lua_newtable(L); /* create a new metatable `m' ... */ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ lua_pushboolean(L, 1); lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ } else { int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ if (lua_getmetatable(L, 1)) { lua_rawget(L, lua_upvalueindex(1)); validproxy = lua_toboolean(L, -1); lua_pop(L, 1); /* remove value */ } luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); lua_getmetatable(L, 1); /* metatable is valid; get it */ } lua_setmetatable(L, 2); return 1; } static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, {"gcinfo", luaB_gcinfo}, {"getfenv", luaB_getfenv}, {"getmetatable", luaB_getmetatable}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, {"loadstring", luaB_loadstring}, {"next", luaB_next}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, {"setfenv", luaB_setfenv}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"unpack", luaB_unpack}, {"epcall", luaB_epcall}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; /* ** {====================================================== ** Coroutine library ** ======================================================= */ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); if (lua_status(co) == 0 && lua_gettop(co) == 0) { lua_pushboolean(L, 0); lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); status = lua_resume(co, narg); if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres+1)) luaL_error(L, "too many results to resume"); lua_pushboolean(L, 1); lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ lua_pushboolean(L, 0); /* must do it this way for the L == co case */ lua_insert(L, -2); return -1; /* error flag */ } } static int luaB_coresume (lua_State *L) { lua_State *co = lua_tothread(L, 1); int r; luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) return 2; /* return false + error message */ else return r + 1; /* return true + `resume' returns */ } static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { if (lua_isstring(L, -1)) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ lua_insert(L, -2); lua_concat(L, 2); } lua_error(L); /* propagate error */ } return r; } static int luaB_cocreate (lua_State *L) { lua_State *NL = lua_newthread(L); luaL_checkany(L, 1); /* any callable is ok */ lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; } static int luaB_cowrap (lua_State *L) { luaB_cocreate(L); lua_pushcclosure(L, luaB_auxwrap, 1); return 1; } static int luaB_yield (lua_State *L) { return lua_yield(L, lua_gettop(L)); } static int luaB_costatus (lua_State *L) { lua_State *co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { case LUA_YIELD: lua_pushliteral(L, "suspended"); break; case 0: { lua_Debug ar; if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ lua_pushliteral(L, "normal"); /* it is running */ else if (lua_gettop(co) == 0) lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ break; } default: /* some error occured */ lua_pushliteral(L, "dead"); break; } } return 1; } static int luaB_corunning (lua_State *L) { if (lua_pushthread(L)) return 0; /* main thread is not a coroutine */ else return 1; } static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, {"running", luaB_corunning}, {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, {NULL, NULL} }; /* }====================================================== */ static void auxopen (lua_State *L, const char *name, lua_CFunction f, lua_CFunction u) { lua_pushcfunction(L, u); lua_pushcclosure(L, f, 1); lua_setfield(L, -2, name); } static void base_open (lua_State *L) { /* set global _G */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setglobal(L, "_G"); /* open lib into global table */ luaL_register(L, "_G", base_funcs); lua_pushliteral(L, LUA_VERSION); lua_setglobal(L, "_VERSION"); /* set global _VERSION */ /* `ipairs' and `pairs' need auxliliary functions as upvalues */ auxopen(L, "ipairs", luaB_ipairs, ipairsaux); auxopen(L, "pairs", luaB_pairs, luaB_next); /* `newproxy' needs a weaktable as upvalue */ lua_createtable(L, 0, 1); /* new table `w' */ lua_pushvalue(L, -1); /* `w' will be its own metatable */ lua_setmetatable(L, -2); lua_pushliteral(L, "kv"); lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ lua_pushcclosure(L, luaB_newproxy, 1); lua_setglobal(L, "newproxy"); /* set global `newproxy' */ } LUALIB_API int luaopen_base (lua_State *L) { base_open(L); luaL_register(L, LUA_COLIBNAME, co_funcs); return 2; } infon/lua-5.1.2/src/lparser.h0000644000076400001440000000432110603200765015571 0ustar dividuumusers/* ** $Id: lparser.h,v 1.57 2006/03/09 18:14:31 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #ifndef lparser_h #define lparser_h #include "llimits.h" #include "lobject.h" #include "lzio.h" /* ** Expression descriptor */ typedef enum { VVOID, /* no value */ VNIL, VTRUE, VFALSE, VK, /* info = index of constant in `k' */ VKNUM, /* nval = numerical value */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in `upvalues' */ VGLOBAL, /* info = index of table; aux = index of global name in `k' */ VINDEXED, /* info = table register; aux = index register (or `k') */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VNONRELOC, /* info = result register */ VCALL, /* info = instruction pc */ VVARARG /* info = instruction pc */ } expkind; typedef struct expdesc { expkind k; union { struct { int info, aux; } s; lua_Number nval; } u; int t; /* patch list of `exit when true' */ int f; /* patch list of `exit when false' */ } expdesc; typedef struct upvaldesc { lu_byte k; lu_byte info; } upvaldesc; struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct lua_State *L; /* copy of the Lua state */ struct BlockCnt *bl; /* chain of current blocks */ int pc; /* next position to code (equivalent to `ncode') */ int lasttarget; /* `pc' of last `jump target' */ int jpc; /* list of pending jumps to `pc' */ int freereg; /* first free register */ int nk; /* number of elements in `k' */ int np; /* number of elements in `p' */ short nlocvars; /* number of elements in `locvars' */ lu_byte nactvar; /* number of active local variables */ upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */ unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */ } FuncState; LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name); #endif infon/lua-5.1.2/src/lzio.c0000644000076400001440000000313010603200765015066 0ustar dividuumusers/* ** $Id: lzio.c,v 1.31 2005/06/03 20:15:29 roberto Exp $ ** a generic input stream interface ** See Copyright Notice in lua.h */ #include #define lzio_c #define LUA_CORE #include "lua.h" #include "llimits.h" #include "lmem.h" #include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; lua_State *L = z->L; const char *buff; lua_unlock(L); buff = z->reader(L, z->data, &size); lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; z->p = buff; return char2int(*(z->p++)); } int luaZ_lookahead (ZIO *z) { if (z->n == 0) { if (luaZ_fill(z) == EOZ) return EOZ; else { z->n++; /* luaZ_fill removed first byte; put back it */ z->p--; } } return char2int(*z->p); } void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; z->data = data; z->n = 0; z->p = NULL; } /* --------------------------------------------------------------- read --- */ size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; if (luaZ_lookahead(z) == EOZ) return n; /* return number of missing bytes */ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; z->p += m; b = (char *)b + m; n -= m; } return 0; } /* ------------------------------------------------------------------------ */ char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { if (n > buff->buffsize) { if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; luaZ_resizebuffer(L, buff, n); } return buff->buffer; } infon/lua-5.1.2/src/linit.c0000644000076400001440000000137110603200765015235 0ustar dividuumusers/* ** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $ ** Initialization of libraries for lua.c ** See Copyright Notice in lua.h */ #define linit_c #define LUA_LIB #include "lua.h" #include "lualib.h" #include "lauxlib.h" static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib = lualibs; for (; lib->func; lib++) { lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } } infon/lua-5.1.2/src/lua.c0000644000076400001440000002352710603200765014706 0ustar dividuumusers/* ** $Id: lua.c,v 1.160 2006/06/02 15:34:00 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ #include #include #include #include #define lua_c #include "lua.h" #include "lauxlib.h" #include "lualib.h" static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); } static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } static void print_usage (void) { fprintf(stderr, "usage: %s [options] [script [args]].\n" "Available options are:\n" " -e stat execute string " LUA_QL("stat") "\n" " -l name require library " LUA_QL("name") "\n" " -i enter interactive mode after executing " LUA_QL("script") "\n" " -v show version information\n" " -- stop handling options\n" " - execute stdin and stop handling options\n" , progname); fflush(stderr); } static void l_message (const char *pname, const char *msg) { if (pname) fprintf(stderr, "%s: ", pname); fprintf(stderr, "%s\n", msg); fflush(stderr); } static int report (lua_State *L, int status) { if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } return status; } static int traceback (lua_State *L) { lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; } static int docall (lua_State *L, int narg, int clear) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ signal(SIGINT, laction); status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); signal(SIGINT, SIG_DFL); lua_remove(L, base); /* remove traceback function */ /* force a complete garbage collection in case of errors */ if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); return status; } static void print_version (void) { l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); } static int getargs (lua_State *L, char **argv, int n) { int narg; int i; int argc = 0; while (argv[argc]) argc++; /* count total number of arguments */ narg = argc - (n + 1); /* number of arguments to the script */ luaL_checkstack(L, narg + 3, "too many arguments to script"); for (i=n+1; i < argc; i++) lua_pushstring(L, argv[i]); lua_createtable(L, narg, n + 1); for (i=0; i < argc; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i - n); } return narg; } static int dofile (lua_State *L, const char *name) { int status = luaL_loadfile(L, name) || docall(L, 0, 1); return report(L, status); } static int dostring (lua_State *L, const char *s, const char *name) { int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); return report(L, status); } static int dolibrary (lua_State *L, const char *name) { lua_getglobal(L, "require"); lua_pushstring(L, name); return report(L, lua_pcall(L, 1, 0, 0)); } static const char *get_prompt (lua_State *L, int firstline) { const char *p; lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); /* remove global */ return p; } static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); if (strstr(msg, LUA_QL("")) == tp) { lua_pop(L, 1); return 1; } } return 0; /* else... */ } static int pushline (lua_State *L, int firstline) { char buffer[LUA_MAXINPUT]; char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); if (lua_readline(L, b, prmt) == 0) return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ b[l-1] = '\0'; /* remove it */ if (firstline && b[0] == '=') /* first line starts with `=' ? */ lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ else lua_pushstring(L, b); lua_freeline(L, b); return 1; } static int loadline (lua_State *L) { int status; lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ return -1; lua_pushliteral(L, "\n"); /* add a new line... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ } lua_saveline(L, 1); lua_remove(L, 1); /* remove line */ return status; } static void dotty (lua_State *L) { int status; const char *oldprogname = progname; progname = NULL; while ((status = loadline(L)) != -1) { if (status == 0) status = docall(L, 0, 0); report(L, status); if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) l_message(progname, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } lua_settop(L, 0); /* clear stack */ fputs("\n", stdout); fflush(stdout); progname = oldprogname; } static int handle_script (lua_State *L, char **argv, int n) { int status; const char *fname; int narg = getargs(L, argv, n); /* collect arguments */ lua_setglobal(L, "arg"); fname = argv[n]; if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); lua_insert(L, -(narg+1)); if (status == 0) status = docall(L, narg, 0); else lua_pop(L, narg); return report(L, status); } /* check that argument has no extra characters at the end */ #define notail(x) {if ((x)[2] != '\0') return -1;} static int collectargs (char **argv, int *pi, int *pv, int *pe) { int i; for (i = 1; argv[i] != NULL; i++) { if (argv[i][0] != '-') /* not an option? */ return i; switch (argv[i][1]) { /* option */ case '-': notail(argv[i]); return (argv[i+1] != NULL ? i+1 : 0); case '\0': return i; case 'i': notail(argv[i]); *pi = 1; /* go through */ case 'v': notail(argv[i]); *pv = 1; break; case 'e': *pe = 1; /* go through */ case 'l': if (argv[i][2] == '\0') { i++; if (argv[i] == NULL) return -1; } break; default: return -1; /* invalid option */ } } return 0; } static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { if (argv[i] == NULL) continue; lua_assert(argv[i][0] == '-'); switch (argv[i][1]) { /* option */ case 'e': { const char *chunk = argv[i] + 2; if (*chunk == '\0') chunk = argv[++i]; lua_assert(chunk != NULL); if (dostring(L, chunk, "=(command line)") != 0) return 1; break; } case 'l': { const char *filename = argv[i] + 2; if (*filename == '\0') filename = argv[++i]; lua_assert(filename != NULL); if (dolibrary(L, filename)) return 1; /* stop if file fails */ break; } default: break; } } return 0; } static int handle_luainit (lua_State *L) { const char *init = getenv(LUA_INIT); if (init == NULL) return 0; /* status OK */ else if (init[0] == '@') return dofile(L, init+1); else return dostring(L, init, "=" LUA_INIT); } struct Smain { int argc; char **argv; int status; }; static int pmain (lua_State *L) { struct Smain *s = (struct Smain *)lua_touserdata(L, 1); char **argv = s->argv; int script; int has_i = 0, has_v = 0, has_e = 0; globalL = L; if (argv[0] && argv[0][0]) progname = argv[0]; lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ luaL_openlibs(L); /* open libraries */ lua_gc(L, LUA_GCRESTART, 0); s->status = handle_luainit(L); if (s->status != 0) return 0; script = collectargs(argv, &has_i, &has_v, &has_e); if (script < 0) { /* invalid args? */ print_usage(); s->status = 1; return 0; } if (has_v) print_version(); s->status = runargs(L, argv, (script > 0) ? script : s->argc); if (s->status != 0) return 0; if (script) s->status = handle_script(L, argv, script); if (s->status != 0) return 0; if (has_i) dotty(L); else if (script == 0 && !has_e && !has_v) { if (lua_stdin_is_tty()) { print_version(); dotty(L); } else dofile(L, NULL); /* executes stdin as a file */ } return 0; } int main (int argc, char **argv) { int status; struct Smain s; lua_State *L = lua_open(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } s.argc = argc; s.argv = argv; status = lua_cpcall(L, &pmain, &s); report(L, status); lua_close(L); return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; } infon/lua-5.1.2/src/lobject.c0000644000076400001440000001256610603200765015550 0ustar dividuumusers/* ** $Id: lobject.c,v 2.22 2006/02/10 17:43:52 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #include #include #include #include #include #define lobject_c #define LUA_CORE #include "lua.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "lvm.h" const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL}; /* ** converts an integer to a "floating point byte", represented as ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* expoent */ while (x >= 16) { x = (x+1) >> 1; e++; } if (x < 8) return x; else return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { int e = (x >> 3) & 31; if (e == 0) return x; else return ((x & 7)+8) << (e - 1); } int luaO_log2 (unsigned int x) { static const lu_byte log_2[256] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; int l = -1; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; } int luaO_rawequalObj (const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2)) return 0; else switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); default: lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); } } int luaO_str2d (const char *s, lua_Number *result) { char *endptr; *result = lua_str2number(s, &endptr); if (endptr == s) return 0; /* conversion failed */ if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */ *result = cast_num(strtoul(s, &endptr, 16)); if (*endptr == '\0') return 1; /* most common case */ while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr != '\0') return 0; /* invalid trailing characters? */ return 1; } static void pushstr (lua_State *L, const char *str) { setsvalue2s(L, L->top, luaS_new(L, str)); incr_top(L); } /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 1; pushstr(L, ""); for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); incr_top(L); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s); break; } case 'c': { char buff[2]; buff[0] = cast(char, va_arg(argp, int)); buff[1] = '\0'; pushstr(L, buff); break; } case 'd': { setnvalue(L->top, cast_num(va_arg(argp, int))); incr_top(L); break; } case 'f': { setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); incr_top(L); break; } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ sprintf(buff, "%p", va_arg(argp, void *)); pushstr(L, buff); break; } case '%': { pushstr(L, "%"); break; } default: { char buff[3]; buff[0] = '%'; buff[1] = *(e+1); buff[2] = '\0'; pushstr(L, buff); break; } } n += 2; fmt = e+2; } pushstr(L, fmt); luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); L->top -= n; return svalue(L->top - 1); } const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); return msg; } void luaO_chunkid (char *out, const char *source, size_t bufflen) { if (*source == '=') { strncpy(out, source+1, bufflen); /* remove first char */ out[bufflen-1] = '\0'; /* ensures null termination */ } else { /* out = "source", or "...source" */ if (*source == '@') { size_t l; source++; /* skip the `@' */ bufflen -= sizeof(" '...' "); l = strlen(source); strcpy(out, ""); if (l > bufflen) { source += (l-bufflen); /* get last part of file name */ strcat(out, "..."); } strcat(out, source); } else { /* out = [string "string"] */ size_t len = strcspn(source, "\n\r"); /* stop at first newline */ bufflen -= sizeof(" [string \"...\"] "); if (len > bufflen) len = bufflen; strcpy(out, "[string \""); if (source[len] != '\0') { /* must truncate? */ strncat(out, source, len); strcat(out, "..."); } else strcat(out, source); strcat(out, "\"]"); } } } infon/lua-5.1.2/src/llimits.h0000644000076400001440000000445110603200765015602 0ustar dividuumusers/* ** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $ ** Limits, basic types, and some other `installation-dependent' definitions ** See Copyright Notice in lua.h */ #ifndef llimits_h #define llimits_h #include #include #include "lua.h" typedef LUAI_UINT32 lu_int32; typedef LUAI_UMEM lu_mem; typedef LUAI_MEM l_mem; /* chars used as small naturals (so that `char' is reserved for characters) */ typedef unsigned char lu_byte; #define MAX_SIZET ((size_t)(~(size_t)0)-2) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ /* ** conversion of pointer to integer ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ #define IntPoint(p) ((unsigned int)(lu_mem)(p)) /* type to ensure maximum alignment */ typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; /* result of a `usual argument conversion' over lua_Number */ typedef LUAI_UACNUMBER l_uacNumber; /* internal assertions for in-house debugging */ #ifdef lua_assert #define check_exp(c,e) (lua_assert(c), (e)) #define api_check(l,e) lua_assert(e) #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) #define api_check luai_apicheck #endif #ifndef UNUSED #define UNUSED(x) ((void)(x)) /* to avoid warnings */ #endif #ifndef cast #define cast(t, exp) ((t)(exp)) #endif #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) /* ** type for virtual-machine instructions ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ typedef lu_int32 Instruction; /* maximum stack for a Lua function */ #define MAXSTACK 250 /* minimum size for the string table (must be power of 2) */ #ifndef MINSTRTABSIZE #define MINSTRTABSIZE 32 #endif /* minimum size for string buffer */ #ifndef LUA_MINBUFFER #define LUA_MINBUFFER 32 #endif #ifndef lua_lock #define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif #ifndef luai_threadyield #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif /* ** macro to control inclusion of some hard tests on stack reallocation */ #ifndef HARDSTACKTESTS #define condhardstacktests(x) ((void)0) #else #define condhardstacktests(x) x #endif #endif infon/lua-5.1.2/src/lstring.c0000644000076400001440000000604210603200765015600 0ustar dividuumusers/* ** $Id: lstring.c,v 2.8 2005/12/22 16:19:56 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ #include #define lstring_c #define LUA_CORE #include "lua.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" void luaS_resize (lua_State *L, int newsize) { GCObject **newhash; stringtable *tb; int i; if (G(L)->gcstate == GCSsweepstring) return; /* cannot resize during GC traverse */ newhash = luaM_newvector(L, newsize, GCObject *); tb = &G(L)->strt; for (i=0; isize; i++) { GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ unsigned int h = gco2ts(p)->hash; int h1 = lmod(h, newsize); /* new position */ lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ newhash[h1] = p; p = next; } } luaM_freearray(L, tb->hash, tb->size, TString *); tb->size = newsize; tb->hash = newhash; } static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { TString *ts; stringtable *tb; if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; ts->tsv.hash = h; ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ tb->hash[h] = obj2gco(ts); tb->nuse++; if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) luaS_resize(L, tb->size*2); /* too crowded */ return ts; } TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { GCObject *o; unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { TString *ts = rawgco2ts(o); if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { /* string may be dead */ if (isdead(G(L), o)) changewhite(o); return ts; } } return newlstr(L, str, l, h); /* not found */ } Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { Udata *u; if (s > MAX_SIZET - sizeof(Udata)) luaM_toobig(L); u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); u->uv.marked = luaC_white(G(L)); /* is not finalized */ u->uv.tt = LUA_TUSERDATA; u->uv.len = s; u->uv.metatable = NULL; u->uv.env = e; /* chain it on udata list (after main thread) */ u->uv.next = G(L)->mainthread->next; G(L)->mainthread->next = obj2gco(u); return u; } infon/lua-5.1.2/src/lzio.h0000644000076400001440000000302010603200765015071 0ustar dividuumusers/* ** $Id: lzio.h,v 1.21 2005/05/17 19:49:15 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #ifndef lzio_h #define lzio_h #include "lua.h" #include "lmem.h" #define EOZ (-1) /* end of stream */ typedef struct Zio ZIO; #define char2int(c) cast(int, cast(unsigned char, (c))) #define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { char *buffer; size_t n; size_t buffsize; } Mbuffer; #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) #define luaZ_buffer(buff) ((buff)->buffer) #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ LUAI_FUNC int luaZ_lookahead (ZIO *z); /* --------- Private Part ------------------ */ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; void* data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; LUAI_FUNC int luaZ_fill (ZIO *z); #endif infon/lua-5.1.2/src/lapi.c0000644000076400001440000005640610603200765015054 0ustar dividuumusers/* ** $Id: lapi.c,v 2.55 2006/06/07 12:37:17 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #include #include #include #include #define lapi_c #define LUA_CORE #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" const char lua_ident[] = "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n" "$Authors: " LUA_AUTHORS " $\n" "$URL: www.lua.org $\n"; #define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) #define api_checkvalidindex(L, i) api_check(L, (i) != luaO_nilobject) #define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} static TValue *index2adr (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); api_check(L, idx <= L->ci->top - L->base); if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_ENVIRONINDEX: { Closure *func = curr_func(L); sethvalue(L, &L->env, func->c.env); return &L->env; } case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] : cast(TValue *, luaO_nilobject); } } } static Table *getcurrenv (lua_State *L) { if (L->ci == L->base_ci) /* no enclosing function? */ return hvalue(gt(L)); /* use global table as environment */ else { Closure *func = curr_func(L); return func->c.env; } } void luaA_pushobject (lua_State *L, const TValue *o) { setobj2s(L, L->top, o); api_incr_top(L); } LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); if (L->ci->top < L->top + size) L->ci->top = L->top + size; res = 1; } lua_unlock(L); return res; } LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; if (from == to) return; lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to)); api_check(from, to->ci->top - to->top >= n); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top++, from->top + i); } lua_unlock(to); } LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); old = G(L)->panic; G(L)->panic = panicf; lua_unlock(L); return old; } LUA_API lua_CFunction lua_atcpu_exceeded(lua_State *L, lua_CFunction cpuf) { lua_CFunction old; lua_lock(L); old = G(L)->cpu_exceeded; G(L)->cpu_exceeded = cpuf; lua_unlock(L); return old; } LUA_API lua_State *lua_newthread (lua_State *L) { lua_State *L1; lua_lock(L); G(L)->cycles -= 1000; luaC_checkGC(L); L1 = luaE_newthread(L); setthvalue(L, L->top, L1); api_incr_top(L); lua_unlock(L); luai_userstatethread(L, L1); return L1; } LUA_API void lua_set_cycles(lua_State *L, int cycles) { lua_lock(L); G(L)->cycles = cycles; lua_unlock(L); } LUA_API int lua_get_cycles(lua_State *L) { int cycles; lua_lock(L); cycles = G(L)->cycles; lua_unlock(L); return cycles < 0 ? 0 : cycles; } /* ** basic stack manipulation */ LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - L->base); } LUA_API void lua_settop (lua_State *L, int idx) { lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - L->base); while (L->top < L->base + idx) setnilvalue(L->top++); L->top = L->base + idx; } else { api_check(L, -(idx+1) <= (L->top - L->base)); L->top += idx+1; /* `subtract' index (index is negative) */ } lua_unlock(L); } LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = index2adr(L, idx); api_checkvalidindex(L, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); } LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); p = index2adr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); lua_unlock(L); } LUA_API void lua_replace (lua_State *L, int idx) { StkId o; lua_lock(L); /* explicit test for incompatible code */ if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci) luaG_runerror(L, "no calling environment"); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); if (idx == LUA_ENVIRONINDEX) { Closure *func = curr_func(L); api_check(L, ttistable(L->top - 1)); func->c.env = hvalue(L->top - 1); luaC_barrier(L, func, L->top - 1); } else { setobj(L, o, L->top - 1); if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ luaC_barrier(L, curr_func(L), L->top - 1); } L->top--; lua_unlock(L); } LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); setobj2s(L, L->top, index2adr(L, idx)); api_incr_top(L); lua_unlock(L); } /* ** access functions (stack -> C) */ LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2adr(L, idx); return iscfunction(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { int t = lua_type(L, idx); return (t == LUA_TSTRING || t == LUA_TNUMBER); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); return (ttisuserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2adr(L, index1); StkId o2 = index2adr(L, index2); return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaO_rawequalObj(o1, o2); } LUA_API int lua_equal (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); notresumable(L, i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); ) lua_unlock(L); return i; } LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { StkId o1, o2; int i; lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); notresumable(L, i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : luaV_lessthan(L, o1, o2); ) lua_unlock(L); return i; } LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) return nvalue(o); else return 0; } LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { TValue n; const TValue *o = index2adr(L, idx); if (tonumber(o, &n)) { lua_Integer res; lua_Number num = nvalue(o); lua_number2integer(res, num); return res; } else return 0; } LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2adr(L, idx); if (!ttisstring(o)) { lua_lock(L); /* `luaV_tostring' may create a new string */ if (!luaV_tostring(L, o)) { /* conversion failed? */ if (len != NULL) *len = 0; lua_unlock(L); return NULL; } luaC_checkGC(L); o = index2adr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } if (len != NULL) *len = tsvalue(o)->len; return svalue(o); } LUA_API size_t lua_objlen (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TSTRING: return tsvalue(o)->len; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); case LUA_TNUMBER: { size_t l; lua_lock(L); /* `luaV_tostring' may create a new string */ l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); lua_unlock(L); return l; } default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (!iscfunction(o)) ? NULL : clvalue(o)->c.f; } LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TUSERDATA: return (rawuvalue(o) + 1); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } LUA_API lua_State *lua_tothread (lua_State *L, int idx) { StkId o = index2adr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { StkId o = index2adr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: return lua_touserdata(L, idx); default: return NULL; } } /* ** push functions (C -> stack) */ LUA_API void lua_pushnil (lua_State *L) { lua_lock(L); setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); setnvalue(L->top, n); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); setnvalue(L->top, cast_num(n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); setsvalue2s(L, L->top, luaS_newlstr(L, s, len)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushstring (lua_State *L, const char *s) { if (s == NULL) lua_pushnil(L); else lua_pushlstring(L, s, strlen(s)); } LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *ret; lua_lock(L); luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); lua_unlock(L); return ret; } LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { const char *ret; va_list argp; lua_lock(L); luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); lua_unlock(L); return ret; } LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); cl = luaF_newCclosure(L, n, getcurrenv(L)); cl->c.f = fn; L->top -= n; while (n--) setobj2n(L, &cl->c.upvalue[n], L->top+n); setclvalue(L, L->top, cl); lua_assert(iswhite(obj2gco(cl))); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushboolean (lua_State *L, int b) { lua_lock(L); setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { lua_lock(L); setpvalue(L->top, p); api_incr_top(L); lua_unlock(L); } LUA_API int lua_pushthread (lua_State *L) { lua_lock(L); setthvalue(L, L->top, L); api_incr_top(L); lua_unlock(L); return (G(L)->mainthread == L); } /* ** get functions (Lua -> stack) */ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); notresumable(L, luaV_gettable(L, t, L->top - 1, L->top - 1); ) lua_unlock(L); } LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; TValue key; lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); notresumable(L, luaV_gettable(L, t, &key, L->top); ) api_incr_top(L); lua_unlock(L); } LUA_API void lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); } LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2s(L, L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { lua_lock(L); luaC_checkGC(L); sethvalue(L, L->top, luaH_new(L, narray, nrec)); api_incr_top(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; Table *mt = NULL; int res; lua_lock(L); obj = index2adr(L, objindex); switch (ttype(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; case LUA_TUSERDATA: mt = uvalue(obj)->metatable; break; default: mt = G(L)->mt[ttype(obj)]; break; } if (mt == NULL) res = 0; else { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } lua_unlock(L); return res; } LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2adr(L, idx); api_checkvalidindex(L, o); switch (ttype(o)) { case LUA_TFUNCTION: sethvalue(L, L->top, clvalue(o)->c.env); break; case LUA_TUSERDATA: sethvalue(L, L->top, uvalue(o)->env); break; case LUA_TTHREAD: setobj2s(L, L->top, gt(thvalue(o))); break; default: setnilvalue(L->top); break; } api_incr_top(L); lua_unlock(L); } /* ** set functions (stack -> Lua) */ LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2adr(L, idx); api_checkvalidindex(L, t); notresumable(L, luaV_settable(L, t, L->top - 2, L->top - 1); ) L->top -= 2; /* pop index and value */ lua_unlock(L); } LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { StkId t; TValue key; lua_lock(L); api_checknelems(L, 1); t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); notresumable(L, luaV_settable(L, t, &key, L->top - 1); ) L->top--; /* pop value */ lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2adr(L, idx); api_check(L, ttistable(t)); setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); luaC_barriert(L, hvalue(t), L->top-1); L->top -= 2; lua_unlock(L); } LUA_API void lua_rawseti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); api_checknelems(L, 1); o = index2adr(L, idx); api_check(L, ttistable(o)); setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1); luaC_barriert(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { TValue *obj; Table *mt; lua_lock(L); api_checknelems(L, 1); obj = index2adr(L, objindex); api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { api_check(L, ttistable(L->top - 1)); mt = hvalue(L->top - 1); } switch (ttype(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) luaC_objbarriert(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) luaC_objbarrier(L, rawuvalue(obj), mt); break; } default: { G(L)->mt[ttype(obj)] = mt; break; } } L->top--; lua_unlock(L); return 1; } LUA_API int lua_setfenv (lua_State *L, int idx) { StkId o; int res = 1; lua_lock(L); api_checknelems(L, 1); o = index2adr(L, idx); api_checkvalidindex(L, o); api_check(L, ttistable(L->top - 1)); switch (ttype(o)) { case LUA_TFUNCTION: clvalue(o)->c.env = hvalue(L->top - 1); break; case LUA_TUSERDATA: uvalue(o)->env = hvalue(L->top - 1); break; case LUA_TTHREAD: sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1)); break; default: res = 0; break; } luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); L->top--; lua_unlock(L); return res; } /* ** `load' and `call' functions (run Lua code) */ #define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) LUA_API void *lua_vcontext (lua_State *L) { return L->ctx; } LUA_API void lua_vcall (lua_State *L, int nargs, int nresults, void *ctx) { int flags; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); if (ctx == NULL) flags = LUA_NOYIELD | LUA_NOVPCALL; else { lua_assert(iscfunction(L->ci->func)); L->ctx = ctx; flags = 0; } luaD_call(L, L->top - (nargs+1), nresults, flags); if (L->top > L->ci->top) L->ci->top = L->top; lua_unlock(L); } /* ** Execute a protected call. */ struct CallS { /* data to `f_call' */ StkId func; int nresults; }; static int f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); luaD_call(L, c->func, c->nresults, LUA_NOYIELD); return 0; } LUA_API int lua_vpcall (lua_State *L, int nargs, int nresults, int errfunc, void *ctx) { int status; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); if (errfunc < 0) errfunc = (L->top - L->base) + errfunc + 1; api_check(L, L->base + errfunc <= L->top - (nargs+1)); if (ctx == NULL || novpcall(L)) { /* use classic pcall */ struct CallS c; c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; status = luaD_pcall(L, f_call, &c, savestack(L, c.func), errfunc, ~LUA_NOVPCALL); } else { /* else use vpcall */ luaD_catch(L, errfunc); L->ctx = ctx; luaD_call(L, L->top - (nargs+1), nresults, 0); L->ci->errfunc = 0; status = 0; } if (L->top > L->ci->top) L->ci->top = L->top; lua_unlock(L); return status; } /* ** Execute a protected C call. */ struct CCallS { /* data to `f_Ccall' */ lua_CFunction func; void *ud; }; static int f_Ccall (lua_State *L, void *ud) { struct CCallS *c = cast(struct CCallS *, ud); Closure *cl; cl = luaF_newCclosure(L, 0, getcurrenv(L)); cl->c.f = c->func; setclvalue(L, L->top, cl); /* push function */ api_incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ api_incr_top(L); luaD_call(L, L->top - 2, 0, LUA_NOYIELD); return 0; } LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { struct CCallS c; int status; lua_lock(L); c.func = func; c.ud = ud; status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0, ~LUA_NOVPCALL); lua_unlock(L); return status; } LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname) { ZIO z; int status; lua_lock(L); G(L)->cycles -= 10000; if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname); lua_unlock(L); return status; } LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0); else status = 1; lua_unlock(L); return status; } LUA_API int lua_status (lua_State *L) { return L->status; } /* ** Garbage-collection function */ LUA_API int lua_gc (lua_State *L, int what, int data) { int res = 0; global_State *g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g->GCthreshold = MAX_LUMEM; break; } case LUA_GCRESTART: { g->GCthreshold = g->totalbytes; break; } case LUA_GCCOLLECT: { luaC_fullgc(L); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(g->totalbytes >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(g->totalbytes & 0x3ff); break; } case LUA_GCSTEP: { lu_mem a = (cast(lu_mem, data) << 10); if (a <= g->totalbytes) g->GCthreshold = g->totalbytes - a; else g->GCthreshold = 0; while (g->GCthreshold <= g->totalbytes) luaC_step(L); if (g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ break; } case LUA_GCSETPAUSE: { res = g->gcpause; g->gcpause = data; break; } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; g->gcstepmul = data; break; } case LUA_GCESTIMATED: { res = cast_int(g->estimate >> 10); break; } default: res = -1; /* invalid option */ } lua_unlock(L); return res; } /* ** miscellaneous functions */ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaD_throw(L, LUA_ERRRUN); lua_unlock(L); return 0; /* to avoid warnings */ } LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); t = index2adr(L, idx); api_check(L, ttistable(t)); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); } else /* no more elements */ L->top -= 1; /* remove key */ lua_unlock(L); return more; } LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); notresumable(L, luaV_concat(L, n, cast_int(L->top - L->base) - 1); ) L->top -= (n-1); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ lua_unlock(L); } LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); if (ud) *ud = G(L)->ud; f = G(L)->frealloc; lua_unlock(L); return f; } LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { lua_lock(L); G(L)->ud = ud; G(L)->frealloc = f; lua_unlock(L); } LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size, getcurrenv(L)); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return u + 1; } static const char *aux_upvalue (StkId fi, int n, TValue **val) { Closure *f; if (!ttisfunction(fi)) return NULL; f = clvalue(fi); if (f->c.isC) { if (!(1 <= n && n <= f->c.nupvalues)) return NULL; *val = &f->c.upvalue[n-1]; return ""; } else { Proto *p = f->l.p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->l.upvals[n-1]->v; return getstr(p->upvalues[n-1]); } } LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; lua_lock(L); name = aux_upvalue(index2adr(L, funcindex), n, &val); if (name) { setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); return name; } LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val; StkId fi; lua_lock(L); fi = index2adr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val); if (name) { L->top--; setobj(L, val, L->top); luaC_barrier(L, clvalue(fi), L->top); } lua_unlock(L); return name; } infon/lua-5.1.2/src/lcode.c0000644000076400001440000005152110603200765015206 0ustar dividuumusers/* ** $Id: lcode.c,v 2.25a 2006/03/21 19:28:49 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #include #define lcode_c #define LUA_CORE #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "ltable.h" #define hasjumps(e) ((e)->t != (e)->f) static int isnumeral(expdesc *e) { return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); } void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ if (fs->pc == 0) { /* function start? */ if (from >= fs->nactvar) return; /* positions are already clean */ } else { previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { int pfrom = GETARG_A(*previous); int pto = GETARG_B(*previous); if (pfrom <= from && from <= pto+1) { /* can connect both? */ if (from+n-1 > pto) SETARG_B(*previous, from+n-1); return; } } } } luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ } int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; fs->jpc = NO_JUMP; j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) luaX_syntaxerror(fs->ls, "control structure too long"); SETARG_sBx(*jmp, offset); } /* ** returns current `pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { fs->lasttarget = fs->pc; return fs->pc; } static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else return (pc+1)+offset; /* turn offset into absolute position */ } static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; } /* ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); else /* no register to put value or register already has the value */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); return 1; } static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); else fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } void luaK_patchlist (FuncState *fs, int list, int target) { if (target == fs->pc) luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); } } void luaK_patchtohere (FuncState *fs, int list) { luaK_getlabel(fs); luaK_concat(fs, &fs->jpc, list); } void luaK_concat (FuncState *fs, int *l1, int l2) { if (l2 == NO_JUMP) return; else if (*l1 == NO_JUMP) *l1 = l2; else { int list = *l1; int next; while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; fixjump(fs, list, l2); } } void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { if (newstack >= MAXSTACK) luaX_syntaxerror(fs->ls, "function or expression too complex"); fs->f->maxstacksize = cast_byte(newstack); } } void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } } static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.s.info); } static int addk (FuncState *fs, TValue *k, TValue *v) { lua_State *L = fs->L; TValue *idx = luaH_set(L, fs->h, k); Proto *f = fs->f; int oldsize = f->sizek; if (ttisnumber(idx)) { lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); return cast_int(nvalue(idx)); } else { /* constant not found; create a new entry */ setnvalue(idx, cast_num(fs->nk)); luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, MAXARG_Bx, "constant table overflow"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[fs->nk], v); luaC_barrier(L, f, v); return fs->nk++; } } int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->L, &o, s); return addk(fs, &o, &o); } int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; setnvalue(&o, r); return addk(fs, &o, &o); } static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); return addk(fs, &o, &o); } static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ sethvalue(fs->L, &k, fs->h); return addk(fs, &k, &v); } void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), nresults+1); SETARG_A(getcode(fs, e), fs->freereg); luaK_reserveregs(fs, 1); } } void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; e->u.s.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { case VLOCAL: { e->k = VNONRELOC; break; } case VUPVAL: { e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } case VGLOBAL: { e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); e->k = VRELOCABLE; break; } case VINDEXED: { freereg(fs, e->u.s.aux); freereg(fs, e->u.s.info); e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); e->k = VRELOCABLE; break; } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ } } static int code_label (FuncState *fs, int A, int b, int jump) { luaK_getlabel(fs); /* those instructions may be jump targets */ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: { luaK_nil(fs, reg, 1); break; } case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } case VK: { luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); break; } case VKNUM: { luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); break; } case VNONRELOC: { if (reg != e->u.s.info) luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); break; } default: { lua_assert(e->k == VVOID || e->k == VJMP); return; /* nothing to do... */ } } e->u.s.info = reg; e->k = VNONRELOC; } static void discharge2anyreg (FuncState *fs, expdesc *e) { if (e->k != VNONRELOC) { luaK_reserveregs(fs, 1); discharge2reg(fs, e, fs->freereg-1); } } static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->u.s.info = reg; e->k = VNONRELOC; } void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); exp2reg(fs, e, fs->freereg - 1); } int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ exp2reg(fs, e, e->u.s.info); /* put value on it */ return e->u.s.info; } } luaK_exp2nextreg(fs, e); /* default */ return e->u.s.info; } void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); } int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { case VKNUM: case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ e->u.s.info = (e->k == VNIL) ? nilK(fs) : (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.s.info); } else break; } case VK: { if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ return RKASK(e->u.s.info); else break; } default: break; } /* not a constant in the right range: put it in a register */ return luaK_exp2anyreg(fs, e); } void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); exp2reg(fs, ex, var->u.s.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); break; } case VGLOBAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); break; } case VINDEXED: { int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); break; } default: { lua_assert(0); /* invalid var kind to store */ break; } } freeexp(fs, ex); } void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int func; luaK_exp2anyreg(fs, e); freeexp(fs, e); func = fs->freereg; luaK_reserveregs(fs, 2); luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); freeexp(fs, key); e->u.s.info = func; e->k = VNONRELOC; } static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.s.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); } void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VK: case VKNUM: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } case VFALSE: { pc = luaK_jump(fs); /* always jump */ break; } case VJMP: { invertjump(fs, e); pc = e->u.s.info; break; } default: { pc = jumponcond(fs, e, 0); break; } } luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } static void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { pc = NO_JUMP; /* always false; do nothing */ break; } case VTRUE: { pc = luaK_jump(fs); /* always jump */ break; } case VJMP: { pc = e->u.s.info; break; } default: { pc = jumponcond(fs, e, 1); break; } } luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { e->k = VTRUE; break; } case VK: case VKNUM: case VTRUE: { e->k = VFALSE; break; } case VJMP: { invertjump(fs, e); break; } case VRELOCABLE: case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); e->k = VRELOCABLE; break; } default: { lua_assert(0); /* cannot happen */ break; } } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } removevalues(fs, e->f); removevalues(fs, e->t); } void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { t->u.s.aux = luaK_exp2RK(fs, k); t->k = VINDEXED; } static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { lua_Number v1, v2, r; if (!isnumeral(e1) || !isnumeral(e2)) return 0; v1 = e1->u.nval; v2 = e2->u.nval; switch (op) { case OP_ADD: r = luai_numadd(v1, v2); break; case OP_SUB: r = luai_numsub(v1, v2); break; case OP_MUL: r = luai_nummul(v1, v2); break; case OP_DIV: if (v2 == 0) return 0; /* do not attempt to divide by 0 */ r = luai_numdiv(v1, v2); break; case OP_MOD: if (v2 == 0) return 0; /* do not attempt to divide by 0 */ r = luai_nummod(v1, v2); break; case OP_POW: r = luai_numpow(v1, v2); break; case OP_UNM: r = luai_numunm(v1); break; case OP_LEN: return 0; /* no constant folding for 'len' */ default: lua_assert(0); r = 0; break; } if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ e1->u.nval = r; return 1; } static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { if (constfolding(op, e1, e2)) return; else { int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; int o1 = luaK_exp2RK(fs, e1); if (o1 > o2) { freeexp(fs, e1); freeexp(fs, e2); } else { freeexp(fs, e2); freeexp(fs, e1); } e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); e1->k = VRELOCABLE; } } static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, expdesc *e2) { int o1 = luaK_exp2RK(fs, e1); int o2 = luaK_exp2RK(fs, e2); freeexp(fs, e2); freeexp(fs, e1); if (cond == 0 && op != OP_EQ) { int temp; /* exchange args to replace by `<' or `<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } e1->u.s.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; switch (op) { case OPR_MINUS: { if (e->k == VK) luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ codearith(fs, OP_UNM, e, &e2); break; } case OPR_NOT: codenot(fs, e); break; case OPR_LEN: { luaK_exp2anyreg(fs, e); /* cannot operate on constants */ codearith(fs, OP_LEN, e, &e2); break; } default: lua_assert(0); } } void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); break; } case OPR_OR: { luaK_goiffalse(fs, v); break; } case OPR_CONCAT: { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_MOD: case OPR_POW: { if (!isnumeral(v)) luaK_exp2RK(fs, v); break; } default: { luaK_exp2RK(fs, v); break; } } } void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); SETARG_B(getcode(fs, e2), e1->u.s.info); e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ codearith(fs, OP_CONCAT, e1, e2); } break; } case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; case OPR_POW: codearith(fs, OP_POW, e1, e2); break; case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; default: lua_assert(0); } } void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } static int luaK_code (FuncState *fs, Instruction i, int line) { Proto *f = fs->f; dischargejpc(fs); /* `pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "code size overflow"); f->code[fs->pc] = i; /* save corresponding line information */ luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, MAX_INT, "code size overflow"); f->lineinfo[fs->pc] = line; return fs->pc++; } int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); lua_assert(getCMode(o) != OpArgN || c == 0); return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); } void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else { luaK_codeABC(fs, OP_SETLIST, base, b, 0); luaK_code(fs, cast(Instruction, c), fs->ls->lastline); } fs->freereg = base + 1; /* free registers with list values */ } infon/lua-5.1.2/src/lua.h0000644000076400001440000003030010603200765014676 0ustar dividuumusers/* ** $Id: lua.h,v 1.218a 2006/06/02 15:34:00 roberto Exp $ ** Lua - An Extensible Extension Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ #ifndef lua_h #define lua_h #include #include #include "luaconf.h" #define LUA_VERSION "Lua 5.1" #define LUA_RELEASE "Lua 5.1.2+rvm+infon" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2007 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" /* mark for precompiled code (`Lua') */ #define LUA_SIGNATURE "\033Lua" /* option for multiple returns in `lua_pcall' and `lua_call' */ #define LUA_MULTRET (-1) /* ** pseudo-indices */ #define LUA_REGISTRYINDEX (-10000) #define LUA_ENVIRONINDEX (-10001) #define LUA_GLOBALSINDEX (-10002) #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) /* thread status; 0 is OK */ #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRERR 5 #define LUA_ERREXC 6 typedef struct lua_State lua_State; typedef int (*lua_CFunction) (lua_State *L); /* ** functions that read/write blocks when loading/dumping Lua chunks */ typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); /* ** prototype for memory-allocation functions */ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 /* ** generic extra include file */ #if defined(LUA_USER_H) #include LUA_USER_H #endif /* type of numbers in Lua */ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; /* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); /* ** basic stack manipulation */ LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_remove) (lua_State *L, int idx); LUA_API void (lua_insert) (lua_State *L, int idx); LUA_API void (lua_replace) (lua_State *L, int idx); LUA_API int (lua_checkstack) (lua_State *L, int sz); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); /* ** CPU Cycle Functions */ LUA_API void lua_set_cycles(lua_State *L, int cycles); LUA_API int lua_get_cycles(lua_State *L); LUA_API lua_CFunction lua_atcpu_exceeded(lua_State *L, lua_CFunction cpuf); /* ** access functions (stack -> C) */ LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_objlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* ** push functions (C -> stack) */ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); LUA_API void (lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); LUA_API void (lua_pushboolean) (lua_State *L, int b); LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ LUA_API void (lua_gettable) (lua_State *L, int idx); LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawget) (lua_State *L, int idx); LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API void (lua_getfenv) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API int (lua_setfenv) (lua_State *L, int idx); /* ** `load' and `call' functions (load and run Lua code) */ LUA_API void (lua_vcall) (lua_State *L, int nargs, int nresults, void *ctx); LUA_API int (lua_vpcall) (lua_State *L, int nargs, int nresults, int errfunc, void *ctx); LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); LUA_API void *lua_vcontext (lua_State *L); #define lua_icontext(L) ((int)(ptrdiff_t)lua_vcontext(L)) #define lua_call(L, na, nr) lua_vcall(L, (na), (nr), NULL) #define lua_icall(L, na, nr, i) \ lua_vcall(L, (na), (nr), (void *)(ptrdiff_t)(i)) #define lua_pcall(L, na, nr, ef) lua_vpcall(L, (na), (nr), (ef), NULL) #define lua_ipcall(L, na, nr, ef, i) \ lua_vpcall(L, (na), (nr), (ef), (void *)(ptrdiff_t)(i)) /* ** coroutine functions */ LUA_API int (lua_vyield) (lua_State *L, int nresults, void *ctx); LUA_API int (lua_resume) (lua_State *L, int narg); LUA_API int (lua_status) (lua_State *L); #define lua_yield(L, nr) lua_vyield(L, (nr), NULL) #define lua_iyield(L, nr, i) lua_vyield(L, (nr), (void *)(ptrdiff_t)(i)) /* ** garbage-collection function and options */ #define LUA_GCSTOP 0 #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCCOUNTB 4 #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCESTIMATED 8 LUA_API int (lua_gc) (lua_State *L, int what, int data); /* ** miscellaneous functions */ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_strlen(L,i) lua_objlen(L, (i)) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) #define lua_pushliteral(L, s) \ lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) #define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) /* ** compatibility macros and functions */ #define lua_open() luaL_newstate() #define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) #define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) #define lua_Chunkreader lua_Reader #define lua_Chunkwriter lua_Writer /* ** {====================================================================== ** Debug API ** ======================================================================= */ /* ** Event codes */ #define LUA_HOOKCALL 0 #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 #define LUA_HOOKTAILRET 4 /* ** Event masks */ #define LUA_MASKCALL (1 << LUA_HOOKCALL) #define LUA_MASKRET (1 << LUA_HOOKRET) #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) typedef struct lua_Debug lua_Debug; /* activation record */ /* Functions to be called by the debuger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook lua_gethook (lua_State *L); LUA_API int lua_gethookmask (lua_State *L); LUA_API int lua_gethookcount (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) `global', `local', `field', `method' */ const char *what; /* (S) `Lua', `C', `main', `tail' */ const char *source; /* (S) */ int currentline; /* (l) */ int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ int i_ci; /* active function */ }; /* }====================================================================== */ /****************************************************************************** * Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ #endif infon/lua-5.1.2/src/lobject.h0000644000076400001440000002045710603200765015553 0ustar dividuumusers/* ** $Id: lobject.h,v 2.20 2006/01/18 11:37:34 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ #ifndef lobject_h #define lobject_h #include #include "llimits.h" #include "lua.h" /* tags for values visible from Lua */ #define LAST_TAG LUA_TTHREAD #define NUM_TAGS (LAST_TAG+1) /* ** Extra tags for non-values */ #define LUA_TPROTO (LAST_TAG+1) #define LUA_TUPVAL (LAST_TAG+2) #define LUA_TDEADKEY (LAST_TAG+3) /* ** Union of all collectable objects */ typedef union GCObject GCObject; /* ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked /* ** Common header in struct form */ typedef struct GCheader { CommonHeader; } GCheader; /* ** Union of all Lua values */ typedef union { GCObject *gc; void *p; lua_Number n; int b; } Value; /* ** Tagged Values */ #define TValuefields Value value; int tt typedef struct lua_TValue { TValuefields; } TValue; /* Macros to test type */ #define ttisnil(o) (ttype(o) == LUA_TNIL) #define ttisnumber(o) (ttype(o) == LUA_TNUMBER) #define ttisstring(o) (ttype(o) == LUA_TSTRING) #define ttistable(o) (ttype(o) == LUA_TTABLE) #define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) #define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) #define ttisthread(o) (ttype(o) == LUA_TTHREAD) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) /* Macros to access values */ #define ttype(o) ((o)->tt) #define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) #define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) #define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) #define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) #define tsvalue(o) (&rawtsvalue(o)->tsv) #define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) #define uvalue(o) (&rawuvalue(o)->uv) #define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) #define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) #define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) /* ** for internal debug only */ #define checkconsistency(obj) \ lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) #define checkliveness(g,obj) \ lua_assert(!iscollectable(obj) || \ ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) /* Macros to set values */ #define setnilvalue(obj) ((obj)->tt=LUA_TNIL) #define setnvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } #define setpvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } #define setbvalue(obj,x) \ { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } #define setsvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ checkliveness(G(L),i_o); } #define setuvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ checkliveness(G(L),i_o); } #define setthvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ checkliveness(G(L),i_o); } #define setclvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ checkliveness(G(L),i_o); } #define sethvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ checkliveness(G(L),i_o); } #define setptvalue(L,obj,x) \ { TValue *i_o=(obj); \ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ checkliveness(G(L),i_o); } #define setobj(L,obj1,obj2) \ { const TValue *o2=(obj2); TValue *o1=(obj1); \ o1->value = o2->value; o1->tt=o2->tt; \ checkliveness(G(L),o1); } /* ** different types of sets, according to destination */ /* from stack to (same) stack */ #define setobjs2s setobj /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue #define sethvalue2s sethvalue #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to table */ #define setobj2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue #define setttype(obj, tt) (ttype(obj) = (tt)) #define iscollectable(o) (ttype(o) >= LUA_TSTRING) typedef TValue *StkId; /* index to stack elements */ /* ** String headers for string table */ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { CommonHeader; lu_byte reserved; unsigned int hash; size_t len; } tsv; } TString; #define getstr(ts) cast(const char *, (ts) + 1) #define svalue(o) getstr(tsvalue(o)) typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { CommonHeader; struct Table *metatable; struct Table *env; size_t len; } uv; } Udata; /* ** Function Prototypes */ typedef struct Proto { CommonHeader; TValue *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines */ struct LocVar *locvars; /* information about local variables */ TString **upvalues; /* upvalue names */ TString *source; int sizeupvalues; int sizek; /* size of `k' */ int sizecode; int sizelineinfo; int sizep; /* size of `p' */ int sizelocvars; int linedefined; int lastlinedefined; GCObject *gclist; lu_byte nups; /* number of upvalues */ lu_byte numparams; lu_byte is_vararg; lu_byte maxstacksize; } Proto; /* masks for new-style vararg */ #define VARARG_HASARG 1 #define VARARG_ISVARARG 2 #define VARARG_NEEDSARG 4 typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ int endpc; /* first point where variable is dead */ } LocVar; /* ** Upvalues */ typedef struct UpVal { CommonHeader; TValue *v; /* points to stack or to its own value */ union { TValue value; /* the value (when closed) */ struct { /* double linked list (when open) */ struct UpVal *prev; struct UpVal *next; } l; } u; } UpVal; /* ** Closures */ #define ClosureHeader \ CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ struct Table *env typedef struct CClosure { ClosureHeader; lua_CFunction f; TValue upvalue[1]; } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; UpVal *upvals[1]; } LClosure; typedef union Closure { CClosure c; LClosure l; } Closure; #define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) #define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) /* ** Tables */ typedef union TKey { struct { TValuefields; struct Node *next; /* for chaining */ } nk; TValue tvk; } TKey; typedef struct Node { TValue i_val; TKey i_key; } Node; typedef struct Table { CommonHeader; lu_byte flags; /* 1<

    lsizenode)) #define luaO_nilobject (&luaO_nilobject_) LUAI_DATA const TValue luaO_nilobject_; #define ceillog2(x) (luaO_log2((x)-1) + 1) LUAI_FUNC int luaO_log2 (unsigned int x); LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif infon/lua-5.1.2/src/lstring.h0000644000076400001440000000145210603200765015605 0ustar dividuumusers/* ** $Id: lstring.h,v 1.43 2005/04/25 19:24:10 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ #ifndef lstring_h #define lstring_h #include "lgc.h" #include "lobject.h" #include "lstate.h" #define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) #define sizeudata(u) (sizeof(union Udata)+(u)->len) #define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) #define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); #endif infon/lua-5.1.2/src/lapi.h0000644000076400001440000000040210603200765015042 0ustar dividuumusers/* ** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ #ifndef lapi_h #define lapi_h #include "lobject.h" LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o); #endif infon/lua-5.1.2/src/lcode.h0000644000076400001440000000527210603200765015215 0ustar dividuumusers/* ** $Id: lcode.h,v 1.48 2006/03/21 19:28:03 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #ifndef lcode_h #define lcode_h #include "llex.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" /* ** Marks the end of a patch list. It is an invalid value both as an absolute ** address, and as a list link (would link an element to itself). */ #define NO_JUMP (-1) /* ** grep "ORDER OPR" if you change these enums */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->u.s.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_jump (FuncState *fs); LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif infon/lua-5.1.2/src/luaconf.h0000644000076400001440000005334410603200765015561 0ustar dividuumusers/* ** $Id: luaconf.h,v 1.82a 2006/04/10 18:27:23 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ #ifndef lconfig_h #define lconfig_h #include #include /* ** ================================================================== ** Search for "@@" to find all configurable definitions. ** =================================================================== */ /* @@ LUA_ANSI controls the use of non-ansi features. ** CHANGE it (define it) if you want Lua to avoid the use of any ** non-ansi feature or library. */ #if defined(__STRICT_ANSI__) #define LUA_ANSI #endif #if !defined(LUA_ANSI) && defined(_WIN32) #define LUA_WIN #endif #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ #endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX #define LUA_DL_DYLD /* does not need extra library */ #endif /* @@ LUA_USE_POSIX includes all functionallity listed as X/Open System @* Interfaces Extension (XSI). ** CHANGE it (define it) if your system is XSI compatible. */ #if defined(LUA_USE_POSIX) #define LUA_USE_MKSTEMP #define LUA_USE_ISATTY #define LUA_USE_POPEN #define LUA_USE_ULONGJMP #endif /* @@ LUA_PATH and LUA_CPATH are the names of the environment variables that @* Lua check to set its paths. @@ LUA_INIT is the name of the environment variable that Lua @* checks for initialization code. ** CHANGE them if you want different names. */ #define LUA_PATH "LUA_PATH" #define LUA_CPATH "LUA_CPATH" #define LUA_INIT "LUA_INIT" /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @* Lua libraries. @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for @* C libraries. ** CHANGE them if your machine has a non-conventional directory ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ #if defined(_WIN32) /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. */ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_PATH_DEFAULT \ ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua" #define LUA_CPATH_DEFAULT \ ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" #else #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/5.1/" #define LUA_CDIR LUA_ROOT "lib/lua/5.1/" #define LUA_PATH_DEFAULT \ "./?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua" #define LUA_CPATH_DEFAULT \ "./?.so;" LUA_CDIR"?.so;" LUA_CDIR"loadall.so" #endif /* @@ LUA_DIRSEP is the directory separator (for submodules). ** CHANGE it if your machine does not use "/" as the directory separator ** and is not Windows. (On Windows Lua automatically uses "\".) */ #if defined(_WIN32) #define LUA_DIRSEP "\\" #else #define LUA_DIRSEP "/" #endif /* @@ LUA_PATHSEP is the character that separates templates in a path. @@ LUA_PATH_MARK is the string that marks the substitution points in a @* template. @@ LUA_EXECDIR in a Windows path is replaced by the executable's @* directory. @@ LUA_IGMARK is a mark to ignore all before it when bulding the @* luaopen_ function name. ** CHANGE them if for some reason your system cannot use those ** characters. (E.g., if one of those characters is a common character ** in file/directory names.) Probably you do not need to change them. */ #define LUA_PATHSEP ";" #define LUA_PATH_MARK "?" #define LUA_EXECDIR "!" #define LUA_IGMARK "-" /* @@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most ** machines, ptrdiff_t gives a good choice between int or long.) */ #define LUA_INTEGER ptrdiff_t /* @@ LUA_API is a mark for all core API functions. @@ LUALIB_API is a mark for all standard library functions. ** CHANGE them if you need to define those functions in some special way. ** For instance, if you want to create one Windows DLL with the core and ** the libraries, you may want to use the following definition (define ** LUA_BUILD_AS_DLL to get it). */ #if defined(LUA_BUILD_AS_DLL) #if defined(LUA_CORE) || defined(LUA_LIB) #define LUA_API __declspec(dllexport) #else #define LUA_API __declspec(dllimport) #endif #else #define LUA_API extern #endif /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API /* @@ LUAI_FUNC is a mark for all extern functions that are not to be @* exported to outside modules. @@ LUAI_DATA is a mark for all extern (const) variables that are not to @* be exported to outside modules. ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access ** when Lua is compiled as a shared library. */ #if defined(luaall_c) #define LUAI_FUNC static #define LUAI_DATA /* empty */ #elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) #define LUAI_FUNC __attribute__((visibility("hidden"))) extern #define LUAI_DATA LUAI_FUNC #else #define LUAI_FUNC extern #define LUAI_DATA extern #endif /* @@ LUA_QL describes how error messages quote program elements. ** CHANGE it if you want a different appearance. */ #define LUA_QL(x) "'" x "'" #define LUA_QS LUA_QL("%s") /* @@ LUA_IDSIZE gives the maximum size for the description of the source @* of a function in debug information. ** CHANGE it if you want a different size. */ #define LUA_IDSIZE 60 /* ** {================================================================== ** Stand-alone configuration ** =================================================================== */ #if defined(lua_c) || defined(luaall_c) /* @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that @* is, whether we're running lua interactively). ** CHANGE it if you have a better definition for non-POSIX/non-Windows ** systems. */ #if defined(LUA_USE_ISATTY) #include #define lua_stdin_is_tty() isatty(0) #elif defined(LUA_WIN) #include #include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else #define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif /* @@ LUA_PROMPT is the default prompt used by stand-alone Lua. @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. ** CHANGE them if you want different prompts. (You can also change the ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) */ #define LUA_PROMPT "> " #define LUA_PROMPT2 ">> " /* @@ LUA_PROGNAME is the default name for the stand-alone Lua program. ** CHANGE it if your stand-alone interpreter has a different name and ** your system is not able to detect that name automatically. */ #define LUA_PROGNAME "lua" /* @@ LUA_MAXINPUT is the maximum length for an input line in the @* stand-alone interpreter. ** CHANGE it if you need longer lines. */ #define LUA_MAXINPUT 512 /* @@ lua_readline defines how to show a prompt and then read a line from @* the standard input. @@ lua_saveline defines how to "save" a read line in a "history". @@ lua_freeline defines how to free a line read by lua_readline. ** CHANGE them if you want to improve this functionality (e.g., by using ** GNU readline and history facilities). */ #if defined(LUA_USE_READLINE) #include #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ #define lua_saveline(L,idx) { (void)L; (void)idx; } #define lua_freeline(L,b) { (void)L; (void)b; } #endif #endif /* }================================================================== */ /* @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles @* as a percentage. ** CHANGE it if you want the GC to run faster or slower (higher values ** mean larger pauses which mean slower collection.) You can also change ** this value dynamically. */ #define LUAI_GCPAUSE 200 /* 200% (wait memory to double before next GC) */ /* @@ LUAI_GCMUL defines the default speed of garbage collection relative to @* memory allocation as a percentage. ** CHANGE it if you want to change the granularity of the garbage ** collection. (Higher values mean coarser collections. 0 represents ** infinity, where each step performs a full collection.) You can also ** change this value dynamically. */ #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ /* @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. ** CHANGE it (define it) if you want exact compatibility with the ** behavior of setn/getn in Lua 5.0. */ #undef LUA_COMPAT_GETN /* @@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. ** CHANGE it to undefined as soon as you do not need a global 'loadlib' ** function (the function is still available as 'package.loadlib'). */ #undef LUA_COMPAT_LOADLIB /* @@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. ** CHANGE it to undefined as soon as your programs use only '...' to ** access vararg parameters (instead of the old 'arg' table). */ #define LUA_COMPAT_VARARG /* @@ LUA_COMPAT_MOD controls compatibility with old math.mod function. ** CHANGE it to undefined as soon as your programs use 'math.fmod' or ** the new '%' operator instead of 'math.mod'. */ #define LUA_COMPAT_MOD /* @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting @* facility. ** CHANGE it to 2 if you want the old behaviour, or undefine it to turn ** off the advisory error when nesting [[...]]. */ #define LUA_COMPAT_LSTR 1 /* @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. ** CHANGE it to undefined as soon as you rename 'string.gfind' to ** 'string.gmatch'. */ #define LUA_COMPAT_GFIND /* @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' @* behavior. ** CHANGE it to undefined as soon as you replace to 'luaL_register' ** your uses of 'luaL_openlib' */ #define LUA_COMPAT_OPENLIB /* @@ luai_apicheck is the assert macro used by the Lua-C API. ** CHANGE luai_apicheck if you want Lua to perform some checks in the ** parameters it gets from API calls. This may slow down the interpreter ** a bit, but may be quite useful when debugging C code that interfaces ** with Lua. A useful redefinition is to use assert.h. */ #if defined(LUA_USE_APICHECK) #include #define luai_apicheck(L,o) { (void)L; assert(o); } #else #define luai_apicheck(L,o) { (void)L; } #endif /* @@ LUAI_BITSINT defines the number of bits in an int. ** CHANGE here if Lua cannot automatically detect the number of bits of ** your machine. Probably you do not need to change this. */ /* avoid overflows in comparison */ #if INT_MAX-20 < 32760 #define LUAI_BITSINT 16 #elif INT_MAX > 2147483640L /* int has at least 32 bits */ #define LUAI_BITSINT 32 #else #error "you must define LUA_BITSINT with number of bits in an integer" #endif /* @@ LUAI_UINT32 is an unsigned integer with at least 32 bits. @@ LUAI_INT32 is an signed integer with at least 32 bits. @@ LUAI_UMEM is an unsigned integer big enough to count the total @* memory used by Lua. @@ LUAI_MEM is a signed integer big enough to count the total memory @* used by Lua. ** CHANGE here if for some weird reason the default definitions are not ** good enough for your machine. (The definitions in the 'else' ** part always works, but may waste space on machines with 64-bit ** longs.) Probably you do not need to change this. */ #if LUAI_BITSINT >= 32 #define LUAI_UINT32 unsigned int #define LUAI_INT32 int #define LUAI_MAXINT32 INT_MAX #define LUAI_UMEM size_t #define LUAI_MEM ptrdiff_t #else /* 16-bit ints */ #define LUAI_UINT32 unsigned long #define LUAI_INT32 long #define LUAI_MAXINT32 LONG_MAX #define LUAI_UMEM unsigned long #define LUAI_MEM long #endif /* @@ LUAI_MAXCALLS limits the number of nested calls. ** CHANGE it if you need really deep recursive calls. This limit is ** arbitrary; its only purpose is to stop infinite recursion before ** exhausting memory. */ #define LUAI_MAXCALLS 2000 /* @@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function @* can use. ** CHANGE it if you need lots of (Lua) stack space for your C ** functions. This limit is arbitrary; its only purpose is to stop C ** functions to consume unlimited stack space. */ #define LUAI_MAXCSTACK 2048 /* ** {================================================================== ** CHANGE (to smaller values) the following definitions if your system ** has a small C stack. (Or you may want to change them to larger ** values if your system has a large C stack and these limits are ** too rigid for you.) Some of these constants control the size of ** stack-allocated arrays used by the compiler or the interpreter, while ** others limit the maximum number of recursive calls that the compiler ** or the interpreter can perform. Values too large may cause a C stack ** overflow for some forms of deep constructs. ** =================================================================== */ /* @@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and @* syntactical nested non-terminals in a program. */ #define LUAI_MAXCCALLS 200 /* @@ LUAI_MAXVARS is the maximum number of local variables per function @* (must be smaller than 250). */ #define LUAI_MAXVARS 200 /* @@ LUAI_MAXUPVALUES is the maximum number of upvalues per function @* (must be smaller than 250). */ #define LUAI_MAXUPVALUES 60 /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. */ #define LUAL_BUFFERSIZE BUFSIZ /* }================================================================== */ /* ** {================================================================== @@ LUA_NUMBER is the type of numbers in Lua. ** CHANGE the following definitions only if you want to build Lua ** with a number type different from double. You may also need to ** change lua_number2int & lua_number2integer. ** =================================================================== */ #define LUA_NUMBER_DOUBLE #define LUA_NUMBER double /* @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @* over a number. */ #define LUAI_UACNUMBER double /* @@ LUA_NUMBER_SCAN is the format for reading numbers. @@ LUA_NUMBER_FMT is the format for writing numbers. @@ lua_number2str converts a number to a string. @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. @@ lua_str2number converts a string to a number. */ #define LUA_NUMBER_SCAN "%lf" #define LUA_NUMBER_FMT "%.14g" #define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ #define lua_str2number(s,p) strtod((s), (p)) /* @@ The luai_num* macros define the primitive operations over numbers. */ #if defined(LUA_CORE) #include #define luai_numadd(a,b) ((a)+(b)) #define luai_numsub(a,b) ((a)-(b)) #define luai_nummul(a,b) ((a)*(b)) #define luai_numdiv(a,b) ((a)/(b)) #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) #define luai_numpow(a,b) (pow(a,b)) #define luai_numunm(a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) #define luai_numisnan(a) (!luai_numeq((a), (a))) #endif /* @@ lua_number2int is a macro to convert lua_Number to int. @@ lua_number2integer is a macro to convert lua_Number to lua_Integer. ** CHANGE them if you know a faster way to convert a lua_Number to ** int (with any rounding method and without throwing errors) in your ** system. In Pentium machines, a naive typecast from double to int ** in C is extremely slow, so any alternative is worth trying. */ /* On a Pentium, resort to a trick */ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ (defined(__i386) || defined (_M_IX86) || defined(__i386__)) /* On a Microsoft compiler, use assembler */ #if defined(_MSC_VER) #define lua_number2int(i,d) __asm fld d __asm fistp i #define lua_number2integer(i,n) lua_number2int(i, n) /* the next trick should work on any Pentium, but sometimes clashes with a DirectX idiosyncrasy */ #else union luai_Cast { double l_d; long l_l; }; #define lua_number2int(i,d) \ { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } #define lua_number2integer(i,n) lua_number2int(i, n) #endif /* this option always works, but may be slow */ #else #define lua_number2int(i,d) ((i)=(int)(d)) #define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) #endif /* }================================================================== */ /* @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. ** CHANGE it if your system requires alignments larger than double. (For ** instance, if your system supports long doubles and they must be ** aligned in 16-byte boundaries, then you should add long double in the ** union.) Probably you do not need to change this. */ #define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } /* @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. ** CHANGE them if you prefer to use longjmp/setjmp even with C++ ** or if want/don't to use _longjmp/_setjmp instead of regular ** longjmp/setjmp. By default, Lua handles errors with exceptions when ** compiling as C++ code, with _longjmp/_setjmp when asked to use them, ** and with longjmp/setjmp otherwise. */ #if defined(__cplusplus) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) try { a } catch(...) \ { if ((c)->status == 0) (c)->status = LUA_ERREXC; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_ULONGJMP) /* in Unix, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* default handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif /* @@ LUA_MAXCAPTURES is the maximum number of captures that a pattern @* can do during pattern-matching. ** CHANGE it if you need more captures. This limit is arbitrary. */ #define LUA_MAXCAPTURES 32 /* @@ lua_tmpnam is the function that the OS library uses to create a @* temporary name. @@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. ** CHANGE them if you have an alternative to tmpnam (which is considered ** insecure) or if you want the original tmpnam anyway. By default, Lua ** uses tmpnam except when POSIX is available, where it uses mkstemp. */ #if defined(loslib_c) || defined(luaall_c) #if defined(LUA_USE_MKSTEMP) #include #define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ strcpy(b, "/tmp/lua_XXXXXX"); \ e = mkstemp(b); \ if (e != -1) close(e); \ e = (e == -1); } #else #define LUA_TMPNAMBUFSIZE L_tmpnam #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif #endif /* @@ lua_popen spawns a new process connected to the current one through @* the file streams. ** CHANGE it if you have a way to implement it in your system. */ #if defined(LUA_USE_POPEN) #define lua_popen(L,c,m) ((void)L, popen(c,m)) #define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) #elif defined(LUA_WIN) #define lua_popen(L,c,m) ((void)L, _popen(c,m)) #define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) #else #define lua_popen(L,c,m) ((void)((void)c, m), \ luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) #define lua_pclose(L,file) ((void)((void)L, file), 0) #endif /* @@ LUA_DL_* define which dynamic-library system Lua should use. ** CHANGE here if Lua has problems choosing the appropriate ** dynamic-library system for your platform (either Windows' DLL, Mac's ** dyld, or Unix's dlopen). If your system is some kind of Unix, there ** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for ** it. To use dlopen you also need to adapt the src/Makefile (probably ** adding -ldl to the linker options), so Lua does not select it ** automatically. (When you change the makefile to add -ldl, you must ** also add -DLUA_USE_DLOPEN.) ** If you do not want any kind of dynamic library, undefine all these ** options. ** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. */ #if defined(LUA_USE_DLOPEN) #define LUA_DL_DLOPEN #endif #if defined(LUA_WIN) #define LUA_DL_DLL #endif /* @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State @* (the data goes just *before* the lua_State pointer). ** CHANGE (define) this if you really need that. This value must be ** a multiple of the maximum alignment required for your machine. */ #define LUAI_EXTRASPACE 0 /* @@ luai_userstate* allow user-specific actions on threads. ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something ** extra when a thread is created/deleted/resumed/yielded. */ #define luai_userstateopen(L) ((void)L) #define luai_userstateclose(L) ((void)L) #define luai_userstatethread(L,L1) ((void)L) #define luai_userstatefree(L) ((void)L) #define luai_userstateresume(L,n) ((void)L) #define luai_userstateyield(L,n) ((void)L) /* @@ LUA_INTFRMLEN is the length modifier for integer conversions @* in 'string.format'. @@ LUA_INTFRM_T is the integer type correspoding to the previous length @* modifier. ** CHANGE them if your system supports long long or does not support long. */ #if defined(LUA_USELONGLONG) #define LUA_INTFRMLEN "ll" #define LUA_INTFRM_T long long #else #define LUA_INTFRMLEN "l" #define LUA_INTFRM_T long #endif /* =================================================================== */ /* ** Local configuration. You can use this space to add your redefinitions ** without modifying the main part of the file. */ #endif infon/lua-5.1.2/src/print.c0000644000076400001440000001152010603200765015247 0ustar dividuumusers/* ** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ #include #include #define luac_c #define LUA_CORE #include "ldebug.h" #include "lobject.h" #include "lopcodes.h" #include "lundump.h" #define PrintFunction luaU_print #define Sizeof(x) ((int)sizeof(x)) #define VOID(p) ((const void*)(p)) static void PrintString(const TString* ts) { const char* s=getstr(ts); size_t i,n=ts->tsv.len; putchar('"'); for (i=0; ik[i]; switch (ttype(o)) { case LUA_TNIL: printf("nil"); break; case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; case LUA_TNUMBER: printf(LUA_NUMBER_FMT,nvalue(o)); break; case LUA_TSTRING: PrintString(rawtsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); break; } } static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d",a); if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: printf("\t; %s",svalue(&f->k[bx])); break; case OP_GETTABLE: case OP_SELF: if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (ISK(b) || ISK(c)) { printf("\t; "); if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: case OP_FORPREP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; default: break; } printf("\n"); } } #define SS(x) (x==1)?"":"s" #define S(x) x,SS(x) static void PrintHeader(const Proto* f) { const char* s=getstr(f->source); if (*s=='@' || *s=='=') s++; else if (*s==LUA_SIGNATURE[0]) s="(bstring)"; else s="(string)"; printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n", (f->linedefined==0)?"main":"function",s, f->linedefined,f->lastlinedefined, S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f)); printf("%d%s param%s, %d slot%s, %d upvalue%s, ", f->numparams,f->is_vararg?"+":"",SS(f->numparams), S(f->maxstacksize),S(f->nups)); printf("%d local%s, %d constant%s, %d function%s\n", S(f->sizelocvars),S(f->sizek),S(f->sizep)); } static void PrintConstants(const Proto* f) { int i,n=f->sizek; printf("constants (%d) for %p:\n",n,VOID(f)); for (i=0; isizelocvars; printf("locals (%d) for %p:\n",n,VOID(f)); for (i=0; ilocvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1); } } static void PrintUpvalues(const Proto* f) { int i,n=f->sizeupvalues; printf("upvalues (%d) for %p:\n",n,VOID(f)); if (f->upvalues==NULL) return; for (i=0; iupvalues[i])); } } void PrintFunction(const Proto* f, int full) { int i,n=f->sizep; PrintHeader(f); PrintCode(f); if (full) { PrintConstants(f); PrintLocals(f); PrintUpvalues(f); } for (i=0; ip[i],full); } infon/lua-5.1.2/etc/0000755000076400001440000000000010603200765013734 5ustar dividuumusersinfon/lua-5.1.2/etc/luavs.bat0000644000076400001440000000137410603200765015563 0ustar dividuumusersrem script to build Lua under "Visual Studio .NET Command Prompt". rem do not run it from this directory, run it from the toplevel: etc\luavs.bat rem it creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src. cd src cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL l*.c del lua.obj luac.obj link /DLL /out:lua51.dll l*.obj cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DLUA_BUILD_AS_DLL lua.c link /out:lua.exe lua.obj lua51.lib cl /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE l*.c print.c del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj loslib.obj ltablib.obj lstrlib.obj loadlib.obj link /out:luac.exe *.obj del *.obj cd .. infon/lua-5.1.2/etc/lua.pc0000644000076400001440000000122210603200765015036 0ustar dividuumusers# lua.pc -- pkg-config data for Lua # vars from install Makefile # grep '^V=' ../Makefile V= 5.1 # grep '^R=' ../Makefile R= 5.1.2 # grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/' prefix= /usr/local INSTALL_BIN= ${prefix}/bin INSTALL_INC= ${prefix}/include INSTALL_LIB= ${prefix}/lib INSTALL_MAN= ${prefix}/man/man1 INSTALL_LMOD= ${prefix}/share/lua/${V} INSTALL_CMOD= ${prefix}/lib/lua/${V} # canonical vars exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: Lua Description: An Extensible Extension Language Version: ${R} Requires: Libs: -L${libdir} -llua -lm Cflags: -I${includedir} # (end of lua.pc) infon/lua-5.1.2/etc/min.c0000644000076400001440000000144310603200765014665 0ustar dividuumusers/* * min.c -- a minimal Lua interpreter * loads stdin only with minimal error handling. * no interaction, and no standard library, only a "print" function. */ #include #include "lua.h" #include "lauxlib.h" static int print(lua_State *L) { int n=lua_gettop(L); int i; for (i=1; i<=n; i++) { if (i>1) printf("\t"); if (lua_isstring(L,i)) printf("%s",lua_tostring(L,i)); else if (lua_isnil(L,i)==2) printf("%s","nil"); else if (lua_isboolean(L,i)) printf("%s",lua_toboolean(L,i) ? "true" : "false"); else printf("%s:%p",luaL_typename(L,i),lua_topointer(L,i)); } printf("\n"); return 0; } int main(void) { lua_State *L=lua_open(); lua_register(L,"print",print); if (luaL_dofile(L,NULL)!=0) fprintf(stderr,"%s\n",lua_tostring(L,-1)); lua_close(L); return 0; } infon/lua-5.1.2/etc/lua.hpp0000644000076400001440000000027710603200765015234 0ustar dividuumusers// lua.hpp // Lua header files for C++ // <> not supplied automatically because Lua also compiles as C++ extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } infon/lua-5.1.2/etc/strict.lua0000644000076400001440000000153110603200765015747 0ustar dividuumusers-- -- strict.lua -- checks uses of undeclared global variables -- All global variables must be 'declared' through a regular assignment -- (even assigning nil will do) in a main chunk before being used -- anywhere or assigned to inside a function. -- local mt = getmetatable(_G) if mt == nil then mt = {} setmetatable(_G, mt) end mt.__declared = {} local function what () local d = debug.getinfo(3, "S") return d and d.what or "C" end mt.__newindex = function (t, n, v) if not mt.__declared[n] then local w = what() if w ~= "main" and w ~= "C" then error("assign to undeclared variable '"..n.."'", 2) end mt.__declared[n] = true end rawset(t, n, v) end mt.__index = function (t, n) if not mt.__declared[n] and what() ~= "C" then error("variable '"..n.."' is not declared", 2) end return rawget(t, n) end infon/lua-5.1.2/etc/all.c0000644000076400001440000000124610603200765014653 0ustar dividuumusers/* * all.c -- Lua core, libraries and interpreter in a single file */ #define luaall_c #include "lapi.c" #include "lcode.c" #include "ldebug.c" #include "ldo.c" #include "ldump.c" #include "lfunc.c" #include "lgc.c" #include "llex.c" #include "lmem.c" #include "lobject.c" #include "lopcodes.c" #include "lparser.c" #include "lstate.c" #include "lstring.c" #include "ltable.c" #include "ltm.c" #include "lundump.c" #include "lvm.c" #include "lzio.c" #include "lauxlib.c" #include "lbaselib.c" #include "ldblib.c" #include "liolib.c" #include "linit.c" #include "lmathlib.c" #include "loadlib.c" #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" #include "lua.c" infon/lua-5.1.2/etc/lua.ico0000644000076400001440000000206610603200765015215 0ustar dividuumusers &(( @DDHDDDDDDDDDDDDDDpDDDDDDDDHDDDDDDDDDDtDDDDDDDDDDGDDDDDDDDDDDDDHDDOxD@DDDOODDHDDDOOODHDDDDOODHDDDDDDOODDDDDDOOtDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDtDHDDDDDDHDHDDDDDDHD@DDDDDDHDDDDDDDDtDtDDDDDDGDDDDDDDDwpDDDDDDDDHxDHpDDDDDDDDpDDDDDDDDDDDGDDHDDDGDDDGDDxDHpwp????G( DHDDDHDDDDDDDDDD@DDDDDHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDHDDD@DDDDDDHtGDHDDDDtG?DDDDDDDDDHDDDH0infon/lua-5.1.2/etc/noparser.c0000644000076400001440000000234510603200765015735 0ustar dividuumusers/* * The code below can be used to make a Lua core that does not contain the * parsing modules (lcode, llex, lparser), which represent 35% of the total core. * You'll only be able to load binary files and strings, precompiled with luac. * (Of course, you'll have to build luac with the original parsing modules!) * * To use this module, simply compile it ("make noparser" does that) and list * its object file before the Lua libraries. The linker should then not load * the parsing modules. To try it, do "make luab". * * If you also want to avoid the dump module (ldump.o), define NODUMP. * #define NODUMP */ #define LUA_CORE #include "llex.h" #include "lparser.h" #include "lzio.h" LUAI_FUNC void luaX_init (lua_State *L) { UNUSED(L); } LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { UNUSED(z); UNUSED(buff); UNUSED(name); lua_pushliteral(L,"parser not loaded"); lua_error(L); return NULL; } #ifdef NODUMP #include "lundump.h" LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) { UNUSED(f); UNUSED(w); UNUSED(data); UNUSED(strip); #if 1 UNUSED(L); return 0; #else lua_pushliteral(L,"dumper not loaded"); lua_error(L); #endif } #endif infon/lua-5.1.2/etc/Makefile0000644000076400001440000000162010603200765015373 0ustar dividuumusers# makefile for Lua etc TOP= .. LIB= $(TOP)/src INC= $(TOP)/src BIN= $(TOP)/src SRC= $(TOP)/src TST= $(TOP)/test CC= gcc CFLAGS= -O2 -Wall -I$(INC) $(MYCFLAGS) MYCFLAGS= MYLDFLAGS= -Wl,-E MYLIBS= -lm #MYLIBS= -lm -Wl,-E -ldl -lreadline -lhistory -lncurses RM= rm -f default: @echo 'Please choose a target: min noparser one strict clean' min: min.c $(CC) $(CFLAGS) $@.c -L$(LIB) -llua $(MYLIBS) echo 'print"Hello there!"' | ./a.out noparser: noparser.o $(CC) noparser.o $(SRC)/lua.o -L$(LIB) -llua $(MYLIBS) $(BIN)/luac $(TST)/hello.lua -./a.out luac.out -./a.out -e'a=1' one: $(CC) $(CFLAGS) all.c $(MYLIBS) ./a.out $(TST)/hello.lua strict: -$(BIN)/lua -e 'print(a);b=2' -$(BIN)/lua -lstrict -e 'print(a)' -$(BIN)/lua -e 'function f() b=2 end f()' -$(BIN)/lua -lstrict -e 'function f() b=2 end f()' clean: $(RM) a.out core core.* *.o luac.out .PHONY: default min noparser one strict clean infon/lua-5.1.2/etc/README0000644000076400001440000000171410603200765014617 0ustar dividuumusersThis directory contains some useful files and code. Unlike the code in ../src, everything here is in the public domain. If any of the makes fail, you're probably not using the same libraries used to build Lua. Set MYLIBS in Makefile accordingly. all.c Full Lua interpreter in a single file. Do "make one" for a demo. lua.hpp Lua header files for C++ using 'extern "C"'. lua.ico A Lua icon for Windows (and web sites: save as favicon.ico). Drawn by hand by Markus Gritsch . lua.pc pkg-config data for Lua luavs.bat Script to build Lua under "Visual Studio .NET Command Prompt". Run it from the toplevel as etc\luavs.bat. min.c A minimal Lua interpreter. Good for learning and for starting your own. Do "make min" for a demo. noparser.c Linking with noparser.o avoids loading the parsing modules in lualib.a. Do "make noparser" for a demo. strict.lua Traps uses of undeclared global variables. Do "make strict" for a demo. infon/lua-5.1.2/README.infon0000644000076400001440000000005010603200765015144 0ustar dividuumusersThis is a modified version of lua-5.1.2 infon/lua-5.1.2/HISTORY0000644000076400001440000001734310603200765014255 0ustar dividuumusersHISTORY for Lua 5.1 * Changes from version 5.0 to 5.1 ------------------------------- Language: + new module system. + new semantics for control variables of fors. + new semantics for setn/getn. + new syntax/semantics for varargs. + new long strings and comments. + new `mod' operator (`%') + new length operator #t + metatables for all types API: + new functions: lua_createtable, lua_get(set)field, lua_push(to)integer. + user supplies memory allocator (lua_open becomes lua_newstate). + luaopen_* functions must be called through Lua. Implementation: + new configuration scheme via luaconf.h. + incremental garbage collection. + better handling of end-of-line in the lexer. + fully reentrant parser (new Lua function `load') + better support for 64-bit machines. + native loadlib support for Mac OS X. + standard distribution in only one library (lualib.a merged into lua.a) * Changes from version 4.0 to 5.0 ------------------------------- Language: + lexical scoping. + Lua coroutines. + standard libraries now packaged in tables. + tags replaced by metatables and tag methods replaced by metamethods, stored in metatables. + proper tail calls. + each function can have its own global table, which can be shared. + new __newindex metamethod, called when we insert a new key into a table. + new block comments: --[[ ... ]]. + new generic for. + new weak tables. + new boolean type. + new syntax "local function". + (f()) returns the first value returned by f. + {f()} fills a table with all values returned by f. + \n ignored in [[\n . + fixed and-or priorities. + more general syntax for function definition (e.g. function a.x.y:f()...end). + more general syntax for function calls (e.g. (print or write)(9)). + new functions (time/date, tmpfile, unpack, require, load*, etc.). API: + chunks are loaded by using lua_load; new luaL_loadfile and luaL_loadbuffer. + introduced lightweight userdata, a simple "void*" without a metatable. + new error handling protocol: the core no longer prints error messages; all errors are reported to the caller on the stack. + new lua_atpanic for host cleanup. + new, signal-safe, hook scheme. Implementation: + new license: MIT. + new, faster, register-based virtual machine. + support for external multithreading and coroutines. + new and consistent error message format. + the core no longer needs "stdio.h" for anything (except for a single use of sprintf to convert numbers to strings). + lua.c now runs the environment variable LUA_INIT, if present. It can be "@filename", to run a file, or the chunk itself. + support for user extensions in lua.c. sample implementation given for command line editing. + new dynamic loading library, active by default on several platforms. + safe garbage-collector metamethods. + precompiled bytecodes checked for integrity (secure binary dostring). + strings are fully aligned. + position capture in string.find. + read('*l') can read lines with embedded zeros. * Changes from version 3.2 to 4.0 ------------------------------- Language: + new "break" and "for" statements (both numerical and for tables). + uniform treatment of globals: globals are now stored in a Lua table. + improved error messages. + no more '$debug': full speed *and* full debug information. + new read form: read(N) for next N bytes. + general read patterns now deprecated. (still available with -DCOMPAT_READPATTERNS.) + all return values are passed as arguments for the last function (old semantics still available with -DLUA_COMPAT_ARGRET) + garbage collection tag methods for tables now deprecated. + there is now only one tag method for order. API: + New API: fully re-entrant, simpler, and more efficient. + New debug API. Implementation: + faster than ever: cleaner virtual machine and new hashing algorithm. + non-recursive garbage-collector algorithm. + reduced memory usage for programs with many strings. + improved treatment for memory allocation errors. + improved support for 16-bit machines (we hope). + code now compiles unmodified as both ANSI C and C++. + numbers in bases other than 10 are converted using strtoul. + new -f option in Lua to support #! scripts. + luac can now combine text and binaries. * Changes from version 3.1 to 3.2 ------------------------------- + redirected all output in Lua's core to _ERRORMESSAGE and _ALERT. + increased limit on the number of constants and globals per function (from 2^16 to 2^24). + debugging info (lua_debug and hooks) moved into lua_state and new API functions provided to get and set this info. + new debug lib gives full debugging access within Lua. + new table functions "foreachi", "sort", "tinsert", "tremove", "getn". + new io functions "flush", "seek". * Changes from version 3.0 to 3.1 ------------------------------- + NEW FEATURE: anonymous functions with closures (via "upvalues"). + new syntax: - local variables in chunks. - better scope control with DO block END. - constructors can now be also written: { record-part; list-part }. - more general syntax for function calls and lvalues, e.g.: f(x).y=1 o:f(x,y):g(z) f"string" is sugar for f("string") + strings may now contain arbitrary binary data (e.g., embedded zeros). + major code re-organization and clean-up; reduced module interdependecies. + no arbitrary limits on the total number of constants and globals. + support for multiple global contexts. + better syntax error messages. + new traversal functions "foreach" and "foreachvar". + the default for numbers is now double. changing it to use floats or longs is easy. + complete debug information stored in pre-compiled chunks. + sample interpreter now prompts user when run interactively, and also handles control-C interruptions gracefully. * Changes from version 2.5 to 3.0 ------------------------------- + NEW CONCEPT: "tag methods". Tag methods replace fallbacks as the meta-mechanism for extending the semantics of Lua. Whereas fallbacks had a global nature, tag methods work on objects having the same tag (e.g., groups of tables). Existing code that uses fallbacks should work without change. + new, general syntax for constructors {[exp] = exp, ... }. + support for handling variable number of arguments in functions (varargs). + support for conditional compilation ($if ... $else ... $end). + cleaner semantics in API simplifies host code. + better support for writing libraries (auxlib.h). + better type checking and error messages in the standard library. + luac can now also undump. * Changes from version 2.4 to 2.5 ------------------------------- + io and string libraries are now based on pattern matching; the old libraries are still available for compatibility + dofile and dostring can now return values (via return statement) + better support for 16- and 64-bit machines + expanded documentation, with more examples * Changes from version 2.2 to 2.4 ------------------------------- + external compiler creates portable binary files that can be loaded faster + interface for debugging and profiling + new "getglobal" fallback + new functions for handling references to Lua objects + new functions in standard lib + only one copy of each string is stored + expanded documentation, with more examples * Changes from version 2.1 to 2.2 ------------------------------- + functions now may be declared with any "lvalue" as a name + garbage collection of functions + support for pipes * Changes from version 1.1 to 2.1 ------------------------------- + object-oriented support + fallbacks + simplified syntax for tables + many internal improvements (end of HISTORY) infon/lua-5.1.2/COPYRIGHT0000644000076400001440000000277010603200765014462 0ustar dividuumusersLua License ----------- Lua is licensed under the terms of the MIT license reproduced below. This means that Lua is free software and can be used for both academic and commercial purposes at absolutely no cost. For details and rationale, see http://www.lua.org/license.html . =============================================================================== Copyright (C) 1994-2007 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================================================== (end of COPYRIGHT) infon/lua-5.1.2/INSTALL0000644000076400001440000000743410603200765014222 0ustar dividuumusersINSTALL for Lua 5.1 * Building Lua ------------ Lua is built in the src directory, but the build process can be controlled from the top-level Makefile. Building Lua on Unix systems should be very easy. First do "make" and see if your platform is listed. If so, just do "make xxx", where xxx is your platform name. The platforms currently supported are: aix ansi bsd freebsd generic linux macosx mingw posix solaris If your platform is not listed, try the closest one or posix, generic, ansi, in this order. See below for customization instructions and for instructions on how to build with other Windows compilers. If you want to check that Lua has been built correctly, do "make test" after building Lua. Also, have a look at the example programs in test. * Installing Lua -------------- Once you have built Lua, you may want to install it in an official place in your system. In this case, do "make install". The official place and the way to install files are defined in Makefile. You must have the right permissions to install files. If you want to build and install Lua in one step, do "make xxx install", where xxx is your platform name. If you want to install Lua locally, then do "make local". This will create directories bin, include, lib, man, and install Lua there as follows: bin: lua luac include: lua.h luaconf.h lualib.h lauxlib.h lua.hpp lib: liblua.a man/man1: lua.1 luac.1 These are the only directories you need for development. There are man pages for lua and luac, in both nroff and html, and a reference manual in html in doc, some sample code in test, and some useful stuff in etc. You don't need these directories for development. If you want to install Lua locally, but in some other directory, do "make install INSTALL_TOP=xxx", where xxx is your chosen directory. See below for instructions for Windows and other systems. * Customization ------------- Three things can be customized by editing a file: - Where and how to install Lua -- edit Makefile. - How to build Lua -- edit src/Makefile. - Lua features -- edit src/luaconf.h. You don't actually need to edit the Makefiles because you may set the relevant variables when invoking make. On the other hand, if you need to select some Lua features, you'll need to edit src/luaconf.h. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. We strongly recommend that you enable dynamic loading. This is done automatically for all platforms listed above that have this feature (and also Windows). See src/luaconf.h and also src/Makefile. * Building Lua on Windows and other systems ----------------------------------------- If you're not using the usual Unix tools, then the instructions for building Lua depend on the compiler you use. You'll need to create projects (or whatever your compiler uses) for building the library, the interpreter, and the compiler, as follows: library: lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c interpreter: library, lua.c compiler: library, luac.c print.c If you use Visual Studio .NET, you can use etc/luavs.bat in its "Command Prompt". If all you want is to build the Lua interpreter, you may put all .c files in a single project, except for luac.c and print.c. Or just use etc/all.c. To use Lua as a library in your own programs, you'll need to know how to create and use libraries with your compiler. As mentioned above, you may edit luaconf.h to select some features before building Lua. (end of INSTALL) infon/lua-5.1.2/Makefile0000644000076400001440000000715010603200765014624 0ustar dividuumusers# makefile for installing Lua # see INSTALL for installation instructions # see src/Makefile and src/luaconf.h for further customization # == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT ======================= # Your platform. See PLATS for possible values. PLAT= none # Where to install. The installation starts in the src directory, so take care # if INSTALL_TOP is not an absolute path. (Man pages are installed from the # doc directory.) You may want to make these paths consistent with LUA_ROOT, # LUA_LDIR, and LUA_CDIR in luaconf.h (and also with etc/lua.pc). # INSTALL_TOP= /usr/local INSTALL_BIN= $(INSTALL_TOP)/bin INSTALL_INC= $(INSTALL_TOP)/include INSTALL_LIB= $(INSTALL_TOP)/lib INSTALL_MAN= $(INSTALL_TOP)/man/man1 INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V # How to install. You may prefer "install" instead of "cp" if you have it. # To remove debug information from binaries, use "install -s" in INSTALL_EXEC. # INSTALL_EXEC= $(CP) INSTALL_DATA= $(CP) #INSTALL_EXEC= $(INSTALL) -m 0755 #INSTALL_DATA= $(INSTALL) -m 0644 # Utilities. CP= cp FIND= find INSTALL= install MKDIR= mkdir RANLIB= ranlib # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE ========= # Convenience platforms targets. PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris debug optimize # What to install. TO_BIN= lua luac TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp TO_LIB= liblua.a TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.1 R= 5.1.2 all: $(PLAT) $(PLATS) clean: cd src && $(MAKE) $@ test: dummy src/lua test/hello.lua install: dummy cd src && $(MKDIR) -p $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD) cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN) cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC) cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB) cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN) # $(RANLIB) $(INSTALL_LIB)/$(TO_LIB) local: $(MAKE) install INSTALL_TOP=.. INSTALL_EXEC="cp -p" INSTALL_DATA="cp -p" none: @echo "Please do" @echo " make PLATFORM" @echo "where PLATFORM is one of these:" @echo " $(PLATS)" @echo "See INSTALL for complete instructions." # make may get confused with test/ and INSTALL in a case-insensitive OS dummy: # echo config parameters echo: @echo "" @echo "These are the parameters currently set in src/Makefile to build Lua $R:" @echo "" @cd src && $(MAKE) -s echo @echo "" @echo "These are the parameters currently set in Makefile to install Lua $R:" @echo "" @echo "PLAT = $(PLAT)" @echo "INSTALL_TOP = $(INSTALL_TOP)" @echo "INSTALL_BIN = $(INSTALL_BIN)" @echo "INSTALL_INC = $(INSTALL_INC)" @echo "INSTALL_LIB = $(INSTALL_LIB)" @echo "INSTALL_MAN = $(INSTALL_MAN)" @echo "INSTALL_LMOD = $(INSTALL_LMOD)" @echo "INSTALL_CMOD = $(INSTALL_CMOD)" @echo "INSTALL_EXEC = $(INSTALL_EXEC)" @echo "INSTALL_DATA = $(INSTALL_DATA)" @echo "" @echo "See also src/luaconf.h ." @echo "" # echo private config parameters pecho: @echo "V = $(V)" @echo "R = $(R)" @echo "TO_BIN = $(TO_BIN)" @echo "TO_INC = $(TO_INC)" @echo "TO_LIB = $(TO_LIB)" @echo "TO_MAN = $(TO_MAN)" # echo config parameters as Lua code # uncomment the last sed expression if you want nil instead of empty strings lecho: @echo "-- installation parameters for Lua $R" @echo "VERSION = '$V'" @echo "RELEASE = '$R'" @$(MAKE) echo | grep = | sed -e 's/= /= "/' -e 's/$$/"/' #-e 's/""/nil/' @echo "-- EOF" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) clean test install local none dummy echo pecho lecho # (end of Makefile) infon/lua-5.1.2/README0000644000076400001440000000254210603200765014044 0ustar dividuumusersREADME for Lua 5.1 See INSTALL for installation instructions. See HISTORY for a summary of changes since the last released version. * What is Lua? ------------ Lua is a powerful, light-weight programming language designed for extending applications. Lua is also frequently used as a general-purpose, stand-alone language. Lua is free software. For complete information, visit Lua's web site at http://www.lua.org/ . For an executive summary, see http://www.lua.org/about.html . Lua has been used in many different projects around the world. For a short list, see http://www.lua.org/uses.html . * Availability ------------ Lua is freely available for both academic and commercial purposes. See COPYRIGHT and http://www.lua.org/license.html for details. Lua can be downloaded at http://www.lua.org/download.html . * Installation ------------ Lua is implemented in pure ANSI C, and compiles unmodified in all known platforms that have an ANSI C compiler. In most Unix-like platforms, simply do "make" with a suitable target. See INSTALL for detailed instructions. * Origin ------ Lua is developed at Lua.org, a laboratory of the Department of Computer Science of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). For more information about the authors, see http://www.lua.org/authors.html . (end of README) infon/editor.rb0000644000076400001440000000150710544656352013570 0ustar dividuumusersrequire 'socket' gfx = 0 TCPServer.open(0, 1234) do |srv| while client = srv.accept do client.write " " * 34 client.write([4, 6, 40, 30, 5, 5].pack("c*")) while line = client.readline.chomp do case line when /D.,(.*),(.*)/ client.write([4, 1, $1.to_i / 256, $2.to_i / 256, 0, gfx].pack("c*")) when /K(.*)/ case $1.to_i when ?q: gfx = 0 when ?w: gfx = 1 when ?e: gfx = 2 when ?r: gfx = 3 when ?a: gfx = 4 when ?s: gfx = 5 when ?d: gfx = 6 when ?f: gfx = 7 when ?z: gfx = 8 when ?x: gfx = 9 when ?c: gfx =10 end end end end end infon/luacore.c0000644000076400001440000000111510540115023013523 0ustar dividuumusers#define luaall_c #include "lapi.c" #include "lcode.c" #include "ldebug.c" #include "ldo.c" #include "ldump.c" #include "lfunc.c" #include "lgc.c" #include "llex.c" #include "lmem.c" #include "lobject.c" #include "lopcodes.c" #include "lparser.c" #include "lstate.c" #include "lstring.c" #include "ltable.c" #include "ltm.c" #include "lundump.c" #include "lvm.c" #include "lzio.c" #include "lauxlib.c" #include "lbaselib.c" #include "ldblib.c" #include "liolib.c" #include "linit.c" #include "lmathlib.c" #include "loadlib.c" #include "loslib.c" #include "lstrlib.c" #include "ltablib.c" infon/api/0000755000076400001440000000000010603240423012503 5ustar dividuumusersinfon/api/state.lua0000644000076400001440000003402510603200765014337 0ustar dividuumusers--[[ Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ]]-- global = {} function setupCreature() -- Internal Stuff ----------------- function _set_state(state, ...) _GG.assert(_G[state], "cannot change from state '" .. _state_name .. "' to undefined state '" .. state .. "'") if _debug_state_change then print("creature " .. id .. " is changing from '" .. _state_name .. "' to '" .. state .. "'") end _state_name = state _state_args = {...} end function _state_loop() while true do local function handle_state_change(state, ...) if not state then -- change to idle if not already there if _state_name ~= "idle" then _set_state("idle") end elseif state == true then -- keep state (restart state handler) else -- change to new state _set_state(state, ...) end end if not _G[_state_name] then print("state '" .. _state_name .. "' does not exist. changing to 'idle'") _set_state("idle") end handle_state_change(_G[_state_name](_GG.unpack(_state_args))) wait_for_next_round() end end function _restart_thread() thread = _GG.coroutine.create(_state_loop) end -- Utility functions ---------------- -- Enforces a switch to state 'state' and a restart -- of the corresponding state handler. and_start_state = function(state, ...) _GG.assert(_G[state], "state '" .. state .. "' not defined") return state, ... end -- Enforces being in state 'state'. If the creature -- already is in state 'state', nothing happens. If -- the creature is in any other state, the creature -- switches to 'state'. and_be_in_state = function(state, ...) if _state_name == state then return true else _GG.assert(_G[state], "state '" .. state .. "' not defined") return state, ... end end -- The creature stays in its current state and_keep_state = false -- The creature restarts its current state and_restart_state = true function reload() if _GG.bot then local ok, msg = _GG.epcall(_GG._TRACEBACK, _GG.setfenv(_GG.bot, _G)) if not ok then _GG.print("cannot restart creature " .. id .. ": " .. msg) end end end function restart() message = nil reload() _set_state("restarting") _restart_thread() end function wait_for_next_round() if _GG.can_yield then _GG.coroutine.yield() else _GG.error("cannot wait") end end function execute_event(event, ...) if not _G[event] then return end local function handle_state_change(ok, state, ...) if not ok then _GG.print("calling event '" .. event .. "' failed: " .. state) else if not state then -- no change elseif state == true then -- keep state (restart state handler) _restart_thread() else -- change to new state _set_state(state, ...) _restart_thread() end end end return handle_state_change(_GG.epcall(_GG._TRACEBACK, _G[event], ...)) end -- States --------------------------- function idle() _GG.set_state(id, _GG.CREATURE_IDLE) if onIdle then return onIdle() end end function restarting() if onRestart then return onRestart() end end -- Functions ------------------------ time = _GG.game_time koth_pos = _GG.get_koth_pos world_size = _GG.world_size function suicide() _GG.suicide(id) end function nearest_enemy() return _GG.get_nearest_enemy(id) end function set_path(x, y) return _GG.set_path(id, x, y) end function set_target(c) return _GG.set_target(id, c) end function set_conversion(t) return _GG.set_convert(id, t) end function pos() return _GG.get_pos(id) end function speed() return _GG.get_speed(id) end function health() return _GG.get_health(id) end function food() return _GG.get_food(id) end function max_food() return _GG.get_max_food(id) end function tile_food() return _GG.get_tile_food(id) end function tile_type() return _GG.get_tile_type(id) end function type() return _GG.get_type(id) end function say(msg) return _GG.set_message(id, msg) end function begin_idling() return _GG.set_state(id, _GG.CREATURE_IDLE) end function begin_walk_path() return _GG.set_state(id, _GG.CREATURE_WALK) end function begin_healing() return _GG.set_state(id, _GG.CREATURE_HEAL) end function begin_eating() return _GG.set_state(id, _GG.CREATURE_EAT) end function begin_attacking() return _GG.set_state(id, _GG.CREATURE_ATTACK) end function begin_converting() return _GG.set_state(id, _GG.CREATURE_CONVERT) end function begin_spawning() return _GG.set_state(id, _GG.CREATURE_SPAWN) end function begin_feeding() return _GG.set_state(id, _GG.CREATURE_FEED) end function is_idle() return _GG.get_state(id) == _GG.CREATURE_IDLE end function is_healing() return _GG.get_state(id) == _GG.CREATURE_HEAL end function is_walking() return _GG.get_state(id) == _GG.CREATURE_WALK end function is_eating() return _GG.get_state(id) == _GG.CREATURE_EAT end function is_attacking() return _GG.get_state(id) == _GG.CREATURE_ATTACK end function is_converting() return _GG.get_state(id) == _GG.CREATURE_CONVERT end function is_spawning() return _GG.get_state(id) == _GG.CREATURE_SPAWN end function is_feeding() return _GG.get_state(id) == _GG.CREATURE_FEED end function random_path() local x1, y1, x2, y2 = world_size() local i = 0 while true do for i = 1, 300 do local x, y = math.random(x1, x2), math.random(y1, y2) if set_path(x, y) then return x, y end end wait_for_next_round() end end function in_state(state) if _GG.type(state) == "function" then return _G[_state_name] == state elseif _GG.type(state) == "string" then return _state_name == state else return false end end -- Blocking Actions ----------------- function sleep(msec) local now = time() while now + msec < time() do wait_for_next_round() end end function random_move() return move_to(random_path()) end function move_to(tx, ty) local x, y = pos() if x == tx and y == ty then return true end if not _GG.set_path(id, tx, ty) then return false end return move_path(tx, ty) end function move_path(tx, ty) if not _GG.set_state(id, _GG.CREATURE_WALK) then return false end while _GG.get_state(id) == _GG.CREATURE_WALK do wait_for_next_round() end local x, y = pos() return x == tx and y == ty end function can_eat() return food() < max_food() end function heal() if not begin_healing() then return false end while is_healing() do wait_for_next_round() end return true end function eat() if not begin_eating() then return false end while is_eating() do wait_for_next_round() end return true end function feed(target) if not set_target(target) then return false end if not begin_feeding() then return false end while is_feeding() do wait_for_next_round() end return true end function attack(target) if not set_target(target) then return false end if not begin_attacking() then return false end while is_attacking() do wait_for_next_round() end return true end function convert(to_type) if not set_conversion(to_type) then return false end if not begin_converting() then return false end while is_converting() do wait_for_next_round() end return type() == to_type end function spawn() if not begin_spawning() then return false end while is_spawning() do wait_for_next_round() end return true end end function createCreature(id, parent) local creature = { id = id; parent = parent; global = global; print = print; error = error; math = math; table = table; string = string; _GG = _G; -- Reference to the global environment _state_name = 'none' } creature._G = creature setmetatable(creature, { __tostring = function(self) local x, y = get_pos(self.id) local states = { [0]="idle", [1]="walk", [2]="heal", [3]="eat", [4]="attack", [5]="convert", [6]="spawn", [7]="feed"} return "" end, __concat = function (op1, op2) return tostring(op1) .. tostring(op2) end }) setfenv(setupCreature, creature)() return creature end ------------------------------------------------------------------------ -- Callbacks von C ------------------------------------------------------------------------ function this_function_call_fails_if_cpu_limit_exceeded() end -- global table containing all your creatures creatures = creatures or {} function player_think(events) can_yield = false -- Handle the events since the last round. for n, event in ipairs(events) do if event.type == CREATURE_SPAWNED then local id = event.id local parent = event.parent ~= -1 and event.parent or nil local creature = createCreature(id, parent) creatures[id] = creature creature.restart() creatures[id].execute_event("onSpawned", parent) elseif event.type == CREATURE_KILLED then local id = event.id local killer = event.killer ~= -1 and event.killer or nil assert(creatures[id]) creatures[id].execute_event("onKilled", killer) creatures[id] = nil elseif event.type == CREATURE_ATTACKED then local id = event.id local attacker = event.attacker creatures[id].execute_event("onAttacked", attacker) elseif event.type == PLAYER_CREATED then -- TODO else error("invalid event " .. event.type) end end can_yield = true -- Iterate all creatures and execute their code by resuming the creatures coroutine for id, creature in pairs(creatures) do if type(creature.thread) ~= 'thread' then creature.message = 'uuh. self.thread is not a coroutine.' elseif coroutine.status(creature.thread) == 'dead' then if not creature.message then creature.message = 'main() terminated (maybe it was killed for using too much cpu/memory?)' end else creature.execute_event("onTick") if get_tile_food(creature.id) > 0 then creature.execute_event("onTileFood") end if get_health(creature.id) < 5 then creature.execute_event("onLowHealth") end local ok, msg = coroutine.resume(creature.thread) if not ok then creature.message = msg -- If the coroutine was interrupted for using too much -- CPU, the following function call will abort the -- player_think function (since no more function calls -- are possible at this point). The code that caused -- too much CPU can be seen by inspecting the traceback -- that was saved in creature.message. Use 'i' in the client. this_function_call_fails_if_cpu_limit_exceeded() end end end can_yield = false end infon/api/oo.lua0000644000076400001440000003534010603240423013630 0ustar dividuumusers--[[ Copyright (c) 2006 Florian Wesch . All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ]]-- ------------------------------------------------------------------------ -- Creature Class ------------------------------------------------------------------------ Creature = {} function Creature:moveto(tx, ty) local x, y = self:pos() if x == tx and y == ty then return true end if not self:set_path(tx, ty) then return false end if not self:begin_walk_path() then return false end local review = game_time() while self:is_walking() do self:wait_for_next_round() if game_time() > review + 500 then self:set_path(tx, ty) review = game_time() end end x, y = self:pos() return x == tx and y == ty end function Creature:heal() if not self:begin_healing() then return false end while self:is_healing() do self:wait_for_next_round() end return true end function Creature:eat() if not self:begin_eating() then return false end while self:is_eating() do self:wait_for_next_round() end return true end function Creature:feed(target) if not self:set_target(target) then return false end if not self:begin_feeding() then return false end while self:is_feeding() do self:wait_for_next_round() end return true end function Creature:attack(target) if not self:set_target(target) then return false end if not self:begin_attacking() then return false end while self:is_attacking() do self:wait_for_next_round() end return true end function Creature:convert(to_type) if not self:set_conversion(to_type) then return false end if not self:begin_converting() then return false end while self:is_converting() do self:wait_for_next_round() end return self:type() == to_type end function Creature:spawn() if not self:begin_spawning() then return false end while self:is_spawning() do self:wait_for_next_round() end return true end function Creature:suicide() suicide(self.id) end function Creature:nearest_enemy() return get_nearest_enemy(self.id) end function Creature:set_path(x, y) return set_path(self.id, x, y) end function Creature:set_target(c) return set_target(self.id, c) end function Creature:set_conversion(t) return set_convert(self.id, t) end function Creature:pos() return get_pos(self.id) end function Creature:speed() return get_speed(self.id) end function Creature:health() return get_health(self.id) end function Creature:food() return get_food(self.id) end function Creature:max_food() return get_max_food(self.id) end function Creature:tile_food() return get_tile_food(self.id) end function Creature:tile_type() return get_tile_type(self.id) end function Creature:type() return get_type(self.id) end function Creature:screen_message(msg) return set_message(self.id, msg) end function Creature:begin_idling() return set_state(self.id, CREATURE_IDLE) end function Creature:begin_walk_path() return set_state(self.id, CREATURE_WALK) end function Creature:begin_healing() return set_state(self.id, CREATURE_HEAL) end function Creature:begin_eating() return set_state(self.id, CREATURE_EAT) end function Creature:begin_attacking() return set_state(self.id, CREATURE_ATTACK) end function Creature:begin_converting() return set_state(self.id, CREATURE_CONVERT) end function Creature:begin_spawning() return set_state(self.id, CREATURE_SPAWN) end function Creature:begin_feeding() return set_state(self.id, CREATURE_FEED) end function Creature:is_idle() return get_state(self.id) == CREATURE_IDLE end function Creature:is_healing() return get_state(self.id) == CREATURE_HEAL end function Creature:is_walking() return get_state(self.id) == CREATURE_WALK end function Creature:is_eating() return get_state(self.id) == CREATURE_EAT end function Creature:is_attacking() return get_state(self.id) == CREATURE_ATTACK end function Creature:is_converting() return get_state(self.id) == CREATURE_CONVERT end function Creature:is_spawning() return get_state(self.id) == CREATURE_SPAWN end function Creature:is_feeding() return get_state(self.id) == CREATURE_FEED end function Creature:distance(other) return get_distance(self.id, other) end function Creature:sleep(msec) local time = game_time() while time + msec > game_time() do self:wait_for_next_round() end end function Creature:main_restarter() local wrap do if self.onThreadFatal then wrap = function(func, ...) while true do local _, msg = epcall(_TRACEBACK, func, ...) if not self:onThreadFatal("main failed: " .. msg) then break end end error("thread terminated") end else wrap = function(func, ...) return func(...) end end end wrap(function () if self.onRestart then self:onRestart() end while true do self:main() self:wait_for_next_round() end end) end function Creature:traceback() print(_TRACEBACK(self.thread)) end function Creature:restart() set_state(self.id, CREATURE_IDLE) self.message = nil self.thread = coroutine.create(self.main_restarter) if self.onThreadStart then self:onThreadStart() end end function Creature:wait_for_next_round() assert(can_yield, "you cannot wait_for_next_round() in interactive mode") coroutine.yield() if self.onThreadResume then self:onThreadResume() end end function Creature:assert(...) return assert(...) end if ldb then local debugged_creature_id function Creature:onThreadStart() self.is_in_debugger = nil end function Creature:onThreadFatal(msg) self:enter_debugger(msg, {"up 2"}) return false end function Creature:onThreadResume() if self.debug_me then local msg = self.debug_me self.debug_me = nil self:enter_debugger(msg, {"up 4"}) end end function Creature:enter_debugger(msg, cmd) self.is_in_debugger = true self.message = "Debugger active (activate with 'd" .. self.id .. "')" debugged_creature_id = self.id print("debugger started for creature " .. self) local ok, msg = pcall(ldb, msg, cmd) if not ok then print("internal debugger error: " .. msg) end self.is_in_debugger = nil self.message = nil debugged_creature_id = nil coroutine.yield() end function Creature:assert(v, msg) if not v then self:enter_debugger(msg or "assertation failed", {"up 3"}) return nil else return v end end function onCommand(cmd) local id = tonumber(cmd:match("^d([0-9]+)$")) if id then if id == debugged_creature_id then print("already debugging creature " .. id) elseif not creatures[id] then print("creature " .. id .. " does not exist") elseif not creatures[id].is_in_debugger then creatures[id].debug_me = "execution stopped" else debugged_creature_id = id print("debugging creature " .. creatures[debugged_creature_id]) coroutine.resume(creatures[debugged_creature_id].thread, "bt") end return end local debugger_available = creatures[debugged_creature_id] and creatures[debugged_creature_id].is_in_debugger if cmd == "help" then print(" d attach debugger to creature ") print(" clist show creature list") if debugger_available then coroutine.resume(creatures[debugged_creature_id].thread, cmd) end elseif cmd == "clist" then print("creatures (* = active debugger, ! = in debug mode):") for id, creature in pairs(creatures) do print(string.format("%s%s %d - %s", debugged_creature_id == id and "*" or " ", creature.is_in_debugger and "!" or " ", id, tostring(creature))) end elseif debugger_available then coroutine.resume(creatures[debugged_creature_id].thread, cmd) else print("Huh? Try '?' for help on infon, or 'help' for help on the debugger") end end function onRoundStart() onRoundStart = nil print("-----------------------------------------") print("This server has the ldb debugger enabled.") print("Type 'help' to get the debugger commands.") print("-----------------------------------------") end function debug_hook(creature) return not creature.is_in_debugger end end ------------------------------------------------------------------------ -- Callbacks von C ------------------------------------------------------------------------ function this_function_call_fails_if_cpu_limit_exceeded() end -- global table containing all your creatures creatures = creatures or {} function player_think(events) can_yield = false -- Handle the events since the last round. for n, event in ipairs(events) do if event.type == CREATURE_SPAWNED then local id = event.id local parent = event.parent ~= -1 and event.parent or nil local creature = {} setmetatable(creature, { __index = Creature, __tostring = function(self) local x, y = get_pos(self.id) local states = { [0]="idle", [1]="walk", [2]="heal", [3]="eat", [4]="attack", [5]="convert", [6]="spawn", [7]="feed"} return "" end, __concat = function (op1, op2) return tostring(op1) .. tostring(op2) end }) creatures[id] = creature creature.id = id if creature.onSpawned then local ok, msg = pcall(creature.onSpawned, creature, parent) if not ok then print("onSpawned failed: " .. msg) end else print("onSpawned method deleted") end creature:restart() elseif event.type == CREATURE_KILLED then local id = event.id local killer = event.killer ~= -1 and event.killer or nil assert(creatures[id]) if creatures[id].onKilled then local ok, msg = pcall(creatures[id].onKilled, creatures[id], killer) if not ok then print("cannot call onKilled: " .. msg) end else print("onKilled method deleted") end creatures[id] = nil elseif event.type == CREATURE_ATTACKED then local id = event.id local attacker = event.attacker if creatures[id].onAttacked then local ok, msg = pcall(creatures[id].onAttacked, creatures[id], attacker) if not ok then print("onAttacked failed: " .. msg) end else print("onAttacked method deleted") end elseif event.type == PLAYER_CREATED then if onGameStart then local ok, msg = pcall(onGameStart) if not ok then print("onGameStart failed: " .. msg) end end else error("invalid event " .. event.type) end end -- If onRoundStart is available, call it now. if onRoundStart then local ok, msg = pcall(onRoundStart) if not ok then print("onRoundEnd failed: " .. msg) end end can_yield = true -- Iterate all creatures and execute their code by resuming the creatures coroutine for id, creature in pairs(creatures) do if type(creature.thread) ~= 'thread' then creature.message = 'uuh. self.thread is not a coroutine.' elseif coroutine.status(creature.thread) == 'dead' then if not creature.message then creature.message = 'main() terminated (maybe it was killed for using too much cpu/memory?)' end else if not debug_hook or debug_hook(creature) then local ok, msg = coroutine.resume(creature.thread, creature) if not ok then creature.message = msg -- If the coroutine was interrupted for using too much -- CPU, the following function call will abort the -- player_think function (since no more function calls -- are possible at this point). The code that caused -- too much CPU can be seen by inspecting the traceback -- that was saved in creature.message. Use 'i' in the client. this_function_call_fails_if_cpu_limit_exceeded() end end end end can_yield = false -- If onRoundEnd is available, call it now. if onRoundEnd then local ok, msg = pcall(onRoundEnd) if not ok then print("onRoundEnd failed: " .. msg) end end end infon/api/state-default.lua0000644000076400001440000000116010545131242015751 0ustar dividuumusersfunction bot() function onSpawned(parent) if parent then print("Creature " .. id .. " spawned by " .. parent) else print("Creature " .. id .. " spawned") end end function onAttacked(attacker) end function onRestart() end function onKilled(killer) if killer == id then print("Creature " .. id .. " suicided") elseif killer then print("Creature " .. id .. " killed by Creature " .. killer) else print("Creature " .. id .. " died") end end function onIdle() end end infon/api/oo-default.lua0000644000076400001440000000250110545130443015250 0ustar dividuumusers-------------------------------------------------------------------------- -- Default Code -------------------------------------------------------------------------- -- Called after the Creature was created. You cannot -- call long-running methods (like moveto) here. function Creature:onSpawned(parent) if parent then print("Creature " .. self.id .. " spawned by " .. parent) else print("Creature " .. self.id .. " spawned") end end -- Called each round for every attacker on this -- creature. No long-running methods here! function Creature:onAttacked(attacker) -- print("Help! Creature " .. self.id .. " is attacked by Creature " .. attacker) end -- Called by typing 'r' in the console, after creation (after -- onSpawned) or by calling self:restart(). No long-running -- methods calls here! function Creature:onRestart() end -- Called after being killed. Since the creature is already -- dead, self.id cannot be used to call the Lowlevel API. function Creature:onKilled(killer) if killer == self.id then print("Creature " .. self.id .. " suicided") elseif killer then print("Creature " .. self.id .. " killed by Creature " .. killer) else print("Creature " .. self.id .. " died") end end -- Your Creature Logic here :-) function Creature:main() end infon/demo-decode.rb0000644000076400001440000001476710552756360014462 0ustar dividuumusersrequire 'socket' require 'zlib' require 'stringio' class Tile attr_accessor :food, :type, :gfx def initialize(type, gfx, food) @food, @type, @gfx = food, type, gfx end end class Creature attr_accessor :type, :state, :food, :health, :target, :message, :speed, :x, :y, :id, :player, :vm_id def initialize(player, vm_id, x, y) @player, @vm_id, @x, @y = player, vm_id, x, y end end class Player attr_accessor :name, :color, :cpu, :score, :id end class InfonDemo attr_reader :players, :world, :creatures, :time, :world_w, :world_h, :koth_x, :koth_y def initialize(file) #@file = StringIO.new(File.read(file)) @file = File.open(file, "rb") class << @file alias_method :orig_read, :read attr_accessor :traffic attr_accessor :compress attr_accessor :zstream attr_accessor :buf def read(x) if @compress while @buf.size < x @buf << @zstream.inflate(orig_read(1)) @traffic += 1 end ret = @buf[0...x] @buf = @buf[x..-1] else ret = orig_read(x) @traffic += x end ret end def read8 read(1)[0] end def read16 ret = read8 ret = ret & 0x7F | read8 << 7 if ret & 0x80 != 0 ret end def read32 read(4).unpack("N")[0] end def readXX(len) read(len).unpack("A*")[0] end end @file.traffic = 0 @file.buf = "" @file.compress = false @file.zstream = Zlib::Inflate.new @world = Hash.new @time = 0 @creatures = Hash.new @players = Hash.new end def tick loop do len = @file.read8 case type = @file.read8 when 0: pno = @file.read8 mask = @file.read8 if mask & 1 != 0 if @file.read8 == 0 @players.delete(pno) else player = @players[pno] = Player.new player.id = pno end else player = @players[pno] end if mask & 2 != 0 player.name = @file.readXX(@file.read8) end if mask & 4 != 0 player.color = @file.read8 end if mask & 8 != 0 player.cpu = @file.read8 end if mask & 16 != 0 player.score = @file.read16 - 500 end when 1: pos = [@file.read8, @file.read8] food_type, gfx = @file.read8, @file.read8 @world[pos] = Tile.new(food_type & 0xF0 >> 4, gfx, food_type & 0xF) when 2: msg = @file.readXX(len) when 3: cno = @file.read16 mask = @file.read8 if mask & 1 != 0 pno = @file.read8 if pno == 0xFF @creatures.delete(cno) else creature = @creatures[cno] = Creature.new(pno, @file.read16, @file.read16, @file.read16) creature.id = cno end else creature = @creatures[cno] end if mask & 2 != 0 creature.type = @file.read8 end if mask & 4 != 0 fh = @file.read8 creature.food = fh >> 4 creature.health = fh & 0x0F end if mask & 8 != 0 creature.state = @file.read8 end if mask & 16 != 0 dx, dy = @file.read16, @file.read16 x = ((dx & 1) == 1 ? -1 : 1) * (dx >> 1) y = ((dy & 1) == 1 ? -1 : 1) * (dy >> 1) creature.x += x creature.y += y end if mask & 32 != 0 creature.target = @file.read16 end if mask & 64 != 0 creature.message = @file.readXX(@file.read8) end if mask & 128 != 0 creature.speed = @file.read8 end when 4: puts @file.readXX(len) #quit return false when 5: king = @file.read8 when 6: @world_w, @world_h, @koth_x, @koth_y = @file.read8, @file.read8, @file.read8, @file.read8 when 7: smileno = @file.read16 when 8: @time = @file.read32 when 9: @time += @file.read8 return true when 10: intermission = @file.readXX(len) when 32: welcome = @file.read(len).delete("\n").strip when 254: @file.compress = true when 255: version = @file.read8 # puts "server protocol version %d" % @file.read8 else raise "???: unknown packet type #{type}" @file.readXX(len) end end end def dump_world @world_w.times do |x| @world_h.times do |y| case @world[[x,y]].type when 0: print "#" when 1: print " " when 2: print "~" else print "?" end end puts end end end if $0 == __FILE__ infon = InfonDemo.new(ARGV[0]) while infon.tick print "%2d:%02d " % [infon.time / 1000 / 60, infon.time / 1000 % 60] #puts "%d %d" % [infon.players.size, infon.creatures.size] 20.times do |i| if creature = infon.creatures[i] print "%d %d " % [creature.x, creature.y] else print "0 0 " end end puts end end infon/README.txt0000644000076400001440000001325210603200765013440 0ustar dividuumusers ___ __ ____ _ _ _ .--..-. |_ _|_ __ / _| ___ _ __ | __ ) __ _| |_| |_| | ___ / / \ \'-. _ | || '_ \| |_ / _ \| '_ \ | _ \ / _` | __| __| |/ _ \ / / _( o)_ ; \ | || | | | _| (_) | | | | | |_) | (_| | |_| |_| | __/ O O / ' -.\ |___|_| |_|_| \___/|_| |_| |____/ \__,_|\__|\__|_|\___| \___;_/-__ ;) _ __/ \ //-. / \ _ __ ___ _ __ __ _ ; / // \ / _ \ | '__/ _ \ '_ \ / _` | ' (INFON ) ) / ___ \| | | __/ | | | (_| | \( ) ) /_/ \_\_| \___|_| |_|\__,_| ' / / '.__.- -' For more information on the game, see the website at _ \\ // _ http://infon.dividuum.de/ (_'_/ \_'_) Playing: Please visit http://infon.dividuum.de/ There you'll find tutorials, a function reference and example code. Compiling the Game: Requirements: Server: libevent (tested with 1.1a) zlib Client: libevent zlib 2D SDL based renderer: SDL (tested with 1.2.8) SDL_image SDL_gfx SGE 3D OpenGL based renderer: SDL OpenGL Type 'make', edit config.lua, run ./infond then ./infon localhost. If you need help, please visit the channel #infon on irc.freenode.net. Contact: Florian 'dividuum' Wesch Please send me your bots, images of events, patches etc.. License: The game itself is released under the GPL. See http://www.gnu.org/licenses/gpl.txt for details The binary release of the 2D renderer (sdl_gui.so / sdl_gui.dll) is linked against: SDL http://www.libsdl.org SDL_image http://www.libsdl.org/projects/SDL_image/ SDL_gfx http://www.ferzkopp.net/Software/SDL_gfx-2.0/ SGE http://www.etek.chalmers.se/~e8cal1/sge/ All of them are covered by the LGPL. See http://www.gnu.org/licenses/lgpl.txt for details The binary release of the 3D renderer (gl_gui.so / gl_gui.dll) is linked against: SDL http://www.libsdl.org This library is covered by the LGPL. See http://www.gnu.org/licenses/lgpl.txt for details The binary releases of both client (infon / infon.exe) and server (infond) include libevent: libevent http://www.monkey.org/~provos/libevent/ Copyright (c) 2002, 2003 Niels Provos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The server uses a modified lua 5.1.2: lua http://www.lua.org/ Copyright (C) 1994-2007 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The Datafiles included in client and server distribution: gfx/5x7.fnt - From SDL_gfx (LGPL) gfx/font.png - From SDL_sge (LGPL) gfx/creature.mdl - From the "Hack and Slash: Y2K Apocalypse Edition" Quake Mod (GPL). Originally called dog.mdl :-) infon/infond-wrapper.c0000644000076400001440000000247610552756360015061 0ustar dividuumusers/* * This program is intended as a wrapper that starts up infond in its * own chroot environment. * * You'll need the statically compiled server (infond-static). */ #include #include #include #include #include #define must_not_fail(c) do { \ if ((c) != 0) { \ perror(#c " failed"); \ exit(EXIT_FAILURE); \ } \ } while (0) int main() { const char *uid_s = getenv("INFOND_UID"); const char *gid_s = getenv("INFOND_GID"); if (!uid_s || !gid_s) { fprintf(stderr, "both INFOND_UID and INFOND_GID must be set\n"); exit(EXIT_FAILURE); } int fd; for (fd = 3; fd < 1024; fd++) close(fd); uid_t uid = atol(uid_s); gid_t gid = atol(gid_s); must_not_fail(chroot(".")); must_not_fail(chdir("/")); must_not_fail(setgid(gid)); must_not_fail(setuid(uid)); if (getuid() == 0) { fprintf(stderr, "uid is 0. won't continue\n"); exit(EXIT_FAILURE); } if (getgid() == 0) { fprintf(stderr, "gid is 0. won't continue\n"); exit(EXIT_FAILURE); } char *argv[] = { "infond-static", NULL }; char *envp[] = { NULL }; execve("/infond-static", argv, envp); perror("execve failed"); return EXIT_FAILURE; }