A downloadable game

1234567890123456789012345678901234567890123456789012345678901234567890123456789

Circle-Circle Dot-Dot (CC-DD)

for the Commander X16 (by Steve Lewis - Xiphod)

=====================

Submitted for the 2026 "15th Edition of BASIC 10 Liner Contest"

Category "PUR-80"


Files:

X16CCDD.PRG     CC-DD game in Commander X16 BASIC Tokenized Format (use LOAD)

X16CCDD.BAS     CC-DD game in ASCII text format (can past into X16 emulator)

X16CCDD-1.JPG   Running CC-DD on the CX16 Official Emulator R49

X16CCDD-2.JPG   Running CC-DD on physical CX16 Hardware

X16CCDD.GIF     Animated GIF of CC-DD in emulator

X16CCDD.TXT     This description of the game software

Firstly, Thank You for permitting me to participate in this contest.

I found out about from gotBASIC discord channel.

Second, when I started on this, I wasn't aware of the broader categories of 120 or "extreme" 256 columns.  The X16 system allows an on-system way to enter BASIC using these expanded number of columns.  It was quite a challenge constraining myself to the 80 columns, which I enjoyed.  

Third, since POKE is stated as allowed, I assumed also VPOKE.  I understand this means the program is fairly CX16 VERA specific.  The new Aquarius+ uses a similar VERA build, so perhaps it may be mostly compatible there also.

CC-DD Game Description

======================

After LOAD and RUN, the game does a brief initialization of a single 16x16 SPRITE that is the 'target of interest.'  Meanwhile, a starfield is generated across the screen.  The only objective is to move the mouse into the center orbiting area of the 'target.'  Note, this does NOT mean the moving target icon itself, but an invisible area near the center of where that icon is orbiting.

That's it!  There is no time limit, but the expectation is that the player would find the target area before the starfield completely fills the screen.

Failing to do so, the target is randomly re-located and the starfield clears, indicating it is another round for someone else to play.

You can play any time for practice.  But the real intent is to play while intoxicated, or after having been spun around quickly three times (even while blindfolded, as is a tradition done with pinatas).  The game is intentionally a low stress party game.


The Name: CC-DD

===============

Circle-Circle Dot-Dot is part of an old rhyme we would say when I was in elementary school (we could make ourselves immune to the "cooties" we might get if we accidentally touched anyone of the opposite-sex).  The game here doesn't really have anything to do with that rhyme.

But since the target-SPRITE goes in a circle, and the starfield is made up of dots, it was just the only short-funny title I cold come up with.

However, I will say that an alternate concept I had for this game was to use a red-background and you would navigate the "ship" through a blood cell.  In that case, the target-white icon would be like a "white" blood cell, and you'd have missions to go attack places, while avoiding the debris field.

Background

==========

My original intent was to have a game where you would navigate the ship (a 16x16 icon) through the generated starfield (which in that case would have been an asteroid field).  A red target would randomly appear, and you would use the keyboard to navigate the ship towards this target- doing so without touching any of the dot-asteroids, which would also be generated as you were playing.

The biggest struggling on that is the X16 has no built in BASIC keyword for SPRITE collision detection (and in any case, my asteroids would just be a single pixel, not separate sprites).  The X16 does have "hardware" ISR-based collision detection between whole sprites.

I felt my idea would not be possible in 10-lines, especially given the way CBM V2 BASIC has limited IF-THEN-ELSE capability.  The X16 extends C64 BASIC quite a bit, but maintains the same IF-THEN-ELSE limits.  That limitation also made keyboard key checking "expensive" (due to not being able to monitor for multiple keys on the same line, at least not very easily).

So, I had to simplify the idea further.  So CC-DD is the result of that simplification.   I liked the idea of having at least one SPRITE, and keeping the randomly generated starfield concept - which here is an example of BASIC doing "two things at once": animating the SPRITE, while also producing the background.

