0 D$404mNJN…L04e$ĞFHuqaY}ÎÒ},…•¡mª,Òª™mÂÊÚÔ^ŞîÖ Ğ!Ce—šËíïÍ«©gE#ûÿÿÿÿÿK@˜ÊíşÿîÍšh52e3De‡šxgETv˜Ëİ»ªh2Tvˆ©ËíïÍ«‰xV4êÿÿ½Êıÿ®!4Q!"CUv˜ºıïÿÿÿÿÿÿÿÿÿ!Ce‡©ËíïÍ«‰gE#!Ce‡©ËíïÍ«‰gE#!Ce‡©ËíïÍ«‰gE# étP0  ? ğ à à à Ğ Ğ ĞĞÀÀ°°°°°ÀÀ Oï¿Oï¿,::: : ::::::::::::::::::::::::::d@ªªª ª ªªªªªªªªªªªªªªªªªªªªªªªªªªd@P0  h€hh h°hÀhĞhàhğhhh h0h@hPh`hpopopopopopopopopopopopopopop` `aabbcdefghijklmnnooooooooooosssssssssss s@s`spspsps`s@ss°ss€s€s€ss°sĞsğssd9PQRRSTUVWWX Y@Z`[p\p\p]`^@__°__€_€_€__°_Ğ_ğ__9ŠŠt``P`0``````````````````````````` % 0  ? ğ à à à Ğ Ğ ĞĞÀÀ°°°°°ÀÀ @@@ @ @@ğ@à@à@ğ@@@ğ@@@@ğ@@@@@@@@@@@@@@tÄÄÄÄÄÄÄÄÄÄÄ Ä@Ä`ÄpÄpÄpÄ`Ä@ÄİÄĀĀĀÄİÄĞÄğÄÄd9°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°t  ¡¡¢¢££¤¤¥¥¦¦§§¨¨©©ªª««¬¬­­®¯t°°±±²²³³´´µµ¶¶··¸¸¹¹ºº»»¼¼½½¾¿t—€€€€€* € €€ € € * €€¥€ €¤€ ¥€ €€ €€¤€ ¥€ €¤€€¤ §ğ€€€€€@« € €€ € « €€€€€€€€  * J€€ € €  €  € € € € ¤€ € ¤€ €¤€ €¤€ €¤€ €¤€ €¤€ €¤€ ‹€€ € ‹€  ‹A‹€ « €€ € €‹€€ € ‹€ ‹‹€  €€ € € * J€€ € €  €  € € € €  € € €€ ¤€ € ¤€ €¤€ €¤€ €¤€ €¤€  U ¤€ u €¤ € ‹€€ «€  €  «€€€ ‹A‹€« €€ €@‹ € €‹€€ € ‹€ ‹‹€  €€ ‹ € L l € € € *J€€ €  €  € €  €  € €  €  € €  u€¤€ € ¤€  u€ ¤€ € ¤€ €¤€ €¤€ ‘€ ¤€‘ € ¤€ «€«€‹€ € € ‹ ««€€ € ‹€ ËDË€@€ € «€ € G'Œ€ € G'Œ€ €I'Œ€ €I'Œ€ €I'Œ€ €I'Œ€  ‘€ G'Œ ‘ € G'Œ€ *J€€ €  €  € €  €  € € €* € €€ € € € q€¤ q €¤€  r€ ¤ q€€¤€ € ¤€ € ¤ €¤€€¤ ‹ B‹€€ «€ € @‹ «€€  ‹ D‹€€ € @« € €€ € « €q€ q€ € ‹€  r €«€ €€ € µ € €€ € µ €€•¤µ€ •¤€€•¤µ €€¤€€  €•¤€µ€ •¤€€ •¤€€¤€ ‹€€ € ‹€  ‹A‹€ « @€€ µ€• €€ ‹€€ € ‹€ ‹‹€  €€ €µ €€€ ‹€ B«« «€€ @ ‹ «€€€ ‹A‹€ « « D€ € @ • • •• € € €‹€ B‹««€€ @‹ « € €€«€  € €€ € l € € € *J€€ €  €  € €  €  € €  €  € €  •€¤€ µ ¤ • €€ ¤€µ €€¤€ €•¤µ•€ ¤‘€¤€‘ € ¤€ «€«€‹€ € ‹€ k «B«€ @€€ ‹€k «€ A€  €€€‹€ @k @€ G'Œ€ € G'Œ€ €I'Œ€ €I'Œ€ €I'Œ€ € I'Œ ‘€€G'Œ ‘ € G'Œ€ *J€€ €  €  € €  €  € € €J€j€ €  q€¤ q €¤€  r€ ¤ q€€¤€ € ¤€ €¤ ¶€€–€ ‹ B‹€€ «€ € @‹ «€€  ‹ C‹€€ @Õ µ €€€ @q€ q€ € ‹€  r €«€ €G'Œ€€ D'¬€  ¤D'¬€€  ¤ *J€€ €  €  € €  €  € € €* € €€ € €€ q€¤ q €¤€  r€ ¤ q€€¤€ € ¤€ € ¤ €¤€€  ‹ B‹€€ «€ € @‹ «€€  k k€€ € « € €€ € €« q€ q€ € ‹€  r €‹€ €€ € Ë € €€ € €€.€  € N€ .€* € . € € € N€ .€ € .€  /€  € @/@O€ @/€€ € € € € € @/IO€ @/€€€ /€  @¬ ¬ €Ä,É¥ p€ ɀɀ ¥ p€ É€€  @² ²² Ä,É¥ p€ É€€  p€€  p€ ¥ Í€€ Lí€ €€ ‘€Í€€ ñ€í€€ .€  € N€ .€* € . € € N€ .€ € .€  /€  € @/@O€ @/€€ € € € € € @/IO€o€ € C€ o€ €  € Í€€ Lí€ €€ €€‘€ C±€ ‘€ ±€  € /€  € @/@O€ @/€€ € € € € € @/IO€o€ € C€  € €€ € €@¬ ¬ €Ä,É¥ p€ ɀɀ ¥ p€ É€€  @² ²² Ä,É¥ p€ É€€  p€€  p€ ¥ ¥Í€€ Lí€ €€ €€‘€ C±€  € €€ € €³€€€ €  ³ ³€€ €€€ € .€  € N€ .€* € . € € N€ .€€ .€ /€  € @/@O€ @/€€ € € € € € @/IO€ O€€ O€ “C³€€ @“€€€ “€ € “€ ³ “€€Ó€ €Ó€ ³€€€ €  ³ ³€€ €€€ “ /€  € @/@O€ @/€€ € € € € € @/IO€ O @U € € € u€@¬ ¬ €Ä,É¥ p€ ɀɀ ¥ p€ É €  @² ²² Ä,É¥ p€ É€€  p€€  p€ ¥ ³€€ “€€€ “ t“ p€ € ³ “€€ € “€ €  ““³.€  € N€ .€* € . € € € N€ .€ € .€  @u• €  € € €  €  € € €  €  € € €  u uu• u • €  €  €  €  €  €  €  €  €  €  €  € • • ••@²² ² Ä,É¥ p€ ɀɀ ¥ p€ É€€  @²²² Ä,É¥ p€ É€€  p€€  p€ ¥ ³€€€ € “ ³€€€ €€€ Ó .€  € N€ .€* € . € € € N€ .€€ .€€@u• €  € € €  €  € € €  €  € € €  €  €  €  €  €  €  €  €  €  € O€€ O€€@²² ² Ä,É¥ p€ ɀɀ ¥ p€ É€€  @²²² Ä,É¥ p€ É€€  p€€  p€  ³€€ “€€€ “€  “€ ³ “€€Ó€ €Ó€ ³€€€ € “ ³€€€ €€ s€ “ ³€³ €³€€ “€€€ “ t“ p€ € ³ “€€Ó€ €Ó€ €€€€€€€ @¬ ¬ €Ä,É¥ p€ ɀɀ ¥ p€ É€€  @² ²² Ä,É¥ p€ É€€  p€€  p€ ¥ T t€” € T € ” ´€€T €t€” € T € Ô€ ´ ”€ t€ T t €€€€ € €€ J*€€  €  €  €  € €€€€ €  p€ € p€  p€  p€ €€ ¤¤3©º²­û©º²­û©º²­û©º²­û©º²­û©º²­û©º²­û©º²­ûÂÔıÀ?İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİİİİİİİİÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİıİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİİ!!!!!!!!İİİİİİİİİİİİİİİİİİİİİİİİİİxpwwwĞİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİİ """"İİİİİİİİİİİİİİİİİİİİİİİİw™™™™™y×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİ!!!!! "!!!!İİİİİİİİİİİİİİİİİİİİİİx©©©©©™wØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİİ""""" """""Ñİİİİİİİİİİİİİİİİİİİİ}™šªªª­ªššyİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİİ!!"!"""" ""!"!!İİİİİİİİİİİİİİİİİİİݘ™©ªÚÚÚªª™™ØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİ"""""#"#"#""""İİİİİİİİİİİİİİİİİİ} ªª­­İ­­­ªšyİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİİ!!"""""""""""""!!Ñİİİİİİİİİİİİİİİİݘ©ÚÚÚİİİÚª™™ØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİ"""######### ##""İİİİİİİİİİİİİİİİİ—ªªİİÜÜ šÙİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌİİ!!""""2"222"2""""!!Ñİİİİİİİİİİİİİİİ}©ÚİİwİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌÌÌÌÌÌÌÌÌÌÌÌİİ"""########### ##""Ñİİİİİİİİİİİİİİİ} ªİ ÜÜÜÜİ­šİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌÌÌÌÌÌÌÌÌÌÌÌİ!""""2"2222222""""!!İİİİİİİİİİİİİİݘ©ª ÍÍÍÍÍİݪª™ØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌÌÌÌÌÌÌÌÌÌÌÌİ"""######3#3#3## ##""Ñİİİİİİİİİİİİİİ—ª ÜÜÌÌÌÜÜÜİ­š×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌÌÌÌÌÌÌÌÌÌÌÌ!! 2"22222222222""""!!İİİİİİİİİİİİİİ— İÍÍÌÍÌÍÍİݪ™×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌÌ"" #####3#3#3#3## ##""İİİİİİİİİİİİİİ—­İÜÌÌÌÌÌÜÜ­­šÙİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌÌ!!" "2222222222222""""!ĞİİİİİİİİİİİİİÚİÍÍÍÌÌÌÍİݪ™×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌÌ"""##3#333333333## ##""Òİİİİİİİİİİİİı™ ĞİÌÌÌÌÌÌÌÜİ­šğİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌ!!""0222222232222220""""!İİİİİİİİİİİİİ©İÍÍÌÌÌÍÍİݪ ×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌ"""# 3#33333333333###""İİİİİİİİİİİİİ—ª ĞÜÌÌÌÌÌÜÜ­­ÙİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌ!!!""2222223232222220""!!Ğİİİİİİİİİİİİ©ÚÀÍÍÌÍÍÍİÚ ×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌ"""##03333333333333# ##"Ğİİİİİİİİİİİİ—ªİ ÌÌÌÜÜÜ š×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ ÌÌÌ!!""2222323232323222"""!!Ñİİİİİİİİİİİİ©ÚÚÍЪ™ØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌÌÌÌÌÌÌÌÌÌÌ"""###033333333333#3###""Òİİİİİİİİİİİİ}™ªİİÜ İ­šyİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÀÌ"""""""ÂÌ!!""""2022323232322222 """İİİİİİİİİİİİ}—©ÚÚİİÍİİİÚª™wİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌ"""""""""""""####333333333333333##"İİİİİİİİİİİİݪªİİÜÜÜİİ­­šÙİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌ ""ÌÌÌÌÌÌÌ,"" !"""22203333333332322"""!İİİİİİİİİİİİİx ©ÚÚİİİİÚªªyØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌ "" """""##3#333333333333###""İİİİİİİİİİİİİ} ªª­­İ­­­ªšyİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌ""""""""""" !""2222203333333232222 ""!İİİİİİİİİİİİİݘ ©ªªÚªªª©™ĞİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌ"""""""ÂÌÌÌÌÌÌÌÌÌ""####33033333333333# #""İİİİİİİİİİİİİİ}™ªªª­ªššyİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ !""222223333333323222""!İİİİİİİİİİİİİİİx—©©©™™wØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ"""##33330333333333###""Ñİİİİİİİİİİİİİİİw™™y×İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ!""222222333333232222"""!İİİİİİİİİİİİİİİİİxw—wwØİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ""####33330333333333###""İİİİİİİİİİİİİİİİİİİıİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ! """222232303333232222 "!İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ ""##3#333333333333### "İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ!""22222232323232222" "İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ"####33333330333333## "İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİ!! ""222222323303222222" ! İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ""####333333303#3####ÒİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ!! ""222222323202222""ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ" ###33333333330#####Ñİİİİİİİİİİİİİİİ""ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ!!"22222222323230""!Ğİİİİİİİİİİİİİİ!!!!!!!!!ĞİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ" ###3#333333333İİİİİİİİİİİİİİ"""""""""ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİ!!"222222222222222 !İİİİİİİİİİİİİ!!!!"""""""!!İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİ"" ###3#333333333#####" Òİİİİİİİİİİİİİ""""#####""ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİ!!""222222222222222"2""" Ñİİİİİİİİİİİİ!!""""""!!İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİ""#####3#3#3#3######""İİİİİİİİİİİİİ""##"ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİ!!!" 2"22222222222"""""!İİİİİİİİİİİİ!!"""2"2""!!İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİ""" ####3#3#3######""Ñİİİİİİİİİİİİ""" #3#3#### "ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİ!!""22222222222""""""İİİİİİİİİİİİ!!"0222222222" !İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİ""""#############""Ñİİİİİİİİİİİİ"" ##3#3#3#####İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİ!!!!""2"2"2""""""!!!Ğİİİİİİİİİİİİ!"0222222222222"!ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİ""""###########""İİİİİİİİİİİİİ""#3#3333333#3### ÒİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİ!!!!"" """"""""!!!Ğİİİİİİİİİİİİ!!022222323222222" İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİ""""" #"#""""İİİİİİİİİİİİİ""###333333333###"İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİ!!!!"""İİİİİİİİİİİİİİ! "2222223232222 İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİ""""""""Ñİİİİİİİİİİİİİİ"###33333333333 # ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİ!!!!!"!"!"!!!!İİİİİİİİİİİİİİİ!! "2222323333322"" !ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİ""""""İİİİİİİİİİİİİİİİ ##33333333333 ##ÒİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİ!!!!!!!!İİİİİİİİİİİİİİİİİ!"222222323332022"!ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİ İİİİİİİİİİİİİİİİİİ"##333333333333##"ÒİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ! ""222233333322""!ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİÑİİİİİİİİİİİİİİİİİİİİİİ "##3333333033###İİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ! "22222233032222"!ÑİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ" ##333333033333##"ÒİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ!!""2222330332322"" !Ñİİİİİİİİİİİİİİ šššİİİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ""##3333333333### Òİİİİİİİİİİİİİ© ªª©™İİİİİİİİİİİİİİİİİİİİÍÌÌÌÌİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİİ!""222232322222"" Ñİİ™™™™™™™™™™™™ ª«««š™™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™""###33333333###"‘™™™™™™™™™™™™™© ºººªª™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ ""222323232222"!™™™™™™™™™™™™™™ª«»«»  š™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ ""#33333333####"™™™™™™™™™™™™™  ººº °ªª™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™!!"22222222222"" !™™™™™™™™™™™™™ª »» °»««š™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™"3#3333333#3##"’™™™™™™™™™™™™™© ºº»»ºª™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ "22222222222"""‘™™™™™™™™™™™™™ª »»»»««š™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ ""####3#3#3#### ™™™™™™™™™™™™™™  °»»ººª™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™!!!""222222222"""!™™™™™™™™™™™™™™ «»»»»««™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™"""####3#3##### "‘™™™™™™™™™™™™™™© º»»»º ™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ !"""2222222"""!™™™™™™™™™™™™™™™   °»»«  š™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™""######### ‘™™™™™™™™™™™™™™™ ªº  ª™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ !!""""""""""!™™™™™™™™™™™™™™™™ ª««»«««š™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™""""#####"‘™™™™™™™™™™™™™™™™™©ªºººªª™™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ !"""""!!!™™™™™™™™™™™™™™™™™™ «««ªš™™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™""""""‘™™™™™™™™™™™™™™™™™™™© ªª©™™™™™™™™™™™™™™™™™™™™™ÉÌÌÌÌ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™!! !!!!‘™™™™™™™™™™™™™™™™™™™™™šªš™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™""‘™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™™™™ùÿÿÿÿÿÿ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™ùÿÿÿÿÿÿ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸ™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™Éò-- title: Basketball and Alarms -- author: RBBS vs TPOLM^2 -- desc: demo for RSync 2026 -- site: -- license: MIT License -- version: 1.0 -- script: lua -- (begin Somatic playroutine) do local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o=peek,math.max,math.floor,false,255,true,80484,nil,{so="$!&+BR!WrQ/\"pYD?$4@7O%M'*_&ebB^'c%&h(Dn#.)]Tk>+!;^N,:\"Q^-R^Dn-S']N#QR4C/M8=r-SI/.-Sctp-SmG52)[BQ3BB5a4[(ea3BoSf4[;;!6:4.07RmRq'c%&h(Dn#.)]Tk>+!=*G8kViP:/?BK\"98E%",extraSongData="#!!`Z.#CrZQ!.Y@V!!a/=!rtUJ!ItCb!#QF3!WW4n!WW4.M\\Z9n'qGC+!!!!R+9m?!#64f@h1,nD!!*1P\"V#u'!Iu3lJ0\"^k.0'HoLPUbBLj+&eG@kH!GB\\74!191S]\"=DfG\\0rE6pt!cG!Q+`q>YsJ!<!C[!m!CQq[!C6]C!c\\4;!bVKB\"(_IQ\"$lpn\")\\)^\"I&no\"E\"2a\"^_7]\"aL+F\"`jZ]#($@7#+>OE#?q2b#?Lm_#_i>k#^ub6#seQ;$)dhJ$CUt-$?#np$VUPE$\\/6O$Y]TK%\"835$srut%X(4-$2(W-7?(QJKB(eXkK(k)HQ)7]bG)3+]T)K>cT)IrhU)gMG:)]/SF)ijuL*/+@r*C^$%*D?G5",cp={"$!!`]nX9em.%=eQ`!\"a_\"/BIkl!!E:u!!!!,!-!Gl$ig@N!.YO[!!]!=aP_$ig;7J-?>]!==8[$ig8-","#!!ri0<\"/hY\"oraq\"U4r1PRRVD!.Yjd!!ri0;ucmu%01s0\"UkA9PRRVD\"ou#\\\"qQ5!!<6]J-H)U%M!K$!!!!/!0mNa!\"ApY\":P82%=eTj!!*CV\"UkA8#lp4jDu]k<","!!!rl1.KBGK#67AH\"U9Ju%\"JHh!!*CV\"UkA3$%O'*J-ubc!=OD]$ig;9J0#,L$OhOi!<6J#n-e9%01F!#n-e?\"9>4t!!!H.EI\\2s!!7]OJ-Z/U!sAV\"J-cX7$ip>1\"9>6J%1n$q!<KQ\"U9J[$igM=!,DrBCB/l+!It=S!!%01s0#7pk=!!!3'Mgu3H!!<3$!.YRjJ/&(b!t>6]J-cVa#7^aW!!!!.J-?,W!==8[\"onZ6J-?,W!=aP_\"onZ1J-QJ_\"G$OQ!!!!!","$!!EQ-+om-'!<<3-!$Zps\"on[VJ-QX9*W^d4!<<9'!!iQKJ.3%i\"TSN.!$Zps\"on[6J-QVc\"TSN4!$Zq\"%\"JN_!!s,8+ohTC#QS@b#7uD(!<<*\"","!!!*(M\"T\\T*\"9>9K#mPna!<<3)!5sBq$ig=)J-cF1\"p'5Y%\"JNdJ-H#S!sAV\"J-ubc!Mt;Q#(QmYJ-HF4\"pTS^!<<3)!2P,Q$ig=)J-ubc!Mk5L\"on\\#J-cF1\"p\"]+\"9>6J$Od\"9V18jV","$!&=p(V@XaJ+<(;7)#uo#0Gsj5)ZUEi!!!!!","$!!EQ--iec-!<0 do local y,z=a(q+r),8-s local aa=v>s&ab w=w|ac<=8 then s=0 r=r+1 end x=x+aa v=v-aa end return w end local function ad(ae) local af,ag=u(ae),1<=1 then return 1 end local du=dt/31 du=cc(du,-1,1) if du==0 then return ds end local dv=2^(4*math.abs(du)) return du>0 and ds^dv or 1-(1-ds)^dv end local function dw(dx,dy) local dz=p(j+dx*bx) for ea=0,by-1 do dy[ea]=dz.u(4) end end local function eb(ec,ed) local ee,ef=j+ec*bx,0 for eg=0,bx-1 do local eh,ei=ci(ed[ef]),ci(ed[ef+1]) poke(ee+eg,ei<<4|eh) ef=ef+2 end end local function ej(ek,el) local em=cg(1-el) em=em*em local en,eo,ep=by,.03+.95*em,0 for eq=0,en-1 do ep=ep+ek[eq] end local er=ep/en local function es(et,eu,ev) for ew=et,eu,ev do local ex=ek[ew] er=er+eo*(ex-er) ek[ew]=er end end es(0,en-1,1) es(en-1,0,-1) end local ey={} local function ez(fa,fb) local fc=fb or 1 if fc<=1.001 then return end local fd=by for fe=0,fd-1 do ey[fe]=fa[fe] end for ff=0,fd-1 do local fg=ff/fd*fc local fh=c(fg) local fi=fg-fh local fj=fi*fd local fk=c(fj) local fl,fm,fn=fj-fk,(fk+1)%fd,ey[fk] local fo=ey[fm] local fp=fn+(fo-fn)*fl fa[ff]=fp end end local fq,fr,fs,ft,fu={},{},{},{},g local function fv(fw,fx,fy,fz,ga,gb) if fw==bb then local gc=ga if gc<=0 then return 0 end local gd=fz%gc/gc return (1-math.cos(gd*math.pi*2))*.5 end if fx==h or fx<=0 then return gb end return cg(fy/fx) end local function ge(gf) if not gf then return d end local gg=gf.b if gg==bc then return f end if gg==be then return f end if gf.i then return f end local gh=gf.m if gh==bg and gf.n>0 then return f end return d end local function gi(gj,gk,gl) gk[gl]=gj&15 gk[gl+1]=gj>>4&15 return gl+2 end local function gm(gn) if gn==h or gn<=0 then return h end local go=ft[gn] if go~=h then return go or h end local gp=as(fu+gn) if gp==h or #gp==0 then ft[gn]=d return h end for gq=1,#gp do local gr,gs,gt=gp[gq].waveBytes,{},0 for gu=1,16 do gt=gi(gr[gu] or 0,gs,gt) end gp[gq].samples=gs end ft[gn]=gp return gp end local function gv(gw,gx,gy) local gz=gw.morphGradientNodes local ha=#gz if gz==h or ha==0 then return d end if ha==1 then local hb=gz[1].samples for hc=0,by-1 do gy[hc]=hb[hc] end return f end local hd,he,hf=gx,ha-1,1 for hg=1,ha-1 do local hh=gz[hg].durationTicks10 if hh>0 then if hd0 then hs=hq%hr/hr end local ht if hs<.5 then ht=hs*4-1 else ht=3-hs*4 end local hu=hn.f+hn.g*ht hu=cc(hu,1,30) local hv=hu/31*by for hw=0,by-1 do hp[hw]=hw0 and io>0 then local iq=fv(ii.q,ii.o,ik,il,ii.h,0) local ir=1-dr(iq,ii.p) local is=1+ii.n/e*io*7*ir ez(fq,is) end if ii.i then local it=fv(ii.l,ii.j,ik,il,ii.h,1) local iu=dr(it,ii.k) ej(fq,iu) end eb(ii.d,fq) end local function iv(iw,ix) local iy=bv and bv[iw] if not ge(iy) then return end local iz,ja=fr[iw],br[(ix or 0)+1] or e ih(iy,iw,0,iz,ja) end local function jb(jc,jd) local je=p(l+jc*bz+jd*3) return je.u(6),je.u(6),je.u(6),je.u(6) end local function jf(jg,jh) if jg==h or jg==0 then return 0,0 end local ji=jg-1 local jj=k+ji*ca+jh*cb local jk,jl,jm=a(jj),a(jj+1),a(jj+2) local jn,jo=jk&15,jm&31|(jl>>7&1)<<5 return jn,jo end local function jp(jq,jr) return i.songOrder[jq*4+jr+1] end local function js(jt,ju,jv) if jt==bs and ju==bt and jv==bu then return end bs=jt bt=ju bu=jv local jw=b(0,bh-1) local jx,jy,jz,ka=jb(jt,ju) local kb={jx,jy,jz,ka} for kc=0,bo-1 do local kd=jp(jw,kc) local ke=kd~=h and bw[kd] or h local kf=ke and ke[jv+1] or h if kf and kf.effectId==1 then br[kc+1]=kf.paramU8 or e elseif kf and kf.effectId==2 then local kg=bp[kc+1] if kg and kg>=0 then local kh=bv and bv[kg] local ki=kh and kh.h or 0 if ki>0 then fr[kg]=c((kf.paramU8 or 0)/e*ki) end end end local kj=kb[kc+1] local kk,kl=jf(kj,jv) if kk==0 then elseif kk<4 then bp[kc+1]=-1 bq[kc+1]=0 else bp[kc+1]=kl bq[kc+1]=0 iv(kl,kc) end end end local function km(kn) local ko=bp[kn+1] if ko==-1 then return end local kp,kq=bq[kn+1],bv and bv[ko] if not ge(kq) then bq[kn+1]=kp+1 return end local kr,ks=fr[ko],br[kn+1] or e ih(kq,ko,kp,kr,ks) bq[kn+1]=kp+1 end local function kt(ku,kv,kw) js(ku,kv,kw) for kx=1,#fs do local ky=fs[kx] fr[ky]=fr[ky]+1 end for kz=0,bo-1 do km(kz) end end local function la() local lb=i.extraSongData if not lb then return end bv={} bw={} fs={} ft={} dn(lb,g) local lc,ld,le=a(g),a(80485),g+n for lf=1,lc do local lg=ah(le) local lh=lg.a lg.i=lg.i~=0 if lg.b==bc then lg.morphGradientNodes=gm(lg.e or 0) end bv[lh]=lg fs[#fs+1]=lh le=le+m end for li=1,ld do local lj=al(le) bw[lj.patternIndex]=lj.cells le=le+o end end la() function somatic_get_song_order_count() return #i.songOrder/4 end local function lk(ll,lm) local ln,lo,lp=dn(ll,g),p(g),{} local lq=ln*8//lm for lr=1,lq do lp[lr]=lo.u(lm) end return lp end i.rpd=lk(i.rp,16) i.songOrder=lk(i.so,8) local function ls(lt,lu) local lv=i.rpd local lw=#lv/2 if lt=mq then for mr=0,bl-1 do poke(mp+mr,0) end bk=f return end ly(bh,mp) end end -- (end Somatic playroutine) -- example main loop... local lastKnownOrder = 0 local lastKnownRow = 0 ---------------- ----- GFX ------ ---------------- local scene_frame = 0 -- frames in current scene local sweetie16_pal = "1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57" -- set the palette function tovram(str) local o = 0 for c = 1, #str, 2 do -- walk colors local v = tonumber(str:sub(c, c + 1), 16) -- get color (v)alue poke(0x3fc0 + o, v) o = o + 1 -- set color end end function sweetie16_init() tovram(sweetie16_pal) poke(0x3FF8, 0) -- border poke(0x3FF9, 0) -- screen offset poke(0x3FFA, 0) end function no_fn() end function playroutine() cls(0) local y = 2 print("PLAYROUTINE TEST", 52, y, 12) y = y + 8 -- "track" is -1 otherwise kinda worthless -- "playingSongOrder" is the song order index of the pattern currently being played (0-255) -- "currentFrame" is the TIC-80 internal frame counter; kinda worthless. -- "currentRow" is the current row within the pattern being played (0-63). local track, playingSongOrder, currentFrame, currentRow = somatic_get_state() print(string.format("t:%d ord:%d f:%d r:%d", track, playingSongOrder, currentFrame, currentRow), 60, y, 6) y = y + 8 for ch = 0, 3 do local sid, ticks = somatic_get_channel_state(ch) print(string.format("ch%d sfx:%d t:%d", ch, sid, ticks), 60, y, 12) y = y + 8 end end function intro_init() sweetie16_init() end function intro_scene() cls() print("Photosensitivy Warning", 60, 20, (time() // 500 % 2) * 2) end function alarmclock_init() sweetie16_init() end function alarmclock_scene() poke(0x3FF8, 15) cls(15) local px = 140 local py = 0 local dx = 61 local dy = 41 rect(px, py, dx, dy, 2) for i = py, py + dy, 10 do circ(px, i, 3, 2) circ(px + dx - 1, i, 3, 2) end for i = px, px + dx, 10 do circ(i, py + dy - 1, 3, 2) end rect(px + 4, 0, dx - 8, dy - 4, 12) clip(px + 4, 0, dx - 8, dy - 4) circ(px + 10, py + dy, 20, 3) circ(px + 20, 0, 10, 9) circ(px + 50, 30, 20, 4) clip() rect(0, 80, 240, 136, 3) local shakex = math.random() * 5 - 3 rect(80 + shakex, 58, 50, 2, 12) rect(40 + shakex, 60, 170, 60, 12) rect(46 + shakex, 66, 156, 46, 0) print("07:00", 50 + shakex, 76, 6, 0, 5) end function alarmclock_bdr(l) if l > 83 then poke(0x3FF8, 3) end end function alarmclockg_scene() alarmclock_scene() print("Greetings fly out to", 10, 20, 4) end local abs = math.abs local sin = math.sin local cos = math.cos -- enfys bytejam function cooking_scene() poke(0x3FF8, 6) cls(8) local t = time() / 100 local fv = -abs(sin(t / 4) * 16) local fv2 = -abs(sin(t / 4 - 0.2) * 32) local fv3 = -abs(sin(t / 4 - 0.4) * 32) local fv4 = -abs(sin(t / 4 - 0.6) * 32) local fv5 = -abs(sin(t / 4 - 0.8) * 32) for i = 0, 16 do rect(0 + i * 22, 0, 20, 136, 6) rect(0 - 2 + i * 22, 0, 2, 136, 5) end rect(20, 10, 80, 80, 12) rect(22, 12, 76, 76, 10) rect(16, 85, 100, 6, 12) for i = 0, 32 do line(60 - i, 80 + i, 170 + i, 80 + i, 13) end rect(60, 50, 110, 30, 14) rect(28, 113, 175, 24, 14) elli(115, 98, 18, 4, 14) elli(115, 96, 18, 4, 15) elli(70, 98, 18, 4, 14) elli(70, 96, 18, 4, 15) elli(160, 98, 18, 4, 14) elli(160, 96, 18, 4, 15) for i = 0, 12 do elli(115 + sin(i / 2) * 16, 95 + cos(i / 2) * 4, 1, 2, 3 + math.random() * 2) end elli(120, 85 + fv, 32, 11, 0) elli(120, 85 + fv, 30, 9, 14) elli(120, 83 + fv, 30, 7, 15) rect(151, 83 + fv, 25, 3, 15) rect(151, 84 + fv, 25, 3, 14) for i = 0, 8 do line(180, 80 + i + fv, 240, 78 + i, 2) end elli(170, 83 + fv, 15, 8, 4) for i = 0, 5 do circ(44 + (i * 28), 128, 5, 1) end --sosig :) for i = 0, 8 do circ(105 + sin(i / 4 - 1 + sin(t / 2) / 2) * 12, 68 + cos(i / 4 - 1 + sin(t / 2) / 2) * 12 + fv3, 4, 2) end for i = 0, 8 do circ(105 + sin(i / 4 - 1 + sin(t / 2) / 2) * 12, 68 + cos(i / 4 - 1 + sin(t / 2) / 2) * 12 - 2 + fv3, 1, 3) end --egg for i = 0, 18 do circ(115 + sin(i + t / 8) * 4, 78 + cos(i + t / 8) * 2 + fv2, 2, 4) circ(115 + sin(i + t / 8) * (8 + fv2 / 8 + 2), 78 + cos(i + t / 8) * 4 + fv2, 2, 12) end for i = 0, 30 do circ(115 + i, 68 + sin(i / 2) * (2 + sin(t / 2 + 1)) + fv5, 1, 1) circ(115 + i, 68 + sin(i / 2) * (2 + sin(t / 2 + 1)) + 2 + fv5, 1, 2) circ(115 + i, 68 + sin(i / 2) * (2 + sin(t / 2 + 1)) + 4 + fv5, 1, 1) circ(115 + i, 68 + sin(i / 2) * (2 + sin(t / 2 + 1)) + 6 + fv5, 1, 2) end for i = 0, 8 do circ(135 + sin(i / 4 - 1 - sin(t / 2 + 1) / 2) * 12, 68 + cos(i / 4 - 1 - sin(t / 2 + 1) / 2) * 12 + fv4, 4, 2) end for i = 0, 8 do circ( 135 + sin(i / 4 - 1 - sin(t / 2 + 1) / 2) * 12, 68 + cos(i / 4 - 1 - sin(t / 2 + 1) / 2) * 12 - 2 + fv4, 1, 3 ) end end function cookingg_scene() poke(0x3FF8, 6) cls(8) local t = time() / 100 local fv = -abs(sin(t / 4) * 16) local fv2 = -abs(sin(t / 4 - 0.2) * 32) local fv3 = -abs(sin(t / 4 - 0.4) * 32) local fv4 = -abs(sin(t / 4 - 0.6) * 32) local fv5 = -abs(sin(t / 4 - 0.8) * 32) for i = 0, 16 do rect(0 + i * 22, 0, 20, 136, 6) rect(0 - 2 + i * 22, 0, 2, 136, 5) end rect(20, 10, 80, 80, 12) rect(22, 12, 76, 76, 10) rect(16, 85, 100, 6, 12) for i = 0, 32 do line(60 - i, 80 + i, 170 + i, 80 + i, 13) end rect(60, 50, 110, 30, 14) rect(28, 113, 175, 24, 14) elli(115, 98, 18, 4, 14) elli(115, 96, 18, 4, 15) elli(70, 98, 18, 4, 14) elli(70, 96, 18, 4, 15) elli(160, 98, 18, 4, 14) elli(160, 96, 18, 4, 15) for i = 0, 12 do elli(115 + sin(i / 2) * 16, 95 + cos(i / 2) * 4, 1, 2, 3 + math.random() * 2) end elli(120, 85 + fv, 32, 11, 0) elli(120, 85 + fv, 30, 9, 14) elli(120, 83 + fv, 30, 7, 15) rect(151, 83 + fv, 25, 3, 15) rect(151, 84 + fv, 25, 3, 14) for i = 0, 8 do line(180, 80 + i + fv, 240, 78 + i, 2) end elli(170, 83 + fv, 15, 8, 4) for i = 0, 5 do circ(44 + (i * 28), 128, 5, 1) end print("Slipstream", 90 + sin(sin(t / 2) / 2) * 12, 68 + cos(sin(t / 2) / 2) * 12 + fv3, 12) print("RBBS", 115 + sin(t / 8) * 4, 78 + cos(t / 8) * 2 + fv2, 12) print("TPOLM", 130 + sin(-sin(t / 2 + 1) / 2) * 12, 66 + cos(-sin(t / 2 + 1) / 2) * 12 + fv4, 12) end -- enfys bytejam function tram_scene() poke(0x3FF8, 11) cls(11) local t = time() / 100 for j = 0, 8 do for i = 0, 16 do circ((j * 64) - t * 8 % 128, 98 - i * 4, 6, 1) end for i = 0, 7 do circ((j * 64) - t * 8 % 128, 58 - i * 4, 15, 5) end end rect(0, 100, 240, 40, 13) circ(56, 104, 8, 15) circ(86, 104, 8, 15) circ(156, 104, 8, 15) circ(186, 104, 8, 15) rect(56, 106, 30, 4, 14) rect(156, 106, 30, 4, 14) line(0, 108, 240, 108, 14) tram(0, -1 + math.sin(t / 2)) line(0, 113, 240, 113, 14) line(0, 8, 240, 8, 14) line(0, 7, 240, 7, 14) for j = 0, 3 do for i = 0, 50 do rect(0 + i * 5 - t * 8 % 5, 116 + j * 5, 4, 4, 14) end end end function tram(x, y) rect(30 + x, 80 + y, 190, 30, 4) rect(30 + x, 50 + y, 190, 30, 12) for i = 0, 7 do rect(31 + i * 24 + x, 51 + y, 20, 28, 10) end tri(224 + x, 80 + y, 220 + x, 110 + y // 1, 230 + x, 110 + y // 1, 4) rect(220 + x, 50 + y, 5, 30, 12) rect(220 + x, 80 + y, 5, 30, 4) rect(221 + x, 51 + y, 3, 28, 10) rect(197 + x, 51 + y, 22, 50, 4) rectb(197 + x, 51 + y, 22, 50, 15) rect(199 + x, 53 + y, 8, 22, 10) rect(209 + x, 53 + y, 8, 22, 10) rect(199 + x, 77 + y, 8, 22, 10) rect(209 + x, 77 + y, 8, 22, 10) rect(197 - 166 + x, 51 + y, 22, 50, 4) rectb(197 - 166 + x, 51 + y, 22, 50, 15) rect(199 - 166 + x, 53 + y, 8, 22, 10) rect(209 - 166 + x, 53 + y, 8, 22, 10) rect(199 - 166 + x, 77 + y, 8, 22, 10) rect(209 - 166 + x, 77 + y, 8, 22, 10) rect(32 + x, 46 + y, 190, 4, 12) rect(36 + x, 42 + y, 182, 4, 14) rect(197 + x, 101 + y, 22, 5, 14) rect(31 + x, 101 + y, 22, 5, 14) for i = 0, 3 do line(160 + i + x // 1, 41 + y // 1, 130 + i + x // 1, 20 + y // 1, 15) line(160 + i + x // 1, 10 + y // 1, 130 + i + x // 1, 20 + y // 1, 15) end local posx = 64 rect(posx, 82 + y, 120, 22, 12) print("TPOLM", posx + 6, 84 + y, 2, 0, 2) print("cosmetics for cats!", posx + 36, 96 + y, 1, 0, 1, 1) --print("For",posx+82,87+y,6,0,1) --print("cats!",posx+98,95+y,7,0,1,1) --line(posx+106,105+y,posx+118,105+y,0) end function tram_bdr(l) if l > 10 and l < 13 then poke(0x3FF8, 14) elseif l > 103 then if l == 112 or l == 117 or l > 119 then poke(0x3FF8, 14) else poke(0x3FF8, 13) end else poke(0x3FF8, 11) end end local tst = 0 function tramg_init() sweetie16_init() tst = time() end function tramg_scene() poke(0x3FF8, 11) cls(11) local t = (time() - tst) / 100 for j = 0, 8 do for i = 0, 16 do circ((j * 64) - t * 8 % 128, 98 - i * 4, 6, 1) end for i = 0, 7 do circ((j * 64) - t * 8 % 128, 58 - i * 4, 15, 5) end end local groups = { "Fulcrum", "Treepan", "Rivals", "Rift", "Flush", "FairLight", "Atlantis", "Jumalauta", "TPOLM", "Fire", "DESiRE", "Resource", "Eucalyptus", "LFG", "OftenHide", "Marquee Design", "Otomata Labs", "Forsaken", "Stargaze", "5711", "Haujobb", "Team 210", "Rebels", "Spectrox", "F4CG", "AMMB", "and you...", } math.randomseed(1) for i = 1, #groups do print(groups[i], 240 + i * 36 - t * 6, 12 + (i * 6) % 20, 8, 2) end rect(0, 100, 240, 40, 13) circ(56, 104, 8, 15) circ(86, 104, 8, 15) circ(156, 104, 8, 15) circ(186, 104, 8, 15) rect(56, 106, 30, 4, 14) rect(156, 106, 30, 4, 14) line(0, 108, 240, 108, 14) tram(0, -1 + math.sin(t / 2)) line(0, 113, 240, 113, 14) line(0, 8, 240, 8, 14) line(0, 7, 240, 7, 14) for j = 0, 3 do for i = 0, 50 do rect(0 + i * 5 - t * 8 % 5, 116 + j * 5, 4, 4, 14) end end end function draw_court(offsetX) offsetX = offsetX or 0 local GROUND_STRIP_HEIGHT = 40 rect(0, 136 - GROUND_STRIP_HEIGHT, 240, GROUND_STRIP_HEIGHT, 9) -- ground -- draw hoop rect(85 + offsetX, 52, 9, 60, 12) rect(60 + offsetX, 20, 60, 40, 12) rect(64 + offsetX, 24, 52, 32, 0) rect(79 + offsetX, 38, 21, 16, 12) rect(83 + offsetX, 42, 13, 8, 0) ellib(89 + offsetX, 53, 12, 2, 2) ellib(89 + offsetX, 54, 12, 2, 2) end function basket_scene() poke(0x3FF8, 13) cls(13) draw_court() -- print("tpolm",96,24,12,0,1,1) end function basket_bdr(l) if l > 99 then poke(0x3FF8, 9) end end local sqrt = math.sqrt local min = math.min local max = math.max local frame = 0 local TIC80_WIDTH = 240 local TIC80_HEIGHT = 136 local GROUND_COLOR = 9 -- BASKETBALL STATE / PARAMS local X = 80 local Y = 60 local BALL_RADIUS = 23 local SHADOW_COL_DEFAULT = 15 local SEAM_COL_DEFAULT = 0 local BALL_RAMP_DEFAULT = { 0, 1, 2, 3 } -- palette dark -> light local BALL_RAMP_BLUE = { 8, 9, 10, 11 } -- the only other nice-looking one i found. local SHADE_MIN = 0.2 -- ball shading range local SHADE_MAX = 1.0 local groundY = TIC80_HEIGHT - 4 local HMAX = 90 -- height when shadow is smallest local rotX = 0.0 -- rot state local rotY = 0.5 local rotZ = 0.61 -- we don't have actual 3D perspective; it's just a 2D circle and we calc -- Z. based on Z, fake perspective by scaling seam widths and AA. local SEAM_WIDTH_MIN = 0.01 -- seam width at max distance local SEAM_WIDTH_MAX = 0.06 -- seam width when closest -- ellipse loops implicit distance field params local ratio = 0.57 local az = 1 local k = 0.5 -- light dir in view space local lx, ly, lz = 0.25, 0.33, 1.0 -- animation stuff local DX = 1. local DY = 0 local AUTO_ROTX_SPEED = 0.02 local AUTO_ROTY_SPEED = 0.03 local AUTO_ROTZ_SPEED = 0.01 local GRAVITY_STRENGTH_DEFAULT = 0.3 local AUTOROTATE_EXTENT = 0.1 -- utilities local function clamp(x, a, b) if x < a then return a end if x > b then return b end return x end local function smoothstep(edge0, edge1, x) local t = clamp((x - edge0) / (edge1 - edge0), 0, 1) return t * t * (3 - 2 * t) end local function rot3D(x, y, z, rx, ry, rz) local cz = cos(rz) local sz = sin(rz) local x1 = x * cz - y * sz local y1 = x * sz + y * cz local z1 = z local cy = cos(ry) local sy = sin(ry) local x2 = x1 * cy + z1 * sy local y2 = y1 local z2 = -x1 * sy + z1 * cy local cx = cos(rx) local sx = sin(rx) local x3 = x2 local y3 = y2 * cx - z2 * sx local z3 = y2 * sx + z2 * cx return x3, y3, z3 end -- sample bayer 4x4 matrix at integral pixel (x,y) in [0..1] local function bayer4(x, y) x = math.floor(x) y = math.floor(y) local xi = x % 4 local yi = y % 4 local v if yi == 0 then v = ({ 0, 8, 2, 10 })[xi + 1] elseif yi == 1 then v = ({ 12, 4, 14, 6 })[xi + 1] elseif yi == 2 then v = ({ 3, 11, 1, 9 })[xi + 1] else v = ({ 15, 7, 13, 5 })[xi + 1] end return (v + 0.5) / 16 end -- int pixel (x,y), coverage cov in [0..1], palette indices colA,colB -- returns either colA or colB based on dithering local function dither_lerp(x, y, cov, colA, colB) if cov <= 0 then return colB end if cov >= 1 then return colA end return (cov > bayer4(x, y)) and colA or colB end local function lerp(a, b, t) return a + (b - a) * t end -- shade -> palette index. loses chroma; this is grayscale -> dithered palette. local function dither_ramp(x, y, shade, ramp) shade = clamp(shade, 0, 1) local n = #ramp if n <= 1 then return ramp[1] end -- which two colors to dither between local p = shade * (n - 1) local i = math.floor(p) if i >= n - 1 then return ramp[n] end -- lightest local frac = p - i return dither_lerp(x, y, frac, ramp[i + 2], ramp[i + 1]) end -- intersection of unit sphere with plane through origin. -- If plane normal is N, seam is where dot(P, N) = 0. -- Distance to seam band is approx |dot(P,N)| local function sdf_great_circle(Px, Py, Pz, Nx, Ny, Nz) return abs(Px * Nx + Py * Ny + Pz * Nz) end -- Approx distance to implicit surface/curve f(P)=0: -- dist ~ |f| / |grad f| local function sdf_implicit(f, gx, gy, gz) local g = sqrt(gx * gx + gy * gy + gz * gz) if g < 1e-6 then return 1e9 end return abs(f) / g end -- ellipse-loop seams: implicit function that produces two opposing loops (mirror around sign) -- Parameters: -- ay, az: ellipse axis scales (eccentricity-ish) -- k: pushes loops away from meridian (x=0); 01 = tall, <1 = squished -- visual params ballRamp = opts.ballRamp or BALL_RAMP_DEFAULT, seamColor = opts.seamColor or SEAM_COL_DEFAULT, shadowColor = opts.shadowColor or SHADOW_COL_DEFAULT, -- radius pulsing radiusPulseMin = opts.radiusPulseMin or 10, radiusPulseMax = opts.radiusPulseMax or 40, radiusPulseSpeed = opts.radiusPulseSpeed or 0.04, radiusPulseOffset = opts.radiusPulseOffset or 0, -- phase offset } setmetatable(self, Basketball) return self end function Basketball:reset_autorotate() local e = self.autorotateExtent self.autoRotXSpeed = lerp(-e, e, math.random()) self.autoRotYSpeed = lerp(-e, e, math.random()) -- self.autoRotZSpeed = lerp(-e, e, math.random()) end function Basketball:randomize() self:reset_autorotate() self.dx = lerp(0.5, 3.0, math.random()) * (math.random(2) <= 1 and -1 or 1) self.dy = lerp(0.5, 3.0, math.random()) * (math.random(2) <= 1 and -1 or 1) self.radius = lerp(4, 16, math.random()) if math.random(2) <= 1 then self.ballRamp = BALL_RAMP_DEFAULT else self.ballRamp = BALL_RAMP_BLUE end end -- update physics & rotation, including bounces function Basketball:update(frameIdx, bounceEnergyEnabled, applyGravity) self.rotY = self.rotY + self.autoRotYSpeed self.rotX = self.rotX + self.autoRotXSpeed self.rotZ = self.rotZ + self.autoRotZSpeed self.x = self.x + self.dx self.y = self.y + self.dy if applyGravity then self.dy = self.dy + (self.gravityStrength or GRAVITY_STRENGTH_DEFAULT) end -- horizontal bounces if self.x < self.radius then self.x = self.radius self.dx = -self.dx self:reset_autorotate() elseif self.x > (TIC80_WIDTH - self.radius) then self.x = TIC80_WIDTH - self.radius self.dx = -self.dx self:reset_autorotate() end -- vertical bounces if self.y < self.radius then self.y = self.radius self.dy = -self.dy self:reset_autorotate() elseif self.y > (groundY - self.radius) then self.y = groundY - self.radius -- random bounce energy. if bounceEnergyEnabled then self.dy = lerp(-1, -8, math.random()) else self.dy = -self.dy end self:reset_autorotate() end end local function draw_shadow(ball) local ballX, ballY, r = ball.x, ball.y, ball.radius local h = groundY - (ballY + r) local u = clamp(h / HMAX, 0, 1) local rx = r * 1 - u -- shrinks with height local ry = 1 + r * u * 0.15 -- flatter with height elli(ballX, groundY, rx, ry, ball.shadowColor or SHADOW_COL_DEFAULT) end local function draw_bball(ball) local cx, cy, R = ball.x, ball.y, ball.radius local BALL_RAMP = ball.ballRamp or BALL_RAMP_DEFAULT local SEAM_COL = ball.seamColor or SEAM_COL_DEFAULT -- constant-area local s = sqrt(ball.aspect) local rx = R / s local ry = R * s local rz = rx local yextent = math.floor(ry + 0.5) -- scanline ellipse bounds for sy = -yextent, yextent do -- screen y local yn = sy / ry local inside2 = 1 - yn * yn if inside2 >= 0 then -- early out optimization local xspan = math.floor(rx * sqrt(inside2) + 0.5) -- ellipse x extent for sx = -xspan, xspan do -- screen x local screenX, screenY = cx + sx, cy + sy -- unit-sphere param (for seams / rotation) local ux = sx / rx local uy = sy / ry local u2 = ux * ux + uy * uy local z2 = 1 - u2 if z2 >= 0 then local uz = sqrt(z2) -- on unit sphere -- cheaper shading just using z local shade = lerp(SHADE_MIN, SHADE_MAX, uz) local base = dither_ramp(screenX, screenY, shade, BALL_RAMP) -- seam space uses rotated unit-sphere point local px, py, pz = rot3D(ux, uy, uz, ball.rotX, ball.rotY, ball.rotZ) local seam_w = lerp(SEAM_WIDTH_MIN, SEAM_WIDTH_MAX, uz) local d = sdf_great_circle(px, py, pz, 0, 1, 0) -- Equator d = min(d, sdf_great_circle(px, py, pz, 1, 0, 0)) -- Meridian d = min(d, sdf_ellipse_loops(px, py, pz, ratio, az, k)) local seam_cov = (d - seam_w) < 0 and 1 or 0 local col = seam_cov > 0 and SEAM_COL or base -- step; no AA. pix(screenX, screenY, col) end end end end end function Basketball:draw(shadow) if shadow==true then draw_shadow(self) end draw_bball(self) end ------------------------------------------------------------------------ -- random balls = gravity-affected, bouncing balls with different sizes/speeds local random_balls = { Basketball.new({ radius = 10, dx = -0.2, dy = -0.1, --gravityStrength = 0.05, ballRamp = { 8, 9, 10, 11 }, -- blue ramp }), Basketball.new({ radius = 16, dx = 0.5, dy = 0.2, --gravityStrength = 0.05, ballRamp = { 0, 15, 8, 7, 9, 10, 13, 12 }, -- full palette luma ramp }), Basketball.new({ -- big boy radius = 24, dx = 0.4, dy = 1, }), Basketball.new({ radius = 32, dx = 1.2, dy = 1, }), } function balls_scene_random() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- update balls for i = 1, #random_balls do random_balls[i]:update( frame, true, -- bounce energy enabled true -- gravity enabled ) end -- animate court local movementSpeed = 0.4 draw_court(scene_frame * movementSpeed - 30) for i = 1, #random_balls do random_balls[i]:draw(true) end end ------------------------------------------------------------------------ -- another scene with just floating random balls in various directions. do local floating_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), } for i = 1, #floating_balls do floating_balls[i]:randomize() end function balls_scene_floating() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- update balls for i = 1, #floating_balls do floating_balls[i]:update( frame, false, -- no bounce energy false -- no gravity ) end -- animate court local movementSpeed = 0.25 draw_court(scene_frame * movementSpeed - 30) for i = 1, #floating_balls do floating_balls[i]:draw(true) end end end ------------------------------------------------------------------------ -- another scene with just floating random balls in various directions. do local axis_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), } local speed = 3 for i = 1, #axis_balls do axis_balls[i]:randomize() axis_balls[i].dx = speed * (math.random(2) == 1 and -1 or 1) axis_balls[i].dy = speed * (math.random(2) == 1 and -1 or 1) end function balls_scene_axis() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- update balls for i = 1, #axis_balls do axis_balls[i]:update( frame, false, -- no bounce energy false -- no gravity ) end -- animate court local movementSpeed = 0.25 draw_court(scene_frame * movementSpeed - 30) for i = 1, #axis_balls do axis_balls[i]:draw(true) end end end ------------------------------------------------------------------------ -- bball scene with more ordered placement do local movementSpeed = 0.4 local local_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), -- Basketball.new({}), -- Basketball.new({}), -- Basketball.new({}), -- Basketball.new({}), } local spread_x = 80 -- how much to space out over sin wave local offset_x = 120 for i = 1, #local_balls do -- distribute evenly over screen Y -- and over a sin wave in X local t = (i - 1) / (#local_balls - 1) local_balls[i].radius = 7 local minY = local_balls[i].radius local maxY = groundY - local_balls[i].radius local_balls[i].y = lerp(minY, maxY, t) local_balls[i].x = offset_x + math.sin(t * math.pi * 2) * spread_x local_balls[i].dx = -movementSpeed --1.5 -- fixed speed to keep order local_balls[i].dy = 1.5 -- fixed speed to keep order end function balls_scene_sin() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- update balls for i = 1, #local_balls do local_balls[i]:update( frame, false, -- no bounce energy false -- no gravity ) end -- animate court draw_court(scene_frame * movementSpeed * 0.4 - 30) for i = 1, #local_balls do local_balls[i]:draw(true) end end end ------------------------------------------------------------------------ -- bball scene with rotating mvmt do local local_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), } for i = 1, #local_balls do local t = (i - 1) / (#local_balls - 1) local_balls[i].radius = 10 local minX = local_balls[i].radius local maxX = TIC80_WIDTH - local_balls[i].radius -- distribute evenly over screen X (because it's wider.) local_balls[i].x = lerp(minX, maxX, t) local_balls[i].y = TIC80_HEIGHT // 2 local_balls[i].angle_speed = lerp(0.01, 0.05, t) end function update_rotating_ball(ball) ball.rotY = ball.rotY + ball.autoRotYSpeed ball.rotX = ball.rotX + ball.autoRotXSpeed ball.rotZ = ball.rotZ + ball.autoRotZSpeed local angle_speed = ball.angle_speed*2 local cos_a = cos(angle_speed) local sin_a = sin(angle_speed) local x = ball.x - TIC80_WIDTH / 2 local y = ball.y - groundY / 2 local new_x = x * cos_a - y * sin_a local new_y = x * sin_a + y * cos_a ball.x = new_x + TIC80_WIDTH / 2 ball.y = new_y + groundY / 2 end function balls_scene_rotating() frame = frame + 1 poke(0x3FF8, 13) cls(13) for i = 1, #local_balls do update_rotating_ball(local_balls[i]) end -- animate court local movementSpeed = 0.25 draw_court(scene_frame * movementSpeed - 30) for i = 1, #local_balls do local_balls[i]:draw(true) end end end ------------------------------------------------------------------------ -- bball scene with infinite X scrolling do local local_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), } local N = #local_balls local radius = 10 local spacing = (TIC80_WIDTH + radius * 2) / N local period = spacing * N local scrollX = 0 local speed = 2 for i = 1, N do local b = local_balls[i] b.radius = radius b.baseX = (i - 1) * spacing b.y = radius end local function wrap(x, m) return x - math.floor(x / m) * m end function balls_scene_scrolling() frame = frame + 1 poke(0x3FF8, 13) cls(13) scrollX = scrollX + speed -- animate court local movementSpeed = 0.25 draw_court(scene_frame * movementSpeed - 30) for i = 1, N do local b = local_balls[i] b.rotY = b.rotY + b.autoRotYSpeed b.rotX = b.rotX + b.autoRotXSpeed b.rotZ = b.rotZ + b.autoRotZSpeed local xw = wrap(b.baseX + scrollX, period) b.x = xw - radius -- shifts so one is off screen left when scrollX=0 b:draw(true) end end end ------------------------------------------------------------------------ -- bball scene: stationary, but animated aspect ratio do local movementSpeed = 0.5 local local_balls = { Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), Basketball.new({}), } local N = #local_balls for i = 1, N do local t = (i - 1) / (N - 1) local b = local_balls[i] b:randomize() b.ramp = BALL_RAMP_DEFAULT -- color cycles b.radius = lerp(10, 20, t) b.x = lerp(b.radius, TIC80_WIDTH - b.radius, t) -- keep y random. b.dx = movementSpeed b.dy = 0 b.aspect_t = lerp(-1, 1, t) end local maxAspect = 5 function aspect_from_N11(t, max) -- helps make a better linearly animatable param -- maxAspect e.g. 3.0 means range is [1/3 .. 3] return maxAspect ^ t end function balls_scene_pulsing() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- animate court draw_court(scene_frame * movementSpeed * 0.4 - 30) for i = 1, N do local b = local_balls[i] b:update( frame, false, -- no bounce energy false -- no gravity ) local aspect_t = math.sin(frame * 0.2 + i) -- -1..1 b.aspect = aspect_from_N11(aspect_t, maxAspect) b:draw(true) end end end ------------------------------------------------------------------------ -- bball scene: stationary single ball do local movementSpeed = 0.4 local local_balls = { Basketball.new({ radius = 34, x = 150, y = 90, dx = -movementSpeed, dy = 0, autoRotXSpeed = 0.02, autoRotYSpeed = 0.022, autoRotZSpeed = 0.01, }), } local N = #local_balls function balls_scene_the_loner() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- animate court with parallax local parallax = 0.4 draw_court(scene_frame * movementSpeed * parallax - 30) -- .4 parallax for i = 1, N do local b = local_balls[i] b:update( frame, true, -- no bounce energy true -- no gravity ) b:draw(true) end end end ------------------------------------------------------------------------ -- bball scene: dribble single ball do local movementSpeed = 0.4 local local_balls = { Basketball.new({ radius = 34, x = 150, y = 90, dx = 10, dy = 20, autoRotXSpeed = 0.2, autoRotYSpeed = 0.0, autoRotZSpeed = 0.0, }), } local N = #local_balls function balls_scene_dribble() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- animate court with parallax local parallax = 0.4 draw_court(scene_frame * movementSpeed * parallax - 30) -- .4 parallax for i = 1, N do local b = local_balls[i] b:update( frame, true, -- no bounce energy true -- no gravity ) b:draw(true) end end end ------------------------------------------------------------------------ -- bball scene: finger spin single ball do local movementSpeed = 0.0 local local_balls = { Basketball.new({ radius = 34, x = 140, y = 72, dx = 0, dy = 0, autoRotXSpeed = 0.2, autoRotYSpeed = 0.1, autoRotZSpeed = 0.0, }), } local N = #local_balls function balls_scene_finger() frame = frame + 1 poke(0x3FF8, 13) cls(13) -- animate court with parallax local parallax = 0.4 draw_court(scene_frame * movementSpeed * parallax - 30) -- .4 parallax local fx = 140 local fy = 119 elli(fx,fy+2,4,16,3) elli(fx-8,fy+6,4,8,3) elli(fx-16,fy+8,4,5,3) elli(fx-24,fy+10,4,5,3) elli(fx-12,fy+14,16,6,3) for i = 1, N do local b = local_balls[i] b:update( frame, true, -- no bounce energy false -- no gravity ) b:draw(false) end end end ------------------------------------------------------------------------ -- these different bball scenes are available -- -- balls_scene_random -- balls_scene_floating -- balls_scene_axis -- balls_scene_sin -- balls_scene_rotating -- balls_scene_scrolling -- balls_scene_pulsing -- balls_scene_the_loner -- balls_scene_dribble *new* -- balls_scene_finger *new* -- "ball_scene" is removed because it was the same as balls_scene_the_loner except less animated function red_miss() local col = { 1, 12, 3, 4 } poke(0x3FF8, 2) cls(2) math.randomseed(time() / 60 / 2) for i = 0, 100 do local xx = math.random(200) - (time() / 2) % 120 local yy = math.random(136) local sy = (yy + 16) // 6 local ex = xx + math.random(240) local c = math.random(4) -- draw the correct start of the line on other side if xx < 0 and ex > 0 then line(240 + xx, yy, 240, yy, col[c]) end -- hide wrap around if ex > 240 - sy then ex = 240 - sy end -- print the normal line line(xx, yy, ex, yy, col[c]) end local padx = 6 local pady = 40 local pad = 2 print("MISS", padx + 2, pady + 2, 0, true, 9, false) print("MISS", padx, pady, 1, true, 9, false) end function blue_score() local col = { 8, 9, 13, 12 } poke(0x3FF8, 10) cls(10) math.randomseed(time() / 60 / 2) for i = 0, 100 do local xx = math.random(200) - (time() / 2) % 120 local yy = math.random(136) local sy = (yy + 16) // 6 local ex = xx + math.random(240) local c = math.random(4) -- draw the correct start of the line on other side if xx < 0 and ex > 0 then line(240 + xx, yy, 240, yy, col[c]) end -- hide wrap around if ex > 240 - sy then ex = 240 - sy end -- print the normal line line(xx, yy, ex, yy, col[c]) end local padx = 6 local pady = 40 local pad = 2 print("SCORE", padx + 2, pady + 2, 0, true, 7, false) print("SCORE", padx, pady, 12, true, 7, false) end function slanted(l) poke(0x3FF9, -l / 6) end function slanted_badtrip(l) poke(0x3FF9, -l / 6) math.randomseed(time()) i = 1 poke(0x3fc0 + i * 3, math.random() * 255) poke(0x3fc0 + i * 3 + 1, math.random() * 255) poke(0x3fc0 + i * 3 + 2, math.random() * 255) end local score_timer = 0 function score_init() sweetie16_init() score_timer = time() / 1000 end function score_board(mins, stime, home, vis) poke(0x3FF8, 13) cls(13) rect(20, 10, 200, 110, 0) rectb(20, 10, 200, 110, 15) rectb(30, 20, 180, 90, 15) print("rbbs electronics", 88, 13, 12, 0, 1, 1) print(mins .. (stime + math.floor(score_timer - time() / 1000)), 64, 30, 4, 0, 4) print("4", 112, 64, 4, 0, 2) print("period", 106, 76, 12, 0, 1, 0, false) print("HOME", 60, 64, 12, 0, 2, 1) print(home, 54, 82, 2, 0, 4) print("GUEST", 144, 64, 12, 0, 2, 1) print(vis, 140, 82, 2, 0, 4) end function score1_scene() score_board("02:", 23, 68, 71) end function score2_scene() score_board("02:", 19, 68, 71) end function score3_scene() score_board("02:", 19, 70, 71) end function score4_scene() score_board("01:", 42, 74, 75) end function score5_scene() score_board("01:", 42, 74, 77) end function bottle(posx, posy, dx, dy, bc, tc) -- bottom elli(posx + dx / 2, posy + dy, dx / 2, dy / 10, bc) -- bottle rect(posx, posy, dx + 1, dy, bc) -- cap elli(posx + dx / 2, posy, dx / 2, dy / 10, tc) rect(posx, posy, dx + 1, dy / 6, tc) -- straw rect(posx + dx / 2.45, posy - dy / 6, dx / 5, dy / 6, tc) -- logo clip(posx + dx / 4, posy + dy / 3, dx / 4, dy / 4) circ(posx + dx / 2, posy + dy / 2, 6, tc) clip(posx + dx / 2 + 2, posy + dy / 2, dx, dy / 2) circ(posx + dx / 2, posy + dy / 2, 12, tc) clip() end function waterbottle_scene() poke(0x3FF8, 3) cls(3) rect(0, 97, 240, 40, 15) bottle(20, 40, 40, 80, 12, 0) bottle(110, 40, 40, 80, 12, 0) local px = 22 local padx = 36 local py = 84 local pady = 42 for x = px, px + padx, 2 do for y = py, py + pady, 2 do if pix(x, y) == 12 then pix(x, y, math.sin(time() / 1000 + x / 10 + math.sin(y + time() / 10000 + x) * 10) * 2 + 10) end end end px = 112 py = 74 pady = 64 for x = px, px + padx, 2 do for y = py, py + pady, 2 do if pix(x, y) == 12 then pix(x, y, math.sin(time() / 1000 + x / 10 + math.sin(y + time() / 10000 + x) * 10) * 2 + 10) end end end end bottlet=0 function laced_init() sweetie16_init() bottlet = time() end function lacedbottle_scene() poke(0x3FF8, 3) cls(3) rect(0, 97, 240, 40, 15) local movb = (time() - bottlet) // 100 bottle(20, 40, 40, 80, 12, 0) bottle(80, 40, 40, 80, 12, 0) bottle(160-movb, 40, 40, 80, 12, 0) local px = 22 local padx = 36 local py = 84 local pady = 42 for x = px, px + padx, 2 do for y = py, py + pady, 2 do if pix(x, y) == 12 then pix(x, y, math.sin(time() / 1000 + x / 10 + math.sin(y + time() / 10000 + x) * 10) * 2 + 10) end end end px = 82 py = 74 pady = 64 for x = px, px + padx, 2 do for y = py, py + pady, 2 do if pix(x, y) == 12 then pix(x, y, math.sin(time() / 1000 + x / 10 + math.sin(y + time() / 10000 + x) * 10) * 2 + 10) end end end px = 162-movb for x = px, px + padx, 2 do for y = py, py + pady, 2 do if pix(x, y) == 12 then pix(x, y, math.sin(time() / 1000 + x / 10 + math.sin(y + time() / 1000 + x) * 10) * 3 + 4) end end end end function waterbottle_bdr(l) if l > 100 then poke(0x3FF8, 15) end end local pbtex = {} function rotozoom_init() for y = 0, 135 do pbtex[y] = {} for x = 0, 239 do pbtex[y][x] = pix(x, y) end end frame = 0 end function rotozoom_scene() -- rotozoomer, stolen from gasman local a = frame / 50 local s = 2 + 0.8 * math.sin(a) local cx = 120 + 120 * math.sin(a) local cy = 68 + 120 * math.sin(a / 2) for y = 0, 135 do for x = 0, 239 do local dx = x - cx local dy = y - cy --tx=(cx+math.cos(a)*s*dx+math.sin(a)*s*dy)//1 --ty=((cy+math.cos(a)*s*dy-math.sin(a)*s*dx)//1) pix( x, y, pbtex[(cy + math.cos(a) * s * dy - math.sin(a) * s * dx) // 1 % 136][(cx + math.cos(a) * s * dx + math.sin( a ) * s * dy) // 1 % 240] ) end end frame = frame + 1 end -- for the ball scene function badtripball_bdr(l) poke(0x3fc0 + 3 + (l / 16) % (12 * 3), math.random() * 255) if l > 99 then poke(0x3FF8, 9) end end -- for the score board function badtripboard_bdr(l) math.randomseed(time()) for i = 1, 15 do poke(0x3fc0 + i * 3, math.random() * 255) poke(0x3fc0 + i * 3 + 1, math.random() * 255) poke(0x3fc0 + i * 3 + 2, math.random() * 255) end poke(0x3FF9, math.sin(l / 16 + time() / 1000 + math.sin(time() / 500) * 5) * 10) end function score6_scene() score_board("01:", 14, 76, 79) end local st = 0 function czoom_init() sweetie16_init() st = time() cls() end -- dash of mantratronic in here function czoom_scene() dt = time() - st local a = dt * 0.001 local b = a * 3 local c = a * 5 local ms = math.sin(a) * 20 local ts = math.sin(b) * 30 local mc = math.sin(c) * 30 memcpy(0x4000, 0, 120 * 136) local f = 60 for y = 0, 135 do local q = y * 120 local r = q + f if y < 68 then memcpy(r, r - 1 + 0x4000, f) memcpy(q + 120, q + 240 + 0x4000, f) else memcpy(r, r - 120 + 0x4000, f) memcpy(q, q + 1 + 0x4000, f) end end frame = frame + 1 random_balls[3]:update(frame, true, true) random_balls[2]:update(frame, true, true) random_balls[3]:draw(false) random_balls[2]:draw(false) end local galt = 0 function galaxy_init() sweetie16_init() galt = time() --poke(0x3FF8,12) --cls(12) end local gx, gy, gt = 0, 0, 0 local px, py = 0, 0 -- previous x,y; tracking rate of change function F(i, c) local r = math.pi * 2 / 110 local u = math.sin(i + gy) + math.sin(r * i + gx) local v = math.cos(i + gy) + math.cos(r * i + gx) / 2 gx = u + gt gy = v local x, y = u * 55 + 120, v * 55 + 70 -- map uv to xy screen local dx, dy = x - px, y - py px, py = x, y local sp = dx * dx + dy * dy -- squared speed local col = 1 + (math.floor(sp) % 15) circ(x, y, 0, col) end function galaxy_scene() poke(0x3FF8, 12) cls(12) gt = time() / 1000 -- taking out of loop for performance for i = 0, 110, 1 do for j = 0, 110, 1 do F(i, j) end end end function galaxy0_scene() poke(0x3FF8, 12) cls(12) local px = 50 local py = 20 local sx = math.sin(time() / 200) * 3 local sy = math.sin(time() / 100) * 3 print("Basketball", px + 12 + sx, py + 6 + sy, 0, 0, 2, false) print("Basketball", px + 12, py + 6, 4, 0, 2, false) print("and", px + 56 + sx, py + 26 + sy, 0, 0, 2, false) print("and", px + 56, py + 26, 3, 0, 2, false) print("Alarms", px + 36 + sx, py + 46 + sy, 0, 0, 2, false) print("Alarms", px + 36, py + 46, 2, 0, 2, false) print("RSync 2026", px + 32 + sx, py + 76 + sy, 0, 0, 2, true) print("RSync 2026", px + 32, py + 76, 6, 0, 2, true) for i = 0, 110, 1 do for j = 0, 110, 1 do F(i, j) gt = time() / 1000 end end end function galaxy1_scene() galaxy_scene() local px = 20 local py = 20 + (time() - galt) / 200 rect(px, py, 98, 52, 0) print("tenfour", px + 6, py + 6, 7, 0, 2, false) print("audio", px + 50, py + 21, 12, 0, 2, true) print("code", px + 58, py + 34, 12, 0, 2, true) --highlight line(px + 2, py + 2, px + 6, py + 2, 12) pix(px + 8, py + 2, 12) line(px + 2, py + 2, px + 2, py + 4, 12) pix(px + 2, py + 6, 12) --shadow for sx=px+2,px+98-2,2 do for sy=py+52,py+52+5 do pix(sx+(sy%2),sy,0) end end for sx=px+98,px+98+4,2 do for sy=py+3,py+52+5 do pix(sx+(sy%2),sy,0) end end end function galaxy2_scene() galaxy_scene() local px = 70 local py = 40 - (time() - galt) / 200 rect(px, py, 108, 52, 0) print("ps", px + 6, py + 6, 14, 0, 2, false) print("code", px + 70, py + 21, 12, 0, 2, true) print("design", px + 54, py + 34, 12, 0, 2, true) line(px + 2, py + 2, px + 6, py + 2, 12) pix(px + 8, py + 2, 12) line(px + 2, py + 2, px + 2, py + 4, 12) pix(px + 2, py + 6, 12) --shadow for sx=px+2,px+108-2,2 do for sy=py+52,py+52+5 do pix(sx+(sy%2),sy,0) end end for sx=px+108,px+108+4,2 do for sy=py+3,py+52+5 do pix(sx+(sy%2),sy,0) end end end function galaxy3_scene() galaxy_scene() local px = 130 local py = 40 + (time() - galt) / 200 rect(px, py, 90, 40, 0) print("enfys", px + 6, py + 6, 6, 0, 2, false) print("add code", px + 20, py + 22, 12, 0, 2, true) line(px + 2, py + 2, px + 6, py + 2, 12) pix(px + 8, py + 2, 12) line(px + 2, py + 2, px + 2, py + 4, 12) pix(px + 2, py + 6, 12) --shadow for sx=px+2,px+90-2,2 do for sy=py+40,py+40+5 do pix(sx+(sy%2),sy,0) end end for sx=px+90,px+90+4,2 do for sy=py+3,py+40+5 do pix(sx+(sy%2),sy,0) end end end function score7_scene() score_board("00:", 32, 77, 83) end function stars(scrolly) math.randomseed(1) for i = 0, 1000 do circ( math.random(240), (math.random(136) + scrolly) % 136, math.random() * 1.5, (4 + math.random(2) // 1 * 8) * math.abs(math.sin(time() / math.random(2000)) // 1) ) end end function mountains(x, y, t, seed, height, cidx) math.randomseed(seed) for i = 20, -10, -2 do w = 70 + i * 2 + math.random(3) h = height - math.sin(i * 5 + math.random(8)) * height / 2 lx = (20 + i * 12 - t) % 320 + x tx1 = lx + w * 0.33 tx2 = lx + w * 0.5 tx3 = lx + w * 0.67 px = tx2 ex = lx + w ly = 136 - y py = ly - h ey = ly tri(lx, ly, lx + w / 2, ly - h, lx + w, ly, 14) for d = 1, 3 do ty1 = ly - h * ((3 - d) * 0.2 + 0.27) c = cidx - d tri(lx, ly, lx + w / 3, ty1, lx + w, ly, c) tri(lx, ly, lx + w / 2, ty1, lx + w, ly, c) tri(lx, ly, lx + w / 3 * 2, ty1, lx + w, ly, c) end end end -- stolen from ToBach! function grass(y, dy, t) for i = 0, 250 do line((i - t) % 250, (100 + math.sin(i) * 10) * dy + y, (i - t) % 250, 135 * dy + y, 7) end for i = 0, 250 do dx = (i - t) % 250 line(dx - 3 + math.sin(time() / 500 + i) * 2, (110 + math.sin(i) * 10) * dy + y, dx, 135 * dy + y, 8) end end -- brand new cow generator!!! -- with rumination support! function cow(x, y, w, seed, t) math.randomseed(seed) -- body rect(x + w * 0.5, y + w * 0.5, w * 3, w * 2, 7) -- spots on body for i = 0, 15 do rect( x + w * (0.5 + math.random() * 2), y + w * (0.5 + math.random() * 2), w * 3 * (math.random() * 0.45), w * 2 * (math.random() * 0.5), 15 ) end -- clean up overflow underneath rect(x + w * 0.5, y + w * 2.5, w * 3, w, 0) -- clean up overflow on right rect(x + w * 3.5, y + w * 0.5, w, w * 3, 0) --elli(x+w*2.4,y+w*1.5,w*2,w*1.3,12) -- legs rect(x + w * 0.5, y + w * 2, w * 0.8, w, 7) rect(x + w * 2.7, y + w * 2, w * 0.8, w, 7) -- left horn circ(x + w * 0.35, y - w * 0.1, w * 0.3, 3) circ(x + w * 0.45, y - w * 0.2, w * 0.3, 0) -- right horn circ(x + w * 0.62, y - w * 0.1, w * 0.3, 3) circ(x + w * 0.52, y - w * 0.2, w * 0.3, 0) -- left ear elli(x - w * 0.2, y + w * 0.2, w * 0.4, w * 0.2, 7) elli(x - w * 0.2, y + w * 0.2, w * 0.3, w * 0.1, 4) -- right ear elli(x + w * 1.2, y + w * 0.2, w * 0.4, w * 0.2, 7) elli(x + w * 1.2, y + w * 0.2, w * 0.3, w * 0.1, 4) --head block rect(x, y, w, w, 7) -- eyes circ(x + w * 0.3, y + w * 0.3, w * 0.1, 2) circ(x + w * 0.7, y + w * 0.3, w * 0.1, 2) -- mouth rect(x, y + w, w, w * 0.25, 7) rect(x + w * 0.3, y + w * 1.25, w * 0.4, w * 0.1, 6) rect(x + math.sin(t / 2) + 1, y + w * 1.3 + math.sin(t) * 2, w, w * 0.2, 7) --rect(x+w*.3,y+w*1.4,w*.5,w*.4,4) -- nostrils circ(x + w * 0.3, y + w * 1.05, w * 0.05, 3) circ(x + w * 0.65, y + w * 1.05, w * 0.05, 3) end function twinkle_init() sweetie16_init() poke(0x3FF8, 0) vbank(1) sweetie16_init() vbank(0) end function twinkle() cls() stars(0) mountains(-80, 55, 0, 3, 52, 11) grass(56, 0.2, 0) -- road rect(0, 80, 240, 80, 15) speed = 0 -- road markers --[[for i=0,5 do rect((i*80-speed)%320-80, 100, 30,8,4) end--]] grass(90, 0.4, 0) vbank(1) cow(120, 39, 20, 18, time() / 400) print( "... meanwhile in Switzerland\nzombie cows are afoot\n\ncome see them 27 Feb - 1 Mar\nMountainBytes 2026", 10, 88, 4 ) vbank(0) end scenes = { { init = intro_init, frame = intro_scene, bdr = no_fn, start = 0, row = 0, },{ init = alarmclock_init, frame = alarmclock_scene, bdr = alarmclock_bdr, start = 1, row = 0, },{ init = sweetie16_init, frame = cooking_scene, bdr = no_fn, start = 1, row = 32, },{ init = sweetie16_init, frame = tram_scene, bdr = tram_bdr, start = 2, row = 0, },{ init = sweetie16_init, frame = basket_scene, bdr = basket_bdr, start = 2, row = 32, },{ init = sweetie16_init, frame = balls_scene_random, bdr = basket_bdr, start = 3, row = 0, },{ init = sweetie16_init, frame = red_miss, bdr = slanted, start = 3, row = 32, },{ init = sweetie16_init, frame = blue_score, bdr = slanted, start = 3, row = 48, },{ init = sweetie16_init, frame = balls_scene_finger, bdr = basket_bdr, start = 4, row = 0, },{ init = sweetie16_init, frame = waterbottle_scene, bdr = waterbottle_bdr, start = 4, row = 32, },{ init = alarmclock_init, frame = alarmclock_scene, bdr = alarmclock_bdr, start = 5, row = 0, },{ init = sweetie16_init, frame = cooking_scene, bdr = no_fn, start = 5, row = 32, },{ init = sweetie16_init, frame = tram_scene, bdr = tram_bdr, start = 6, row = 0, },{ init = sweetie16_init, frame = balls_scene_the_loner, bdr = basket_bdr, start = 6, row = 32, },{ init = sweetie16_init, frame = balls_scene_random, bdr = basket_bdr, start = 7, row = 0, },{ init = sweetie16_init, frame = balls_scene_axis, bdr = basket_bdr, start = 7, row = 32, },{ init = sweetie16_init, frame = balls_scene_rotating, bdr = basket_bdr, start = 7, row = 48, },{ init = sweetie16_init, frame = waterbottle_scene, bdr = waterbottle_bdr, start = 8, row = 0, },{ init = sweetie16_init, frame = balls_scene_dribble, bdr = basket_bdr, start = 8, row = 16, },{ init = sweetie16_init, frame = blue_score, bdr = slanted, start = 8, row = 48, },{ init = sweetie16_init, frame = balls_scene_the_loner, bdr = basket_bdr, start = 9, row = 0, },{ init = sweetie16_init, frame = red_miss, bdr = slanted, start = 9, row = 32, },{ init = score_init, frame = score1_scene, bdr = no_fn, start = 10, row = 0, },{ init = sweetie16_init, frame = blue_score, bdr = slanted, start = 10, row = 32, },{ init = score_init, frame = score2_scene, bdr = no_fn, start = 10, row = 48, },{ init = no_fn, frame = score3_scene, bdr = no_fn, start = 10, row = 56, },{ init = sweetie16_init, frame = balls_scene_the_loner, bdr = basket_bdr, start = 11, row = 16, },{ init = sweetie16_init, frame = red_miss, bdr = slanted, start = 11, row = 32, },{ init = score_init, frame = score4_scene, bdr = no_fn, start = 11, row = 48, },{ init = no_fn, frame = score5_scene, bdr = no_fn, start = 11, row = 56, },{ init = laced_init, frame = lacedbottle_scene, bdr = waterbottle_bdr, start = 12, row = 0, },{ init = rotozoom_init, frame = rotozoom_scene, bdr = no_fn, start = 12, row = 32, },{ init = sweetie16_init, frame = balls_scene_pulsing, bdr = badtripball_bdr, start = 13, row = 0, },{ init = sweetie16_init, frame = red_miss, bdr = slanted_badtrip, start = 13, row = 48, },{ init = score_init, frame = score6_scene, bdr = badtripboard_bdr, start = 14, row = 0, },{ init = sweetie16_init, frame = balls_scene_pulsing, bdr = badtripball_bdr, start = 14, row = 32, },{ init = sweetie16_init, frame = basket_scene, bdr = badtripboard_bdr, start = 15, row = 0, },{ init = sweetie16_init, frame = red_miss, bdr = slanted_badtrip, start = 15, row = 32, },{ init = score_init, frame = score7_scene, bdr = badtripboard_bdr, start = 16, row = 0, },{ init = sweetie16_init, frame = balls_scene_random, bdr = badtripball_bdr, start = 16, row = 32, },{ init = sweetie16_init, frame = basket_scene, bdr = badtripboard_bdr, start = 17, row = 0, },{ init = sweetie16_init, frame = red_miss, bdr = slanted_badtrip, start = 17, row = 32, },{ init = galaxy_init, frame = galaxy_scene, bdr = no_fn, start = 18, row = 0, },{ init = galaxy_init, frame = galaxy0_scene, bdr = no_fn, start = 18, row = 32, },{ init = galaxy_init, frame = galaxy1_scene, bdr = no_fn, start = 20, row = 0, },{ init = galaxy_init, frame = galaxy2_scene, bdr = no_fn, start = 20, row = 48, },{ init = galaxy_init, frame = galaxy3_scene, bdr = no_fn, start = 21, row = 32, },{ init = czoom_init, frame = czoom_scene, bdr = no_fn, start = 22, row = 0, },{ init = alarmclock_init, frame = alarmclockg_scene, bdr = alarmclock_bdr, start = 24, row = 0, },{ init = sweetie16_init, frame = cookingg_scene, bdr = no_fn, start = 24, row = 32, },{ init = tramg_init, frame = tramg_scene, bdr = tram_bdr, start = 25, row = 0, },{ init = twinkle_init, frame = twinkle, bdr = no_fn, start = 29, row = 0, } } current_scene_id = 1 scenes[current_scene_id].init() somatic_init(scenes[current_scene_id].start, 0) function TIC() if keyp(55) then if current_scene_id < #scenes then current_scene_id = current_scene_id + 1 scene_frame = 0 scenes[current_scene_id].init() somatic_init(scenes[current_scene_id].start, 0) end end if keyp(54) then if current_scene_id > 1 then current_scene_id = current_scene_id - 1 scene_frame = 0 scenes[current_scene_id].init() somatic_init(scenes[current_scene_id].start, 0) end end somatic_tick() local track, playingSongOrder, currentFrame, currentRow = somatic_get_state() if track ~= -1 then -- if playing lastKnownOrder = playingSongOrder lastKnownRow = currentRow else trace("TPOLM says Moo!") exit() end if btnp(2) then -- left somatic_init(math.max(0, playingSongOrder - 1), 0) end if btnp(3) then -- right -- clamping... local nextPattern = math.min(somatic_get_song_order_count() - 1, playingSongOrder + 1) somatic_init(nextPattern, 0) end if btnp(1) then -- down if track == -1 then somatic_init(lastKnownOrder, lastKnownRow) else somatic_stop() end end --hide cursor poke(16379, 2) -- get global music sync refs local _pO = playingSongOrder local _row = peek(0x13FFE) if current_scene_id < #scenes and _pO >= scenes[current_scene_id + 1].start and _row ~= 255 and _row >= scenes[current_scene_id + 1].row then current_scene_id = current_scene_id + 1 scene_frame = 0 scenes[current_scene_id].init() end scenes[current_scene_id].frame() scene_frame = scene_frame + 1 -- print(current_scene_id .. " " .. _pO .. " " .. _row, 0, 130) end function BDR(l) scenes[current_scene_id].bdr(l) end