 rem ---------------------------------------------------------
 rem ---Ring Raiders C64 Atari 2600 SuperCharger BASIC program 
 rem ---Protect the 9 Rings of Saturn with Photon Torpedoes & Rainbows 
 rem ---Star Raiders and Star Ship genre
 rem ----------------------------------------------------------------------------------
 rem --- 20250102 Streamlining for Atari 2600 (removing Tracker Editor, etc)...
 rem --- Beta running with 2029 & 2039 of 2048 bytes in banks 1 & 3  
 rem --- todo: Find intermittent frame going over cycle... found main spot where m=7...
 rem --- Add starfield (crunch to fit)
 rem --- Add AI algorithm to rebuild music in system bank (~200 bytes free)...
 rem --- 20250108 loadbalanced over cycle frameskip to gameloop2; bottom vertical blank cycles 
 rem ----------------------------------------------------------------------------------
 rem --- 20241019 Added twinkling stars and stars moving Fx behind Rings
 rem --- 20241019 Color coded TIE Fighter class status indicator 
 rem --- 20241012 Added 3D TIE Fighter 
 rem --- Hi score timer persist hi score every 5 minutes if current hi exceeded....
 rem --- 29241010 Patched Tracker module to return to main SID tune after edit
 rem --- 20241007 RC5 reset MUSICINDEX to zero when exiting Editor (minor)
 rem --- 20241003 RC4 add the ability to display and edit pattern [freeze display hear sound Tx]
 rem --- 20241002 SIDFx try changing SID4,SID5,SID6 arrays ... test dynamic instrument revision...
 rem --- 20241002 RC3 increase speed on warp (always fast forward)...
 rem --- 20240921 added photon torpedeoes to 3d cube cargo ship too 
 rem --- and increased challenge for missed photon torpedoes...
 rem ---20240920 added explosion when Saucer or 3D cube are hit (4 frames...)
 rem    and when Saucer or 3D cube impact the Ring (ring pieces in explosion)
 rem ---20240920 Saucer shoots Photo Torpedeo at player if above horizon or close (alt w/sidewinder)
 rem ---no harm to player if Torpedeo is dodged...
 rem ---20240919 adding horizontal drift to 3D objects (testing optimization)
 rem ---20240918 tuned relative spatial movement coordinate geometry for 3D floating Fx 
 rem ---20240911 horizon expansion demo b, multicolor frontier 
 rem ---(scale sprites across 3 expanding color illusion zones like Rainbow Walker!)
 rem ---20240903 Last Star Fighter 3D / 2.5D expanding rings like Buck Rogers/Solaris perspective
 rem ---20240830 inspiration from Star Raiders cover art showing Saturns Rings.
 rem ---
 rem ------------------------------------------------------
 rem ---Tracker script programmable demo in the game:    --
 rem ------------------------------------------------------
 rem ---Holding the Button long enough loads a new SID 
 rem ---moving stick in 4 directions plays chords or subtunes  
 rem ---when held or released, main tune resumes after.
 rem ---New Tracker controls:
 rem ---shift-lock or holding left shift = Space Waltz mode 
 rem ---left shift + left = new SID using algoritm 2
 rem ---left shift + right = Starts Tracker Editor 
 rem ---left shift + up/down = algorithms revise SID instrument array (Tracker has 39 instruments)  
 rem ------------------------------------------------------
 rem --- sid 21/31 ring 5 nice combination...
 rem ----------------------------------------------------------------------------------
 rem -- variable map
 rem -- p color seed var (excludes 0, background color black)
 rem -- q,r temp vars used by color routines
 rem -- m delay counter (in frames) to call palette switching routine
 rem -- t alt frame toggle (0,1)
 rem -- n Fx for palette switching (0 color chaser, 1 red & blue, 2, b&w greyscale, etc) different
 rem -- x,y,z,w,v screamer x,y,pos index,sprite animation,player0/missile0 size bitmask 
 rem -- f counter for next SID (130 frames button held)
 rem -- e,h sidewinder weapon x,y
 rem -- g = Photo Torpedo, missle1 in action and used in rebuidmusic levelup (repos missile)
 rem -- s - 1 up slow, 2 down slow (when stick is not engaged)
 rem -- l Rainbow Rings frames delay duration
 rem -- o holds n index
 rem -- k enemy weapon toggle (alternates) sidewider or Saucers Photon Torpedeo 
 rem -- i,j saucer and 3d cube explosion state (0 no explosion), i is reused in rebuildmusic
 rem ---u extra saucer or cube attack
 rem ---var1 used to hook left shift/shift-lock/bwcolor & and stick up/down to Tx instruments
 rem ---var1,var2,bx,by,score used by Tracker Editor (cannot Tx instruments from Editor)
 rem ---(reusing px)  px hiscore timeout (3 minutes play to obtain highest score/ StarShip scoring system
 rem -- py (0/1) toggle between green 3Dcube and 3D TIE Fighter
 rem -----------------------------------------
 rem ---init section, runs once: -------------
 rem -----------------------------------------
 
 gosub testr
 
 rem --- 20241002 SIDFx try changing SID4,SID5,SID6 arrays ... test dynamic instrument revision:
 rem gosub rebuildsid456a

 rem passing line fx
 rem HMBL = $FF
 rem WSYNC = $C0 : HMOVE = $C0
 rem ENABL=2
 rem HMBL = $C0



 missile1x=80:s=1
 h=45:k=0
 rem rem for x=1 to 20:gosub rebuildmusic:next x
 rem data titles "RINGWORLD=0     RAINBOWMETER=000  SID=00"       

 rem for x=0 to 60
 rem iF x<4 then y=80+x:w=titles(x):w=w-64:DisplayList3Shadow(y)=w :rem titles(x)-65
 rem iF x<37 and x>33 then y=80+x:w=titles(x):w=w-64:DisplayList3Shadow(y)=w :rem titles(x)-65
 rem DisplayList3Shadow(87)=128
 rem 20241005 preserve initial musical score... 
 rem f x<20 then gosub rebuildmusic:rem advance SID
 rem next x
 rem DisplayList3Shadow(154)=53:rem display 5 as median SID 4,5,6 set SID Orchestra reference got playah...
 
 rem DisplayList3Shadow(119)=48:DisplayList3Shadow(118)=48

 rem hiscore 
 rem DisplayList3Shadow(105)=48:DisplayList3Shadow(106)=48:DisplayList3Shadow(107)=48
 q=8:r=4:n=1

 rem DisplayList3Shadow(85)=49:rem Starts on RING 1

initscore 
 rem DisplayList3Shadow(111)=48:DisplayList3Shadow(110)=48
 rem DisplayList3Shadow(109)=48
 return

incp
 p=p+1
 if p=16 then p=1
 return


newsidewinder
 rem 20240920 alternate sidewinder with Saucers Photon Tordpedeo if Saucer is far away:
 rem 20240921 allow 3dcube to use photo torpedeo if Saucer is too far away... 
 if k<>0 then goto knot0
repeatphotonshot
 if player1y>45 then k=1:e=player1x+4:h=player1y-3:return 
 rem - this launches more photon torpedoes...
trythis
 k=1:e=x:h=y:return
knot0
 k=0 
 e=0:h=screamers(z):z=z+1
 return


screamerrender rem -----------------------------------------------------------------
 rem moving this to fix cube animation! otherise some w values missed 
 rem --- dont think this can move...
 rem 20250109 tuning object animation (not a bug) if w<4 then w=w+1 else w=0
 rem 3D cube and Tie Fighters look better at this animation rate:
 if w<4 then w=w+t else w=0
 if y=0 then v=0:y=92:x=screamers(z):z=z+1
 if z>32 then z=0

 y=y-2
 rem 20250102
 if y<2 then j=5:player0y=7:gosub decreasescore:rem change back color fx removed, add sound Fx?
 rem if y<2 then j=5:player0y=7: rem change back color fx removed, add sound Fx?


 rem push to outside loop when t=1

 rem sprite 1 multiplexed alternate () sidewider weapon (e,h)
 rem 20250102 freeing ROM/total bank 1 memory used by RAM array access...
 rem if k=0 then e=e+4:player0colors(1)=4:goto donek
 if k=0 then e=e+4:goto donek
 rem 20250102 freeing ROM/total bank 1 memory used by RAM array access...
 rem h=h-6:player0colors(1)=h/2
 h=h-6

 if e<80 then e=e+5 else e=e-5:rem homing beam, check if within range when hit [decrease score]
donek 
 rem if h<5 then gosub newsidewinder:rem altenates with saucher photon torpedeo
 rem wait for wraparound to reach ...
 if h>245 then gosub decreasescore:gosub newsidewinder:rem altenates with saucher photon torpedeo
 if e>160 then gosub decreasescore:gosub newsidewinder:rem altenates with saucher photon torpedeo 
 rem if h>245 then gosub newsidewinder:rem altenates with saucher photon torpedeo
 rem if e>160 then gosub newsidewinder:rem altenates with saucher photon torpedeo 

 if z>32 then z=0
skipnextj

 rem sprite 2
 if player1y=0 then gosub rebuildsaucer 
 if z>32 then z=0
 rem flip sprite 4 different ways, backwards/upsidedown:

 if i=0 then goto normalsaucer else i=i-1
 if i=1  then loadplayer1(64):REFP1=0:rem 40 is explosion sequence animatino
 if i=2 then loadplayer1upsidedown(56):REFP1=255
 if i=3 then loadplayer1upsidedown(48):REFP1=0
 if i=4 then loadplayer1(40):REFP1=255
 if i=0 then gosub rebuildsaucer:gosub maybesaucerattack
 goto donesaucer
normalsaucer
 if w=0  then loadplayer1(24):REFP1=0:rem 24 is Saucer
 if w=1 then loadplayer1upsidedown(24):REFP1=255
 if w=2 then loadplayer1upsidedown(24):REFP1=0
 if w=3 then loadplayer1(24):REFP1=255
 player1y=player1y-4
donesaucer


 rem --changing back color bad Fx --- if player1y<4 then COLUBK=1:player1y=0
 rem 20250102
 if player1y<4 then player1y=7:i=5:gosub decreasescore:rem add sound Fx?
 rem if player1y<4 then player1y=7:i=5:rem add sound Fx?
 
 rem now scale sprite based on zone using NUSIZ0 000 , 101, 111 (last 3 bits)

 d=0:rem v&%00000000 --------- d is a tempvar, not using v (v is preserved)
 if player1y<31 then d=%00000111:goto donescaleplayer1
 if player1y<52 then d=%00000101
donescaleplayer1
 rem if missile1y<31 then d=d|%00110000:goto donescaleplayer1b
 if missile1y<52 then d=d|%00110000

donescaleplayer1b rem and (missile 1 too)
 NUSIZ1=d   :rem v&%00000000

 if r>0 then COLUP1=r else COLUP1=15
 return

decreasescore rem --- only take away points in 1's and 10 digit column... encourages 100 point incremental goals!
 rem if DisplayList3Shadow(111)>48 then DisplayList3Shadow(111)=DisplayList3Shadow(111)-1:return
 rem if DisplayList3Shadow(110)=48 then return
 rem DisplayList3Shadow(111)=53:DisplayList3Shadow(110)=DisplayList3Shadow(110)-1 
 rem 220250103 reusing px variable in place of C64 screen RAM to count 10 hits for Warp Fx
 if px>0 then px=px-1
 return
 
 rem tilemap screamers to relative BITIndex 
 rem data screamers 1,5,10,4,15,11,19,3,7,2,18,16,12,6,15,3,18,1,4,7,11,4,14,17,12,13,2,3,16,4,17,18,3,19,5,6,11,14,8,19,13,2,14,19,1,5,4,12

 rem overlay x,y coordinates
 data screamers 10,50,100,40,150,110,30,90,152,8,16,45,20,130,95,115,150,110,30,90,152,80,20,40,150,125,22,110,5

 rem if screamers hit last row increment border color or flash screen for M frames (better, M can set COLUBK=0)


 rem ------------------------------------------------
 rem ---gameloop subroutine, runs every frame:    ---
 rem ------------------------------------------------

 rem 30/25 or 60/50 Hz Fx: leave MBR filter on/off in template

 scrollvirtualworldtoggle=1

 t=1-t:rem toggles variable between 0 and 1

 rem 202409919 Horizontal cross drift for 3D objects --------
horozontaldrift
 if m<>2 then goto horozontaldrift2
 if screamers(z)<40 then player1x=player1x+3:goto donehorizontaldrift else player1x=player1x-2:goto donehorizontaldrift
horozontaldrift2 
 if m<>5 then goto donehorizontaldrift
 if screamers(z)<60 then x=x+2 else x=x-2:rem ai drift driven off of z index to center on z axis ;) 
 rem ... remember to seed random generator for z...
