0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉAŠösï÷ôôô”°ÂVl†3!333!3331#2313331333333333333"333#3333333333"3"323#333333333333>#333#3333#2333333333333333333"333#3333333333"3"323#333333333333>#333#3333#23333333333333333"33#3333333"3"23#444C444C433CC3444C444C433CC3@ˆ‰ˆ‰˜™˜™™˜™˜‰ˆ‰ˆˆ‰ˆ‰˜™˜™™˜™˜‰ˆ‰ˆá>33á33313"313231333!23>!23î13333333333333333.33#"3333#233#33333ã>33ã33333"333233333#23>#23î33333333333333333.33#"3333#233#33333ã>33ã33333"333233333#23>#23î33333333333333.3#"333#33#333ˆˆˆˆ˜™˜™™˜™˜‰ˆ‰ˆˆˆˆˆ˜™˜™™˜™˜‰ˆ‰ˆá>33á31311333333311333333311333333311333333311333UU113113331"3UUQUUQ11333331"3#UU113133331"1!UUQUUQ113333331UUUQQU133333"3QUQUQ33331"õîàÝîÝàíîàÝíàÖÝàmíîÞ îîîmmmîîîîàÝàÝîîÞÝnÝÞÖàîæÖníÖí àíàæàíîæîÝîÖîÖàî îíííîîàÝîÝÞîÞÝnÝÞÖàî ímÞæîmîàÝîÝàíîàíîàÖmàíî îîmmî‰˜€‰‰‰™˜‰ˆ‰˜˜™àÝîîÞÝÐÌàà àÐ ÞÞÞîî  ÞÝàÝîîÐÌàà àÐ ÞÞÞîî  àÝàíîàÝÍÝàÍÍààààà  Ý îàÝîîÞÝÍìÞàÍÞà Þàîî  àÝàîîàíÝÝàÝÝÐàÐàà  Ì îàÝîîÞÝÍìÞàÍÞà Þàîî  ÍìàÞààÍÞàîÝî ˜˜˜ˆ™™™ˆ‰˜˜˜™™ˆ€™™€©š€©š™™€""!33!33""ààÝÞîàÀÍíàîÀíàÝîíàîÞmàÞÝÞîîîÞÝÝÖnÝÝîÞÖîàîmîÖîníînÞíÞíÞíÝíàîÝæÞmíàîàíÝîÜ Þ îÞîÝޙ™©ª ªš ™™!"23!3#"àîÞmàÞÝÞîîÞÝînÝíÞÖîàî ÐРРа   1""îààÝÞîÝÞîîÞîÝÞíÝàíÝîÝÞ ÞíÞîÝíííííípæggpvv`gvàÝîîÞÝÍìÍàÞàîààí ÀÌÌ,""ÂÌÌ Ì Ý ÐÀÌÌ ,""ÂÂÌÌ, À ÐÐ ÐÌÌ ""ÂÀÌÌ,ÐÌÐÝ Ð330""#B$#B"#B$0""ªª ™™𹛉𻻉𛹉 ™™ˆˆªª ™›𹻉𹛉𹛉 ™™ˆˆàÜÀÝàîî,Ò",Ò"íÝîîÝ"íÝ"íàÜÀÝàîîÜ"ÝÜ"ÝíÝîî"-â"-âDDD$4ãî#4>3.4>3#4ãî#433.4îî#"""",Ò",Ò"àîîÀÝÜàÝ"íÝ"íîîÝíÜ"ÝÜ"ÝàîîÀÝÜà"-â"-âîîÝíîÞ ÐðþðÿÿàîîÝý-ýÝýÿÿÿîÞ ÐðþîîÝý-ýÝýÿÿîÞ ÐðþðÿÿàîîÝý-ýÝýÿÿÿîÞ ÐðþîîÝý-ýÝýÿÿÌÀÝÜíÜ.Ì ÝíîÝ"ß âîÿðÿîîðÿþïîýÐþíÿ"ï"îÿïîîÿÿàðÿÿà âîÿðÿîîðÿþïîíÐþÿ"ï"îÿïîîÿÿïþïÿ âîÿðÿîîðÿþïÿîîàþ"ï"îÿïîîýîßíÿÐðÿÿà âîÿðÿîîðÿþïîîàþÿ"ï"îÿïîîÿÿïýïÿÌÌÀÝÝÀÝÝÀÝÝÀÌÌÜ.ÜýÜÝÌÌÌÌÝÝÝÝÝÝÝÝÝÝÝÝÌÌÌÌ"ßÿÝÝÝÌÌÌÌÝÝÝÝÝÝÝÝÝÝÝÝÌÌÌÌÌÌÝÝÝÝÝÝÌÌ ÐÝÝÝÐîîîÐîîîÐîîîÐîîîÐîîîÐîîîÝÝÝ îîîîîîîîîîîîîîîîîîÿðÝÿÿßâ""â/ÿÝ.ýâý Ýòß-ðÝòßÝÿðýÝßîï/ÿÝâý"ý Ýòß-ðÝòßÝÿðýÝßîï/ð/ÝðÒý/ÝÿÝýÝßîýòþßßßßßðíÿÿßâ""â/òòòòòÞ.ýÿÿò."",Ò",Ò"àîîÀÝÜàÝ"Ý"Ý"Ý"îîîîÝÝÝÝÝÝÝÝîîîîÝ"Ý"Ý"Ý"îîîîÝÝÝÝÝÝÝÝîîîîÝ"íÝ"íîîÝíÐîîîÐîîîÐîîîÐîîîÐîîîÐîîîðÿÿÿîîîîîîîîîîîîîîîîîîÿÿÿÝÝí/ÿÿßâðÝÿâý.ýÝÿï"ß.ðÝÿâýîýÝÿï/ßîðýÝßÝÿðÝòß-Ýò òþîýÝßÿÝý/ÝðÒý/ÝðÝÝí/ÿÿßâðÝßßßßßòÞÝÝ.ýÿÿÝòòòòòÜ"ÝÜ"ÝàîîÀÝÜà"Ý"Ý"Ý"ÝîîîîÝÝÝÝÝÝÝÝîîîî"Ý"Ý"Ý"ÝîîîîÝÝÝÝÝÝÝÝîîîî"-â"-âîîÝí²}/!%&!%&/////1%&456///!%&$%&////////123/!56//// //!"#$#$#$#$%#$#$%$%$%$%$%$%$%$%$%%$%%$%$%$%&!"#!%&#$#$#$#$#$#///12343434345343454545454545454545545545454561%&45634343434343//!%&$%&/!"#$#$#$#$#$#$#$#$%&/!"#$%&/  123!56/12343434343434343456/123456!$#$#$#$#$#$#$#$#$#$#&/!"#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$$#$$#$#$#$%&!"#!%&#$!"#$%&1434343434343434343436123434343434343434343434343434344344343434561%&45634/123456!$#$#$#$#&!"#$#$%&/!"#$%&!"#$#$#$#$#$#$#$#$#$$#$$%&!%&/$%&/!"#143434343612343456!"#$%&12343434343434343434434456123!56!"#!"#$#$%&!"#$#$%&/1234561256!"#//!%&ABCCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDEFABCABCDEFQRSTSTSTSTSTSTSTSTSTSTUVABCDCDEFABCDCDEF/ABCDEFABEFQRSTUVSTSTSTSTQRSTSTSTSTSTSTSTSTSTSTSTSTSTUV1%&!56 !"#$%&000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123456@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@!"##$#$#$#$#$#$#$#$#$#$#$#$$%&123343434343443434343434456!"##$#$#$#$#$$#$#$#$#$#$$%&123343434343434343434343434456#$#$#$#$#$#$##$#$#$$%&QRUUV3434343434343343434456!"##$#$#$#$##$#$#$#$#$#$$%&123343434343343434343434456!"##$#$#$##$#$#$#$#$#$#$$%&123343434334343434343434456#$##$#$#$#$#$#$#$#$$%&QRUUV3433434343434343434456!"##$##$#$#$#$#$#$#$#$#$$%&123343343434343434343434456!"##$#$#$#$#$#$#$#$#$#$#$#$$%&123343434343434343434343434456!"$#$#$#$#$#$#$$%&12QRSTUV4343QRSTUV434343434456!"##$#$#$#$#$#$#$#$#$#$#$$%&/1233434343434343434343434456!"##$#$#$#$#$#$#$#$#$#$#$#$$%&123343434343434343434343434456/!"##$#$#$##$#$##$ 343434#$$%&///12334$34456/!"##$QRSRSTUV#$#$4QRSTUV4#$$%&/123343434343434343434343434456/!"##$#$#$#$#$#$#$#$#$#$#$#$$%&/123343434343434343434343434456//$#$#$#$#$#$#$#$#$#$#$$%&QRSTUV434343434343434343434456/$%&/!"#456123!"#$#$#$#$#$#$#$#$#$#$#$#$#$%&DEF// ABC123434343434343434343456ABCDCDCDCDCDCDQRSTUVCDCDCDCDEF!"#$$#$#$#$#$#$#$#$%&#$%&#$%&1234434343434343434%&34563456!"#$$#$#$#$#$#$#$#$#$#$#$##$%&#$%&/!"#$1234434343434343434343434334%&3456/QRRUV1234#$#$#$#$#$#$#$#$#$#$#$#$%&#$%&/!"#$343434343434343434343434563456//QRRUV/1234CDCDCDCDCDCDCDCDCDCDCDCDCDCDEF#$%&/!"#$3456/!"#$#$%&QRRUV///!"#$!"#$#$%#$%#$%#$%#$%#$%#$%%#$%&3456/!"#$#$%&/!"#$3456/QRUV!"#$123434343434343453434343453456#$%&/!"#$3456///QRUV1234CDEF/ABCD!"###$#$#$%#$%#$%#$%#$#$#$#$%&!"3334343453453453453434343456QRSTSTSTSTSTSTSTSTSTSTSTSTSTUV!"#$$#$#$#$#$#$#$#$%&1234434343434343434%&QRSTUV!"#$$#$#$#$#$#$#$#$#$#$#$##$%&//1234434343434343434343434334%&//#$#$#$#$#$#$#$#$#$#$#$#$%&/34343434343434343434343456/QRSTUV/QRSTUVCDCDCDCDCDCDCDCDCDCDCDCDCDCDEF/QRSTUV//!"#$#$#$%&!"#$#$#$%&!"#$#$#$%&!"#$#$%#$%#$%#$%#$%#$%#$%%#$%&//!#$#$##$%&!#$#$##$%&!"343434%&///13#3433456!"#$#$#$%&13#343345612CDCDCD56 !"#$%&!"#$%&/QRSTUV/!#34$$34%&!#$#$##$%&!#34$$34%&!"%&!"#$#$#$#$#$#$%#$#$%#$%&!"#$%&!"#$%&123434343434343453434343453456/1#$344345613#34334561#$34434561256!"#$#$#$#$#$#$%#$#$%#$%&ABCDCDCDCDCDCDCDECDCDCDCDECDEFQRSTUVQRSTUV/!#$#$#$#$&!#$#$#$#$&!#$#$#$#$&!"!"#$%&%&!"#$#$#$#$%#$%#$#$%&!"#$%&!"#$#$#$#$#$#$%#$#$%#$%&!"#$%& !"#$%& !"#$%& !"& //134343434613434343461343434346121234565612343434345345343456123456123434343434345343453456!"#$#$#$#$#$#$#$%#$#$#$#$%#$%&123456000123456000123456000126000000000000000000000000000000ABABCDEFEFABABCDEFEFABABCDEFEFABABCDEFEFABCDCDCDCDECDECDCDEFABCDEFABCDCDCDCDCDCDECDCDECDEFABCDCDCDCDCDCDCDECDCDCDCDECDEFABCDEF@@@ABCDEF@@@ABCDEF@@@ABF@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@QRSTSTSTSTSTSTSTSTSTSTSTSTSTUV////////QRRSTUV////QRRSTUV///QRSTUV//////!"#$#$#$#$#$#$#$#$#$#$#$#$#$%&123434343434343434343434343456ABCDCDCDCDCDCDCDCDCDCDCDCDCDEF/////!"//////////////// //!"//////!"#$%&/!"////////123456///!"//////////// ////ABCDEFABCDCDCDEF!"#$%&/!"//////////////!"#$%&!"//// ///////////////123456!"/////!"#$%&!"#$%&!"#$#$#$#$%&///!"#$%&!"#$#$#$%&///!"#$%&/!"//123456/1234561234343434561234561234343456123456!"123434343434343434334534533456123456//!"#$%&ABCDEF!"#$%&!"#$%&ABCDCDCDCDEF///!"#$%&ABCDEFABCDCDCDEF//!"#$%&///!"!"#$#$#$#$#$#$#$#$##$%#$%##$%&!"#$%&123456123456!"#$%&////123456/////!"123434343434343434334534533456123456//!"#$%&!"#$%&123456!"#$%&!"!"#$#$#$#$#$#$#$#$##$%#$%##$%&!"#$%& !"#$%&!"#$#$#$#$%#$#$#$#$#$%&!"#$%&!"#$%& !"#$#$#$#$%$#"#$#$#$#$%$#"#$#$#$#$#$#$#$#$#$#$#$$#$#$#$#$#$%& !"#$%&!"12343434343434343433453453345612345600000000000000000000000001234561234343434534343434345612345612345600000000000000000123434343454323434343454323434343434343434343434434343434345600000000000000000000000000000012345612ABCDCDCDCDCDCDCDCDCCDECDECCDEFABCDEF@@@@@@@@@@@@@@@@@@@@@@@@@ABCDEFABCDCDCDCDECDCDCDCDCDEFABCDEFABCDEF@@@@@@@@@@@@@@@@@ABCDCDCDCDEDCBCDCDCDCDEDCBCDCDCDCDCDCDCDCDCDCDCDDCDCDCDCDCDEF@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ABCDEFQRSTSSTSTSTSTSTSTUSTSTAB////////////////////// ß ÐÐÐÀÀÀÀÀÀÐÐÀÀÀÀÐÐÐÐÐààð ðn]L:)(öæÕÅŽŽ€€££“““‚‚‚¯ï^l|+Ú*yI¹Èù7vÖeD³3SBòáPpðÀ:977J6l5í4î322í1Œ0›1Ú23È3W3v4v5u6d8S9:;b;Ð>Ð? €L€LKJ I I±GÁFÂEÒDãBôA@@%@&@6@7@G@XAhAiAzB{C|C}D~FnG_HOH/ 0‘0¢1Ã1å233*3K4\5m6~8~9~;~L>;>*>>?ç?Ö?Å?³?²?¡? ?„ýû úPùpú`û@ü0ü ýþþþðþàþàÿÐÿÐÿÀÿÀÿ°ÿ°ÿ ÿ ÿ ÿÿÿ€ÿ€ÿ€ÿ€ÿ€\Z.Y=XKX[XZYYZH[(\÷]×]·]Š]–\†[&ZUZeYuYuZtZt[s\R\2]]á]À^ ^  ``` ``` ``` ``` ``` `` ` `` ` `` ` `` ` `` ` `` ``` ``` ``` ``` ``` @`` @`` @`` @`` @`` @` A A A A A AAAAAAA A A A A A A A A A A A A A A A A€p€q€p€q€p€q€q€p€q€p€q€p€q€p€q€p€q€p€q€p€q€q€p€q€q€q€q€p€p`` ``` ```` ``` ``` ` ``€ ``€ ```€€`€€`€400€0€000€€00 €W„„„„„À?àîîÞmàÝàÞÝ ÐÝ pæ ÐÝÐÝ Ý ÐÝÝÝÝÝÝÝÝÝÝÝÝÝÝîÝýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞîîÐ ggÐ Ý Ý ÐÝÝÝÝÝÝÝÝÝÝÝÝÝííîþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÝîÐ Ý pvvÐ ÐÝ ÝÝÝÝÝÝÝÝÝÝÝÝÝíÝíþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿnÝí Ð `g Ð ÐÝÝÝÝÝÝÝÝÝÝÝÝÝíÖÝþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÖî vÝ Ðàmíàî îÞ À À ÐÐÐÐÐÐÀÀ ÐÐÐÐ @ÀÀÐÐ@303@3034@CÀ4C4C@33@304C34CDD33DD4CîîîUUU3@3PUUUUUUUUUUUUUUUUUUUUßÝíUUUV040CeUUUUUUUeUUUUUUUUUUUUVßÒUUUV34C3444C444C444C444C444C444C444C444C444C444C444C1C3PeUUUVVUUeUUUVVUUeeUUUV@ßÝ @UeUUVC0C0444C444C444C444C444C444C444C444C444C444C444"4eUUVUVVUeUUVUVVUUeeUeUUVÿÿïUeUVU@3C343434343434343434343431"1UeUVUVUUUeUVUVUUUUeUeUVUàÿÿÿUeUVe@C3CC33CC33CC33CC33CC33CC33CC33CC33CC33CC33CC3VeUVUUUVVeUVUUUVeUUUeUVeþ"ÿî.VUUUeVUUUeUUVVUUUeUUVeUUVUUUeî"îîÿVUUUUUUUUeUUUUUUUeUUUUUUVUUUUþÿïÿUQUQUUUUUQUUUUUQUUUUQUQUPUUUUUUîîþUUUUUUUUUUUUUUUUUQUQUQQQUQeUUUUUUÿÿîUUUUUUUUUUeUUUUU3À11311111311113PeUUUVVUïþÞUUVVUUeeUUeUUUVV333313333333333333333333333eUUVUVVUÿþï]UVVUUeeUeUUVUVV33"313"333"333"333"33"333"3UeUVUVUUUeUVUVUUUUeUUeUVUVU232313#3#3#333#3#3#33232323VeUVUUUVVeUVUUUVeUUUVeUVUUU233"1"33#2333"33#23333#233"VUUUeUUVVUUUeUUVeUUVVUUUeUU333313333333333333333333333UUUUeUUUUUUUeUUUUUUVUUUUeUU333313333333333333333333333UUUUQUUUUUQUUUUUUUUQ333313333333333333333333333UQUQQQUUQ>3"3 @ 1ˆ3>3"33333>3"33333>3"311311111311111131133#3ÐБ™933#33#3333#33#3333#31333333333333333333333333333333˜ª‰33333#3333333#33333313"333"333"333"33"3333"333"3333˜ª‰333333#2333333#2333313#3#3#333#3#3#3323233#3#3#3"3"ÐБ™93"3"33333"3"33333"3"1"33#2333"33#23333#23"33#23323#1ˆ3323#3333323#3333323#1333333333333333333333333333333á>333333ã>333333ã>333331333333333333333333333333333333á3333333ÝÝÝÝÝÝÝ3ã3333331333333333333333333333333333333@À13"33333íîîîîîþ333"3333À133>3"33333>3"33333>3"3333333.313233.33íîîîîîþ333233.3!3333#33#3333#33#3333#33#333#"31333#"33íîþÿïîþ33333#"3!3333333#3333333#3333333#33>33#!"!23>33#2íîßÝýîþ2#23>33#1#2333333#2333333#2333333#2î33#23!23î33#óÿÿ-îÒïþ3#23î33#1333"3"33333"3"33333"3"33333333!3#13ƒ8333#""þ"Þïþ33333333133323#3333323#3333323#3333UUUUUUUUUUUˆ"13™™333ÓÝÝþ"Þïþ33333333á>333333ã>333333ã>333333ã>3UUUUUUUUUUUV™ 1ƒ©š833óÿÿ-îÒïþ33333333á3333333ã3333333ã3333333ã33UUVVUUeeUUUV ˜ª‰À1ƒ©š8"33íîßÝýîþ3333>3"3 13"3333333"3333333"3333333"VUVVUUeeUeUUVИª‰!3™™3#33íîþÿïîþ3#3333#3Ð13233.3333233.3333233.33332VUVUUUUeUeUVU !3ƒ83333íîîîîîþ3#3333331333#"333333#"333333#"33333VUUUVeUUUeUVeà݈1#233333íîîîîîþ33#23333!23>33#2#23>33#2#23>33#2#23UeUUVeUUVUUUeîÝ Ð€1333"3"3ÿÿÿÿÿÿÿ33333"3"îîî!23î33#3#23î33#3#23î33#3#23UeUUUUUUVUUUUàíî™™133323#3333323#3333323#ßÝí133333333333333333333333333UUQUUUUQUQUàÝíîîšá>333333ã>333333ã>33333ßÒ133333333333333333333333PUUQQQUQàÖÝmmm€©šá3333333ã3333333ã333333ßÝ 133333333333333333333333eU11113àmíîîîA™™ 13"3333333"3333333"3333ÿÿï133>3"33333>3"33333>3"33PeU333333333333îÞ"€Ð13233.3333233.3333233.3àÿÿÿ!3333#33#3333#33#3333#33eUU333"33"333"3àÝ 1"1333#"333333#"333333#"3þ"ÿî.!3333333#3333333#3333333UeU3#3#33232323îîˆ!23Ž83#2#23>33#2#23>33#î"îîÿ1#2333333#2333333#233333VeU3#23333#233"ÞÝ ™ Ð!23™™3#3#23î33#3#23î33#þÿïÿ1333"3"3ãîî>"3"33333"3"3VUU333333333333ÐÌà ˜ª‰13ƒ©š833333333333333333ðîîþ133323#3óÝÝ>23#3333323#3UUUUUUUUUUUUUUUUUUUå]å]UUU˜ª‰13ƒ©š8333333PUUUUUUUUUUUUUõÿÿîUUUá>333333ó--33333ã>333333UUUUeUUUUUUUeUUUUUÕ\Þ]UUUV™ 133™™3333333eUUUUUUUeUUUUUå^õßUUUVá3333333óÝÝ33333ã3333333UUeUUUVVUUeUUUVVÞUÞeUUUVÀˆ@1Ž8"33333>PeUUUVVUUeUUUVVåUeï]UUV13"33333óÿÿ>ó33333"33333113UeUUVUVVUeUUVUVVî^înUeUUV€!!213#33#333eUUVUVVUeUUVUVVUUeÿÞeUUV13233.333þïóÿÿ3333233.33133UUeUVUVUUUeUVUVUUUUeUeUVU™™!#3333#333UeUVUVUUUeUVUVUUUUeUeUVU1333#"33ã/òïî"333333#"3313"VVeUVUUUVVeUVUUUVeUUUeUVe€©š1#133333#23VeUVUUUVVeUVUUUVeUUUeUVe!23>33#2ã.âîþÿ#2#23>33#213#VVUUUeUUVVUUUeUUVeUUVUUUe€©š1333"3"33333VUUUeUUVVUUUeUUVeUUVUUUe!23î33#3ãÿÿþÿ3#3#23î33#31"3UUUUUeUUUUUUUeUUUUUUVUUUU™™133323#33333UUUUeUUUUUUUeUUUUUUVUUUU13333333ãîî?333333333333133UUUUUQUUUUUQUUUUQUQU€133333333333UUUUQUUUUUQUUUUQUQUPUUUUUUïþý_UUUUUUUUUUUUUUUUQUQQQUQˆ133333333333UQUQQQUQeUUUUUUïÝï^UUUUUUUUUeUUUUU111311111311113 ™ 13ƒ83"33333>11311111311113PeUUUVVUßõï^UVVUUeeUUeUUUVV333333333333333333333333Иª‰Ð!3™™3#33#33313333333333333333333333eUUVUVVUeUÿîUVVUUeeUeUUVUVV333"333"333"333"33"333"3˜ª‰!ƒ©š8333#33313"333"333"333"33"333"3UeUVUVUUUeUVUVUUUUeUUeUVUVU333#3#3#333#3#3#33232323™ 1ƒ©š83333#2313#3#3#333#3#3#33232323VeUVUUUVVeUVUUUVeUUUVeUVUUU33"33#2333"33#23333#233"ЈÐ13™™"3"333331"33#2333"33#23333#233"VUUUeUUVVUUUeUUVeUUVVUUUeUU33333333333333333333333313ƒ823#3333313333333333333333333333UUUUeUUUUUUUeUUUUUUVUUUUeUU333333333333333333333333á>3333333333á>333333333333333333333UUUUQUUUUUQUUUUUQUUU133313331333133313331á31333313331á3133331333133313331UQUQUQ1111111111111113111113111113111113111333333333333333333333333331"331"31"13311"13311"#!!!ˆ™ ˜ª‰˜ª‰ ™ ™ ™ ™ ™ ™ ™™™™ ™ ™ ™ ™ ™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ˆ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™ ™ ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆ™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆˆˆ‰ˆ‰ˆˆˆ™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™˜™ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ˆ‰ϓ-- title: Erazor -- author: tlalice -- desc: contra-inspired Run'n'Gun made for the Retro Flavored Jam -- site: gemini://tlalice.cities.yesterweb.org -- license: WTFPL -- version: 0.1 -- script: lua -- menu: HARD MODE HOLD TO SHOOT TOGGLE MUSIC -- Level Data -- cam = { x = 0, y = 0, } options = { hard = false, holdToShoot = false, mus = true, update = false } function HARDMODE() options.hard = not options.hard options.update = true end function TOGGLETOSHOOT() options.holdToShoot = not options.holdToShoot options.update = true end function MUSIC() options.mus = not options.mus options.update = true if options.mus then music() elseif currState == "Level" then music(0) end end GameMenu = {HARDMODE, TOGGLETOSHOOT, MUSIC} function MENU(i) GameMenu[i+1]() end level1 = { playerSpawn = {0, 32}, startScreen = {0, 0}, bank = 0, screens = 6, vertical = false, enemySpawns = { {"Robot", 32*8, 9*8}, {"Robot", 32*8, 7*8}, {"Turret", 33*8, 6*8}, {"Robot", 38*8, 7*8}, {"Robot", 40*8, 7*8}, {"Robot", 42*8, 7*8}, {"Robot", 58*8, 3*8}, {"Robot", 60*8, 3*8}, {"Turret", 61*8, 8*8}, {"Robot", 62*8, 3*8}, {"Robot", 70*8, 4*8}, {"Robot", 73*8, 4*8}, {"Robot", 76*8, 4*8}, {"Robot", 79*8, 4*8}, {"Robot", 70*8, 10*8}, {"Robot", 73*8, 10*8}, {"Robot", 76*8, 10*8}, {"Robot", 79*8, 10*8}, {"Turret", 80*8, 8*8}, {"Turret", 107*8, 10*8}, {"Turret", 128*8, 10*8}, {"Turret", 159*8, 10*8}, {"Turret", 169*8, 10*8}, {"Turret", 168*8, 4*8}, {"Turret", 160*8, 4*8}, {"Robot", 96*8, 8*8}, {"Robot", 99*8, 8*8}, {"Robot", 106*8, 6*8}, {"Robot", 108*8, 6*8}, {"Robot", 128*8, 6*8}, {"Robot", 130*8, 6*8}, {"UFO", 178*8, 2*8}, {"Box", 5*8, 0, "Machinegun"}, {"Box", 50*8, 0, "Shotgun"}, {"Box", 106*8, 0, "Machinegun"}, {"Box", 30*8, 0, "Life"}, {"Box", 82*8, 0, "Life"}, {"Box", 162*8, 0, "Shotgun"}, {"Box", 114*8, 0, "Grenade"}, }, } level2 = { playerSpawn = {194*8, 76*8}, startScreen = {6, 4}, bank = 0, screens = 5, vertical = true, enemySpawns = { {"UFO", 193*8, 3*8}, {"Robot", 184*8, 56*8}, {"Robot", 186*8, 56*8}, {"Robot", 188*8, 56*8}, {"Robot", 200*8, 56*8}, {"Robot", 202*8, 56*8}, {"Robot", 204*8, 56*8}, {"Turret", 200*8, 53*8}, {"Robot", 199*8, 44*8}, {"Robot", 201*8, 44*8}, {"Drone", 193*8, 41*8}, {"Turret", 202*8, 27*8}, {"Drone", 194*8, 26*8}, {"Drone", 189*8, 6*8}, {"Drone", 200*8, 6*8}, {"Box", 193*8, 51*8, "Machinegun"}, {"Box", 184*8, 34*8, "Shotgun"}, {"Box", 184*8, 36*8, "Life"}, {"Box", 184*8, 68*8, "Shotgun"}, {"Box", 184*8, 35*8, "Life"}, {"Box", 185*8, 0*8, "Life"}, {"Box", 190*8, 0*8, "Shotgun"}, }, } level3 = { playerSpawn = {8, 104*8}, startScreen = {0, 6}, bank = 0, screens = 8, vertical = false, enemySpawns = { {"Box", 32, 102*8, "Shotgun"}, {"Box", 64, 102*8, "Grenade"}, {"Drone", 40*8, 106*8}, {"Drone", 47*8, 105*8}, {"Drone", 47*8, 113*8}, {"Drone", 54*8, 106*8}, {"Turret", 78*8, 111*8}, {"Drone", 70*8, 107*8}, {"Drone", 78*8, 107*8}, {"Drone", 86*8, 107*8}, {"Robot", 68*8, 112*8}, {"Robot", 72*8, 112*8}, {"Robot", 76*8, 112*8}, {"Robot", 80*8, 112*8}, {"Robot", 84*8, 112*8}, {"Robot", 88*8, 112*8}, {"Turret", 92*8, 113*8}, {"Turret", 98*8, 111*8}, {"Drone", 104*8, 105*8}, {"Drone", 116*8, 105*8}, {"Drone", 107*8, 112*8}, {"Drone", 113*8, 112*8}, {"Robot", 115*8, 107*8}, {"Robot", 119*8, 107*8}, {"Robot", 123*8, 107*8}, {"Robot", 127*8, 107*8}, {"Turret", 171*8, 111*8}, {"Turret", 176*8, 111*8}, {"Turret", 161*8, 111*8}, {"Turret", 161*8, 106*8}, {"Robot", 135*8, 112*8}, {"Robot", 139*8, 112*8}, {"Robot", 143*8, 112*8}, {"Robot", 147*8, 112*8}, {"Robot", 151*8, 112*8}, {"Robot", 155*8, 112*8}, {"Robot", 159*8, 112*8}, {"Robot", 163*8, 112*8}, {"Robot", 137*8, 112*8}, {"Robot", 141*8, 112*8}, {"Robot", 145*8, 112*8}, {"Robot", 149*8, 112*8}, {"Robot", 153*8, 112*8}, {"Robot", 157*8, 112*8}, {"Robot", 151*8, 112*8}, {"Robot", 165*8, 112*8}, {"Box", 134*8, 102*8, "Life"}, {"Box", 136*8, 102*8, "Life"}, {"Box", 138*8, 102*8, "Machinegun"}, {"Box", 140*8, 102*8, "Grenade"}, {"Box", 142*8, 102*8, "Grenade"}, {"Drone", 188*8, 113*8}, {"Drone", 193*8, 111*8}, {"Drone", 198*8, 113*8}, {"UFO", 193*8, 116*8}, {"UFO", 236*8, 107*8}, {"Drone", 224*8, 109*8}, {"Drone", 230*8, 109*8}, {"Turret", 238*8, 114*8}, }, } level4 = { playerSpawn = {8, 70*8}, startScreen = {0, 4}, bank = 0, screens = 6, vertical = false, enemySpawns = { {"Box", 7*8, 68*8, "Grenade"}, {"Box", 9*8, 68*8, "Machinegun"}, {"Box", 11*8, 68*8, "Grenade"}, {"Robot", 31*8, 73*8}, {"Robot", 33*8, 73*8}, {"Robot", 35*8, 73*8}, {"Turret", 34*8, 77*8}, {"Drone", 34*8, 70*8}, {"Cross", 48*8, 73*8}, {"Robot", 50*8, 78*8}, {"Robot", 52*8, 78*8}, {"Robot", 54*8, 78*8}, {"Robot", 56*8, 78*8}, {"Robot", 58*8, 78*8}, {"Drone", 64*8, 76*8}, {"Drone", 68*8, 72*8}, {"Drone", 72*8, 76*8}, {"Drone", 76*8, 72*8}, {"Drone", 80*8, 76*8}, {"Drone", 84*8, 72*8}, {"Drone", 88*8, 76*8}, {"Cross", 102*8, 72*8}, {"Cross", 110*8, 72*8}, {"Turret", 128*8, 79*8}, {"Turret", 140*8, 79*8}, {"Cross", 134*8, 74*8}, {"Drone", 128*8, 72*8}, {"Drone", 140*8, 72*8}, {"Box", 49*8, 68*8, "Shotgun"}, {"Box", 126*8, 67*8, "Life"}, {"Box", 134*8, 67*8, "Machinegun"}, {"Box", 142*8, 67*8, "Life"}, {"Cross", 161*8, 72*8}, {"Cross", 170*8, 72*8}, {"UFO", 177*8, 72*8}, {"Box", 169*8, 78*8, "Shotgun"}, {"Box", 160*8, 78*8, "Machinegun"}, }, } level5 = { playerSpawn = {222*8, 93*8}, startScreen = {7, 5}, bank = 0, screens = 4, vertical = true, enemySpawns = { {"Box", 211*8, 85*8, "Shotgun"}, {"Cross", 222*8, 87*8}, {"Robot", 224*8, 81*8}, {"Robot", 226*8, 81*8}, {"Robot", 228*8, 81*8}, {"Robot", 230*8, 81*8}, {"Robot", 232*8, 81*8}, {"Robot", 234*8, 81*8}, {"Cross", 224*8, 75*8}, {"Drone", 233*8, 77*8}, {"Drone", 215*8, 77*8}, {"Turret", 237*8, 61*8}, {"Turret", 211*8, 59*8}, {"Turret", 237*8, 57*8}, {"Turret", 211*8, 55*8}, {"Turret", 237*8, 53*8}, {"Box", 214*8, 51*8, "Life"}, {"Box", 215*8, 51*8, "Life"}, {"Box", 216*8, 51*8, "Grenade"}, {"Box", 217*8, 51*8, "Grenade"}, {"Box", 218*8, 51*8, "Grenade"}, {"Box", 219*8, 51*8, "Shotgun"}, {"Box", 223*8, 80*8, "Machinegun"}, {"Drone", 224*8, 41*8}, {"Cross", 212*8, 38*8}, {"Cross", 236*8, 38*8}, {"UFO", 224*8, 35*8}, {"Turret", 210*8, 46*8}, {"Turret", 238*8, 46*8}, {"Box", 210*8, 42*8, "Machinegun"}, {"Box", 238*8, 42*8, "Shotgun"}, {"Box", 215*8, 40*8, "Machinegun"}, {"Box", 217*8, 40*8, "Shotgun"}, {"Box", 218*8, 40*8, "Grenade"}, {"Box", 219*8, 40*8, "Life"}, }, } levels = { level1, level2, level3, level4, level5, } currentLevel = 1 currentLevelData = {} function cmpSpawns(a, b) if currentLevelData.vertical then return a[3] > b[3] end return a[2] < b[2] end function setLevel(n, keepPlayer) keepPlayer = false or keepPlayer sync(4, currentLevelData.bank) currentLevel = n currentLevelData = levels[n] levelStartX = currentLevelData.startScreen[1] * 30 * 8 levelStartY = currentLevelData.startScreen[2] * 17 * 8 if not currentLevelData.vertical then levelEndX = levelStartX + (currentLevelData.screens-1) * 30 * 8 levelEndY = levelStartY else levelEndY = levelStartY - (currentLevelData.screens-1) * 17 * 8 levelEndX = levelStartX end cam.x = levelStartX cam.y = levelStartY local px = levels[n].playerSpawn[1] local py = levels[n].playerSpawn[2] if keepPlayer then player.x = px player.y = py player.state = "Falling" player.dead = false player.vx = 1 player.iframes = 120 else player = createPlayer(px, py) end currentLevelData.spawnInd = 1 table.sort(currentLevelData.enemySpawns, cmpSpawns) currentLevelData.randomSpawnTimer = 500 bullets = {player = {}, enemy = {}} enemies = {} explosions = {} pickups = {} grenades = {} lastScreen = false if not options.mus then music(0) end end function clampCamera() local sx = levelStartX local sy = levelStartY local maxX = levelEndX local maxY = levelEndY if currentLevelData.vertical then cam.y = math.max(cam.y, maxY) if cam.y == maxY then lastScreen = true end else cam.x = math.min(cam.x, maxX) if cam.x == maxX then lastScreen = true end end end function levelSpawn(spwn) local spawnTable = { Robot = spawnRobot, Turret = spawnTurret, UFO = spawnUFO, Drone = spawnDrone, Cross = spawnCross } local t = spwn[1] local x = spwn[2] local y = spwn[3] local f = spawnTable[t] local new = {} if f then new = f(x, y) if options.hard then new.hits = new.hits * 2 end else if t == "Box" then new = spawnBox(x, y, spwn[4]) end end new.index = #enemies+1 table.insert(enemies, new) end function randomSpawn() if not currentLevelData.vertical then local x = cam.x + 240 if x >= levelEndX then return end local y = cam.y + (math.floor(math.random(14))*8) local tile = tileAt(x+8, y+24) local found = fget(tile, 0) local done = false while not found and not done do y = y + 8 tile = tileAt(x+8, y+24) found = fget(tile, 0) done = y - cam.y > 120 end if found then levelSpawn({"Robot", x, y}) currentLevelData.randomSpawnTimer = math.floor(math.random(200, 300)) if options.hard then currentLevelData.randomSpawnTimer = math.floor(math.random(100, 150)) end end else local x = cam.x + (math.floor(math.random(30)))*8 local y = ((cam.y - 16)//8) * 8 if y >= levelEndY then return end local tile = tileAt(x+8, y+24) local found = fget(tile, 0) local done = false while not found and not done do x = x + 8 tile = tileAt(x+8, y+24) found = fget(tile, 0) done = x - cam.x > 240 end if found then levelSpawn({"Robot", x, y}) currentLevelData.randomSpawnTimer = math.floor(math.random(400, 500)) end end end function levelUI() rect(0,0,240,8,0) spr(306,2,0) spr(307,10,0) print(player.lives, 18, 2, 13, true, 1, true) spr(336, 30, 0) spr(307,38,0) print(player.grenades, 46, 2, 13, true, 1, true) if player.weapon ~= 0 then print("AMMO:", 60, 2, 13, true, 1, true) rect(80, 2, player.ammo, 4, 13) end if not currentLevelData.vertical then local t = cam.x - levelStartX t = t / (levelEndX - levelStartX) rect(140, 2, 80, 4, 15) rect(140, 2, t*80, 4, 13) spr(306, 136+t*80, 0, 0) else local t = cam.y - levelEndY t = t / (levelStartY - levelEndY) t = 1.0 - t rect(140, 2, 80, 4, 15) rect(140, 2, t*80, 4, 13) spr(306, 136+t*80, 0, 0) end end scroll = 0 function updateLevel() local maxX = cam.x + 240 local maxY = cam.y local ld = currentLevelData local spawnN = ld.spawnInd local currSpawn = ld.enemySpawns[spawnN] if ld.randomSpawnTimer == 0 then randomSpawn() else ld.randomSpawnTimer = ld.randomSpawnTimer - 1 end if scroll == 3 then if not currentLevelData.vertical then cam.x = cam.x + 1 else cam.y = cam.y - 1 end elseif scroll > 3 then scroll = 0 end if not currentLevelData.vertical then scroll = scroll + 1 else scroll = scroll + 0.5 end if not currSpawn then return end if not ld.vertical then if maxX >= currSpawn[2] then levelSpawn(currSpawn) ld.spawnInd = ld.spawnInd + 1 end else if (maxY-24) <= currSpawn[3] then levelSpawn(currSpawn) ld.spawnInd = ld.spawnInd + 1 end end end -- END Level Data -- -- Bullet Logic -- bullets = { player = {}, enemy = {}, } function bulletEnemyCheck(bl, e) local hitBoxTable = { Robot = {6, 4, 12, 20}, Turret = {0, 0, 16, 16}, UFO = {0, 0, 32, 24}, Box = {-2, -2, 10, 10}, Drone = {0,0,16,16}, Cross = {-1,-1,17,17}, } local lx = bl.x - e.x local ly = bl.y - e.y local box = hitBoxTable[e.type] local xc = lx >= box[1] and lx <= box[3] local yc = ly >= box[2] and ly <= box[4] local colliding = xc and yc if colliding then enemyHit(e) end return colliding end function bulletPlayerCheck(bl, pl) local hitBoxTable = { Grounded = {4, 1, 12, 15}, Jumping = {4, 2, 12, 12}, Falling = {3, 1, 8, 15}, Down = {1, 9, 16, 15} } if pl.state == "Dead" then return false end local box = hitBoxTable[pl.state] local lx = bl.x - pl.x local ly = bl.y - pl.y local xc = lx >= box[1] and lx <= box[3] local yc = ly >= box[2] and ly <= box[4] local colliding = xc and yc if colliding then playerDie() --setLevel(currentLevel) end return colliding end function updateGrenades() for k, g in pairs(grenades) do g.vy = g.vy + 0.1 g.vx = g.vx * 0.98 g.x = g.x + g.vx g.y = g.y + g.vy local tile = tileAt(g.x+4, g.y+12) if g.vy > 0 and (fget(tile, 0) or fget(tile, 2)) then g.vy = g.vy * -0.9 g.vx = g.vx * 0.97 end local r = (g.t // 4) % 4 g.t = g.t - 1 if g.t == 0 then for k, en in pairs(enemies) do local dx = en.x - g.x local dy = en.y - g.y local d = dx*dx + dy*dy if d <= (48 * 48) then enemyHit(en, 5) end end grenades[k] = nil sfx(14, 1, 30, 3) explodefx(g.x, g.y, 32) end spr(336, g.x-cam.x, g.y-cam.y, 0, 1, 0, r) end end function updateBullets() for k, bul in pairs(bullets.player) do bul.x = bul.x + bul.vx bul.y = bul.y + bul.vy local ofx = bul.x - cam.x local collided = false for j, en in pairs(enemies) do collided = collided or bulletEnemyCheck(bul, en) end if ofx < 0 or ofx > 240 or collided then table.remove(bullets.player, k) end end for k, bul in pairs(bullets.enemy) do bul.x = bul.x + bul.vx bul.y = bul.y + bul.vy if bulletPlayerCheck(bul, player) then bullets.enemy[k] = nil end local ofx = bul.x - cam.x if ofx < 0 or ofx > 240 then bullets.enemy[k] = nil end end end function drawBullets() for k, bul in pairs(bullets.player) do local flip = 0 if bul.vx < 0 then flip = 1 end local t = bul.t spr(t, bul.x-4-cam.x, bul.y-4-cam.y, 0, 1, flip) end for k, bul in pairs(bullets.enemy) do local flip = 0 if bul.vx < 0 then flip = 1 end local t = bul.t spr(t, bul.x-4-cam.x, bul.y-4-cam.y, 0, 1, flip) end end -- END Bullet Logic -- function createPlayer(x, y) local newPlayer = { x = x, y = y, state = "Falling", vx = 1, vy = 0, flip = false, shotTimer = 0.0, passThroughTime = 0, frame = 0, aimDir = 0, jumpBuffer = 0.0, iframes = 120, weapon = 0, grenades = 3, deadTimer = 0, dead = false, ammo = 0, lives = 10, } return newPlayer end function playerDead(pl) if player.deadTimer == 0 then if currentLevelData.vertical then player.y = cam.y + 80 player.x = cam.x + 16 else player.y = cam.y + 16 player.x = cam.x + 16 end player.vx = 1 player.vy = 0 player.iframes = 120 player.dead = false return "Falling" end player.deadTimer = player.deadTimer - 1 player.vx = player.vx * 0.95 player.vy = player.vy + 0.3 return "Dead" end function playerDie() if player.dead then return end if player.iframes > 0 then return end sfx(13, 30, 15, 3) player.dead = true player.deadTimer = 60 player.lives = player.lives - 1 player.vx = -4 player.vy = -3 player.weapon = 0 player.ammo = 0 end function playerShouldFire(pl) if pl.shotTimer ~= 0 then return false end if pl.weapon == 1 then return btn(4) end if options.holdToShoot then return btn(4) end return btnp(4) end function spawnGrenade(x, y, vx, vy) local newGrenade = { x = x, y = y, vx = vx, vy = vy, t = 75, } table.insert(grenades, newGrenade) return end function playerThrowGrenade(pl, dir) local dirXTable = { Up = 0, UpRight = 0.7, Right = 1.0, DownRight = 0.7, Down = 0.0, DownLeft = -0.7, Left = -1.0, UpLeft = -0.7, } local dirYTable = { Up = -1.0, UpRight = -0.7, Right = 0.0, DownRight = 0.7, Down = 1.0, DownLeft = 0.7, Left = 0.0, UpLeft = -0.7, } if player.grenades == 0 then return end local sox = 12 local soy = 6 if pl.flip then sox = 4 end if pl.state == "Down" then soy = 12 end if btn(0) and pl.vx == 0 then sox = 6 if pl.flip then sox = 10 end end sox = sox + pl.x soy = soy + pl.y local vx = dirXTable[dir] * 3 local vy = dirYTable[dir] * 2 - 1 player.grenades = player.grenades - 1 spawnGrenade(sox, soy, vx, vy) end function playerFire(pl, dir) local dirXTable = { Up = 0, UpRight = 0.7, Right = 1.0, DownRight = 0.7, Down = 0.0, DownLeft = -0.7, Left = -1.0, UpLeft = -0.7, } local dirYTable = { Up = -1.0, UpRight = -0.7, Right = 0.0, DownRight = 0.7, Down = 1.0, DownLeft = 0.7, Left = 0.0, UpLeft = -0.7, } local delays = { 12, 7, 15 } local sprites = { 320, 304, 288 } local speeds = {3, 4, 2.5} pl.shotTimer = delays[pl.weapon+1] local sox = 12 local soy = 6 if pl.flip then sox = 4 end if pl.state == "Down" then soy = 12 end if btn(0) and pl.vx == 0 then sox = 6 if pl.flip then sox = 10 end end local speed = speeds[pl.weapon+1] if pl.weapon == 2 then for i=-2,2 do local a = i a = a / 6.0 local vxo = dirXTable[dir] local vyo = dirYTable[dir] local vx = vxo * math.cos(a) - vyo * math.sin(a) local vy = vxo * math.sin(a) + vyo * math.cos(a) newBullet = { x = pl.x + sox, y = pl.y + soy, vx = vx * speed, vy = vy * speed, t = sprites[pl.weapon+1], } table.insert(bullets.player, newBullet) end else newBullet = { x = pl.x + sox, y = pl.y + soy, vx = dirXTable[dir] * speed, vy = dirYTable[dir] * speed, t = sprites[pl.weapon+1], } table.insert(bullets.player, newBullet) end local note = 25 + math.random(0,10) sfx(12, note, 15, 3) if pl.ammo > 0 then pl.ammo = pl.ammo - 1 else pl.weapon = 0 end end function tileAt(x, y) return mget(x//8, y//8) end function updateTurret(tr) local dx = player.x - (tr.x+8) local dy = player.y - (tr.y+8) local a = math.atan2(dy, dx) local pi = 3.14159265 a = (a + pi) / (2 * pi) a = (math.floor((a*8)+0.5)) % 8 tr.r = a if tr.timerShot == 0 then local tableX = {} tableX[0] = -1 tableX[1] = -0.7 tableX[2] = 0 tableX[3] = 0.7 tableX[4] = 1 tableX[5] = 0.7 tableX[6] = 0 tableX[7] = -0.7 local vx = tableX[a] local vy = -tableX[(a+2)%8] enemyFire(tr.x+8, tr.y+7, 305, vx*3, vy*3) tr.timerShot = 60 else tr.timerShot = tr.timerShot - 1 if options.hard then tr.timerShot = tr.timerShot - 1 end end end function drawTurret(tr) local id = 480 local x = tr.x - cam.x local y = tr.y - cam.y spr(480, x, y, 0, 1, 0, 0, 2, 2) if tr.r % 2 == 0 then spr(482, x, y, 0, 1, 0, tr.r//2, 2, 2) else spr(484, x, y, 0, 1, 0, tr.r//2, 2, 2) end end function playerGrounded(pl) if pl.dead then return "Dead" end pl.vx = 0 if btn(3) then pl.vx = 1 pl.flip = false end if btn(2) then pl.vx = -1 pl.flip = true end local tile = tileAt(pl.x+8, pl.y+20) local tile2 = tileAt(pl.x+8, pl.y+12) if not (fget(tile, 0) or fget(tile, 1) or fget(tile2, 2)) then return "Falling" end if fget(tile, 1) then pl.vx = pl.vx * 0.2 end if btnp(5) or pl.jumpBuffer > 0 then pl.vy = -4 return "Jumping" end if btn(1) and pl.vx == 0 and not fget(tile, 1) then return "Down" end if playerShouldFire(pl) then local vert = "" local hori = "" local dir = "" if pl.flip then hori = "Left" else hori = "Right" end if btn(0) then vert = "Up" elseif btn(1) then vert = "Down" end if vert ~= "" and pl.vx == 0 then dir = vert else dir = vert .. hori end playerFire(pl, dir) end if btnp(7) then local vert = "" local hori = "" local dir = "" if pl.flip then hori = "Left" else hori = "Right" end if btn(0) then vert = "Up" elseif btn(1) then vert = "Down" end if vert ~= "" and pl.vx == 0 then dir = vert else dir = vert .. hori end playerThrowGrenade(pl, dir) end return "Grounded" end function playerJumping(pl) if pl.dead then return "Dead" end if pl.vy > 0 then return "Falling" end pl.vy = pl.vy + 0.25 if btn(3) then pl.vx = 1 pl.flip = false end if btn(2) then pl.vx = -1 pl.flip = true end if playerShouldFire(pl) then dir = "" if not pl.flip then dir = "Right" if btn(0) then if btn(3) then dir = "UpRight" else dir = "Up" end elseif btn(1) then if btn(3) then dir = "DownRight" else dir = "Down" end end else dir = "Left" if btn(0) then if btn(2) then dir = "UpLeft" else dir = "Up" end elseif btn(1) then if btn(2) then dir = "DownLeft" else dir = "Down" end end end playerFire(pl, dir) end if btnp(7) then dir = "" if not pl.flip then dir = "Right" if btn(0) then if btn(3) then dir = "UpRight" else dir = "Up" end elseif btn(1) then if btn(3) then dir = "DownRight" else dir = "Down" end end else dir = "Left" if btn(0) then if btn(2) then dir = "UpLeft" else dir = "Up" end elseif btn(1) then if btn(2) then dir = "DownLeft" else dir = "Down" end end end playerThrowGrenade(pl, dir) end return "Jumping" end function playerFalling(pl) if pl.dead then return "Dead" end if (pl.vy < 5) then pl.vy = pl.vy + 0.25 end if btn(3) then pl.vx = 1 pl.flip = false end if btn(2) then pl.vx = -1 pl.flip = true end if btnp(5) then pl.jumpBuffer = 10 end if pl.passThroughTime == 0 then local ga = tileAt(pl.x+8, pl.y+20) local gb = tileAt(pl.x+8, pl.y+12) local grounded = fget(ga, 0) or fget(ga, 1) local grounded2 = fget(gb, 2) if grounded then pl.vy = 0 pl.y = (8 * ((pl.y+20) // 8)) - 20 return "Grounded" end if grounded2 then pl.vy = 0 pl.y = (8 * ((pl.y+12) // 8)) - 12 return "Grounded" end else pl.passThroughTime = pl.passThroughTime - 1 end if playerShouldFire(pl) then dir = "" if not pl.flip then dir = "Right" if btn(0) then if btn(3) then dir = "UpRight" else dir = "Up" end elseif btn(1) then if btn(3) then dir = "DownRight" else dir = "Down" end end else dir = "Left" if btn(0) then if btn(2) then dir = "UpLeft" else dir = "Up" end elseif btn(1) then if btn(2) then dir = "DownLeft" else dir = "Down" end end end playerFire(pl, dir) end if btnp(7) then dir = "" if not pl.flip then dir = "Right" if btn(0) then if btn(3) then dir = "UpRight" else dir = "Up" end elseif btn(1) then if btn(3) then dir = "DownRight" else dir = "Down" end end else dir = "Left" if btn(0) then if btn(2) then dir = "UpLeft" else dir = "Up" end elseif btn(1) then if btn(2) then dir = "DownLeft" else dir = "Down" end end end playerThrowGrenade(pl, dir) end return "Falling" end function playerDown(pl) if pl.dead then return "Dead" end if not btn(1) then return "Grounded" end if btn(2) or btn(3) then return "Grounded" end if playerShouldFire(pl) then if pl.flip then playerFire(pl, "Left") else playerFire(pl, "Right") end end if btnp(7) then if pl.flip then playerThrowGrenade(pl, "Left") else playerThrowGrenade(pl, "Right") end end if btn(5) then pl.passThroughTime = 9 return "Falling" end return "Down" end function updatePlayer(pl) stateF = { Grounded = playerGrounded, Falling = playerFalling, Jumping = playerJumping, Down = playerDown, Dead = playerDead, } pl.state = stateF[pl.state](pl) pl.x = pl.x+ pl.vx pl.y = pl.y+pl.vy if pl.jumpBuffer > 0 then pl.jumpBuffer = pl.jumpBuffer -1 end if pl.shotTimer > 0 then pl.shotTimer = pl.shotTimer - 1 end if pl.iframes > 0 then pl.iframes = pl.iframes - 1 end if (pl.x - cam.x) < -16 then playerDie() end if (pl.y - cam.y > 150) then playerDie() end end function drawPlayer(pl) if pl.iframes > 0 then if pl.iframes % 3 == 0 then return end end local inWater = fget(tileAt(pl.x+8, pl.y+20), 1) local x = pl.x - cam.x local y = pl.y - cam.y if pl.state == "Dead" then spr(293, x, y+8, 0, 1, 0, 0, 2, 1) return end if pl.state == "Down" then local flip = 0 if pl.flip then flip = 1 end spr(290, x, y+8, 0, 1, flip, 0, 3, 1) elseif pl.state == "Jumping" then local flip = 0 if pl.flip then flip = 1 end local r = (pl.frame//4)%4 spr(268, x, y, 0, 1, flip, r, 2, 2) else local flip = 0 if pl.flip then flip = 1 end local frame = pl.frame//10 local uid = 256 local lid = 272 local uy = y local ly = y+8 if inWater then local wf = (frame) % 2 if frame%2 == 1 then uy = uy + 1 end lid = 270 + 16*wf else if pl.vx ~= 0 then lid = 276 + (2*(frame%4)) if frame%2 == 1 then uy = uy + 1 end end end if btn(0) then if pl.vx ~= 0 then uid = 258 else uid = 260 end elseif btn(1) then uid = 262 end spr(uid, x, uy, 0, 1, flip, 0, 2, 1) spr(lid, x, ly, 0, 1, flip, 0, 2, 1) end pl.frame = pl.frame + 1 end function enemyFire(x, y, t, vx, vy) local newBullet = { x = x, y = y, vx = vx, vy = vy, t = t, } if options.hard then newBullet.vx = newBullet.vx * 1.35 newBullet.vy = newBullet.vy * 1.35 end local note = 25 + math.random(0,10) sfx(12, note, 15, 3) table.insert(bullets.enemy, newBullet) end function updateRobot(rb) rb.x = rb.x + rb.dir rb.frame = rb.frame + 1 local d = {} d[-1] = 2 d[1] = 18 local tile = tileAt(rb.x + d[rb.dir], rb.y+24) local tile2 = tileAt(rb.x + d[rb.dir], rb.y+16) local grounded = fget(tile, 0) grounded = grounded or fget(tile2, 2) if not grounded then rb.dir = rb.dir * -1 end local dy = player.y - rb.y local dx = player.x - rb.x local sx = -1 if dx >= 0 then sx = 1 end local inRange = dy >= -8 and dy <= 8 inRange = inRange and sx == rb.dir if inRange then if rb.timerShot == 0 then enemyFire(rb.x, rb.y+12, 321, rb.dir*2, 0) rb.timerShot = 30 end end if rb.timerShot > 0 then rb.timerShot = rb.timerShot - 1 if options.hard then rb.timerShot = rb.timerShot - 1 end end end function drawRobot(rb) local x = rb.x - cam.x local y = rb.y - cam.y+4 local f = 2 * ((rb.frame//10) % 4) local flip = 0 if rb.dir == 1 then flip = 1 end spr(448+f, x, y, 0, 1, flip, 0, 2, 2) local d = {} d[-1] = -2 d[1] = 18 end function updateUFO(ufo) ufo.frames = ufo.frames + 1 ufo.y = ufo.y + math.sin(ufo.frames / 10.0) / 5.0 local sx = ufo.x // (8*30) local sy = ufo.y // (8*17) local minX = (sx * (8*30))+16 local minY = (sy * (8*17))+16 local maxX = minX + (8*25) local maxY = minY + (8*12) if ufo.moveTimer == 0 then ufo.tx = math.random(minX, maxX) ufo.ty = math.random(minY, maxY) ufo.moveTimer = math.random(120, 240) else ufo.moveTimer = ufo.moveTimer - 1 end local dx = ufo.tx - ufo.x local dy = ufo.ty - ufo.y local l = dx * dx + dy * dy if l > 3 then l = math.sqrt(l) dx = dx / l dy = dy / l ufo.x = ufo.x + dx ufo.y = ufo.y + dy end if ufo.shotTimer == 0 then for i=0,13 do local t = i / 12.0 local a = 2 * 3.14159265 * t local vx = math.cos(a) local vy = math.sin(a) enemyFire(ufo.x + 16, ufo.y +12, 289, vx*3, vy*3) end ufo.shotTimer = 120 else ufo.shotTimer = ufo.shotTimer - 1 end end function drawUFO(ufo) local uid = 460 local x = ufo.x - cam.x local y = ufo.y - cam.y spr(uid, x, y, 0, 1, 0, 0, 4, 2) local lid = 492 if (ufo.frames // 10) % 2 == 0 then lid = 508 end spr(lid, x, y+16, 0, 1, 0, 0, 4, 1) end function updateDrone(ufo) ufo.frames = ufo.frames + 1 ufo.y = ufo.y + math.sin(ufo.frames / 10.0) / 5.0 if ufo.shotTimer == 0 then for i=0,9 do local t = i / 8.0 local a = 2 * 3.14159265 * t local vx = math.cos(a) local vy = math.sin(a) enemyFire(ufo.x + 8, ufo.y + 8, 289, vx*2, vy*2) end ufo.shotTimer = 120 else ufo.shotTimer = ufo.shotTimer - 1 if options.hard then ufo.shotTimer = ufo.shotTimer - 1 end end end function drawDrone(ufo) local uid = 428 + 2 * ((ufo.frames//6) % 2) local x = ufo.x - cam.x local y = ufo.y - cam.y spr(uid, x, y, 0, 1, 0, 0, 2, 2) end function updateCross(c) c.frames = (c.frames + 1) % 60 c.r = c.frames // 30 if c.shotTimer == 0 then for i=0,5 do local t = i / 4.0 local a = 2 * 3.14159265 * t if c.r == 0 then a = a + (3.14159265 / 4.0) end local vx = math.cos(a) local vy = math.sin(a) enemyFire(c.x + 8, c.y + 8, 289, vx*2, vy*2) end c.shotTimer = 15 else c.shotTimer = c.shotTimer - 1 if options.hard then c.shotTimer = c.shotTimer - 1 end end end function drawCross(c) local uid = 486 + 2 * (c.r) local x = c.x - cam.x local y = c.y - cam.y spr(uid, x, y, 0, 1, 0, 0, 2, 2) end mapAnimFrames = 0 function mapAnim(tile, x, y) if tile == 16 or tile == 32 then local frame = ((mapAnimFrames // 10) + x) % 2 local out = 16 + 16 * frame return out end if tile == 25 then local px = (player.x+8)//8 local py = (player.y+12)//8 local dx = x - px if y == py then if px == x then return 42 elseif dx == -1 or dx == 1 then return 41 end end end if tile == 48 then return tile + (16 * ((mapAnimFrames // 15 + x*y) % 2)) end if tile == 64 then return tile - (16 * ((mapAnimFrames // 15 + x*y) % 2)) end return tile end function explodefx(x, y, r) local newFx = { x=x, y=y, r=r, index = #explosions+1, t = 0, } table.insert(explosions, newFx) end function updateExplosions() for k, e in pairs(explosions) do local c = 1 + ((e.t // 3) % 4) local t = e.t/15 t = t * t local r = math.sin(3.14*t) * e.r circ(e.x-cam.x, e.y-cam.y, r, c) if e.t >= 15 then explosions[k] = nil else e.t = e.t + 1 end end end gameTicks = 0 function BOOT() options.hard = pmem(0) == 1 options.holdToShoot = pmem(1) == 1 options.mus = pmem(2) == 1 end local robot = {x=22*8, y = 9*8, frame = 0, dir = -1} enemies = {} function spawnRobot(x, y) local newRobot = { type = "Robot", x = x, y = y, frame = 0, dir = -1, hits = 1, timerShot = 0 } return newRobot end function spawnTurret(x, y) local newRobot = { type = "Turret", x = x, y = y, r = 0, hits = 5, timerShot = 0, } return newRobot end function spawnUFO(x, y) local new = { type = "UFO", x = x, y = y, tx = x, ty = y, frames = 0, shotTimer = 60, moveTimer = 60, hits = 25, } return new end function spawnDrone(x, y) local new = { type = "Drone", x = x, y = y, frames = 0, shotTimer = 60, hits = 7, } return new end function spawnCross(x, y) local new = { type = "Cross", x = x, y = y, frames = 0, r = 0, shotTimer = 60, hits = 9, } return new end function spawnShotgunBox(x, y) local new = { type = "Box", x = x, y = y, frames = 0, hits = 1, item = "Shotgun", grounded = false, } return new end function spawnBox(x, y, i) local new = { type = "Box", x = x, y = y, frames = 0, hits = 1, item = i, grounded = false, } return new end function spawnMachinegunBox(x, y) local new = { type = "Box", x = x, y = y, frames = 0, hits = 1, item = "Machinegun", grounded = false, } return new end function updateBox(box) local tile = tileAt(box.x+4, box.y+16) local tile2 = tileAt(box.x+4, box.y+8) if fget(tile, 0) or fget(tile2, 2) then box.grounded = true return end box.frames = box.frames + 1 box.x = box.x+math.sin(box.frames/60.0)/2.0 box.y = box.y+0.5 end function drawBox(box) local t = 432 spr(t, box.x-cam.x, box.y-cam.y, 0) local d = math.floor((math.sin(box.frames/16.0))+0.5) if not box.grounded then t = 400 + (d*16) spr(t, box.x-cam.x, box.y-cam.y-8, 0) end end function boxDrop(box) local newPickup = { x = box.x, y = box.y, i = box.item, index = #pickups+1, grounded = false, } table.insert(pickups, newPickup) end function getWeapon(p) local ammo = { Shotgun = 10, Machinegun = 30, } local weapons = { Shotgun = 2, Machinegun = 1, } player.weapon = weapons[p.i] player.ammo = ammo[p.i] if options.hard then player.ammo = player.ammo // 2 end end function updatePickups() local sprs = { Shotgun = 417, Machinegun = 418, Grenade = 336, Life = 306, } local onGetTable = { Shotgun = getWeapon, Machinegun = getWeapon, Grenade = function(p) player.grenades = player.grenades + 1 end, Life = function(p) player.lives = player.lives + 1 end } for k, p in pairs(pickups) do if not p.grounded then p.y = p.y + 1 local tile = tileAt(p.x+4, p.y+12) if fget(tile, 0) or fget(tile, 2) then p.grounded = true end end local dx = player.x - p.x local dy = player.y - p.y if (dx*dx + dy*dy) < (12*12) then onGetTable[p.i](p) pickups[p.index] = nil sfx(15, 80, 30, 3) end spr(sprs[p.i], p.x-cam.x, p.y-cam.y, 0) end end function turretDrop(tr) if math.random(0,10) == 0 then local items = {"Life", "Machinegun"} local newPickup = { x = tr.x+6, y = tr.y+6, i = items[math.random(1, 2)], index = #pickups+1, grounded = false, } table.insert(pickups, newPickup) end end function droneDrop(tr) local items = {"Life", "Shotgun", "Shotgun", "Grenade", "Grenade"} local newPickup = { x = tr.x+6, y = tr.y+6, i = items[math.random(1, #items)], index = #pickups+1, grounded = false, } table.insert(pickups, newPickup) end function enemyHit(en, dmg) local deathTable = { Box = boxDrop, Turret = turretDrop, Drone = droneDrop, Cross = droneDrop, } dmg = dmg or 1 en.hits = en.hits - dmg if en.hits <= 0 then sfx(14, 30, 15, 3) enemies[en.index] = nil if deathTable[en.type] then deathTable[en.type](en) end explodefx(en.x+8, en.y+8, 8) end end function updateEnemies() local updateTable = { Robot = updateRobot, Turret = updateTurret, UFO = updateUFO, Box = updateBox, Drone = updateDrone, Cross = updateCross, } local drawTable = { Robot = drawRobot, Turret = drawTurret, UFO = drawUFO, Box = drawBox, Drone = drawDrone, Cross = drawCross, } for k, v in pairs(enemies) do updateTable[v.type](v) drawTable[v.type](v) local sx = v.x - cam.x local sy = v.y - cam.y if sx < -16 and not currentLevelData.vertical then enemies[k] = nil elseif sy > 136 and currentLevelData.vertical then enemies[k] = nil end end end local fadeT = 0; function stateLevel() cls(13) mapAnimFrames = mapAnimFrames + 1 local mx = cam.x / 8 local my = cam.y / 8 local ox = cam.x % 8 local oy = cam.y % 8 map(mx, my, 32, 18, -ox, -oy, -1, 1, mapAnim) updatePlayer(player) updateLevel() clampCamera() updateGrenades() updateBullets() updateEnemies() updatePickups() gameTicks = gameTicks + 1 drawBullets() drawPlayer(player) updateExplosions() nEnemies = 0 for k,v in pairs(enemies) do nEnemies = nEnemies + 1 end levelUI() if lastScreen and nEnemies == 0 then fadeT = 0 if not options.mus then music(1,-1,-1,false) end if currentLevel == #levels then fadeNextState = "End" else fadeNextState = "Clear" end return "Fade" end if player.lives < 0 then fadeT = 0 fadeNextState = "Continue" return "Fade" end return "Level" end function stateMainScreen() cls(0) local hard = "off" if options.hard then hard = "on" end local hts = "off" if options.holdToShoot then hts = "on" end local mus = "on" if options.mus then mus = "off" end print("Hard Mode: " .. hard) print("Hold to shoot: " .. hts, 0, 8) print("Music: " .. mus, 0, 16) print("Erazor", 33, 49, 14, false, 3) print("Erazor", 32, 48, 13, false, 3) print("[Jump] to start", 48, 80, 13, false, 1, true) print("[A] - jump", 32, 100, 13, true, 1, true) print("[B] - shoot", 32, 107, 13, true, 1, true) print("[Y] - grenade", 32, 114, 13, true, 1, true) print("unsure what keys map to each button?\ncheck your gamepad options on [Esc]", 32, 124, 13, true, 1, true) if btn(5) then setLevel(1) return "Level" end return "MainScreen" end function fullScreenFade(t) local m = {0, 3/4, 2/4, 1/4} for y=0,136 do for x=0,240 do local ix = (x % 2)+1 local iy = (y % 2)+1 local i = iy * 2 + ix local ir = (i % 4) + 1 local d = m[ir] if d < t then pix(x, y, 0) end end end end function stateContinue() cls(0) print("Game Over", 33, 49, 14, true, 3) print("Game Over", 32, 48, 13, true, 3) print("[Jump] to continue", 48, 96, 13, true) print("[Fire] to exit to the main menu", 48, 104, 13, true) if btnp(5) then setLevel(currentLevel) return "Level" end if btnp(4) then currentLevel = 1 return "MainScreen" end return "Continue" end function stateEnd() cls(0) print("Congratulations!", 33, 49, 14, true, 2) print("Congratulations!", 32, 48, 13, true, 2) if btnp(5) then fadeT = 0 fadeNextState = "MainScreen" return "Fade" end return "End" end function stateClear() cls(0) print("Level Clear", 33, 49, 14, true, 3) print("Level Clear", 32, 48, 13, true, 3) print("[Jump] to continue", 48, 96, 13, true) if not options.hard then print("+3", 64, 80, 13, true) spr(306, 78, 78) print("+2", 64, 88, 13, true) spr(336, 78, 86) end if btnp(5) then if not options.hard then player.lives = player.lives + 3 player.grenades = player.grenades + 2 end currentLevel = currentLevel + 1 setLevel(currentLevel, true) return "Level" end return "Clear" end function stateFade() fadeT = fadeT + 1 fullScreenFade(fadeT / 60) if fadeT == 60 then return fadeNextState end return "Fade" end currState = "MainScreen" function TIC() if options.update then local v = 0 if options.hard then v = 1 end pmem(0, v) v = 0 if options.holdToShoot then v = 1 end pmem(1, v) v = 0 if options.mus then v = 1 end pmem(2, v) options.update = false end local states = { MainScreen = stateMainScreen, Level = stateLevel, Fade = stateFade, Continue = stateContinue, Clear = stateClear, End = stateEnd, } currState = states[currState]() end