Even though the X16 is 8MHz standard, the interpreted BASIC is still quite slow.  To keep to the 80-column limit, I ended up having to remove most of the "%" for 16-bit numeric processing (so most of the variables are using the CBM-style 5-byte numeric processing).  

So, there is a little trick into how the starfield is generated: when a non-black color is decided, the VERA-write address is set to increment a single pixel at a time.  But if a black-pixel is chosen, VERA is accelerated to "auto-increment" four pixels at a time.  While the starfield generation isn't especially fast, I feel it is still sufficient to make the game interesting.

My only other trick is how to make the target-icon SPRITE circle around.

Many can probably guess how- from a center decided random point, the X has a sin(t) term added, while Y has a cos(t) term added (both with a magnitude of 20-- which originally I wanted to randomize that as well).  There t is a kind of time-increment at 0.1 units for however fast the main loop goes.

Interestingly enough, if you stare at the circle target SPRITE icon, you'll notice it kind of smear towards the direction it is spinning (an optical illusion only, but it is why I stuck with the simple circle icon).

One last thing I'll add is the oddly staggered arrangement of DATA sequences.  

This was purely due to the 80-column limitation.  And I recalled that READ doesn't really care where the DATA values are in the code, it blindly just goes along and finds the next one.

It's a silly code sequence, but I hope someone finds it at least a little entertaining or amusing.  If anything, it is an interesting view of what the Commander X16's built in BASIC can offer.

VERA Notes

==========

Unlike the original C64, the CX16 only talks to the display via "VERA ports."

The VERA has 128KB RAM, and you express the "H" "M" "L" address using $9F20, $9F21, $9F22.  Only 17-bits are needed ($1FFFF), the highest bits in the "H" register indicate how many pixels to increment (or decrement) during each read/write to the "VERA Data Port" (that basically express what color you want to write at whatever the current "target address" is).  

That "target  address" register is $9F23.

VERA has many other features, like scaling pixels, and overlaying SPRITEs at a few different priority layers.  And some advanced VERA FX features to help with some multiplication/vector things.

One main default graphics mode of the CX16 is a 320x240 1bpp video made, called SCREEN 128 (or $80), which is what CC-DD is using.  320x240 is 76,800 bytes.  To avoid having to even deal with the "H" bit, I "pretend" the screen is only about 204 rows (65535/320).  SPRITEs can be moved off the screen in any direction, and the KERNEL handles that just fine.  But I limit the circling SPRITE target icon to move towards the middle region of the screen (and likewise you'll notice the starfield doesn't go all the way to the bottom of the graphics mode).  These were small steps to help keep the program to 10 lines.

One regret is the program has no audio, unfortunate since the CX16 has so much audio capability.  If I had targeted to the 120 or 256 col. categories, that's likely what would have been added.

Notes

=====

You could make the hit box larger (EASY MODE) vs smaller (HARD MODE).

Making the target-sprite be randomly ellipsoid would make things harder also (instead of fixed 20 amplitude, do a random-pick on both X and Y).

Another extension would be supporting gamepad and keyboard.  But since the CX16 natively supports mouse (*and* the mouse wheel), I do like the challenge of making simple games that make use of this interface.

You can easily tighten up the starfield or make it more sparse.  Probably increasing the chance of "black" (and thus offsetting indexes by four more often) would speed it up substantially.

I also want to let the sprite go in CW or CCW direction, but again the 10 row and 80-col limited restricted me on that.

1234567890123456789012345678901234567890123456789012345678901234567890123456789


CC-DD Line by Line Code Explanation

===================================

LINE 10: 

Enter graphics/text overlay video mode (320x240 pixel with 40x30 text).

Initialize RNG with clock timer.

Activate mouse icon and state-polling.

Store first portion of sprite DATA.

Line 20:

Set short single letter variable (V) for VERA base address.

A1 at $3100 is offset of the chosen sprite index.