donehorizontaldrift
 rem --------------------------------------------------------


 rem 20250109 loadbalancing moving this to the bottom vertial blank
 if l>0 then l=l-1
 if l=1 then n=o:gosub advancepallette


 rem ---this  caused ineresting Fx on scaled 3D cube, perhaps make intermittent? v=%00000000
 if t=0 then goto skipt1: rem need this for sidewinder?
 rem flip sprite 4 different ways, backwards/upsidedown:
 rem py alternates with 40 and 72 (cube or ship, shoud have different color too)
 if j=0 then goto load3dcubenormally else j=j-1
 if j=1  then loadplayer0(64):REFP0=0
 if j=2 then loadplayer0upsidedown(56):REFP0=255
 if j=3 then loadplayer0upsidedown(48):REFP0=0
 if j=4 then loadplayer0(40):REFP0=255
 rem 20250102 removed reference to C64 screen location DisplayList3Shadow(87):
 rem if j=0 then py=1-py:DisplayList3Shadow(87)=DisplayList3Shadow(87)+py:gosub rebuild3dcube:gosub maybesaucerattack:rem maybe3dcubeattack too! :)
 if j=0 then py=1-py:gosub rebuild3dcube:gosub maybesaucerattack:rem maybe3dcubeattack too! :)

 player0colors(0)=8-j
 goto done3dcube

