AppleIIbot 280 char Applesoft Demos -- Part 1
Flame Demo (64-byte assembly)
link
My first idea was to see if we could get some assembly language going,
so a good thing to try is my 64B Flame Demo.
This first attempt uses the traditional method of entering assembly
language from BASIC via Applesoft: you have DATA statements holding the
raw 8-bit data for the 6502 Machine Language, you READ the values and
then POKE them to a free
area of memory (often $300 (which is 768 in decimal, on 6502 machines
$ is used to mean hexadecimal)) and then you CALL
to it.
Note this code is longer than 256 chars long which means while it is
a valid Applesoft program, you can't type it in on an actual Apple II
as it will overflow the keyboard input buffer. You can however tokenize
it and load from disk, which must be what the Apple II bot does.
1 FOR X=768TO832:READ A:POKE X,A:NEXT:CALL 768:DATA 44,80,192,44,82,192,32,112,252,169,255,145,42,136,16,251,169,22,133,37,32,34,252,160,39,104,240,5,10,240,4,144,2,73,29,72,48,10,177,40,41,7,170,189,57,3,145,40,136,16,230,198,37,16,221,48,205,0,187,0,170,0,153,0,221
This worked, but then 4am got me thinking about more compact ways to try
and fit larger programs. I looked into the way that Sellam Abraham did things
with his "Mesmerizer Exorciser" Kansasfest 2020 Hackfest entry, but it turns
out that is a bit too big to fit in a tweet.
My next attempt loads a short assembly language program that then decodes
a string. The string is machine language with each byte split into
two values: the first
shifted left by three then xored with the second to get the value.
Why not just include raw 8-bit values? On twitter we're going
to assume you can only pass in ASCII text, so that limits you to 7-bit values.
In addition you can't send control characters (the first 32 values) and
on Apple II+ you can't send lowercase, further reducing things. In the
end you are sort of limited to around 6-bits (64 values) and have to
construct the machine code from that.
Also note that by now I had remembered that Applesoft ignores all spaces
so you can leave them out to get more room even though that makes the code
really hard to read.
1 FOR X=768TO789:READ A:POKE X,A:NEXT:CALL768:DATA162,0,189,106,8,48,12,10,10,10,93,171,8,157,0,12,232,208,239,76,0,12
9 "MBPMBPLFW]WZMYJW]JXLLLW\LEVHIVHZHAKANI^MMH]_OIZMYJTPLJSNQH_H]H[HSD@@DB@@@DAGAB@@CAFEE@BD@G@@EB@D@BAE@@BA@AGBEADA@@@FFE@E@E@C@B@A@E"+
Link to the assembly source:
fire_extreme.s
Circles Demo (101-byte assembly)
link
This is an unreleased demo of mine based on part of Hellmood's "Memories"
256-byte x86 Demo
This program uses 4+4 bit encoding, so it takes two bytes to represent
each machine language byte.
This is a bit wasteful but it's a lot easier to write a 4+4
decoder than a more efficient 6+2 one. Applesoft in particular makes
things really difficult as it has no shift or bitwise logic functions.
It's not easy to write decoders in assembly either, so multiplication
in Applesoft it is. The A=(A-INT(A)) code is the way to get a
remainder (modulus) in Applesoft.
Note in this case I abandoned using a string. It has some problems,
the worst being that you can't include a quote character (ASCII 34).
Using a REM remark (comment) statement takes slightly more room but
everything after it is ignored.
You might ask how we load values from a REM statement. In Applesoft the
whole program is loaded into memory, REM statements and all. Programs
are loaded at $800 in tokenized format, but it's fairly easy to poke
around and find where lines get loaded in memory and then use PEEK to load
the values in.
2 GR:FOR X=0TO100:A=(PEEK(2245+X/2)-32)/4:IFJTHENA=(A-INT(A))*4
3 J=NOTJ:POKE768+X,(PEEK(2144+X)-32)*4+A:NEXT:CALL768:REM+4PY_H&A\RH%A\B&N3 ""?2 29_*'222A^JN8 A,I\B( ^I\( ^I^B( ^I\( ^Y\B$SY\R$P,N)('&&%%$$##""!!!! 5 ="""". ! &.)+)!.*#!'$!( ' . !, ) "."!!+&"""')#)$ $,
Link to assembly source:
circles.s
Autumn (117 byte assembly)
link
This is a slightly shorter version of my
Seasons demo (without color cycling) that was entered in the Outline
Online 2020 Demo Party.
This is using 6+2 coding.
The top 6 bits of the machine code byte are converted to ASCII by shifting
them two bits to the right and then adding 32. The bottom two bits
are accumulated in groups of three and then encoded in the same way
and stored at the end of the string.
Qkumba figured out the crazy use of the exponent (^) operator
to handle the proper shifting to reconstruct the original values.
Because the BASIC decoder uses a lot
of multiplies and shifts, this is fairly slow to decode which is why
it has the {B9} directive to skip 9 seconds. It should skip more but there
were only 4 free chars in the tweet so we couldn't fit a longer delay.
{B9}
1REM(V\I\I\B.Y\A\FY\R@:A\9\&B9\A\F9\R@:A\9\9]9]9]9]L'Y^T Y^I\:@A\D Y\.J Y\A\J Y\A\I^")^1^A^*!" JI\,HI\*\TG([]I\I\I\(5]3 P")90'6"F)=8KBI.)H%1@&1F1WA6%=:S50@"E,\
2FORI=0TO116:C=INT((PEEK(2171+I/3)-32)/4^(I-INT(I/3)*3)):POKE768+I,((PEEK(2054+I)-32)*4)+C-INT(C/4)*4:NEXT:CALL768
Link to assembly source:
autumn.s
Spaceship -- Applesoft Shapetable
link
After managing to fit Autumn in, I gave up on assembly language and went
back to coding in Applesoft. One thing Applesoft has going for it is
"Shape Tables" which are a software vector drawing library included
in the Applesoft BASIC ROMs.
To use shape tables, you map out the vectors. You can only do
draw+move UP/DOWN/LEFT/RIGHT and pen-up move (no-draw) UP/DOWN/LEFT/RIGHT.
Each operation is three bits, you can pack two or sometimes three directives
per byte and there's a header with the number of shapes and the offset
of the shapes.
Typically you'd POKE the shapetable into memory via DATA
statements (there's no easy way to
load them, though oddly there is a dedicated command to loading them from
cassette tape). POKEing wastes a lot of space, so I thought maybe we
can stick it in a REM statement like before. There's a trick here, you
need to have your shapetable be valid ASCII. To do that you need the second
value in each byte to not be a not-draw instruction, and also you can't
have a third value.
Once you have your shapes, you can DRAW them at a location, or XDRAW
to xor draw (which makes it easier to draw and erase). There is ROT
to rotate and SCALE to scale.
Line 2 in the code tells Applesoft where the shapetable is by POKEing
the shapetable address into the proper zero page addresses.
The shape table in the REM depends on being at line 5, because we depend on the
actual layout of the BASIC program.
We point the shapetable to address $814. If you look there in memory you find the values
29 08 05 00 B2 37 ...
The 29 08 (little endian) is actually part of the linked list of the BASIC
program in memory pointing to the next line. The 05 00 is the line number.
And B2 is the token for REM followed by the data. By pointing at the
29 we say we have $29 shapes, but that doesn't matter as we only use
the first one. The next value is ignored. The next is the offset to
the first shape (from the beginning). Since this is 5 it skips the REM
and goes to the data.
The rest is just regular Applesoft BASIC, it draws some random stars,
moves the spaceship, and draws some flames and then repeats.
2POKE232,20:POKE233,8
5REM7:'%%,5..>'<29'
6HGR2:FOR X=1 TO 100:HCOLOR=7:HPLOT RND(1)*280,RND(1)*192:NEXT
7SCALE=5:FORR=0TO16:ROT=R:GOSUB9:GOSUB9:NEXT:FOR X=100TO270:GOSUB9
8HCOLOR=5:HPLOTX-30,86+RND(1)*16TOX-10,91:X1=X+SQR(X/25):GOSUB9:X=X1:NEXT:GOTO6
9XDRAW1ATX,91:RETURN
Animated Nyan Cat -- Shape Tables and Page Flipping
link
I wanted to do something with page-flipping and shape tables, possibly
the only two graphics features the Apple II can do better than other
8-bit computers. I was thinking something like my
Shapetable Party demo.
In the end trying to make complex ASCII shape tables was too much work.
But then, oddly, I had a dream where I made a HGR version of Nyan Cat.
So here it is, a program that brought a lot of joy.
Not much exciting about it, the poptart-cat shapetable is done more or
less like in the previous example. It uses HGR:HGR2 to clear both
graphics pages and leaves things on PAGE2. The rainbow and cat are
first drawn on PAGE2 (the routine at line 8 draws them). Then
they are drawn again at a slightly different offset on PAGE1.
The POKE 230,32 tells the Applesoft routines to draw to PAGE1
($2000) instead of PAGE2 ($4000). Ideally we'd switch back to page1
so we could see both being drawn, as there's
an annoying pause while PAGE1 is drawn and you can't see it. However
I was out of characters to flip before drawing.
As some have pointed out, I used tail-call optimization here, where instead
of GOSUB9 one last time in line 8 I fall through to line 9 and let the
return from there return from the GOSUB to line 8. This is something
I do a lot in 6502 assembly and it's fun to do it in BASIC too.
The actual rendering loop is line 7 which just flips pages rapidly.
The V=0 call was added to slow the animation a bit, it roughly is as slow
as the GOTO7. I tried putting slower things (like SQR() square root)
to slow it even more, but you have to put things twice or the animation
is unbalanced and there wasn't enough room for two.
It was a bit more of a pain than you think to get the HGR colors to
plot in rainbow order. Also in size coding like this you run into issues
where it takes less characters to have things to the upper left part
of the screen as the coordinates can be less than 3 digits.
2POKE232,20:POKE233,8
5REM$,.,6>???$$--5
6ROT=0:SCALE=5:P=49236:HGR:HGR2:GOSUB8:Q=1:POKE230,32:GOSUB8
7POKEP+1,0:V=0:POKEP,0:GOTO7
8C=5:Y=80:XDRAW1AT134,102+Q*2:GOSUB9:C=1:GOSUB9:C=6:GOSUB9:C=2
9HCOLOR=C:FORZ=YTOY+5:FORX=0TO13:Q=NOTQ:HPLOTX*8,Z+QTOX*8+7,Z+Q:NEXTX,Z:Y=Z:RETURN
Double Hires Pattern
link
I was interested in seeing if I could get some better colors going.
I have done demos that do
Vapor Lock and
mid-screen race-the beam mode switching
but I was pretty sure the Linux-based emulator used by the Apple II bot
can't do that type of cycle-counted effects.
The emulator did seem to be emulating an Apple IIe, which opened things
up for double hi-res graphics. Those are tricky to do and you can't
easily program them from Applesoft. I actually tried at first but had
some issues fitting in a reasonable amount of room, so assembly language
it is.
This was just a first test but it made a neat pattern. I had a lot of trouble
just getting horizontal lines drawn. To do that in double-hires you
have to draw an increasingly rotated-by-one bit version of the color
across 4 bytes on two different bank-switched graphics pages, a huge pain.
{B10}
1REM(X\(V\C7PC#PC PJ(AYJ A_J(Y_I_(* Y_I_RPT[3$ H H ($]H)C5P(1 C5P(1 B$\8I_D)R@)_8 XP)%%1&9Z)OF!S+ !7 ' #1GA#
2FORI=0TO77:C=INT((PEEK(2132+I/3)-32)/4^(I-INT(I/3)*3)):POKE768+I,((PEEK(2054+I)-32)*4)+C-INT(C/4)*4:NEXT:CALL768
Link to assembly source:
raster2.s
Double Hi-res Rasterbars (126 byte assembly)
link
My goal was to get two colors of double hi-res rasterbars going.
It turns out this is much harder than it sounds. I did get one
rasterbar moving fairly easily, but getting a second independent bar
was trouble. Even then it was 136 bytes which was too big for the loader.
So I size optimized the code like crazy, including using the "BIT" trick
to avoid a jump and various other things and got it down to 126 bytes.
The pattern ended up being a bit nonsensical, as I had to use an EOR (xor)
to calculate the location of the second bar, but there is more than one
color.
Then I optimized down the BASIC loader. It's still qkumba's 6+2 loader
but I found some parenthesis I could remove, did some algebra and orders-of-operation
changes to remove some more parenthesis, and did some tricks with
integer variables. Applesoft does everything in floating point, but
you can specify 16-bit integer values which will truncate, which removes
the need for an INT (though qkumba later noticed that might not be
necessary).
1REM(X\(V\C7PC#PC P1YJ (+ J!(+ F,!R0L"HR+HBC* RTYA_F2$JJ!A_I_R!D 2 * &9_JO= A_F2Y_H H ($]H)C5P(; C5P(; B$\:JQ_$R8I_D)R@)_8 $(, W[_XP)%%:0'TP!((Z !!=5!V-AY-4"0P%T!T0@QT9X0.Y
2FORI=768TO894:C%=(PEEK(1924+I/3)-32)/4^(I-INT(I/3)*3):POKEI,C%+4*(PEEK(1286+I)-32-INT(C%/4)):NEXT:CALL768
Link to source code:
raster4.s
Box-drawn Pumpkin
link
I got the idea for this while sitting in a really long faculty meeting.
It's just drawing a bunch of boxes. Each box is 5 values: color and x1,x2
to y1,y2. These are drawn in Applesoft with HLIN calls.
I drew a jack-o-lantern as it seemed the seasonable thing to do, also
people were doing that on the Atari bot.
0GR:POKE49234,0:FORI=0TO13:READC,A,B,Q,Z:COLOR=C:FORY=QTOZ:HLINA,BATY:NEXTY,I
9DATA 1,0,39,31,47,9,11,27,10,44,9,8,30,13,42,9,6,32,16,37,9,5,33,20,30,4,17,21,4,9,13,11,15,18,22,13,24,28,18,22,13,10,28,31,34,13,12,26,35,36,9,14,15,31,33,9,22,23,34,36,13,19,20,22,27,13,17,22,26,27
Then I had the thought: this is just plain data, and the value are always 0 to 48,
so why not make it 6-bit encoded ASCII in a REM statement?
The updated code had a lot of PEEKs, so I tried a new trick where we use
a DEF FN function definition to save some space (and at the same time
find a bug in my Applesoft tokenizer utility with regards to parsing the DEF
token). The updated code is a lot slower, but it makes it more fun* to
watch as it is being drawn. (* see 4am's standard disclaimer)
{B1}
0REM! G?O)+;*L)(>-J)&@0E)%A4>$15$)-+/26-8<26-*<?B-,:CD)./?A)67BD-346;-16:;
1DEFFNP(X)=PEEK(2054+X)-32:GR:POKE49234,0:FORI=0TO65STEP5:COLOR=FNP(I):FORY=FNP(I+3)TOFNP(I+4):HLINFNP(I+1),FNP(I+2)ATY:NEXTY,I
Box-drawn Person
link
The pumpkin was only 14 boxes, but with the new compressed representation
you can fit up to 30 so I was looking for a more complex image to draw.
I thought I'd try to do a person but I underestimated how hard it is
to optimally take a complex sprite and translate it into boxes.
So it took a while to try to do is manually.
I did not design the sprite myself, it's based on one that
came up on a google search
for pixelart
here
I optimized the code slightly so you can fit in one more box than
the previous code.
The below code is slightly better than the one in the actual tweet, it frees
up another few bytes and also uses a GET A at the end to pause and not
scroll the graphics.
0REM/ G O))>(O),;$')18"# ,<@G -909/-927$/727,6627,0027+,9:?+.7*/+06()+24(C+35@I+-8@A+/6BC),1FG)7<FG)8<CE$35HI,19JK,.:LM/-;NO#,-:;#89:;#24@A#46>?(>>BO(((.L
1DEFFNP(X)=PEEK(2054+I*5+X)-32:GR:POKE49234,0:FORI=0TO29:COLOR=FNP(0):FORY=FNP(3)TOFNP(4):HLINFNP(1),FNP(2)ATY:NEXTY,I:GETA
Box-drawn Selfie
link
Nothing new in this one, but I thought it would be fun in a recursive sort
of way to have the AppleIIbot draw its own self portrait.
(Yes I know the AppleIIbot is really a Raspberry Pi, but its avatar
picture on twitter is this image).
A shame there's no beige in the lo-res palette, the machine looks like
it's in desperate need of some retro-bright.
0REM/ G O(*;!K-#4HI-#6DG-%7@C-(8<?('.CF((2DG(-2??%#4JK%&3LM(47LM(<<(6-)8":(*5$8 +4&7(BD3H(BB5I%<C34%;A56-9A7K :@8@ :@BJ%;@<<%;@FF#???@#??IJ%=>9>%=>CH,77"#
1DEFFNP(X)=PEEK(2054+I*5+X)-32:GR:POKE49234,0:FORI=0TO29:COLOR=FNP(0):FORY=FNP(3)TOFNP(4):HLINFNP(1),FNP(2)ATY:NEXTY,I:GETA
Arbitrary 40x24 bitmap
link
For some reason I got the idea to see if I could make 4am's Beagle Bros
disk-care-alligator bitmap.
At first I was trying to do it at 40x48 in GR mode, but that wouldn't fit
in a tweet. 40x24 was more promising, and then I realized that if
it's going to be in black and white I can just use NORMAL / INVERSE
spaces and eliminate all of the excess co-ordinate and color setting.
I have a utility that will take a png file and create the 6-bit encoded
data to stick in the REM statement. Need to figure out a way to
print the last 6 chars without scrolling the screen.
1REM_'> $^__XW?#__'\][C__!>W\Y_/&W:?\_SC=W/^?^1_]G_G_P=_Y_8><W?\/+, \/_S4&__S_T+C__\/]/P_/_3\_XYS_,X?@\\/K@/N$_CK"&OP_YO*B?^?^_*PA_'__;XX_#F9&$__1F9.X_?8F9&^_/8F9P_
2HOME:FORY=0TO158:Z=PEEK(2054+Y)-32:FORI=0TO5:NORMAL:Q=INT(Z/2):IFQ*2<>ZTHENINVERSE
3Z=Q:PRINT" ";:NEXT I,Y:GETA
Kay Savetz pointed out we can save a byte by using
IF Q*2-Z instead of Q*2<>Z
I also managed to shave some more bytes off: ? vs PRINT (had to fix my
tokenizer for that), use % to avoid INT(), and notice that HOME technically
wasn't needed (in fact scrolling up might be a mildly cooler effect).
Just barely had enough
room to add a conditional so we only skip the last char instead of the
last 6 at the end.
1REM_'> $^__XW?#__'\][C__!>W\Y_/&W:?\_SC=W/^?^1_]G_G_P=_Y_8><W?\/+, \/_S4&__S_T+C__\/]/P_/_3\_XYS_,X?@\\/K@/N$_CK"&OP_YO*B?^?^_*PA_'__;XX_#F9&$__1F9.X_?8F9&^_/8F9P_
2FORY=0TO159:Z=PEEK(2054+Y)-32:FORI=0TO5:NORMAL:Q%=Z/2:IFQ%*2-ZTHENINVERSE
3Z=Q%:IFY+I-164THEN?" ";
4NEXT I,Y:GETA
V1 QR Code
link
I realized that the previous entry could be used to generate QR codes.
But what to link to? Especially as to fit on the Apple II screen you
are limited to V1 of the QR spec (21x21 pixels) which in general limits
you to a 17 character long URL. Anyway it was a pain but you can
probably guess what it links to.
Extra obfuscation on the INVERSE/NORMAL front here compared to last time.
You can thank Qkumba for that. It saves a few chars but I
do think it slows the whole thing down a bit.
1REM________!L%P__??M]]__7T>1___%U6T__?17%]__W74?___!4%P____7____'$JJ___5?=W___")(^__7_Q1___7(1^____E#]__'0PF___]]XU__?11R\__74WY___%UP___??=+___'0!M_______________
2FORY=0TO159:Z=PEEK(2054+Y)-32:FORI=0TO5:Q%=Z/2:POKE50,(Q%*2-Z)*192+255:Z=Q%:IFY+I-164THEN?" ";
4NEXT I,Y:GETA
80 column bitmap -- Apple II Forever!
link
The bitmap mode is a bit chunky at 40x24 effective resolution, so I thought
I'd try putting the bot in 80-column mode. This does effectively
reduce the resolution to 80x12 although on the plus side you don't
have to worry about the screen scrolling when you get to the end.
1REM______/X__ X_______N__[WO_/ # [& .<'^?^O_C_CC_[W=__.X.X.XN#W?W]_[N[N[N[NM_=W_O'N#G#GS!XP=X_Y[NGNGN\O[WO_? X@[@#. . ^__O[O[__________@_@__
2PR#3:FORY=0TO140:Z=PEEK(2054+Y)-32:FORI=0TO5:NORMAL:Q%=Z/2:IFQ%*2-ZTHENINVERSE
3Z=Q%:?" ";:NEXTI,Y
4?"F O R E V E R";
RLE Encoded Color Picture
link
The black and white bitmaps were nice, but I thought I'd try to see if
I could get some more colorful images. I previously tried with the rectangle plots
but they're a pain to use because you have to manually map out the
rectangles.
One obvious thing to try is Run-Length Encoding an image. It's a very
simple compression algorithm that should be small enough to fit in a
tweet.
In this case it is drawing a bunch of horizontal lines, with the color
stored in one 6-bit value and the width of the line (the run) in another.
You can fit about 70 runs this way.
This is lo-res graphics again, but to save space we are outputting the
graphics as text. This works because on the Apple II it goes to
the same place in RAM. The CALL to 64500 is
the monitor "ADVANCE" routine which moves the cursor to the right.
The crazy PEEKing is getting the current cursor location at (BASL)+CH and
poking the color in (we can't just use PRINT here as Applesoft PRINT
strips out control characters and such).
I tried a lot of crazy methods to get this smaller but none really worked well.
There are a few ways you can shave a byte here or there, but it involves
putting long calculations inside of the primary loop which slows down
the decoding by a lot.
1REM E,! F,! D,& */! 6-& +/" 5)& +/# 4!' */$ 3"' */% 3&% +'& @"! !/+"% 2-$""/!!#"$/#"& /-&""/"!!$#"!/$"' --$)#""/+"( .-%""/+") /-#""'*/+ 1"! !/)'!/,
2GR:VTAB1:FORI=0TO72:C=PEEK(2054+I*2)-32:L=PEEK(2055+I*2)-32
5FORY=1TOL:POKEPEEK(40)+PEEK(41)*256+PEEK(36),C*17:CALL64500:NEXTY,I
I did try to see if I could offload some of this to assembly language as
all that PEEKing takes lots of room. I even have a version that
uses USR() to call a custom assembly routine at $0A and decodes the
argument to an int and then calls STORADV. It ends up being too big.
1REM E,! F,! D,& */! 6-& +/" 5)& +/# 4!' */$ 3"' */% 3&% +'& @"! !/+"% 2-$""/!!#"$/#"& /-&""/"!!$#"!/$"' --$)#""/+"( .-%""/+") /-#""'*/+ 1"! !/)'!/,
2FORI=1TO11:READA,V:POKEA,V:NEXTI
4GR:VTAB1:FORI=0TO72:C=PEEK(2054+I*2)-32:L=PEEK(2055+I*2)-32
5FORY=1TOL:X=USR(C*17):NEXTY,I
6 DATA 10,76,11,0,12,3,768,32,769,12,770,225,771,165,772,161,773,76,774,240,775,251
I did try for a full-assembly version. If I could get it small enough,
the RLE data and the payload would fit in the 128B assembly loader.
I did get it working, but even when using a more advanced RLE encoding
(runs of 15 plus color fit in one byte, with an overflow to two bytes
if it doesn't fit) it still is not quite as compact as the BASIC version
and won't fit in a tweet. It does use the fun trick of loading so the
end of the program is a backwards jump living at $3f5 and using the &
command to jump to it.
1REM\)'\)'\);H'\%;L+\%:L/\%<H3\$<H7\$5L9\($$O4\$3(',0/8\#;(+$-$3<T3.(O@X7(OD\#/(IO\$$$G%S (0^J A)(6^H N; 2(9^:2222\ZR#T!RN; JA_I,(\^RT^I_R3S 3P $( ,&3Q0,+SR@L8>N<>X2Y2N<^D\#<%\0, H*U QR!L #..
2FORI=0TO140:C%=(PEEK(2194+I/3)-32)/4^(I-INT(I/3)*3):POKE876+I,C%+4*(PEEK(2054+I)-32-INT(C%/4)):NEXT:&
Animated 80s grid
link
I wanted to see if I could do one of those retro 80s battlezone type
grid animations. I really wanted to have blue mountains in the
background too, but couldn't manage to get it to fit.
In the original version I only managed a single star, but eventually
managed to shoehorn in a purple mountain.
No real tricks here, the primary thing holding back more features is
because Applesoft doesn't crop out-of-bounds lines so you have to manually
clip them at the screen boundary or else get an error.
The code does do page flipping for smooth animation. The CALL-3086 calls
the ROM "clear screen to black" routine which saves a lot of complexity
but kills the framerate.
I could get a blue mountain if I let the grid be entirely purple, it's just
that due to how the Apple II does color the purple vertical lines have gaps
in them that look pretty awful so having them be white looks a lot better.
1HGR2:Z=96:K=279
2FORJ=0TO7:HCOLOR=2:S=Z+12*J:POKE230,32+32*P:P=NOTP:POKE49236+P,0:CALL-3086
3S=S/2:Y=Z+S:HPLOT0,YTOK,Y:IFS>1THEN3
4HPLOT0,ZTO133,80TOK,Z:HCOLOR=3:Y=99:G=2:FORI=1TO8:A=16*I:IFY>191THENY=191
7X=(A*3-268)*(I>5):HPLOTX,YTOA,ZTO276-A,ZTOK-X,Y:G=G+G:Y=Y+G:NEXTI,J:GOTO2
Horizon Flyer
link
I wanted to get something more exciting than the previous 80s horizon
so I added some shape tables into the mix. Not really that different
than the previous shape table tricks, but by reusing the shape as both
the flyer and the gateways I managed to get something interesting.
I spent some time trying to speed things up but it's difficult with such
a small amount of code. Also the shape isn't perfect, and not symmetric,
I should fix that.
2POKE232,20:POKE233,8
5REM#%%-...
6HGR2:ROT=0:Z=96:K=140
7S=Z+J:POKE230,32+32*P:P=NOTP:POKE49236+P,0:CALL-3086:HCOLOR=6:HPLOT0,ZTOK,80TO279,Z:HCOLOR=1
8S=S/2:Y=Z+S:HPLOT0,YTO279,Y:SCALE=1+S/5:XDRAW1ATK,Y:IFS>1THEN8
9SCALE=2:XDRAW1ATK+16*SIN(H),180:H=H+0.3:J=(J+12)*(J<84):GOTO7
On to part 2
Back to Main AppleIIbot page