̬̬̬̈̬̬̬̬̈̬̬̬̬̬̪쬪̬̬̬̪쬪 >>@DD@DD0@D@DD3DDD4C0DD03 DD"BD3@ "033D " 033@D@033DD33DD "33DD03@D@D " " 03""33#@ 33D "33@DD 03BDD@0" BDDD3# D0303"BDDD@3#@DD 0DDD0 DDD@D3 "3C "3DDDDD00 "300DDD@DDDPU033CDD0@DDDUU%"SU3 0D@DDDUU30UU 03"bf0UU033UUUED "" ff`f0 3SU"033 PUUU" "`fffff0 00"033"PUUU 3`fff`fff̪ 3 2PUU00`fff`fff̪03U0330ff0`fff̬; 0U03`fff̪;"PUU ""`f̬ " PUU@"", 0f"PUUD̻̼ffff U@̼̼lflff ̼ ff` "23̼̻̼̻lfff03 ̼˻ kf`̼̼˼̼RUkf`f̼̼̻̼̼̼̼\Ukf`f03 3@D̼̻˼̻\UUkff`f033@D̼̻˻\UU̻ff`f 033̻f̼̼UUU̼lf`f233̼efff˼̻UU̻\Uff """3\ffff˼̼ PU\UPff 0 """"˼`fVU̻̼̼̻ \UUUff0 23lffUU̼̻ UUefUfU33fPefU̻̻ [Uffef PUU33̻lffV̼ 0lffff̬PUU0#"3303lPUf̼3fff̪QUUPU0323D$33̼\PUe̻ 0lf̬ DUUU33D33̼\PUU̼̼  DDUU33CD33\PUU̻ DUUU033CD03UPUU̻  PUUQU0333CD\UU  UUU0003DD̼PUU !UUU3 0@DDD̼UUUUUU033D$@DDDUPUUU   PUU330@DDUffVUU ADU03@DDPfffUe   DD3033DDDDffff;0@DDD00033 DD`fff;0 @DDD3233"DD0f030 "@DDDD333 BPUU3000 DU@DD333DUUU0030#"PUU@DD333BUUUU@D3032 UUUADD53#DUUUU0 "333fUUUDT03BPUUU "3#3cffUUUEDUU3UUE"" 3"2fffPUUDDPU00UUUD" 0fff UEDDD000033PUUD "0#2#fff0 @DDD0 "PUU333"bff03BDDD03"PUU0#"3#3f631DD0 PUU@D#"333AD33PUUPU""00PUU 0UU5#3"0U"2PUUU330D"2SUUU3203#@DD@D 0SUUU2 "3`f330"3CDUUU%2ff`f 3003#033D0 "UUU%" 0`fffff3@D033D30"UUU%2`ffffff@D0003DD0U5D03#RUU0`fffffffDDDD$SUU@0"U53fffeffff@DDD0DDSUU "0003f`Vffff@DDD0CDSUU "00330fff@DD0330U5303f`ffDD30330`ff`f@DD03 fffb`@DDPU03 "0300fffUe@DDUU" 33fffPUUDTUUU0  030`fUUDUUD0003@D@D"03fPPUD3333DDD 30ED0033DDPU03@DD333DDUU030@DD00 03@D RUUU "00`@DD"4 "RUUU 3`f@DU @D PUUU"0`ffPDTUU3 @D UU 3ffPEPUU433"03D"RU3feffPEPUUD33@D33C@D 0`ffP`UTUUED3333CDD03fff@UUEDD3@33CDDDDfffDUUDD03D@DDDfff@T0UU0@DDDD`ffD3SU3#@DDDffPE03#@DDD "ff@E033@DDD@ "DfT033DDD0CDf@033UEDTeT3#3PUUDTU033PUU@DTUD233PUUDBDU@ "033U@ "DTU@@3@DDDDDUDDDDDDUEDDDD@DD03@DDD@D@DDD@DD@DDD0@DC@DD3D@D "0DD433D"@DC033DDD 03 033DDDD"03U3CDDDD 33PUUDDDD ""33PUUD 333PU0PUU0303303UUU33333UU33333UU "3333PU0303-- title: The Lost Soul -- author: jtruk -- date: 2023-10-31 -- release: Out of party (Halloween!) N_HEAD_DOTS=800 local T,S,C,R,MIN,MAX,FMOD=0,math.sin,math.cos,math.random,math.min,math.max,math.fmod local ABS,PI,TAU=math.abs,math.pi,math.pi*2 local HEAD_DOTS=nil local DRIPS=nil local POINTS=nil -- Colours: c='b' is black => 0, c='r' is red => 1-7, c='w' is white => 8-14 -- Points are: x, y, z, and colour -- SphereDots are: an elevation, rotation, and colour function clamp(v,l,h) return MIN(MAX(v,l),h) end function BOOT() HEAD_DOTS=spreadSphereDots(N_HEAD_DOTS) DRIPS={} end function setRGB(c,r,g,b) local addr=0x3fc0+c*3 poke(addr,r) poke(addr+1,g) poke(addr+2,b) end function BDR(y) setRGB(0,0,0,0) for c=0,6 do local i=((c+1)/6)*255 setRGB(c+1,i,i/5,i/3) setRGB(c+8,i,i,i) end end function TIC() local rX=S(T/100)*.1 local rY=S(T/50)*.2 local rZ=S(T/180)*.2 local tX=S(T/120)*.5 local tY=S(T/65)*.3 local tZ=.45+S(T/170)*.95 local headPoints=movePoints(getHeadPoints(),tX,tY,tZ,rX,rY,rZ) local otherPoints=movePoints(makeOtherPoints(rX+tX/6,rY+tY/6),tX,tY,tZ,rX,rY,rZ) local newDrip=headPoints[R(1,#headPoints)] makeDrip(newDrip.x,newDrip.y,newDrip.z) doDrips() cls() clearPoints() addPoints(headPoints) addPoints(DRIPS) addPoints(otherPoints) drawPoints() T=T+1 end -- Spread some dots around a sphere function spreadSphereDots(nDots) local dots={} for i=1,nDots do dots[#dots+1]={ e=R()*math.pi, r=R()*math.pi*2, c='r', } end return dots end function sphereDotToPoint(d,e,r,c,zover) return rotX({x=S(r)*d,y=C(r)*d,z=0,c=c,zover=zover},e) end function getHeadPoints() local ps={} for i=1,#HEAD_DOTS do local d=HEAD_DOTS[i] ps[#ps+1]=sphereDotToPoint(1,d.e,d.r,d.c,0) d.e=d.e-0.004 end return ps end function makeOtherPoints(rX,rY) local ps={} local rXS=-rX*.2 local rYS=rY*.2 local nPoints=300 local mouthW=.15+math.sin(T/40)*.07 local mouthH=.1+math.sin(T/30)*.05 for i=1,nPoints do local a=i/nPoints*PI*2 local x=S(a) local y=C(a) local xr=x*R() local yr=y*R() ps[#ps+1]=sphereDotToPoint(1.01,1.6+xr*.08,-.2+yr*.15,'w',0) ps[#ps+1]=sphereDotToPoint(1.01,1.6+xr*.08,.2+yr*.15,'w',0) if i%8==0 then ps[#ps+1]=sphereDotToPoint(1.02,1.6+xr*.05+rXS,-.2+yr*.05+rYS,'r',0) ps[#ps+1]=sphereDotToPoint(1.02,1.6+xr*.05+rXS,.2+yr*.05+rYS,'r',0) ps[#ps+1]=sphereDotToPoint(1.03,1.6+xr*.02+rXS,-.2+yr*.02+rYS,'b',0) ps[#ps+1]=sphereDotToPoint(1.03,1.6+xr*.02+rXS,.2+yr*.02+rYS,'b',0) end ps[#ps+1]=sphereDotToPoint(1,1.15+mouthH*xr+ABS(xr*.05),mouthW*yr,'r',0) ps[#ps+1]=sphereDotToPoint(1,1.15+(mouthH*xr+ABS(xr*.05))*.8,mouthW*yr*.8,'b',1) end return ps end function movePoints(ps,tX,tY,tZ,rX,rY,rZ) for i=1,#ps do local p=rotZ(rotY(rotX(ps[i],rX),rY),rZ) p.x,p.y,p.z=p.x-tX,p.y-tY,p.z-tZ end return ps end function getNextDripN() for i=1,#DRIPS do if not DRIPS[i].alive then return i end end return #DRIPS+1 end function makeDrip(x,y,z) DRIPS[getNextDripN()]={x=x,y=y,z=z,c='r',zover=0,alive=true} end function doDrips() for i=1,#DRIPS do local d=DRIPS[i] d.y=d.y+.005+ABS(d.y/30) if d.y>2 then d.alive=false end end end function rotX(p,r) p.y,p.z=p.y*C(r)-p.z*S(r),p.y*S(r)+p.z*C(r) return p end function rotY(p,r) p.x,p.z=p.x*C(r)-p.z*S(r),p.x*S(r)+p.z*C(r) return p end function rotZ(p,r) p.x,p.y=p.x*C(r)-p.y*S(r),p.x*S(r)+p.y*C(r) return p end function clearPoints() POINTS={} end function addPoints(ps) for i=1,#ps do POINTS[#POINTS+1]=ps[i] end end function drawPoints() table.sort(POINTS,function (a,b) if a.zover==b.zover then return a.zFMOD(c,1) then c=c+1 end c=clamp(1+c,1,6) elseif p.c=='w' then c=z*1.2 if R()>FMOD(c,1) then c=c+1 end c=clamp(7+c,8,14) end circ(x,y,z,c) end end