load3dcubenormally

 rem TIE Fighter 
 if py=0 then goto load3dcube 
 rem player0colors(0)=player0y/20
 rem player0colors(0)=15:rem player0x/16
 rem 20250102 now need Atari 2600 fade colors for TIE fighers in color RAM array player0colors(0-7) ...
 rem if DisplayList3Shadow(87)=144 then DisplayList3Shadow(87)=128 else player0colors(0)=DisplayList3Shadow(87)&%01111111
 if w=0 then loadplayer0(72):REFP0=0
 if w=1 then loadplayer0upsidedown(80):REFP0=0
 if w=2 then loadplayer0(72):REFP0=255
 if w=3 then loadplayer0(96):REFP0=255
 goto almostdone3dcube

 
load3dcube rem green
 player0colors(0)=5
 if w=0  then loadplayer0(8):REFP0=0
 if w=1 then loadplayer0upsidedown(8):REFP0=255
 if w=2 then loadplayer0upsidedown(8):REFP0=0
 if w=3 then loadplayer0(8):REFP0=255
almostdone3dcube
 player0y=y:player0x=x 
done3dcube

 if y<31 then v=%00000111:goto donescaleplayer0 else v=0
 rem if y<52 then v=%11110101:goto donescaleplayer0
 if y<52 then v=%00000101:rem goto donescaleplayer0

donescaleplayer0
 rem NUSIZ0=v
 rem goto skipt0
skipt1 rem now using missile1, not skipped... no multiplexing
 rem if e=0 or t=1 then goto skipt0
 rem t0 -- multiplex sidewinder:
 rem flip sprite 4 different ways, backwards/upsidedown:
 
 missile0y=h:missile0x=e

 if h<48 then v= v|%11110000
 NUSIZ0=v
 
 if w>2 then missile0y=missile0y-2 else missile0y=missile0y+2 
 
donescaleplayer0a

skipt0
 rem -----------------------------------------------------
 rem twinkle stars


 m=m+1
 
 rem -- 20240921 deactivating this - to hectic to watch double speed palette switching on top of fast scrolling...
 rem if m<>3 then goto skipdoublespeedscroll: rem -----------faster palette switching when speeding
 rem if joy0up=1 or joy0down=1 then goto fasterinmotion