A2 is used to "walk" the bits in the sprite data bytes.

  Per SPRITE command on line 50, the sprite is set as a 16x16, 1 BYTE per "pixel".  The sprite bytes are really an offset into the palette table, so they could be very colorful.  In this case, each two bytes of the DATA sequence corresponds to a 16-bit sprite width (each bit either off=0=black, or on=1=white).  For ON, we could have chosen a different palette index to change the color of the sprite.

Line 30:

"VERA" POKE the sprite byte. 

Increment to next VERA linear address.

Shift right 1 bit on A2.  (divide by 2)

If A2 reaced 0, then reset to walk back again from MSB. Set A4 to loop again for the next byte.

Line 40:

Knowing sprite is 16x16 bytes, when the A1 address offset passes $31FF we know we are done.

So this is hard-coded rather than having yet-another-counter variable.

If done preparing the sprite, then use SPRMEM to associated sprite index with our now-initialized memory.  Set A4 to 8 so NEXT A4 later will not-loop.

Use this line to store in another set of DATA sequence for the sprite.

Line 50:

Loop the sprite-reading init loop (unless it was declared done above).

If it is done, set KERNAL attributes of sprite index 1: 

  give it priority 3, palette offset 0, no flip, 16x16 x-y, 8-bit color depth (1 byte) R is used to avoid drawing past $FFFF pixels.

  320x240 = 76800, but drawing past 65535 means managing the "17th bit" of the VERA offset address (and that bit is the LSB in V+2).

  Writing to that would override whatever the current Address Increment is, and with 80-col there was no way to bit-mask preserve that during POKEV+2.

  So choice was to just limit the graphics to 320x"204.79" region.

  R is used to remember this constraint and re-initialize this after each session.

Use line to store more of the sprite data sequence.

Line 60:

Clear the screen (full fill RECT with palette index 0 implied).

Init the two lower bytes of the VERA target offset address, back to 0.

Use A as the active offset counter remaining (R).

Set X/Y to a random center of the sprite (avoiding the edges, since the sprite will orbit that center at about 20-36 pixels).

  

Line 70:

DX%/DX% is the distance between the current mouse X/Y and the target sprite center.

B% is initialized to the assumed background color of 0 (black).

Give a basically 8% chance of a colored "star pixel" being output.

  This could be RND(.)>0.92 but to me scaling it by 1000 gave a cleaner looking result.  If a color is decided, B% becomes the palette offset byte value.

  For B%, the % indicates an two-byte integer value. (so INT is not needed)

  

Line 80:

POKEV+2 decides the VERA Auto Address Increment value (written into the first 4-bit nibble of that register).  So $3x defaults 4-byte increment.

  SNG is used to evaluate B% to either 0 (keep 4-byte increment default), or 1 (adjust to 1-byte increment).  This increment is applied any time we write to the VERA Data Point (POKEV+3 will auto increment POKEV,POKEV+1 depending on this auto address increment setting).

POKEV+3 draws the resulting pixel decision (black/increment 1, or color/increment 4).

  Store the current VERA offset address.  When we use MOVSPR in the next line,  this will displace the offset as we are using it for the starfield effect.

    So after the MOVSPR, we have to restore the last generated star offset.

    I = what we call VERA MEDIUM address byte

    J = VERA LOW address byte

  K = 4 (assume we incremented by 4), if B% was non-black then set K = 1 (incremented by 1)

  

Line 90:

  Move the SPRITE 1 index to the X/Y center plus the AC/AD (sin/cos) offsets decided in the last iteration of the loop (which is initially none).

  Restore the VERA offset address using I and J as described above.

  "A" (address) is decremented by the auto increment account.

    This is to ensure we stop at the 320x204 constraint (since not dealing with the 17th VERA bit).

  If the DX/DY computed earlier is within the "hit box" distance of 6 pixels, OR the full starfield has been rendered (reached row limit via monitoring VERA offset) then GOTO 60 as "new round"

