0+SŠ4‡Q«R6_WOÂÃÇÿñè÷+ÿ£ÿì'ä6)­ÿƒvœÿw¨ÿ̪ 0ÿÿÿÿÿÿÿÿ2Tv˜ºÜþïÍ«‰gE#2Tv˜ºÜþ2Tv˜ºÜþê $$ $$‚ˆˆ ÄÄ ww"f' $$’™™ „„ ™™"f) ""¢ªª ÅÅ ª™"f% "B$D‚ˆˆ ¤¤ ˆH$"ˆ( "Ò-ÝÒ-Ýâîî ­­- îÞ-"î. (‚ Ø� ÝÝ ¡¡- ÝÝ- ÝÝ fÝ && && ff ¶¶ ffbvw' rr bvw' "w"bvw' r"' bvw' ""'"" ff& $''‚ˆˆ ÄÄ ww w'"" ff& $))’™™ „„ ™™ ™)"" ff& "**¢ªª ÅÅ ª™ ª* b 'RU UU% UU% UU%RU "Ò-ÝÒ-Ýâîî ­­- îÞ-"î."" ff& Ø�- ÝÝ ¡¡- ÝÝ- ÝÝ ÝÝ && && ffb¶¶& fa && && ¶¶ fabfa&rw'rr rw' w"rw'r"' rw' "' $$ $$‚ˆˆ ÄÄ ww w' $$’™™ „„ ™™ ™) ""¢ªª ÅÅ ª™ ª* "Ò-ÝÒ-Ýâîî ­­- îÞ-"î. (‚ Ø� ÝÝ ¡¡- ÝÝ- ÝÝ ÝÝ ‚"" ww'‚""  ' ' ' ' '‚‚ "" fhb†bˆ f†""rw' '"' wf&r"r wf'"'ÝÝ pww§§wwwpwwp $$’™™ „„ ™™ ™i& ""¢ªª ÅÅ ª™ ªj& "Ò-ÝÒ-Ýâîî ­­- îÞ-"î. (‚ Ø� ÝÝ ¡¡- ÝÝ- ÝÝ Ým& && && ¶¶ fabfa& $$ $$‚ˆˆ ÄÄ ww"" $$’™™ „„ ™™"" ""¢ªª ÅÅ ª™"" "B$D‚ˆˆ ¤¤ ˆH$"" "Ò-ÝÒ-Ýâîî ­­- îÞ-"" (‚ Ø� ÝÝ ¡¡- ÝÝ-"" && && ff ¶¶ fa"" ww'r" B$ DD ET TE $B $B "" DD ID$’DD$BDD$RDD%RUU% ""pppppppppwwpwwwppppwwpwwppppww" U U U U%%%% Â, ,ÂÂÍÜ,ÂÜÍ,ÒÌÌ- ÝÝ"" ""BDD$R¥U%B¤D$BDD$BDD$ """$ I”’”I)’”I)’”I) I”"""$ ³;2;³#2;³#2;³# ³;""pwppp R"URE UDRED UDDREDDUDDDUUUUDDDDUT%DUDT%DDUDDT%UUUUDDDT% ""ÒÝÝ-R¥U%Ò­Ý-ÒÝÝ-ÒÝÝ- """" ÝÝ ÖÝ-bÝÝ-ÒÝÝ-RÝÝ%RUU% "" ""òþþ.òÿÿ/233#233#233# """$ ³³2;;+2;;+2;;+ ³³""pªpªª§ªšpªª™pªªš§ªªª§ªªª§šªªª ªª ªªª©ªª ª™ª š™©ªš™©ªª™ªªppgpwppˆ‡‡Žˆx‡Žˆx‡ˆˆxpˆˆ‡xpwppˆ‡‡Žˆx‡Žˆx‡ˆˆxpˆˆ‡xp"UU UUU""% % % % % %UUUUUUUU""""""""UUUU•Y™Y•Y™Y•Y™YUUUUUUUU""""""""UUU%™Y™%™Y™%™Y™%U%UU%%"%%%%% ""‚ˆ�(R¥…%‚­Ý-ÒÝ�-ÒÝÝ- """" ˆˆ †Ý(b�Ý-ÒÝ�-RÝÝ%RUU% "" ""òþþ.òÿÿ/rww'233#233# ""§™©ª§šªª§ªªªpªªªpªªª§ªªpªªpªªªªªªªªªªªªªªªª ™ªª ™ªªªª ª pppppwpppp"% UU ""•Y™YUUUU""""™Y™%UUUU""""%U%""UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPPPUUPPPUUPPPUUPPPUUUUUPPPPPPPPPPPPUUUUpwwpwwpppwwpppppppppwwpwwpppwwpwwpppwwpwwwwpwwpppppwwwwpwwpppppppppppppwwpwwpwwppwwpppwwpwwpwwpwwppwwpppppwwpwwppwppwwpwwpwwpppppppwwpppppppppwwpwwpppppwwpwwàîàî€èîîˆ.àîî(àîî"îîîîîîˆîŽˆ"Žè!èîî!âîî  ªª  ªªªªªªª™ªªš™ ª™™ªª™™  ªªªª ªªª™ªª™©ªª™™ª ™™ªªpwwpwwppppwpwpwpppppwwpwpwwpppppppppppppwwpwwpwwwpwwwpwpwpwpwpwpwpwwpwwpppppppppppppwwpwwpppppppwwpwwpwwpwwpwwppwwpppppwwpwwpppppppwwpwwpwwwpwwpwwpppwwpwwpwppppàîî"îî(àˆ.€ˆî€èîîà!âîî!èî"Žèîîˆî™™ ª™™ªªš™ªª™ªªª  ªªªª  ™™ªª™™ª ™©ªª™ªªªªªªª ªª  "' '&' &&&". ... &&&Ñ ÐÑÕ]Ð]Õ ÑÝÝÝÝpwwpwwppwwpwwppwwpwwpwwpwwpppppppppppppppppppwwpwwppppppppppppwwppwpwpwpwpwpwpwpwwwppppwwpwwpppppppppppppwwwwppppwwpwwpwpwwpwwpwwpwwpwwpppppppppwwpwwD@™”™”™@™™@D”™™™™™™™™”™ÀÀÌÀÀÌÀÌÌ ÀÀÌÌÌÌ ÀÀ Ì ÀÀÌÌÌÌ "bfbf gg'bf gg'bf "âfbæ ng.bæ gç.bfwpwpwppppwwpwwpwwpwwppwwpwwppwwpwwpwwpwwpwwwwppwwpwwpppppppwwpwwppppwwpwwppwwpwwppwwpwwppppwwpwwpppwwpwwpwwpwwpppppppwwpwwpppwwpppppwwpwwpwwpwwpppwwpwwppp”™I”™I”™””I™””™@™™@DD™™™™™I™I™D ÀÀÌÌÌÀÀÀÌÀÀÀÀÌ À À 3333333333333333333333333333333333333333333333333U33U33U33U3333333333330333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333U33U33U33U3333333333330333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333U33U33U33U333333333333033333333333333333333333333333333333333333333333" U U U U%%%%33333333333333333333333333P33U33PE3UD3PEDUDDPEDDUDDDUUUUDDDDU033T33DU03DT3DDU0DDTUUUUDDDT33333333333333333333333303330333333333333333333PU33333P33U33PE3UD3PEDUUUUUUUUDDDDU033T33DU03UUUUUUUUDDDT333333333333333U033333033333333333333333333333333333333P33U33PE3UD3PEDUDDPEDDUDDDUUUUDDDDU033T33DU03DT3DDU0DDTUUUUDDDT3333333333333333333333330333333 R"URE UDRED UDDREDDUDDDUUUUDDDDUT%DUDT%DDUDDT%UUUUDDDT%3UUUUU33333333333UUUUUUUUUUUU•Y™Y•Y™Y•Y™YUUUUUUUUUUU™Y™™Y™™Y™U03UU3033333333333333333UUU33333333333UUUUUUUU•Y™Y•Y™Y•Y™YUUUUUUU™Y™™Y™™Y™03UU3033333333333333333UUU33333333333UUUUUUUU•Y™Y•Y™Y•Y™YUUUUUUU™Y™™Y™™Y™03UU303333333333333333"UU UUU""% % % % % %UUUUUUUU""""""""UUUU•Y™Y•Y™Y•Y™YUUUUUUUU""""""""UUU%™Y™%™Y™%™Y™%U%UU%%"%%%%%333UU333333333333333333333•Y™YUUUU33333333333333333333™Y™UUUU33333333333333333333033U333333333333333333333333333UU333333333333333333333•Y™YUUUU33333333333333333333™Y™UUUU33333333333333333333033U333333333333333333333333333UU333333333333333333333•Y™YUUUU33333333333333333333™Y™UUUU33333333333333333333033U333333333333333333333333"% UU ""•Y™YUUUU""""™Y™%UUUU""""%U%"",‘’’‘        ’MN’’‘‘’\]^_ ’lmno ’  ’‘‘  ’|}~’’‘’’‘’ ’ ’ ’     ’’’’’’    ‘‘‘‘‘LMNOLMNO’‘‘‘‘\]^_\]^_            lmnolmno’’’’|}~|}~’‘‘’€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€� ������������������������ �€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����� ����� ����� ����� ����€€������� ������ ������ ������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€������� ������ ������ ������€€����������������������������€€����������������������������€€����� ����� ����� ����� ����€€����������������������������€€����������������������������€€����������������������������€€����������������������������€€� ������������������������ �€€����������������������������€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€À?ˆ€ˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆ€ˆˆˆ€ˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆ€ˆˆ€ˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆ€ˆ€ˆˆˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxww‡x‡x‡xww‡ˆˆˆˆxww‡x‡x‡xww‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxww‡x‡x‡xww‡ˆˆˆˆxww‡x‡x‡xww‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆx‡x‡x‡x‡x‡x‡ˆˆˆˆx‡x‡x‡x‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxwwˆx‡x‡x‡x‡ˆˆˆˆxwwˆx‡x‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxww‡x‡x‡x‡x‡ˆˆˆˆxww‡x‡x‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆx‡x‡x‡x‡x‡x‡ˆˆˆˆx‡x‡x‡x‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxww‡xww‡x‡x‡ˆˆˆˆxww‡xww‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆxww‡xww‡x‡x‡ˆˆˆˆxww‡xww‡x‡x‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¨ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¨ŠˆˆªˆˆˆªŠˆˆŠŠˆˆŠŠˆˆªˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆªˆˆˆ¨ŠˆˆªŠˆˆŠŠˆˆªˆˆˆ¨Šˆˆ¨ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆŠˆˆŠŠˆˆŠŠˆˆŠŠˆˆŠˆˆˆŠŠˆˆ¨ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆªˆˆˆªŠˆˆŠŠˆˆ¨ŠˆˆŠˆˆˆªŠˆˆ¨ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ"‚"‚(‚ˆˆ"‚(‚ˆˆ"‚ˆ‚(ˆ(ˆ(ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(ˆ(ˆ‚ˆˆˆ‚‚‚‚ˆˆ‚ˆ(‚ˆˆ"‚ˆˆ(ˆ"ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(ˆ(ˆ‚ˆ"‚"‚‚‚ˆˆ"ˆ‚‚(ˆ(ˆ(ˆ‚‚‚‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(ˆ(ˆ‚ˆˆˆ‚‚‚‚ˆˆ‚ˆ‚‚(ˆ(ˆ(ˆ‚‚‚‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(ˆ"‚(‚ˆˆ"‚"ˆˆˆ"‚(‚(ˆˆ‚(ˆ(ˆ‚‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ""""""""""""""""""""""""""""""""""""""""""""""""""""""‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(""ˆˆˆˆˆ("‚ˆˆˆˆˆˆ"‚ˆˆ("ˆˆˆˆˆˆˆˆˆˆˆˆˆ("ˆˆˆˆˆ"‚ˆ(""ˆˆˆˆ"‚ˆˆ("ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(w'ˆˆˆ(""w"""""ˆˆr‚ˆˆ"'ˆˆˆ("‚""""""ˆ('‚ˆˆˆˆr‚ˆ(''ˆˆˆˆr""‚"'"‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ("'ˆˆˆ(w"r"w"''ˆˆr‚ˆ(r"ˆˆˆ(w"r"''w'ˆ(r"ˆˆˆˆr‚ˆ(''ˆˆˆˆ""w"r"r"ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(r"ˆˆˆ(''r"r'''ˆˆ"‚ˆ('‚ˆˆˆ(''''w"w'ˆˆ"'ˆˆˆˆ"‚ˆ(r"ˆˆˆˆr"''w'''ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ('"ˆˆˆ(''r"''r'ˆˆr‚ˆ(r"ˆˆˆ('''''"''ˆ(r"ˆˆˆˆr‚ˆ(''ˆˆˆˆr"''r"''ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(w'ˆˆˆ(w"w'w'"'ˆˆr‚ˆˆ"'ˆˆˆ(''r"'(''ˆ('‚ˆˆˆˆr‚ˆ(''ˆˆˆˆr"''r"r"ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(""ˆˆˆ('"""""r"ˆˆ"‚ˆˆ("ˆˆˆ("""""(""ˆ("ˆˆˆˆˆ"‚ˆ(""ˆˆˆˆ"""""‚"‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ("ˆˆˆˆˆ"‚ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆ€ˆ€ˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€€ˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆ€ˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆ€ˆ€ˆˆ€ˆ€ˆ€ˆˆ€ˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆ€ˆˆˆˆ€ˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ€€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆ€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ˆˆˆˆ€ˆˆˆˆˆˆˆ€ˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆ€ˆˆˆˆ€ˆˆ€ˆˆˆˆˆ€ˆˆˆˆˆˆ€ˆˆˆˆˆ·Þ-- title: Bun Bun Samurai 16:9 -- author: tmirobot (original PICO-8 game), port to TIC-80 -- desc: PICO-8 game running on TIC-80 through a compatibility layer -- script: lua -- input: gamepad local OX,OY=56,4 local EX,EY=0,0 local wide=false local T_print,T_spr,T_map,T_rect,T_rectb,T_circ,T_line,T_pix,T_clip,T_btn,T_btnp,T_pmem,T_memcpy,T_sync=print,spr,map,rect,rectb,circ,line,pix,clip,btn,btnp,pmem,memcpy,sync local PI2=math.pi*2 flr=math.floor abs=math.abs min=math.min max=math.max sqrt=math.sqrt tostr=tostring tonum=tonumber function ceil(x) return math.ceil(x) end function rnd(n) return math.random()*(n or 1) end function srand(n) math.randomseed(n) end function mid(a,b,c) return math.max(math.min(a,b),math.min(math.max(a,b),c)) end function cos(x) return math.cos(x*PI2) end function sin(x) return -math.sin(x*PI2) end function atan2(dx,dy) return (math.atan(-dy,dx)/PI2)%1 end function sub(s,a,b) return string.sub(s,a,b) end function add(t,v) t[#t+1]=v return v end function del(t,v) for i=1,#t do if t[i]==v then table.remove(t,i) return v end end end function all(t) if not t or #t==0 then return function() end end local i,last=0,nil return function() if t[i]==last then i=i+1 end last=t[i] return last end end function foreach(t,f) for v in all(t) do f(v) end end function split(s,sep,conv) sep=sep or "," if conv==nil then conv=true end local r,p={},1 while true do local a,b=string.find(s,sep,p,true) local piece=string.sub(s,p,(a or 0)-1) if conv then piece=tonumber(piece) or piece end r[#r+1]=piece if not a then break end p=b+1 end return r end -- camera / palette / drawing (PICO-8 128x128 centred on the 240x136 screen) local cx,cy=0,0 local bx,by=-OX,-OY local function rebase() bx,by=cx-OX-EX,cy-OY-EY end function camera(x,y) cx=flr(x or 0) cy=flr(y or 0) rebase() end function __off(a,b) EX,EY=a,b rebase() end local function setclip() if wide then T_clip() else T_clip(56,4,128,128) end end -- gameplay (state>=4) uses the full 240x136 screen; menus keep the centred 128x128 box local function M(init) local gs=g_game_state or 0 local w=(gs==0 or gs>=4) if w~=wide or init then wide=w T_clip() if init or not w then T_rect(0,0,240,136,0) end if w then OX,OY=0,0 else OX,OY=56,4 end setclip() rebase() end end function scr_dw() M() return wide and 240 or 128 end function scr_dh() M() return wide and 136 or 128 end function scr_w() return ((g_game_state or 0)>=4) and 240 or 128 end function scr_h() return ((g_game_state or 0)>=4) and 136 or 128 end local dp={} for i=0,15 do dp[i]=i end local pdirty=false function pal(a,b) if a==nil then if pdirty then for i=0,15 do dp[i]=i poke4(0x7FE0+i,i) end pdirty=false end return end a=flr(a)%16 b=flr(b or 0)%16 dp[a]=b poke4(0x7FE0+a,b) pdirty=true end local function C(c) return dp[flr(c or 0)%16] end function pset(x,y,c) T_pix(flr(x)-bx,flr(y)-by,C(c)) end function rectfill(x0,y0,x1,y1,c) x0,y0,x1,y1=flr(x0),flr(y0),flr(x1),flr(y1) if x0>x1 then x0,x1=x1,x0 end if y0>y1 then y0,y1=y1,y0 end T_rect(x0-bx,y0-by,x1-x0+1,y1-y0+1,C(c)) end function rect(x0,y0,x1,y1,c) x0,y0,x1,y1=flr(x0),flr(y0),flr(x1),flr(y1) if x0>x1 then x0,x1=x1,x0 end if y0>y1 then y0,y1=y1,y0 end T_rectb(x0-bx,y0-by,x1-x0+1,y1-y0+1,C(c)) end function circfill(x,y,r,c) r=flr(r) x=flr(x)-bx y=flr(y)-by c=C(c) if r<1 then T_pix(x,y,c) else T_circ(x,y,r,c) end end function line(x0,y0,x1,y1,c) T_line(flr(x0)-bx,flr(y0)-by,flr(x1)-bx,flr(y1)-by,C(c)) end function cls(c) M() T_rect(OX,OY,wide and 240 or 128,wide and 136 or 128,C(c or 0)) end function spr(n,x,y,w,h,fx,fy) T_spr(flr(n),flr(x)-bx,flr(y)-by,0,1,(fx and 1 or 0)+(fy and 2 or 0),0,w or 1,h or 1) end function map(a,b,sx,sy,w,h) M() T_map(a,b,w or 128,h or 32,flr(sx or 0)-bx,flr(sy or 0)-by,0) end local GL={[142]="Z ",[151]="X ",[139]="< ",[145]="> ",[148]="^ ",[131]="v "} function print(s,x,y,c) s=tostring(s) x=flr(x or 0)-bx y=flr(y or 0)-by local col=C(c or 7) local x0,i,n,seg=x,1,#s,{} local function flush() if #seg>0 then local t=table.concat(seg) T_print(t,x,y,col,true,1,true) x=x+#t*4 seg={} end end while i<=n do local b=s:byte(i) if b==10 then flush() x=x0 y=y+6 elseif b==12 then flush() local d=tonumber(s:sub(i+1,i+1),16) if d then col=C(d) end i=i+1 elseif b>=128 then seg[#seg+1]=GL[b] or "? " else seg[#seg+1]=string.char(b) end i=i+1 end flush() end -- input: PICO-8 left,right,up,down,O,X -> TIC-80 pad ids local BM={[0]=2,3,0,1,4,5} function btn(i) return T_btn(BM[i]) end function btnp(i) return T_btnp(BM[i],15,4) end -- saved data / map reload function cartdata() end function dget(i) return T_pmem(i) end function dset(i,v) T_pmem(i,flr(v)) end function reload() T_sync(4,0,false) end list_enemies = {} list_villagers = {} list_people = {} list_drawstuff = {} list_objects = {} list_parts_back = {} list_parts_front = {} list_parts_blood = {} list_steps = {} list_heads = {} function frnd(n) return flr(rnd(n)) end function frnda(n, o) local addval = o or 1 return frnd(n)+addval end function randc(chance) local c = chance or 50 if frnd(100) < c then return true end return false end function wrap(value, min, max) if value < min then return max elseif value > max then return min else return value end end function table_clear(t) local count = #t for i=0, count do t[i]=nil end end function copy_screen_to_mem() memcpy(0x1800, 0x6000, 0x0800) memcpy(0x4300, 0x6800, 0x1800) end function paste_screen_from_mem() memcpy(0x6000, 0x1800, 0x0800) memcpy(0x6800, 0x4300, 0x1800) end function printc_o(str, y, col, outcol, x) for i=-1,1 do for j=-1,1 do printc(str, y+j, outcol or 2, (x or 64)+i) end end printc(str, y, col, (x or 64)) end function printc(str, y, col, x) print(str, (x or 64)-#str*2, y, col or 7) end function printsprite(str, y, color) pal(7, color) for i=1, #str do local letter, whichalpha = sub(str,i,i), -1 for j in all(g_alphabet_sprites) do whichalpha=whichalpha+(1) if letter == j then spr(131 + flr(whichalpha/9)*16 + whichalpha % 9, 64-(#str*8)/2 + (i-1)*8, y) break end end end pal() end function set_outline() pal(2, g_color_outline) end function m_textfloat(x,y, text, col_main, col_sec) add(list_parts_front, { x=x, y=y, text=text, col_main=col_main or 7, col_sec=col_sec or 5, dur=30, dur_orig=30, draw=function(self) local color = self.col_main if self.dur < self.dur_orig/3 then color = self.col_sec end printc_o(self.text, self.y, color, g_color_outline, self.x) end, update=function(self) self.dur=self.dur-(1) if self.dur == 0 then del(list_parts_front, self) else self.y=self.y-(.3) end end, }) end function a_set_invuln_flash(self) if self.invuln_frames > 0 and self.invuln_frames % 5 < 3 then for i=1,15 do pal(i, 2) end return true end return false end function is_near_objs(obj1, obj2, range) if abs(obj1.x-obj2.x) <= range and abs(obj1.y-obj2.y) <= range then return true end return false end function int_cols(e1, e2, buffer) if e1.just_spawned or e2.just_spawned then return false end local buffer = buffer or 0 local x1, y1, w1, h1, x2, y2, w2, h2 = e1.x-e1.col_w/2-buffer, e1.y-e1.col_h/2-buffer, e1.col_w+buffer*2, e1.col_h+buffer*2, e2.x-e2.col_w/2-buffer, e2.y-e2.col_h/2-buffer, e2.col_w+buffer*2, e2.col_h+buffer*2 if x1+w1 self.duration *.75 then color = self.color_sec end if self.size == 0 then pset(self.x, self.y, color) else rectfill(self.x-s2, self.y-s2, self.x+s2, self.y+s2, color) end end, update=function(self) if self.time > self.duration then if self.layer == 1 then del(list_parts_back, self) elseif self.layer == 2 then del(list_parts_front, self) else del(list_parts_blood, self) end return end if self.speed_move > .1 then a_move_angle(self) self.speed_move=self.speed_move*(self.frict) end self.time=self.time+(1) end, } if layer == 1 then add(list_parts_back, p) elseif layer == 2 then add(list_parts_front, p) else add(list_parts_blood, p) end return p end function m_part_sprite(frame, x,y, dy, col, col_sec, duration, flipx, is_front) local p = { x=x, y=y, frame=frame, col=col, col_sec=col_sec or col, duration=duration, flipx=flipx or false, is_front=is_front or false, time=0, dx=0, dy=dy, ddy=0, draw=function(self) if self.time < self.duration *.75 then pal(7,self.col) else pal(7,self.col_sec) end spr(self.frame, self.x-4, self.y-4, 1, 1, self.flipx) pal() end, update=function(self) self:update_base() end, update_base=function(self) if self.time > self.duration then if self.is_front then del(list_parts_front, self) else del(list_parts_back, self) end return end self.x=self.x+(self.dx) self.y=self.y+(self.dy) self.dy=self.dy+(self.ddy) self.time=self.time+(1) end, } if is_front then add(list_parts_front, p) else add(list_parts_back, p) end return p end function m_part_bomb_spark(x, y) local color, color_second = 10, 9 if randc() then color, color_second = 7, 10 end local p = m_part_sprite(103, x, y, -.2-rnd(.5), color, color_second, 10+rnd(5), false, true) p.ddy = .1 local dx = rnd(.5) if randc() then dx = 0 - dx end p.dx = dx end function m_part_circle(x,y, size, duration, color, color_sec, layer) local p = m_part_angle({size, x, y, 0, 0, duration}, 0, color, color_sec, layer) p.draw=function(self) local color = self.color if self.time > self.duration * .75 then color = self.color_sec end circfill(self.x, self.y, self.size, color) end end function m_part_bloodsplash(x,y,angle) for i=0,36 do local size, xoff, yoff, angleoff,dur=1, rnd(4), rnd(4), rnd(.2), rnd(8) if i > 30 then dur=rnd(1) size=2 elseif i > 15 then dur=rnd(4) end m_part_blood({size, x-2+xoff, y-2+yoff, angle-.1+angleoff, dur}) end end function m_part_impact(entity,size) m_part_circle(entity.x, entity.y, size or 7, 4, 10, 9, 1) end function handle_slash_recovery(speed) local dir = rnd(.125) if randc() then dir = 0-dir end p1.slash_angle, p1.slash_speed, p1.slash_time, p1.slash_has_impacted = abs(p1.slash_angle+.5+dir)%1, speed or 0, 5, true a_anim_set(p1, "attack") end function handle_slash_entity_impact(target) cam:shake(.1, 3) game_pause(2, 0) if not target.is_furniture then m_part_bloodsplash(target.x, target.y, p1.slash_angle) end m_part_impact(target, 10) handle_slash_recovery() end function score_add(entity, score) if score > 0 then sfx(min(26+flr(score/1), 31)) else sfx(32) end g_score_level=g_score_level+(score) local score_color, score_color_sec = 10, 9 if score >= 4 then score_color, score_color_sec = 7, 9 elseif score >= 2 then score_color, score_color_sec = 11, 3 elseif score < 0 then score_color, score_color_sec = 8, 13 end if score ~= 0 then m_textfloat(entity.x, entity.y-8, ""..flr(score*10), score_color, score_color_sec) end end function attempt_deflect_target(target) local reverse_angle = abs(target.angle+.5)%1 if abs(p1.slash_angle - reverse_angle) < .25 then sfx(8) m_part_circle(target.x, target.y, 6, 10, 7, 5, 1) target.is_flying, target.is_flying_impactable, target.windup_time_rem, target.attack_time_rem, target.fly_speed = true, false, 0, 0, 2 local t_dir = rnd(.125) if randc() then t_dir = 0 - t_dir end target.angle= abs(p1.slash_angle+t_dir)%1 handle_slash_recovery(2) return true end return false end function combo(entity, target) entity.was_counted_for_combo = true sfx(frnda(2, 21)) handle_impact_death(entity, target) if not entity.is_furniture then m_part_bloodsplash(target.x, target.y, entity.angle) end target:handle_impact(entity) target.fly_speed, target.angle = entity.fly_speed, entity.angle%1 if entity.is_heavy or entity.is_armored then target.score_multiplier = entity.score_multiplier fly_reset(entity) entity.invuln_frames = 15 if entity.is_armored then attack_reset(entity) end else target.score_multiplier = entity.score_multiplier + 1 end end function slash_target(target) sfx(25) target.fly_speed, target.angle = 3, p1.slash_angle target:handle_impact() handle_slash_entity_impact(target) a_anim_set(p1, "attack") end function a_anim_update(entity, anim_set, tick_multiplier) if tick_multiplier == nil then tick_multiplier = 1 end entity.animtick=entity.animtick-(1 * tick_multiplier) if entity.animtick<=0 then entity.curframe=entity.curframe+(1) local a=anim_set[entity.curanim] entity.animtick=a.ticks if entity.curframe>#a.frames then entity.curframe=1 end end end function a_anim_set(entity, anim) if (anim==entity.curanim) then return end entity.animtick, entity.curanim, entity.curframe = character_anims[anim].ticks, anim, 1 end function a_doflipx(entity) local angle = entity.angle if angle == .25 or angle == .75 then return elseif angle > .25 and angle < .75 then entity.flipx = true else entity.flipx = false end end function constrain_to_screen(obj) return constrain_to_borders(obj, g_level_screen_buffer+4, g_level_screen_buffer+4, scr_w()-4-g_level_screen_buffer, scr_h()-4-g_level_screen_buffer) end function constrain_to_borders(obj, bor_x1, bor_y1, bor_x2, bor_y2) local was_constrained, x, y = false, obj.x, obj.y if x < bor_x1 then x, was_constrained = bor_x1, true elseif x > bor_x2 then x, was_constrained = bor_x2, true end if y < bor_y1 then y, was_constrained = bor_y1, true elseif y > bor_y2 then y, was_constrained = bor_y2, true end obj.x, obj.y = x, y return was_constrained end function game_pause(duration) game_pause_timer = duration end function handle_impact_death(entity, target) if not entity.is_furniture and not entity.is_armored then split_entity(entity, (entity.angle+.5)%1) m_part_bloodsplash(target.x, target.y, entity.angle) if target.is_heavy then if not target.is_bloody then target.sprite=target.sprite+(16) target.is_bloody = true end end end m_part_impact(entity) cam:shake(.5*entity.fly_speed,10) game_pause(2) if entity.is_villager then level_end_villager_died(false) end if not entity.is_heavy and not entity.is_armored then del_from_people(entity) score_add(entity, entity.score * entity.score_multiplier) end end function fly_reset(entity) entity.fly_speed, entity.is_flying, entity.is_flying_impactable, entity.angle, entity.score_multiplier = 0, false, false, get_dir_to_player(entity), 1 end function attack_reset(entity) entity.attack_time_rem, entity.recovery_time_rem, entity.time_between_attacks_rem = 0, entity.recovery_time, entity.time_between_attacks+entity.recovery_time end function a_attack(entity) entity.attack_time_rem=entity.attack_time_rem-(1) a_move_angle(entity, 4) if constrain_to_screen(entity) then sfx(20) attack_reset(entity) end if entity.attack_time_rem <= 0 then attack_reset(entity) end end function a_fly(entity) a_move_angle(entity, entity.fly_speed) entity.fly_speed=entity.fly_speed*(.95) local was_reset = false if entity.fly_speed <= .1 then fly_reset(entity) was_reset = true end if constrain_to_screen(entity) then entity.angle, entity.fly_speed = get_rebound_angle_speed(entity.angle, entity.fly_speed) m_part_impact(entity) entity.is_flying_impactable = false sfx(23) end if not was_reset and entity.is_flying_impactable then for a in all(list_people) do if entity ~= a and a.invuln_frames == 0 and int_cols(entity, a, 2) then if entity.fly_speed > .5 then combo(entity,a) break end end end end end function a_move_angle(entity, speed) if not speed then speed = entity.speed_move end entity.angle = abs(entity.angle)%1 a_doflipx(entity) entity.x=entity.x+(cos(entity.angle) * speed) entity.y=entity.y+(sin(entity.angle) * speed) end character_anims = { ["stand"]= { ticks=10000, hframes={1}, frames={14}, }, ["move"]= { ticks=6, hframes={1,1,1,1}, frames={12,13,14,15}, }, ["run"]= { ticks=7, hframes={17,18,17,18}, frames={12,13,14,15}, }, ["windup"]= { ticks=10000, hframes={17}, frames={45}, }, ["attack"]= { ticks=10000, hframes={33}, frames={46}, }, ["fly"]= { ticks=10000, hframes={49}, frames={47}, }, } function get_direction_to_turn(cur_angle, desired_angle) local angle_delta = desired_angle-cur_angle local turn_result = 0 if -.5 < angle_delta and angle_delta <= .5 then turn_result = angle_delta elseif angle_delta > .5 then turn_result = angle_delta - 1 elseif angle_delta <= -.5 then turn_result = angle_delta + 1 end if turn_result < 0 then return 1 else return -1 end end function get_rebound_angle_speed(angle, speed) local dir = -.125 if randc() then dir = .125 end return (angle+.5+dir)%1, speed * .5 end function get_angle_from_input() if p1.recovery_time_rem > 0 then return 0 end local ml, mr, mu, md, angle = btn(0), btn(1), btn(2), btn(3), -1 if ml then if md then angle = .625 elseif mu then angle = .375 else angle = .5 end elseif mr then if md then angle = .875 elseif mu then angle = .125 else angle = 0 end elseif md then angle = .75 elseif mu then angle = .25 end return angle end function m_player(setx, sety) local p= { name = "", pcolor=7, scolor=6, is_player = true, x=setx, y=sety, angle=0, speed_move=0, speed_move_max=1.25, col_w=6, col_h=6, col_off=0, curanim="move", curframe=1, animtick=0, flipx=true, head_shift=0, body_shift=0, hp_cur=2, is_dead=false, recovery_time_rem = 0, ready_time = 150, invuln_frames = 0, is_slashing = false, init=function(self) end, damage=function(self, source, do_kill) if self.invuln_frames > 0 and not do_kill then return false end local blood_angle = atan2(self.x - source.x, self.y - source.y) m_part_bloodsplash(self.x, self.y, blood_angle) game_pause(5) cam:shake(3, 20) g_player_damaged_time, self.invuln_frames = 10, 60 self.hp_cur=self.hp_cur-(1) if self.hp_cur <= 0 or g_difficulty > 4 or do_kill then self.is_dead, self.head_shift = true, 0 split_entity(self, (blood_angle+.5)%1) sfx(10) level_end_player_died(source.is_static) else sfx(frnda(2)) end return true end, slash=function(self) if not self.is_slashing then sfx(frnda(3,4)) a_anim_set(self, "windup") self.slash_has_impacted, self.is_slashing, self.slash_time, self.slash_speed, self.slash_angle, self.speed_move, self.ready_time = false, true, 5, 6, self.angle, 0, 45 end end, update=function(self) if self.is_dead then return end if self.ready_time > 0 then self.ready_time=self.ready_time-(1) if self.ready_time == 0 then sfx(7) end end check_for_footsteps(self) local blood_rate = 0 if self.hp_cur < 2 then blood_rate = 2 end if blood_rate > 0 then if g_ticks % blood_rate == 0 then local size = 1 if randc(10) then size = 2 end m_part_blood({size, self.x-2, self.y-2, rnd(1), rnd(1), frnda(3,10)}) end end if self.invuln_frames > 0 then self.invuln_frames=self.invuln_frames-(1) end if self.recovery_time_rem > 0 then self.recovery_time_rem=self.recovery_time_rem-(1) return end if btnp(4) then if self.ready_time == 0 then self:slash() end end if self.is_slashing then self.slash_time=self.slash_time-(1) m_part_sprite(49, self.x, self.y, 0, 12, 1, 10, self.flipx, false) self.x=self.x+(cos(self.slash_angle) * self.slash_speed) self.y=self.y+(sin(self.slash_angle) * self.slash_speed) if constrain_to_screen(self) then sfx(23) self.slash_angle, self.slash_speed = get_rebound_angle_speed(self.slash_angle, self.slash_speed) m_part_impact(self) end if self.slash_time == 0 then self.is_slashing, self.recovery_time_rem = false, 10 a_anim_set(self, "attack") end else local input_angle = get_angle_from_input() if input_angle >= 0 then self.angle, self.speed_move = input_angle, self.speed_move_max a_move_angle(self) a_anim_set(self, "move") else self.speed_move = 0 a_anim_set(self, "stand") end if constrain_to_screen(self) then self.speed_move = 0 end end a_anim_update(self, character_anims) end, draw=function(self) if self.is_dead then return end if self.ready_time == 0 and (self.curanim == "move" or self.curanim == "stand") then self.body_shift, self.head_shift = 16, 16 else self.body_shift, self.head_shift = 0, 0 end draw_character(self) end, } p:init() add(list_drawstuff, p) return p end emotion_anims = { ["upset"]= { ticks=7, frames={70,71}, }, ["angry"]= { ticks=7, frames={72,73,70,74}, }, } function m_emotion(entity, emotion) local e = { owner=entity, curanim=emotion, curframe=1, animtick=0, color=g_color_interface, update=function(self) a_anim_update(self, emotion_anims) end, draw=function(self) local frame, c_o = emotion_anims[self.curanim].frames[self.curframe], -4 pal(7, self.color) spr(frame, self.owner.x+c_o, self.owner.y+c_o-10, 1,1, false) pal() end, } entity.emotion = e end function get_flipx_from_angle(angle) if angle > .25 and angle <= .75 then return true end return false end function get_dir_to_player(entity) return (atan2(entity.x - p1.x, entity.y - p1.y)+.5)%1 end function get_yboboffset(self) if self.curanim == "move" then if self.curframe % 2 == 0 then return -1 end end return 0 end function m_step(x,y) local s = { x=x-frnda(4,2), y=y, } add(list_steps, s) end function check_for_footsteps(self) if g_season == 3 and not g_level_indoor then if randc(50) then m_step(self.x, self.y) end end end function draw_character(self) local yboboffset = get_yboboffset(self) if not a_set_invuln_flash(self) then pal(6,self.scolor) pal(7,self.pcolor) end local flip_offset = -1 if self.flipx then flip_offset = 1 end set_outline() spr(character_anims[self.curanim].hframes[self.curframe]+self.head_shift, self.x-4, self.y-7+yboboffset, 1,1, self.flipx) spr(character_anims[self.curanim].frames[self.curframe]+self.body_shift, self.x-4+flip_offset, self.y+1+yboboffset, 1,1, self.flipx) pal() end function split_entity(entity, angle) m_bodypart(entity, 42, entity.pcolor, (angle+.300+rnd(.325))%1) m_bodypart(entity, 56+entity.head_shift, entity.scolor, abs(angle-.300-rnd(.325))%1) end function rndbool() return frnd(2) == 0 end function m_bodypart(entity, sprite, replace_color, angle) local h= { x=entity.x, y=entity.y, replace_color = replace_color, angle=angle, sprite=sprite, speed_move=.5+rnd(.5), flip_x=rndbool(), decay_time=frnda(25,25), update=function(self) if self.speed_move < .1 then self.decay_time=self.decay_time-(1) if self.decay_time < 0 then del(list_heads, self) del(list_drawstuff, self) return end else if g_ticks % 6 == 0 then local size = 1 if randc(33) then size = 2 end m_part_blood({size, self.x, self.y, 0, .25+rnd(.5)}) end end a_move_angle(self) self.speed_move=self.speed_move*(.95) if constrain_to_screen(self) then self.angle, self.speed_move = get_rebound_angle_speed(self.angle, self.speed_move) end end, draw=function(self) local c_o = -4 set_outline() pal(6, self.replace_color) spr(self.sprite, self.x+c_o, self.y+1+c_o, 1,1, self.flip_x) pal() end, } add(list_heads, h) add(list_drawstuff, h) return h end function m_object(x, y, spritelist, is_deadly) local o = { x=x, y=y, col_w=4, col_h=2, spritelist=spritelist, sprite=1, is_static=true, is_deadly=is_deadly, update=function(self) end, dealt_damage=function(self) self.sprite = 2 end, draw=function(self) set_outline() pal(14, 8) pal(1, g_color_detail) spr(self.spritelist[self.sprite], x-4, y-4) pal() end, } add(list_objects, o) add(list_drawstuff, o) return o end function m_food(setx, sety) local o = m_object(setx, sety, {99, 99}, false) o.col_h, o.col_w, o.eat = 6, 6, function(self) p1.hp_cur = 2 m_part_sprite(106, self.x, self.y, -.1, g_color_outline, g_color_outline, 15, false, true) score_add(self, 5) del(list_objects, self) del(list_drawstuff, self) end end function add_to_people(entity) if entity.is_villager then add(list_villagers, entity) else add(list_enemies, entity) end add(list_people, entity) add(list_drawstuff, entity) end function del_from_people(entity) if entity.is_villager then del(list_villagers, entity) elseif not entity.is_furniture then del(list_enemies, entity) end del(list_people, entity) del(list_drawstuff, entity) if #list_enemies == 0 and g_level_enemies_count == 0 then level_end_win() end end function a_alert_checkforwindup(entity) if is_level_active() and entity.windup_time_rem == 0 and is_near_objs(entity, p1, entity.alert_distance) then entity.windup_time_rem, entity.desired_angle = entity.windup_time-entity.emotion_count*3, get_dir_to_player(entity) entity.flipx = get_flipx_from_angle(entity.desired_angle) a_anim_set(entity, "windup") return true else return false end end function a_deviate(entity, time) if randc(10) then entity.deviation_time = frnda(time, time) end end function a_random_turn(entity) local angle_adjust = .25 if randc() then angle_adjust = 0-angle_adjust end entity.angle_desired = abs(entity.angle_desired+angle_adjust)%1 end function m_enemy_villager(setx, sety) local e = m_enemy(setx, sety, true) e.head_shift, e.body_shift, e.pcolor, e.scolor, e.score = 6, 16, 11, 4, -10 e.kill_class=function(self, source) if source == p1 then level_end_villager_died(true) else level_end_villager_died(false) end return false end e.touch_class=function(self) score_add(self, 0-self.score-2.5*self.emotion_count) del_from_people(self) return true end e.move=function(self) a_deviate(self, 5) a_random_turn(self) end e.draw_class=function(self) end return e end function nearest_angle(angle) if angle>.825 or angle < .125 then angle = 0 elseif angle < .375 then angle = .25 elseif angle < .625 then angle = .5 else angle = .75 end return angle end function m_arrow(x, y, angle) local a = { x=x, y=y, col_w=4, col_h=4, angle=angle, speed_move=3, is_static=false, is_deadly=true, sprite=40, flipx=false, draw=function(self) set_outline() spr(self.sprite, self.x-4, self.y-4, 1, 1, self.flipx) pal() end, update=function(self) a_move_angle(self) if constrain_to_screen(self) then self:dealt_damage() end end, dealt_damage=function(self) del(list_objects, self) del(list_drawstuff, self) end, } if angle == .25 or angle ==.75 then a.sprite = 41 end add(list_objects, a) add(list_drawstuff, a) end function m_enemy_archer(setx, sety) local e = m_enemy(setx, sety) e.head_shift, e.pcolor, e.scolor, e.alert_distance, e.windup_time, e.time_between_attacks, e.attack_time, e.attack_is_shot = 4, 14, 13, 60, 30, 60, 30, true e.move=function(self) a_deviate(self, 10) if is_level_active() then self.angle_desired = get_dir_to_player(self) end end e.alert_class=function(self) if abs(self.x - p1.x) < 5 or abs(self.y - p1.y) < 5 then if a_alert_checkforwindup(self) then self.desired_angle = nearest_angle(self.desired_angle) sfx(24) return true else return false end end end e.fire_arrow=function(self) sfx(17) m_arrow(self.x, self.y, self.desired_angle) end e.draw_class=function(self) if self.windup_time_rem > 0 then set_outline() local arrow_sprite, doflipy = 40, false if self.desired_angle == .75 then arrow_sprite, doflipy = 41, true elseif self.desired_angle == .25 then arrow_sprite = 41 end spr(arrow_sprite, self.x-4, self.y-4, 1, 1, self.flipx, doflipy) pal() end end end function m_enemy_wander(setx, sety) local e = m_enemy(setx, sety) e.head_shift, e.pcolor = 1, 9 e.move=function(self) a_deviate(self, 15) a_random_turn(self) end e.alert_class=function(self) return a_alert_checkforwindup(self) end return e end function m_enemy_bomber(setx, sety) local e = m_enemy(setx, sety) e.pcolor, e.scolor, e.head_shift, e.is_fuse_lit, e.is_bomber = 8, 4, 3, false, true e.touch_class=function(self) self:explode(nil, true) return true end e.update_class=function(self) if not self.is_fuse_lit and is_near_objs(self, p1, 25) then self.is_fuse_lit, self.fuse_timer, self.emotion_count, self.speed_move = true, 500, 1, self.speed_move_orig*2 sfx(35) end if self.is_fuse_lit then self.fuse_timer=self.fuse_timer-(1) if self.fuse_timer <= 0 then self:explode(self, true) end if g_ticks % 4 == 0 then m_part_bomb_spark(self.x, self.y-10) end end return true end e.move=function(self) a_deviate(self, 10) if is_level_active() then self.angle_desired = get_dir_to_player(self) end end e.explode=function(self, source, no_score) if source ~= nil and source ~= p1 and not source.is_heavy then self.score_multiplier = source.score_multiplier + 1 end if not self.was_counted_for_combo then self.was_counted_for_combo = true sfx(frnda(2,33)) m_part_circle(self.x, self.y, 20, 6, 10, 8, 2) for i=-6, 6, 2 do for j=-6, 6, 2 do if randc(75) then local size = frnda(2) m_part_blood({size, self.x+i, self.y+j, atan2(self.x - (self.x+i), self.y - (self.y+j)), rnd(2)}) end end end split_entity(self, rnd(1)) cam:shake(3, 10) game_pause(2) if not no_score then score_add(self, self.score * self.score_multiplier) end end for a in all(list_people) do if a ~= self and a ~= source then if not a.was_counted_for_combo and not a.just_spawned and not a.is_armored then if is_near_objs(self, a, 20) then if source ~= nil and not source.is_heavy then source.score_multiplier=source.score_multiplier+(1) end if not a.is_furniture then if a.is_bomber then a:kill(self, no_score) elseif not a.is_heavy then a:kill(self, true) end end if not a.was_counted_for_combo and not a.is_heavy then self.score_multiplier=self.score_multiplier+(1) a.was_counted_for_combo = true if not no_score then score_add(a, a.score * self.score_multiplier) end end end end end end if is_near_objs(self, p1, 20) then p1:damage(self) end del_from_people(self) end e.handle_impact_class=function(self, source) self:explode(source) return true end e.kill_class=function(self, source, no_score) self:explode(source, no_score) return true end e.draw_class=function(self) local x_off = -5 if self.flipx then x_off = -3 end set_outline() spr(20, self.x+x_off, self.y-12+get_yboboffset(self), 1, 1, self.flipx) pal() end return e end function m_enemy_boss(setx, sety) local e = m_enemy_seeker(setx, sety) e.is_armored, e.head_shift, e.pcolor, e.scolor, e.speed_move_orig = true, 5, 13, 6, .5 e:init() end function m_enemy_seeker(setx, sety) local e = m_enemy(setx, sety) e.head_shift = 2 e.move=function(self) a_deviate(self, 10) if is_level_active() then self.angle_desired = get_dir_to_player(self) end end e.alert_class=function(self) return a_alert_checkforwindup(self) end return e end function m_enemy_furniture(setx, sety, sprite, is_heavy) local e = m_enemy(setx, sety) e.update_class=function(self) if self.is_flying then check_for_footsteps(self) a_fly(self) end return false end e.kill_class=function(self) del_from_people(self) return true end e.touch_class=function(self) return true end e.sprite, e.is_furniture, e.is_heavy = sprite, true, is_heavy or false del(list_enemies, e) return e end function m_enemy(setx, sety, is_villager) local e= { x=setx, y=sety, pcolor=10, scolor=7, is_villager = is_villager or false, angle=0, angle_desired=0, alert_distance=15, speed_turn=.01, speed_move_orig=.25+rnd(.1), speed_move=0, windup_time=25, windup_time_rem=0, deviation_time=0, col_w=6, col_h=6, col_off=0, curanim="move", curframe=1, animtick=0, flipx=true, head_shift=0, body_shift=0, emotion=nil, emotion_count=0, emotion_timer=0, fly_speed=0, is_flying=false, attack_time=7, attack_time_rem=0, recovery_time=20, recovery_time_rem=0, time_between_attacks=0, time_between_attacks_rem=0, just_spawned=true, invuln_frames=0, wander_time=0, wander_dir=frnd(7), score=1, score_multiplier=1, was_counted_for_combo=false, init=function(self) if is_level_active() then self.invuln_frames, self.speed_move, self.angle = 30, self.speed_move_orig, (atan2(self.x - p1.x, self.y - p1.y)+.5)%1 constrain_to_screen(self) end end, move=function(self) end, attack_target=function(self) if self.attack_is_shot then self:fire_arrow() attack_reset(self) return end self.attack_time_rem, self.angle = self.attack_time, self.desired_angle a_anim_set(self, "attack") sfx(frnda(3,18)) end, handle_impact_class=function(self) return false end, handle_impact=function(self, source) if not self:handle_impact_class(source) then self.is_flying, self.is_flying_impactable, self.windup_time_rem, self.attack_time_rem = true, true, 0, 0 a_anim_set(self, "fly") self:emotion_add() m_part_impact(self) end end, kill_class=function(self) return false end, kill=function(self, source, no_score, angle, override) if not override then if self:kill_class(source, no_score) then return end end local source_angle = angle or atan2(source.x - self.x, source.y - self.y) m_part_bloodsplash(self.x, self.y, source_angle) split_entity(self, source_angle) if not no_score then score_add(self, self.score) end del_from_people(self) end, alert_class=function(self) return false end, touch_class=function(self) return false end, update_class=function(self) return true end, update=function(self) if self.invuln_frames > 0 then self.invuln_frames=self.invuln_frames-(1) else self.just_spawned = false end if self.just_spawned then return end if not self:update_class() then self.just_spawned = false return end check_for_footsteps(self) if self.is_flying then a_fly(self) elseif self.attack_time_rem > 0 then a_attack(self) elseif self.windup_time_rem > 0 then self.windup_time_rem=self.windup_time_rem-(1) if self.windup_time_rem <= 0 then self:attack_target() end elseif self.recovery_time_rem > 0 then self.recovery_time_rem=self.recovery_time_rem-(1) elseif self.time_between_attacks_rem == 0 and self:alert_class() then else if self.time_between_attacks_rem > 0 then self.time_between_attacks_rem=self.time_between_attacks_rem-(1) end if self.deviation_time > 0 then self.deviation_time=self.deviation_time-(1) else self:move() if abs(self.angle - self.angle_desired) < .05 then self.angle_desired=self.angle end if self.angle ~= self.angle_desired then self.angle = (self.angle + self.speed_turn*get_direction_to_turn(self.angle_desired, self.angle)) end end a_move_angle(self) local anim = "move" if self.is_villager and self.emotion_count > 0 then anim = "run" end a_anim_set(self, anim) if constrain_to_screen(self) then self.angle = (self.angle+.25)%1 end end self:emotion_update() a_anim_update(self, character_anims, self.emotion_count+1) end, draw_class=function(self) end, draw=function(self) if not self.is_furniture then draw_character(self) self:draw_class() if self.emotion and not self.is_flying then self.emotion:draw() end else set_outline() spr(self.sprite, self.x-4, self.y-4) pal() end end, emotion_update=function(self) if self.emotion then self.emotion:update() end if self.emotion_timer > 0 then self.emotion_timer=self.emotion_timer-(1) if self.emotion_timer == 0 then self.emotion_count=self.emotion_count-(1) self:emotion_set_from_count() if self.emotion_count > 0 then self.emotion_timer = 360 end end end end, emotion_set_from_count=function(self) if self.emotion_count == 3 then m_emotion(self, "angry") elseif self.emotion_count >= 1 then m_emotion(self, "upset") else self.emotion = nil end self.speed_move = self.speed_move_orig + .2*self.emotion_count end, emotion_add=function(self) self.emotion_count, self.emotion_timer = min(3, self.emotion_count+1), 360 self:emotion_set_from_count() end, } e:init() add_to_people(e) return e end function get_gen_coords() local gen_x, gen_y, whichside = frnd(scr_w()), frnd(scr_h()), frnd(4) if whichside == 0 then gen_x = 4 elseif whichside == 1 then gen_x = scr_w()-4 elseif whichside == 2 then gen_y = 4 else gen_y = scr_h()-4 end return gen_x, gen_y end function m_enemy_random() local enemy_type = g_enemy_weights[frnda(#g_enemy_weights)] if enemy_type == 5 then if not g_spawned_boss then m_enemy_boss(get_gen_coords()) g_spawned_boss = true else return end elseif enemy_type == 1 then m_enemy_wander(get_gen_coords()) elseif enemy_type == 2 then m_enemy_seeker(get_gen_coords()) elseif enemy_type == 3 then m_enemy_archer(get_gen_coords()) else m_enemy_bomber(get_gen_coords()) end g_level_enemies_count=g_level_enemies_count-(1) end function set_cam_pos(pos) if pos+8<64 then pos=pos+(min(64-(pos+8),4)) end if pos-8>64 then pos=pos+(min(64-(pos-8),4)) end return pos end function m_cam() camera() local c= { pos_x = 64, pos_y = 64, shake_remaining=0, shake_force=0, update=function(self) self.shake_remaining, self.pos_y, self.pos_x = max(0,self.shake_remaining-1), mid(64, set_cam_pos(self.pos_y), 960), mid(64, set_cam_pos(self.pos_x), 960) camera(self:cam_pos()) end, cam_pos=function(self) local shk_x, shk_y, force = 0, 0, self.shake_force if self.shake_remaining>0 then shk_x, shk_y = rnd(force)-force/2, rnd(force)-force/2 end return self.pos_x-64+shk_x,shk_y end, shake=function(self, force, duration) self.shake_force, self.shake_remaining = force, duration end } return c end function save_score() if g_score_total >= g_high_scores[g_difficulty][1] then g_high_scores[g_difficulty][1], g_high_scores[g_difficulty][2] = g_score_total, g_year end local index = 1 for i=1, 8 do for j=1,2 do dset(index, g_high_scores[i][j]) index=index+(1) end end end function level_end() p1.ready_time, g_game_state, g_transition_time = 300, 6, 150 g_score_total=g_score_total+(g_score_level) end function level_end_win() if p1.hp_cur > 1 then score_add(p1, 25) end g_game_transition_to_state = 7 sfx(13) level_end() end function level_end_bad() g_game_transition_to_state = 8 sfx(12) level_end() save_score() end function level_end_villager_died(killed_by_player) if g_difficulty < 7 then return end g_level_end_reason = "let a villager die" if killed_by_player then g_level_end_reason = "killed a villager" end level_end_bad() end function level_end_player_died(killed_by_obstacle) g_level_end_reason = "slain in combat" if killed_by_obstacle then g_level_end_reason = "stumbled into death" end level_end_bad() end function m_splat(x, y, size_base, size_var) local s = { x=x, y=y, size=frnda(size_var, size_base), draw=function(self, color) if color == 0 then circfill(self.x, self.y, self.size+1, color) else circfill(self.x, self.y, self.size, color) end end, } return s end function m_transition_splatter() local t = { list_splats={}, init=function(self) local wipe_position = -60 while wipe_position < 190 do wipe_position=wipe_position+(10) add(self.list_splats, m_splat(wipe_position+2-rnd(4), 48-frnd(6), 10, 8)) add(self.list_splats, m_splat(wipe_position+2-rnd(4), frnda(6, 80), 10, 8)) if randc() then add(self.list_splats, m_splat(wipe_position+4-rnd(8), 30-frnd(15), 2, 5)) end if randc() then add(self.list_splats, m_splat(wipe_position+4-rnd(8), frnda(15,98), 2, 5)) end end end, draw=function(self) rectfill(-60, 41, 190, 87, 0) for s in all(self.list_splats) do s:draw(0) end rectfill(-60, 42, 190, 86, 8) for s in all(self.list_splats) do s:draw(8) end end, } t:init() return t end function is_level_active() if g_game_state == 5 or g_game_state == 6 then return true end return false end function update_weather() if g_weather_part_rate == 0 then return end if g_ticks % g_weather_part_rate == 0 then local part_sprite, part_color, double_rate = g_weather_sprite, g_weather_color, 1 if g_season == 0 then double_rate = 3 elseif g_season == 3 then part_sprite=part_sprite+(frnd(2)) if not g_level_night then part_color=part_color+(frnd(2)) end end for i=0,double_rate do local p = m_part_sprite(part_sprite, frnd(scr_w()+128)-128, -8, g_weather_fall_rate, part_color, part_color, 300, false, true) if g_season == 0 then p.dx, p.splash_loc = .3+rnd(.1), frnda(scr_h(), 16) p.update=function(self) if self.y >= self.splash_loc then for i=0,1 do local s = m_part_sprite(103, self.x, self.y, -rnd(1), 12, 12, 5, false, true) s.ddy, s.dx = .1, rnd(.5) if randc(50) then s.dx = -rnd(.5) end end del(list_parts_front, self) end self:update_base() end else p.update=function(self) if self.y > scr_h() then del(list_parts_front, self) return end if randc(25) then local wshift = g_weather_wind_shift if randc(50) then wshift = -g_weather_wind_shift end self.dx=self.dx+(wshift) end self.dx = mid(-1, self.dx, 1) self:update_base() end end end end end function _update60() g_ticks=g_ticks+(1) cam:update() local fu = function(i) i:update() end if g_game_state == 6 then g_transition_time=g_transition_time-(1) if g_transition_time <= 0 then cam:shake(3, 20) g_game_state = g_game_transition_to_state sfx(9) end if g_ticks % 2 == 0 then return end end if g_game_state == 4 then g_transition_time=g_transition_time-(1) if g_transition_time <= 0 then g_game_state = 5 end end foreach(list_parts_blood, fu) foreach(list_parts_back, fu) foreach(list_parts_front, fu) if g_game_state > 3 and g_game_state < 9 then if game_pause_timer > 0 then game_pause_timer=game_pause_timer-(1) return end update_weather() if g_player_damaged_time > 0 then g_player_damaged_time=g_player_damaged_time-(1) end if g_game_state > 4 then if g_ticks % 25 == 0 and (#list_enemies + #list_villagers) < g_level_people_screen_max then if randc(85) and g_level_enemies_count > 0 then m_enemy_random() else if g_level_villagers_count > 0 then g_level_villagers_count=g_level_villagers_count-(1) m_enemy_villager(get_gen_coords()) elseif g_level_enemies_count > 0 then m_enemy_random() end end end end p1:update() foreach(list_heads, fu) for e in all(list_people) do e:update() if g_game_state == 5 then if int_cols(p1, e, 2) then if p1.is_slashing and not p1.slash_has_impacted then if e.is_villager or (not e.is_furniture and #list_enemies == 1 and g_level_enemies_count == 0) then m_part_impact(e) e:kill(p1, false, p1.slash_angle, not e.is_villager) else if e.attack_time_rem > 0 then if not attempt_deflect_target(e) then slash_target(e) end else slash_target(e) end end break end if not p1.is_slashing and not e.is_flying and int_cols(p1, e) then if not e:touch_class() then if e.attack_time_rem > 0 or g_difficulty > 2 then p1:damage(e) end end end end if e.attack_time_rem > 0 then for v in all(list_villagers) do if not v.is_flying and int_cols(e, v) then v:kill(e, false, e.angle) end end end if e.is_flying then foreach(list_objects, function(o) if o.is_deadly and o.is_static and not e.is_heavy and not e.is_armored and int_cols(e, o, 2) then handle_impact_death(e, o) sfx(25) if not e.is_furniture then o:dealt_damage() end end end) end end end if g_game_state == 5 then if is_timed_mode() then g_rushmode_ticks=g_rushmode_ticks-(1) if g_rushmode_ticks % 60 == 0 and g_rushmode_ticks < 420 then sfx(16) end if g_rushmode_ticks < 60 then p1:damage(p1, true) g_level_end_reason = "ran out of time" level_end_bad() return end end foreach(list_objects, function(o) o:update() if int_cols(o, p1) then if o.is_deadly then p1:damage(o) o:dealt_damage() else o:eat() end end end) end end if g_game_state > 6 then if g_ticks % 5 == 0 then local p = m_part_sprite(86, frnda(230,5), 50+frnd(36), 0, 7, 13, frnda(5,10), false, false) p.dx = -1 end if btnp(4) then if g_game_state == 7 then transition_level() else reset_game() end end elseif g_game_state == 0 then if btnp(4) then sfx(0) sfx(11) g_game_state = 4 reset_level() end if btnp(0) then g_difficulty=g_difficulty-(1) elseif btnp(1) then g_difficulty=g_difficulty+(1) end g_difficulty = wrap(g_difficulty, 1, 8) end if btnp(5) then if g_game_state < 4 then sfx(0) reset_level() if g_game_state == 1 then m_food(68,68) m_enemy_villager(60, 68) elseif g_game_state == 0 then p1 = m_player(64,39) m_enemy_wander(33, 83) m_enemy_seeker(43, 83) m_enemy_archer(53, 83) m_enemy_bomber(63, 83) m_enemy_boss(73, 83) m_object(83, 83, {160,161}, true) m_object(93, 83, {176,177}, true) m_enemy_villager(64, 109) end g_game_state = wrap(g_game_state+1, 0, 3) end end end function level_create() p1 = m_player(120,68) reload(0x2000, 0x2000, 0x1000) local color_choice, block_sel_x, block_sel_y = g_season, frnd(2), 0 if g_year ~= g_year_endgame then if g_year ~= 1 then if randc(25) then g_level_indoor, block_sel_y = true, 1 end if randc(25) then g_level_night = true end if not g_level_indoor then if randc(25) then g_weather_sprite, g_weather_color, g_weather_part_rate, g_weather_wind_shift, g_weather_fall_rate = g_weather_seasondata[g_season*5+1], g_weather_seasondata[g_season*5+2], g_weather_seasondata[g_season*5+3], g_weather_seasondata[g_season*5+4], g_weather_seasondata[g_season*5+5] if g_level_night and g_season ~= 0 then g_weather_color = 1 end end end end else block_sel_x = 2 end if block_sel_y == 0 then g_level_people_screen_max, g_level_screen_buffer = flr((7+g_year)*1.5), 0 end if g_level_indoor then color_choice = 6 end if g_level_night then color_choice = 4 if g_level_indoor then color_choice = 5 end end local colors_string = "03,11,05,00,07,02,11,09,10,05,00,07,04,04,04,09,05,00,07,02,10,07,06,05,00,05,06,00,00,01,05,00,07,02,12,00,01,04,00,07,02,07,00,02,09,00,07,01,07" local cl, offset = split(colors_string), color_choice*7 g_color_ground, g_color_detail, g_color_wall, g_color_outline, g_color_interface, g_color_blood_burn, g_color_title_text = cl[1+offset], cl[2+offset], cl[3+offset], cl[4+offset], cl[5+offset], cl[6+offset], cl[7+offset] local replace_weights, has_placed_food = split("65,81,97,160,176,999"), false for y=0, 16 do for x=0, 29 do local tile, swapped_tile = mget(x+block_sel_x*30, y+block_sel_y*17), false if tile == 160 then if randc() or g_year == g_year_endgame then local coord_x, coord_y, chosen = x*8+4, y*8+4, replace_weights[frnda(#replace_weights)] if chosen > 998 or g_year == g_year_endgame then if has_placed_food then del(replace_weights, 999) end has_placed_food = true m_food(coord_x, coord_y) elseif chosen > 97 then m_object(coord_x, coord_y, {chosen, chosen+1}, true) else if g_level_indoor then chosen=chosen-(1) end m_enemy_furniture(coord_x, coord_y, chosen, chosen > 81) end end swapped_tile = true end if swapped_tile then if g_level_indoor then mset(x, y, 144) else mset(x, y, 0) end else mset(x, y, tile) end end end end function transition_level() g_season=g_season+(1) if g_season > 3 then g_season = 0 g_year=g_year+(1) if g_year == 7 then add(g_enemy_weights, 5) end for i=1, 4 do if g_year+1 >= i then add(g_enemy_weights, i) end end end reset_level() if g_year == g_year_endgame then g_game_state = 9 sfx(15) p1.y = 116 m_enemy_villager(92, 24) m_enemy_villager(148, 24) m_enemy_villager(108, 116) m_enemy_villager(132, 116) g_score_total=g_score_total+(1000) g_level_end_reason = "returned home" save_score() else sfx(11) g_game_state = 4 end end function reset_level() cam=m_cam() table_clear(list_parts_back) table_clear(list_parts_front) table_clear(list_parts_blood) table_clear(list_heads) table_clear(list_enemies) table_clear(list_villagers) table_clear(list_people) table_clear(list_drawstuff) table_clear(list_objects) table_clear(list_steps) g_spawned_boss, g_rushmode_ticks, g_ticks, g_transition_to_state, g_transition_time, g_player_damaged_time, g_level_screen_buffer, g_level_villagers_count, g_level_enemies_count, g_level_people_screen_max, g_score_level, game_pause_timer, g_level_indoor, g_level_night, g_weather_sprite, g_weather_color, g_weather_part_rate, g_weather_wind_shift, g_weather_fall_rate = false, 1200+60*g_year, 0, 0, 150, 0, 16, 3+flr(.5*g_year), 7+3*g_year, flr((4+g_year)*1.5), 0, 0, false, false, 0, 0, 0, 0, 0 if g_game_state > 3 then level_create() end cls(g_color_ground) pal(1, g_color_detail) pal(2, 0) pal(5, g_color_wall) map(0,0,0,0,30,17) pal() copy_screen_to_mem() transition_splatter = m_transition_splatter() end function reset_game() g_game_state, g_level_end_reason, g_year, g_season, g_score_total, g_level_screen_buffer, g_ticks, g_enemy_weights = 0, "defeated the vandals", 1, 0, 0, 16, 0, split("1,1,1,2,2,2,2") reset_level() cam:shake(3, 20) sfx(9) end function _init() cartdata("tmirobot_bunbunsamurai_4") g_alphabet_sprites, g_season_names, g_weather_seasondata, g_difficulty_strings, g_difficulty_descs, g_year_endgame, g_difficulty = split("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9", ",", false), split("spring,summer,fall,winter,140,142,172,174"), split("119,12,1,0,3,121,14,6,.05,.5,123,9,6,.05,.5,121,6,1,.1,1"), split("easy,easy,norm,norm,hard,hard,hell,hell"), split("enemy strikes deal damage,s,enemy touches deal damage,s,hero dies from a single hit,s,villager death ends the game,s"), 10, 3 local index = 1 g_high_scores = {} for i=1,8 do g_high_scores[i] = {} for j=1,2 do g_high_scores[i][j] = dget(index) index=index+(1) end end reset_game() end function sort_by_y(t) for n=2,#t do local i=n while i>1 and t[i].y 3 and g_game_state < 10 then paste_screen_from_mem () for a in all(list_parts_blood) do if a.time == a.duration then a:draw() end end for a in all (list_steps) do pal(7, g_color_detail) spr(87+frnd(2), a.x, a.y) pal() del(list_steps, a) end copy_screen_to_mem() if g_player_damaged_time > 0 then cls(8) end if g_game_state == 9 then rectfill(0,40,240,96,12) end local fd = function(i) i:draw() end sort_by_y(list_drawstuff) foreach(list_parts_blood, fd) foreach(list_parts_back, fd) foreach(list_drawstuff, fd) foreach(list_parts_front, fd) if g_game_state == 4 then __off(56,4) local season_sprite = g_season_names[5+g_season] if g_level_night then season_sprite = 101 end spr(season_sprite, 56, 26, 2, 2) spr(season_sprite, 56, 84, 2, 2) printsprite(g_season_names[g_season+1], 48, g_color_title_text) printsprite("year "..g_year, 70, g_color_title_text) __off(0,0) end if is_level_active() and is_timed_mode() then printc_o(""..flr(g_rushmode_ticks/60), 3, 7, g_color_outline, 120) end else cls(0) end rect(0,0,scr_dw()-1,scr_dh()-1,1) if g_game_state > 0 and g_game_state < 4 then if g_game_state == 1 then print("the \fchero\fd, weary of fighting in\n endless wars, wanders\n the countryside, seeking the\n village he once called home.\n\n\n\n on his journey, he finds a\n nation overrun by filthy\n \fcbandits\fd, vulgar \fcronin\fd,\n and dangerous \fchazards\fd.\n\n\n\nwherever he roams, he protects\n the \fcweak\fd and \fchelpless\fd.",4,6,13) elseif g_game_state == 2 then print(" press \fc\142 \fdto strike enemies,\n killing them if they are\n knocked into another \fcobject\fd.\n\n build \fccombo chains\fd of impacts\n for more \fcprestige\fd.\n\n save \fcvillagers\fd or eat \fcfood\fd\n to gain \fcprestige\fd.\n\n\n\n food also heals \fcwounds\fd.\n\n finish a season at full\n health in order to earn\n \fcbonus prestige\fd.",4,6,13) elseif g_game_state == 3 then printc("difficulty levels", 6, 7) for i=1,8,2 do local i24, scorestring = i*12, "" printc(g_difficulty_strings[i], 6+i24, 9) printc(g_difficulty_descs[i], 14+i24, 12) for j=0,1 do local endyear, yearstr = g_high_scores[i+j][2], "home" if endyear ~= g_year_endgame then yearstr = "year "..endyear end scorestring = scorestring..""..flr(g_high_scores[i+j][1]*10).." "..yearstr if j == 0 then scorestring = scorestring.." - " end end printc(scorestring, 22+i24, 13) end end printc("\151 next", 117, 7, 62) for i in all(list_drawstuff) do i:draw() end return end if g_game_state > 6 then __off(56,4) if g_game_state < 9 then transition_splatter:draw() end printc_o("year "..g_year.." | "..g_season_names[g_season+1].." | "..g_difficulty_strings[g_difficulty], 54, 9) printc_o(g_level_end_reason, 46, 10) printc_o("prestige: "..flr(g_score_total*10), 62, 9) if g_score_total >= g_high_scores[g_difficulty][1] then printc_o("(new record)", 70, 10) end printc_o("press \142 to continue", 78, 7, 2, 62) __off(0,0) elseif g_game_state == 0 then __off(56,4) transition_splatter:draw() printsprite("bun bun", 44, 7) printc("s a m u r a i", 54, 10) printc("TIC-80 Edition", 63, 2) line(10, 71, 118, 71, 2) printc_o("\142 play | \139 "..g_difficulty_strings[g_difficulty].." \145 | \151 info", 76, 7, 2, 56) if is_timed_mode() then printc_o("(rush mode)", 84, 7) end __off(0,0) end end -- screen buffer: the game keeps a persistent canvas (blood stains); keep a copy in unused map RAM local SV=0x8000+34*240 function copy_screen_to_mem() T_memcpy(SV,0,16320) end function paste_screen_from_mem() T_memcpy(0,SV,16320) end -- sound: PICO-8 style synth driving the TIC-80 sound registers local SFXD={ {1,0,0,4,"0b480b480b5d0b5d"}, {0,0,0,12,"0ab30a680a950a600a9a0a5a0a950a510a8a0a420a840a43"}, {0,0,0,13,"0ab40a6b0a5f0a940aa50a980a930a520a8e0a860a470a870a89"}, {4,0,0,32,"0ba70aa70a190bab0baa0aa40a180ba30b200a150b9d0a5a0a590a120b970b950a530a0c0b8f0a8e0a0c0b8b0a4a0a0b0b890a870a040a420b130b090b820b83"}, {0,0,0,15,"07a207a407a707ab07b207b707bb065006540658065d06610665066a066e"}, {0,0,0,14,"07a307a607a907ad07b107b607b8065e066106650667066a06700673"}, {0,0,0,13,"07a207a307a607a907ad07b207b8065a065f06620667066d066f"}, {0,0,0,15,"0b5d0b610b640b650b610b5b0b560b520b4d0b470b480b4b0b540b5f0b65"}, {1,0,0,16,"0a7d0a340a1c0a0b0a120a170a1701ff006d0e2b0e6c0e730e780e7c0e7f0e3f"}, {1,0,0,27,"0b8d0b8e0b900a4d0b930a550a570a5b0b9e0a610a640baa0b910b910a500b910b9a0b910b910b960a4e0a4f0b910b9a0b910a4f0a55"}, {2,0,0,17,"0faf0fae0f900f5c0b630b67036b036e0b710b700b6f0b6c0b690b610b5a0b580b5a"}, {22,0,0,13,"56cf56d256d456d656d956db56d256cf56de56db5c8f00805c8f"}, {22,0,0,13,"56db56d956d656d456d256cf56cd56cf56d256cf5c8f50005c8f"}, {22,0,0,13,"56db56d956d656d456d256cf56cd56cf56d656cf5c8f50c35c8f"}, {22,0,0,32,"52cf52cf52d252d252cf52cf52cd52cd52cf52cf52d252d252d452d452ce52ce52cf52cf52d252d252cf52cf52cd52cd52cf52cf52d452d452cd52cd52c252c2"}, {20,0,0,32,"149f149f149f149f14a214a214a214a2149f149f14a214a2149b149b149b149b1496149614961496149b149b149b149b149b149b149b149b149b149b149b149b"}, {6,0,0,2,"0a1b0a1b"}, {2,0,0,16,"0baf0a180baf0a210a210a1e0a1d0a170a0f0a0a0a080a060a060a030a020a02"}, {0,0,0,9,"045b045c045f046004640464046604680468"}, {0,0,0,9,"045304560459045c045d0461046204650467"}, {0,0,0,8,"0453045504570459045d045f04630466"}, {0,0,0,11,"0bac0bab0ba40ba00b9d0b990b980b980acf0ad00ad2"}, {0,0,0,9,"0ba90ba40ba10b9d0b9a0b9d0b9b0b990b98"}, {0,0,0,10,"0f500f4d0f4c0f4a0f490f480f480f4a0f4d0f4f"}, {0,0,0,6,"1a0d0a110a170a1c0a1f0a23"}, {1,0,0,11,"0a070a070a090a0a0ac60ac50b150b170bd60bd60bd9"}, {0,0,0,12,"0ba80ba60ba30b9f0b9b0b960b940ac70ac90ac90acc0acd"}, {0,0,0,12,"0ba90ba60ba30b9d0b9b0b980b960ad00ad10ad10ad50ad7"}, {0,0,0,12,"0ba70ba40ba10b9e0b9b0b980b960ada0ada0adb0add0adf"}, {0,0,0,12,"0ba70ba40ba10b9f0b9e0b9b0b990ae00ae00ae20ae40ae7"}, {0,0,0,12,"0ba50ba20ba00b9c0b9a0b990b980ae30ae40ae60ae80aeb"}, {0,0,0,12,"0ba70ba40b9f0b9c0b9a0b990b970aea0aec0aef0af00af3"}, {0,0,0,15,"0baf0ba60b9e0b9b0b970b950adb0acc0aca0aca0aca0aca0aed0ac90ac9"}, {3,0,0,16,"0b960b990a870ba80ba80ba50a860b9a0b9b0b9a0a870b9b0b9c0b8b0b850b81"}, {3,0,0,16,"0bad0bad0a870b970b950b950a8c0ba10b9f0b9f0a870ba20b9d0b930b8d0b81"}, {2,0,0,32,"0baa0a170baa0b8d0b8d0b8f0b910b930b910b8e0b8b0b8c0b8c0b8d0b8e0b8f0b8c0b8b0b8c0b8c0b8a0b870b860b850b840b830b820b810b810b810b810b81"}, } local WV,CH,FR={},{},0 local function tri(i) i=i%32 return i<16 and i or 31-i end local function mkw(f) local b={} for i=0,15 do b[i]=flr(f(2*i))|(flr(f(2*i+1))<<4) end return b end local function initwaves() WV[1]=mkw(tri) WV[2]=mkw(function(i) return i<24 and i*15/23 or (31-i)*15/7 end) WV[3]=mkw(function(i) return i*15/31 end) WV[4]=mkw(function(i) return i<16 and 15 or 0 end) WV[5]=mkw(function(i) return i<10 and 15 or 0 end) WV[6]=mkw(function(i) return (tri(i)+tri(i*2))/2 end) WV[7]=mkw(function(i) return 0 end) WV[8]=mkw(function(i) return (tri(i)+tri(i*3))/2 end) end function sfx(n) if n<0 then for i=0,3 do CH[i]=nil end return end local d=SFXD[n+1] if not d then return end if not d.n then d.n={} for k=0,d[4]-1 do local w=tonumber(d[5]:sub(k*4+1,k*4+4),16) d.n[k+1]={w&63,(w>>6)&7,(w>>9)&7,(w>>12)&7} end end local c=-1 for i=0,3 do if not CH[i] then c=i break end end if c<0 then c=0 for i=1,3 do if CH[i].std[2] and pos>=d[3] then pos=d[2]+(pos-d[3]) end local idx=flr(pos) if idx>=d[4] then CH[c]=nil else local nt=d.n[idx+1] local f=pos-idx local p,v,fx=nt[1],nt[3],nt[4] if fx==1 then local pr=d.n[idx] or nt p=pr[1]+(p-pr[1])*f v=pr[3]+(v-pr[3])*f elseif fx==2 then p=p+0.4*math.sin(pos*spd/120.5*7.5*PI2) elseif fx==3 then p=p*(1-f) elseif fx==4 then v=v*f elseif fx==5 then v=v*(1-f) elseif fx>=6 then local g=(idx//4)*4 p=(d.n[g+flr(pos/(fx==6 and 2 or 4))%4+1] or nt)[1] end local fq=flr(65.41*2^(p/12)+.5) if fq<1 then fq=1 elseif fq>4095 then fq=4095 end local vol=flr(v*15/7+.5) if vol<0 then vol=0 elseif vol>15 then vol=15 end local a=0xFF9C+18*c poke(a,fq&255) poke(a+1,(fq>>8)|(vol<<4)) local w=WV[nt[2]+1] for i=0,15 do poke(a+2+i,w[i]) end s.t=pos+2.0082/spd end end end end -- main loop local PC={0x000000,0x1D2B53,0x8A1D34,0x008751,0xAB5236,0x5F574F,0xC2C3C7,0xFFF1E8,0xF7152B,0xFFA300,0xFFEC27,0x00E436,0x29ADFF,0x83769C,0xFF77A8,0xFFCCAA} local started=false function TIC() if not started then started=true for i=1,16 do local c=PC[i] poke(0x3FC0+(i-1)*3,c>>16) poke(0x3FC1+(i-1)*3,(c>>8)&255) poke(0x3FC2+(i-1)*3,c&255) end initwaves() math.randomseed(flr(time()*1000)) M(true) _init() end setclip() _update60() M() _draw() sfxupdate() end