skipdoublespeedscroll
 return:rem --------------------loadbalancing test - call from bottom vertial blank "gosub loadbalanceframeskiploadbalanceframeskip"

loadbalanceframeskip
 if m<7 then goto skiprowcoloring 
 m=0 
 rem HMM0 = $FF
 rem WSYNC = $C0 : HMOVE = $C0
 rem " nop"
 rem ENAM0=2
 rem HMM0 = $C0

 rem passing line fx
 rem HMBL = $FF
 rem WSYNC = $C0 : HMOVE = SUSTAINFORFRAMES:rem $C0
 rem ENABL=2
 rem HMBL = SUSTAINFORFRAMES :rem $C0

 rem if TileCharacters(0)<>123 and t=1 then TileCharacters(0)=123 else TileCharacters(0)=46
 rem if TileCharacters(3)<>123 and t=0 then TileCharacters(3)=123 else TileCharacters(3)=46


fasterinmotion

 d=q:q=r:r=d:rem swap q and r
 COLUBK=0
 gosub alternaterowcolors
 if s=1 and joy0up=0 then BYTErowoffset=BYTErowoffset-12:
 if s=2 and joy0down=0 then BYTErowoffset=BYTErowoffset+12:rem slow drift down
 return:rem 20250102 patching likely over cycle
skiprowcoloring
 
 if score>0 then goto donehit:rem 20241005 (tracker editor is active)

 rem set right/left ring boundries?
 rem if joy0right=1 and BITIndex<71 then MUSICINDEX=45:BITIndex=BITIndex+1:s=1:gosub adjustright
 rem if joy0left=1 and BITIndex>0 then MUSICINDEX=75:BITIndex=BITIndex-1:s=1:gosub adjustleft
 if joy0right=1 then MUSICINDEX=45:BITIndex=BITIndex+1:s=1:gosub adjustright
 if joy0left=1 then MUSICINDEX=75:BITIndex=BITIndex-1:s=1:gosub adjustleft


 if joy0up=1 then MUSICINDEX=160:BYTErowoffset=BYTErowoffset-12:s=1:gosub speedup:goto pickupmain

 rem 20241002 warp forward when The Rainbow is active
 rem superflous, joy0up already 0 if n=0 and joy0up=0 then BYTErowoffset=BYTErowoffset-12:s=1:gosub speedup:goto pickupmain
 if n=0 then BYTErowoffset=BYTErowoffset-12:s=1:gosub speedup:goto pickupmain

 if joy0down=1 then MUSICINDEX=230:BYTErowoffset=BYTErowoffset+12:s=2:gosub slowdown 

pickupmain
 if SWCHB|%11110111=247 and t=1 then SUSTAINFORFRAMES=SUSTAINFORFRAMES+1:gosub shiftlocktogglebw

 rem hit something? stream colors and allow a new palette to be selected if not in motion...
 rem --------------- 
 
 rem 20240921 hitting floating pieces of the ring or photon torpedoes does not increase score:
 rem (but missing them decreases score)
 if CXPPMM & %01000000>0 then k=0:gosub newsidewinder:CXCLR=0:goto donehit:rem hit satellite 
 
 rem if  CXM1P & %01000000>0 then player1y=92:player1x=missile0x:CXCLR=0:gosub increasescore:goto donehit:rem --- rainbow pushes triangle back to top!
 if  CXM1P & %01000000>0 then i=5:CXCLR=0:gosub increasescore:goto donehit:rem --- rainbow pushes triangle back to top!


 rem tst if  CXM1P & %10000000>0 then y=92:v=0:x=player1x+7:CXCLR=0:gosub increasescore
tst if  CXM1P & %10000000>0 then j=5:CXCLR=0:gosub increasescore


donehit

 rem 20241007 -- persist hi score with px counter
 rem -- 20240102 freeing cycles still over .... if px>29 then gosub persisthiscore
 rem -- 20240102 freeing cycles still over .... if f=0 then px=px+1

 rem 20241009 fall thru opt saving cycles if joy0fire=1 and f=0 then f=130 else f=f-1:return 
 
rebuildmusic
 rem create new musical score and instrument defs:"
 rem for i=0 to 255
 rem if i=44 or i=74 or i=159 or i=229 then goto skipnote
 rem d=MusicData(i)&%00011111
 rem MusicData(i)=d+3:rem 3
skipnote 
 rem next i:DisplayList3Shadow(119)=DisplayList3Shadow(119)+1
 rem i=0:rem restore i variable to 0 state, used for explosion status of Saucer
 rem if DisplayList3Shadow(119)=58 then DisplayList3Shadow(119)=48:DisplayList3Shadow(118)=DisplayList3Shadow(118)+1
 return

slowdown
 if m>2 then return
 if y<96 then y=y+1
 if player1y<96 then player1y=player1y+1
 if h<94 then h=h+1:rem missile0y=missile0y+1
 return

speedup
 rem y ... if player0y>4 then player0y=player0y-1
 if t=1 then return
 if y>4 then y=y-1
 if player1y>4 then player1y=player1y-1
 if h>4 then h=h-1:rem missile0y=missile0y-1

 return

adjustleft
 x=x+5
 player1x=player1x+5
 if t=1 then e=e+2:rem missile0x=missile0x+3
 return

adjustright
 x=x-5
 player1x=player1x-5
 if t=1 then e=e-2:rem missile0x=missile0x-3
 return