Line 100:

  BASIC initializes variables as they are used, so implicitly T is initialized to 0 when first encountered here.  Thereafter, we increment T by 0.1 as a "time offset" simulation.  The eventual byte-value wrapping does not really matter here.

  Use this T to update SINE and COSINE offsets into AC/AD (with ~20 pixel amplitude).

  GOTO 70 to restart the main loop.

Down below is a version that will render the starfield across the full 320x240 screen (instead of just the partial 320x204).  The issue was I could not determine a way to consolidate line 75 in a way that preserved the 80-column constraint (basically have to place a logical 1 in the low byte of V+2 when the "A" offset passes $FFFF).

10 SCREEN$80:A=RND(0):T=0:MOUSE1:DATA0,0,0,0,0,0,0,0,0,0
20 V=$9F20:A1=$3100:A2=$80:READA3:FORA4=1TO8:B%=0:IF(A3ANDA2)<>0THENB%=1
30 VPOKE1,A1,B%:A1=A1+1:A2=INT(A2/2):IFA2<1THENREADA3:A2=$80:A4=0
40 IFA1>$31FFTHENSPRMEM1,1,$3100:A4=8:DATA1,192,3,224,3,96,3,224,1,192
50 NEXTA4:SPRITE1,3,0,0,1,1,1:R=320*240:DATA0,0,0,0,0,0,0,0,0,0,0,0,-1
60 RECT0,0,319,239:POKEV+1,$00:POKEV,$00:A=0:X=RND(.)*200+60:Y=RND(.)*180+20
70 DX%=ABS(MX-X):DY%=ABS(MY-Y):B%=0:IFRND(.)*1001>920THENB%=RND(.)*256
75 Z%=$30-$20*SGN(B%)-(A>65535) : REM HIGH = INCREMENT, LOW = VERA BIT 17
80 POKEV+2,Z%:POKEV+3,B%:I=PEEK(V+1):J=PEEK(V):K=4:IFB%>0THENK=1
90 MOVSPR1,X+AC,Y+AD:POKEV+1,I:POKEV,J:A=A+K:IF(DX%<6ANDDY%<6)ORA>RGOTO60
100 T=T+0.1:AC=SIN(T)*20:AD=COS(T)*20:GOTO70 : REM XIPHOD - MARCH 2026

XIPHOD - MARCH 2026 - THANK YOU!

Download

Download
X16CCDD.BAS 715 bytes
Download
X16CCDD.MP4 502 kB
Download
X16CCDD.PRG 571 bytes
Download
X16CCDD.TXT 9.3 kB
Download
X16CCDDA.BAS 737 bytes
Download
X16CCDDA.PRG 612 bytes
Download
X16CCDD-CODE-EXPLAIN.TXT 6 kB

Install instructions

How to Run

==========

On physical X16 hardware:

- Copy PRG to SD-card

- Insert SD-card

- Power on CX16

- Type LOAD"X16CCDD.PRG"

- Enter command RUN

(can also load from IEC device, may need to use command "DOS 9" first)


In emulator:

- The official CX16 emulator is located:  

https://github.com/X16Community/x16-emulator

- Find "Releases" and look for "Pyrite" (R49), pick your platform 

(macOS, Linux, Win32/64)

- Unzip emulator to folder

- Drag/drop or copy X16CCDD.PRG file to that folder

- Run x16emu.exe (the releases are good about including their dependencies)

- LOAD"X16CCDD.PRG"

- RUN

Alternative 1: From command line, you can do x16emu.exe -prg X16CCDD.PRG -run

Alternative 2: After loading x16emu.exe (or equivalent), you can open X16CCDD.BAS (in nano, emacs, notepad, etc.), and then COPY/PASTE that entire content straight into the emulator.  ASCII to PETSCII adaptation, as needed, will be done automatically.

Leave a comment

Log in with itch.io to leave a comment.