maybesaucerattack
 u=u+1
 if u=5 then u=0:k=0:gosub newsidewinder

 return

 rem data paletter 5,5,2,3,12,4,14,7,8,1
 rem data paletteq 13,13,6,14,11,10,6,8,4,15

 rem adding 1st nybble for Atari2600 (otherwise greyscale)
 rem data paletter $55,$d5,$22,$33,$cc,$44,$ee,$77,$88,$11
 rem data paletteq $dd,$5d,$66,$ee,$bb,$aa,$66,$88,$44,$ff
 rem expanding to 18
 data paletter $55,$d5,$22,$33,$cc,$44,$ee,$77,$88,$11,$2c,$84,$0e,$5a,$cc,$4a,$4e,$94,$9c,$b8
 data paletteq $dd,$5d,$66,$ee,$bb,$aa,$66,$88,$44,$ff,$28,$de,$42,$54,$c6,$dc,$44,$9a,$98,$bc



 rem ------------------------------------------------
 rem ---gameloop2 subroutine, runs every frame:    --
 rem ------------------------------------------------
 
 rem loadbalancing -(Televisions bottom vertical blank cycle space)-
 
 gosub loadbalanceframeskip
 
 rem end loadbalancing 


 rem COLUBK=12
 if missile1y=0 and joy0fire=1 and g<>15 then g=15:rem flag in action
 if g=15 then missile1y=missile1y+2 else goto skipmissile1 

 if missile1y>96 then g=0:missile1y=0:missile1x=80
 if joy0left=1 and t=0 then missile1x=missile1x-4
 if joy0right=1 and t=1 then missile1x=missile1x+4
skipmissile1

 
 if score=0 then return:rem score is musical score being edited :)

 rem ---- call tracker editor ------
 if SUSTAINFORFRAMES<5 then SUSTAINFORFRAMES=5:rem SUSTAINFORFRAMES+1

 if score=1 then MUSICINDEX=0:gosub drawtrackergui:score=2:return
 if score>1 then by=score-2:bx=MUSICINDEX+by:gosub doedit:rem edit all 5!
 rem if score=2 then bx=MUSICINDEX:gosub doedit:rem edit v1 note
 rem if score=3 then bx=MUSICINDEX+1:gosub doedit:rem v1 instrument
 rem checknext if score=7 then goto checknext:rem debug on next
 return

 rem ------------------------------------------------------------------------
 rem --- relocated subroutines from 1st gameloop (reserved memory exceeded):
 rem ------------------------------------------------------------------------

 rem 20250102 2143 reverse orign in bank 1, relocating more:
 
 rem 2091 reverse orign, closer...
 rem 2055 reverse origin, closer still...

decp
 p=p-1
 if p=0 then p=15
 return

 rem releasesaucer
 rem player1y=0:gosub decreasescore:i=0:rem i is explosion flag
 rem return

rebuildsaucer
 player1y=92:player1x=screamers(z):z=z+1:rem too aggressive... k=0:gosub newsidewinder
 rem if crashes? if m=3 then k=0:gosub newsidewinder
 rem works k=0:gosub newsidewinder
 return

 rem release3dcube
 rem y=0:gosub decreasescore:j=0:v=0:rem i is explosion flag v is scaling facor
 rem return

rebuild3dcube
 y=92:x=screamers(z):z=z+1
 return


increasescore 
 rem if t=1 then return
 rem DisplayList3Shadow(111)=DisplayList3Shadow(111)+1
 rem if DisplayList3Shadow(111)<>58 then return
 rem DisplayList3Shadow(111)=48:DisplayList3Shadow(110)=DisplayList3Shadow(110)+1 
 
 rem 20250103 reusing px variable in place of C64 screen RAM to count 10 hits for Warp Fx
 if px>16 then px=0 else px=px+1:return

 o=n:n=0:l=255:rem Rainbow Rings Fx!

 rem if DisplayList3Shadow(110)<>58 then return
 rem DisplayList3Shadow(110)=48:DisplayList3Shadow(109)=DisplayList3Shadow(109)+1 

 gosub testr:rem include tennuous Rings! 2025 RC8

 return

advancepallette
 if n<19 then n=n+1 else n=1 
 r=paletter(n):q=paletteq(n)
 rem DisplayList3Shadow(85)=48+n
 return



rebuildsid456a rem 20241002 rebuild instrument defintions - sounds better
 rem for bx=0 to 32
 rem SID4(bx)=SID4(bx)+2:rem SID4(bx)=SID4(bx)&%11110111:mask squelch off
 rem test squelch, interesting not 100% effective SID4(bx)=SID4(bx)^%00001000
 rem SID5(bx)=SID5(bx)+2
 rem SID6(bx)=SID6(bx)+2
 rem next bx
 rem DisplayList3Shadow(154)=DisplayList3Shadow(154)+1
 return 

rebuildsid456b rem 20241002 rebuild instrument defintions - reverse direction
 rem for bx=0 to 32
 rem SID4(bx)=SID4(bx)-2:rem SID4(bx)=SID4(bx)&%11110111
 rem SID5(bx)=SID5(bx)-2
 rem SID6(bx)=SID6(bx)-2
 rem next bx
 rem DisplayList3Shadow(154)=DisplayList3Shadow(154)-1
 return 

rebuildmusic2
 rem create new musical score and instrument defs:"
 rem for i=0 to 255
 rem if i=44 or i=74 or i=159 or i=229 then goto skipnote2
 rem d=MusicData(i)&%00001111
 rem MusicData(i)=d+5:rem 3
skipnote2 
 rem next i:DisplayList3Shadow(119)=DisplayList3Shadow(119)+1
 rem i=0:rem restore i variable to 0 state, used for explosion status of Saucer
 rem if DisplayList3Shadow(119)=58 then DisplayList3Shadow(119)=48:DisplayList3Shadow(118)=DisplayList3Shadow(118)+1
 rem MUSICINDEX=0
 return




shiftlocktogglebw rem ---- either bw color switch or left shift/shift lock thrown
 rem ---------
 if var1=0 and joy0up=1 then var1=1:gosub rebuildsid456a:return
 if var1=0 and joy0down=1 then var1=1:gosub rebuildsid456b:return
 if var1=0 and joy0left=1 then var1=2
 if var1=1 and joy0up=0 and joy0down=0 then var1=0
 if var1=2 and joy0left=0 then var1=0:gosub rebuildmusic2:rem avoid starting left subtune

 rem 20250109 (locked cam when BW switch was engaged) if joy0right=1 then score=1:rem was gosub editpattern
 return

persisthiscore
 rem DisplayList3Shadow(109),DisplayList3Shadow(110),DisplayList3Shadow(111)
 rem reusing px  px=0
 m=3:COLUBK=5
 rem goto setthiscore:rem debug

 rem if DisplayList3Shadow(109) < DisplayList3Shadow(105) then goto resetscore
 rem if DisplayList3Shadow(109) = DisplayList3Shadow(105) and DisplayList3Shadow(110) < DisplayList3Shadow(106) then goto resetscore
 rem if DisplayList3Shadow(110) = DisplayList3Shadow(106) and DisplayList3Shadow(111) < DisplayList3Shadow(107) then goto resetscore

sethiscore 
 rem DisplayList3Shadow(105)=DisplayList3Shadow(109):DisplayList3Shadow(106)=DisplayList3Shadow(110):DisplayList3Shadow(107)=DisplayList3Shadow(111)
resetscore
 gosub initscore: rem same as below
 rem DisplayList3Shadow(109)=48:DisplayList3Shadow(110)=48:DisplayList3Shadow(111)=48 
 return


alternaterowcolors rem expects i and j to have colors
 if n=0 then gosub incp:q=p*16:rem 20250111
 rem rowcolors(8)=q: rem bottom row
 rem rowcolors(7)=q:rem 2nd up from bottom
 rem rowcolors(6)=q:rem 3rd up from bottom
 rem space saving:
 for f=6 to 8:rowcolors(f)=q:next f:rem reused counter for next SID when button is held

 if n=0 then gosub incp:r=p*16
 rem rowcolors(5)=r:rem 4th up from bottom
 rem rowcolors(4)=r:rem 5th up from bottom
 for f=4 to 5:rowcolors(f)=r:next f:f=75:remreused counterf2again; needed more space,,,

 if n=0 then gosub incp:q=p*16
 rowcolors(3)=q:rem 6th up from bottom
 
 if n=0 then gosub incp:r=p*16
 rowcolors(2)=r:rem 7th up from bottom

 rem one more row...
 if n=0 then gosub incp:q=p*16
 rowcolors(1)=q:rem 6th up from bottom
 
 rem --keep top 3 rows black for fade fx over the horizon

 rowcolors(0)=0:rem 2nd
 rowcolors(9)=0:rem top row
 rem rowcolors(1)=0:rem 3rd

 if n=0 then gosub decp:gosub decp:gosub decp:gosub decp:gosub decp:gosub decp

 gosub screamerrender
 return

testr
 for f=239 to 0 step -1
 rem virtualworld(f)=0
 rem f=virtualworld(f)
 rem virtualworld(f)=f^255
 virtualworld(f)=virtualworld(f)^255
 next f

 return


 rem -----------------------TRACKER EDITOR INGAME------------------------------
 rem editpattern rem --- input causes CRT jump like a ZX80 at 30/25 Hz
 rem ------------color coded editor with syntax checking, like vim or vi ;)

doedit
 rem hilight cursor
 rem if score=2 then DisplayList3ShadowColor(8)=1:DisplayList3ShadowColor(9)=1:DisplayList3ShadowColor(31)=14:goto editj:rem 1st datum 
 rem if score=3 then DisplayList3ShadowColor(8)=14:DisplayList3ShadowColor(9)=14:DisplayList3ShadowColor(13)=1:DisplayList3ShadowColor(14)=1:goto editj
 rem if score=4 then DisplayList3ShadowColor(13)=14:DisplayList3ShadowColor(14)=14:DisplayList3ShadowColor(18)=1:DisplayList3ShadowColor(19)=1:goto editj
 rem if score=5 then DisplayList3ShadowColor(18)=14:DisplayList3ShadowColor(19)=14:DisplayList3ShadowColor(23)=1:DisplayList3ShadowColor(24)=1:goto editj
 rem if score=6 then DisplayList3ShadowColor(23)=14:DisplayList3ShadowColor(24)=14:DisplayList3ShadowColor(28)=1:DisplayList3ShadowColor(29)=1:goto editj
 rem if score=7 then DisplayList3ShadowColor(28)=14:DisplayList3ShadowColor(29)=14:DisplayList3ShadowColor(31)=1
editj
 rem if joy0right=0 and joy0up=0 and joy0down=0 and var1=1 then var1=0:rem same input scheme to move joystick incrementally
 rem if joy0up=1 and var1=0 and score=7 then var1=1:score=2:gosub skipcontrols:return:rem next pattern
 rem if joy0down=1 and var1=0 and score=7 then var1=1:score=2:gosub skipcontrols:return:rem next pattern


 rem if joy0up=1 and MusicData(bx)<38 and var1=0 then var1=1:MusicData(bx)=MusicData(bx)+1:SUSTAINFORFRAMES=0:gosub PlayMusic:MUSICINDEX=MUSICINDEX-5:gosub drawtrackergui:SUSTAINFORFRAMES=SUSTAINFORFRAMES+1
 rem if joy0down=1 and MusicData(bx)>0 and var1=0 then var1=1:MusicData(bx)=MusicData(bx)-1:SUSTAINFORFRAMES=0:gosub PlayMusic:MUSICINDEX=MUSICINDEX-5:gosub drawtrackergui:SUSTAINFORFRAMES=SUSTAINFORFRAMES+1
 
 rem if joy0right=1 and var1=0 then var1=1:score=score+1:rem edit next 
 rem 20241010 patched to prevent right tune from always launching after editing (tied to event)
 rem if joy0right=0 and score=8 then score=0:gosub cleartrackergui:DisplayList3ShadowColor(31)=14:MUSICINDEX=0:SUSTAINFORFRAMES=0:rem done
 
 return:rem goto doedit

cleartrackergui
 rem for bx=0 to 79
 rem by=120+bx:rem var2=trkedit(bx):var2=var2-64
 rem rem if bx>30 then by=by+40:rem labels on next line 
 rem if bx>30 and bx < 40 then by=by+40:DisplayList3Shadow(by)=DisplayList3Shadow(88) else DisplayList3Shadow(by)=DisplayList3Shadow(88):rem labels on next line 

 rem next bx
 return

skipcontrols bx=MUSICINDEX+9
 rem if MusicData(bx)=0 then MUSICINDEX=MUSICINDEX+10 else MUSICINDEX=MUSICINDEX+5

 rem SUSTAINFORFRAMES=0:gosub PlayMusic:rem want next pattern 0 duration setting increments MUSICINDEX by 5
 rem MUSICINDEX=MUSICINDEX-5
 rem SUSTAINFORFRAMES=SUSTAINFORFRAMES+1
 
 rem gosub drawtrackergui
 return

drawtrackergui
 rem var1=1:rem init to wait to release joystick
 rem data trkedit "PATTERN INST NOTE INST NOTE LENNEXT DONE"       

 rem for bx=0 to 39
 rem by=120+bx:var2=trkedit(bx):var2=var2-64
 rem if bx>30 then by=by+40:rem labels on next line 
 rem DisplayList3Shadow(by)=var2 
 rem next bx
 rem if MUSICINDEX<100 then DisplayList3Shadow(164)=48:bx=MUSICINDEX:goto donewithmusicindex100s
 rem if MUSICINDEX>=200 then DisplayList3Shadow(164)=50:bx=MUSICINDEX-200:goto donewithmusicindex100s
 rem DisplayList3Shadow(164)=49:bx=MUSICINDEX-100
donewithmusicindex100s
 rem bx=bx/10:by=b:rem (modulus remainder in temp variable b)
 rem bx=bx+48:by=by+48
 rem DisplayList3Shadow(165)=bx
 rem DisplayList3Shadow(166)=by
 rem ----v1 note
 rem var2=MusicData(MUSICINDEX)
 rem if var2>29 then DisplayList3Shadow(168)=51:bx=var2-30:goto donev1tens
 rem if var2>19 then DisplayList3Shadow(168)=50:bx=var2-20:goto donev1tens
 rem if var2>9 then DisplayList3Shadow(168)=49:bx=var2-10:goto donev1tens
 rem DisplayList3Shadow(168)=48:bx=var2
donev1tens
 rem DisplayList3Shadow(169)=bx+48
 rem --- instrument v1
 rem bx=MUSICINDEX+1:var2=MusicData(bx)
 rem if var2>29 then DisplayList3Shadow(173)=51:bx=var2-30:goto donev1tens2
 rem if var2>19 then DisplayList3Shadow(173)=50:bx=var2-20:goto donev1tens2
 rem if var2>9 then DisplayList3Shadow(173)=49:bx=var2-10:goto donev1tens2
 rem DisplayList3Shadow(173)=48:bx=var2
donev1tens2
 rem DisplayList3Shadow(174)=bx+48
 rem --- v2 note
 rem bx=MUSICINDEX+2:var2=MusicData(bx)
 rem if var2>29 then DisplayList3Shadow(178)=51:bx=var2-30:goto donev1tens3
 rem if var2>19 then DisplayList3Shadow(178)=50:bx=var2-20:goto donev1tens3
 rem if var2>9 then DisplayList3Shadow(178)=49:bx=var2-10:goto donev1tens3
 rem DisplayList3Shadow(178)=48:bx=var2
donev1tens3
 rem DisplayList3Shadow(179)=bx+48
 rem --- instrument v2
 rem bx=MUSICINDEX+3:var2=MusicData(bx)
 rem if var2>29 then DisplayList3Shadow(183)=51:bx=var2-30:goto donev1tens4
 rem if var2>19 then DisplayList3Shadow(183)=50:bx=var2-20:goto donev1tens4
 rem if var2>9 then DisplayList3Shadow(183)=49:bx=var2-10:goto donev1tens4
 rem DisplayList3Shadow(183)=48:bx=var2
donev1tens4
 rem DisplayList3Shadow(184)=bx+48
 rem -- duration 
 rem bx=MUSICINDEX+4:var2=MusicData(bx)
 rem if var2>29 then DisplayList3Shadow(188)=51:bx=var2-30:goto donev1tens5
 rem if var2>19 then DisplayList3Shadow(188)=50:bx=var2-20:goto donev1tens5
 rem if var2>9 then DisplayList3Shadow(188)=49:bx=var2-10:goto donev1tens5
 rem DisplayList3Shadow(188)=48:bx=var2
donev1tens5
 rem DisplayList3Shadow(189)=bx+48
 return
 rem ------------------end--TRACKER EDITOR INGAME------------------------------

virtualworld
........xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxx....xxxxxxxx
...xx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xx.xxxxx.....xxxxxxxx
...xx...xxxx......xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxxxx....xxxxx....x.xxxxxxxx
........xxxx.xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xx.xxxxxxxxxxxxxxx.xx.xxxxx....xx.xxxxxxxx
xxxxxxxxxxxx.xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxx.x..xxxxx....xxx.xxxxxxxx
xxxxxxxxxxxx......xxxxxxxxxxxx.....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxx....xxxx.xxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx........xxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxx...xxxxx.xxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxx...........xxxxxxxxxxx.xxxxxxxxxxxxxxx....xxxxx...xxxxx.xxxxxxxx
xx.xxxx......xxxxx..xxxxxxx.............xxxxxxxxx...xxxxxxxxxxxxxx....xxxxx...xxxxx.xxxxxxxx
xx...xxxx....xx.....xxxxxxxx..........xxxxxxxxxx.....xxxxxxxxxxxxx....xxxxx...xxxxx.xxxxxxxx
xx...xxxxxxxxxx..xxxxxxxxxxxx........xxxxxxxxxx.......xxxxxxxxxxxx....xxxxx...xxxx.xxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx......xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxx...xxx.xxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxx...xx.xxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxx.xx....xxxxx....xxxxxxxxxxxxx
.......xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
.xx.xx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
.......xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.....xxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxx
.xx.xx.xxxxxxxxxxxxxx..........xxxxxxxxxxxxxxxxxxxxxx......xxxxxxxxxxxxxxxxxxxxxxxxxx...xxxx
x......xxxxxxxxxxxxxx..........xxxxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxxxxxx.xxx.xxx
xxxxxxxxxxxxxxxxxxxxx..........xxxxxxxxxxxxxxxxxxxxxx........xxxxxxxxxxxxxxxxxxxxxxxx...xxxx

sprites
..xxxx..
.xXXXXx.
XX.xx.XX
XxxxxxXX
x.XXXX.x
XX....XX
.xxxxxx.
..xxxx..

........
..xxxxxx
.x....xx
x....x.x
xxxxx..x
x...x.x.
x...xx..
xxxxx...

X.......
........
.xxxxxx.
xx..XXxx
x.xxxxXx
x.xx...x
xx....xx
.xxxxxx.
24
...x....
..xxx...
.x.xxx..
x..xxxx.
.x.xxxx.
..xxxx..
...xx...
........

........
........
........
........
........
........
........
........
40
x....x..
........
...x..x.
.x...x..
.xxx.x..
.x..x..x
..xxx.x.
x...x...

........
..x..x..
...x....
...x.x..
..xx.x..
..x.x...
...xx.x.
........

........
........
........
...x....
...x.x..
..x.x...
...x....
........

........
........
........
........
...x.x..
...xx...
........
........

72
..X.....
.X.XX...
X.XXXX.X
..XXX.X.
.....X..
........
........
........

........
........
X..XX..X
X.XXXX.X
X.XX.X.X
X..XX..X
........
........

........
........
.X.....X
XX.XX.XX
XXXXXXXX
XX.XX.XX
.X.....X
........

........
X.....X.
XX.XX.Xx
xXXXXXXX
.X.XX.XX
..x....x
........
........


player0colors 5,4,4,4,15,15,15,15


chiptunes
1,23,1,31,12
1,16,1,31,4
1,15,1,31,8
0,0,0,0,14
1,23,1,31,12
1,16,1,31,8
1,15,1,31,15
1,31,1,31,35
0,0,0,0,0
45
1,15,1,7,15
1,13,1,7,15
1,15,1,31,12
1,15,1,31,12
1,15,1,31,12
0,0,0,0,24
75
1,15,1,7,7
1,13,1,7,15
1,15,1,31,7
1,15,1,31,12
1,15,1,31,6
0,0,0,0,12
1,15,1,7,15
1,13,1,7,7
1,15,1,31,15
1,15,1,31,6
1,15,1,31,12
0,0,0,0,24
1,29,1,19,20
1,31,1,23,20
1,29,1,19,20
1,31,1,23,20
0,0,0,0,0
160
1,31,1,31,15
1,31,1,23,15
1,29,1,19,15
1,31,1,23,15
8,24,8,20,8
10,24,10,20,8
8,24,8,20,4
12,9,12,7,4
8,24,8,20,8
10,24,10,20,15
8,24,8,20,8
10,24,10,20,8
8,24,8,20,4
0,0,0,0,0
230
10,24,10,20,4
8,24,8,20,4
10,24,10,20,4
8,24,8,20,4
10,24,10,20,4
7,27,7,27,8



EXT
RA
8,24,8,20,95

7,27,7,27,8
7,13,7,13,8
7,6,7,6,8
0,0,0,0,4
7,27,7,27,8
7,6,7,6,8
7,6,7,6,8
12,3,12,2,4
12,5,12,2,4
7,27,7,27,8
7,13,7,13,8
7,6,7,6,8
0,0,0,0,4
7,27,7,27,8
7,6,7,6,8
7,6,7,6,8
12,3,12,2,4
12,5,12,2,4
0,0,0,0,0

                                                               