This commit is contained in:
Vince Weaver 2018-05-03 12:45:20 -04:00
commit f43650e1ef
10 changed files with 2581 additions and 167 deletions

View File

@ -16,13 +16,16 @@
While making an inside-joke filled game for my retro system of choice,
the Apple II, I needed to create a Final-Fantasy-esque
flying-over-the-planet sequence.
I was originally going to fake this, but then I found that it was just barely
possible to achieve this in real time.
I was originally going to fake this, but why fake graphics when you
can laboriously spend weeks implementing the effect for real.
It turns out the Apple II is just barely capable of generating
the effect in real time.
Once I got the code working I realized it would be great as part of a
graphics demo, so off on that tangent I went.
This went well, despite the fact that all I know about the demoscene I learned
from a few viewings of the Future Crew {\em Second Reality} demo mixed with
dimly remembered Commodore 64 and Amiga flamewars.
graphical demo, so off on that tangent I went.
This turned out well, despite the fact that all I knew about the demoscene I
had learned from a few viewings of the Future Crew {\em Second Reality} demo
combined with dimly remembered Commodore 64 and Amiga usenet flamewars.
% from a few decades ago.
% This started out as some SNES style mode7 pseudo-3d graphics code
@ -33,12 +36,13 @@ dimly remembered Commodore 64 and Amiga flamewars.
%lot of time was wasted fitting it under that arbitrary size limitation.
While I hope you enjoy the description of the demo and the work that
went into it, I do suspect the whole enterprise is only of note
because so few people write demos for the Apple II platform.
went into it, I suspect this whole enterprise is primarily of note
due to the dearth of demos for the Apple II platform.
%So in the end this ends up being impressive mostly because so few people
%have bothered to write demos for this particular platform.
I would like to make a shout out to the FrenchTouch group whose Apple II
demos put this one to shame.
If you are truly interested in seeing impressive Apple II demos,
I would like to make a shout out to FrenchTouch whose works
put this one to shame.
% The codesize ended up being roughly around 8kB, so I thought I'd
% make it into an 8k demo. There aren't many out there for the Apple II.
@ -90,11 +94,13 @@ demos put this one to shame.
\section{The Hardware}
The Apple II was introduced in 1977.
This demo should run on an original system, though I do not
have hardware quite that old to test on.
I like to troll C64 fans by noting this predates the Commodore 64 by
In theory this demo will run on hardware that old, although I do
not have access to a system of that vintage.
I like to troll Commodore fans by noting this predates the Commodore 64 by
five years.
\vspace{1ex}
\noindent
{\bf CPU, RAM and Storage:}
@ -147,28 +153,29 @@ Hardware page flip & Yes \\
\end{tabular}
\end{center}
The hi-res graphics mode was a complex mess of NTSC hacks by Woz.
You got approximately 280x192 resolution, with 6 colors available.
However the colors were from NTSC artifacts and there were limitations
on which colors could be next to each other (in blocks of 3.5 pixels).
There was plenty of fringing on edges, and colors changed depending on
whether they were drawn at odd or even pixels.
The hi-res graphics mode is a complex mess of NTSC hacks by Woz.
You get approximately 280x192 resolution, with 6 colors available.
The colors are NTSC artifacts with limitations
on which colors can be next to each other (in blocks of 3.5 pixels).
There is plenty of fringing on edges, and colors change depending on
whether they are drawn at odd or even locations.
To add to the madness, the framebuffer is interleaved in a complex way,
and pixels are drawn least-significant-bit first (all of this to make
DRAM refresh better and to shave a few 7400 series logic chips from the design).
You do get two pages of graphics, Page 1 is at
\$2000\footnote{On 6502 systems hexadecimal values are
indicated by the dollar sign}
and Page 2 at \$4000.
{\tt \$2000}\footnote{On 6502 systems hexadecimal values are
traditionally indicated by a dollar sign}
and Page 2 at {\tt \$4000}.
Optionally 4 lines of text can be shown at the bottom of the
screen instead of graphics.
The lo-res mode is a bit easier to use.
It provides 40x48 blocks (40x40 if the four
lines of text are displayed at the bottom).
It provides 40x48 blocks, reusing the same memory as the 40x24 text mode.
(As with hi-res you can switch to a 40x40 mode with four lines of
text displayed at the bottom).
Fifteen colors are available (there are two greys which are indistinguishable).
Again the addresses are interleaved. Lo-res Page 1 is at \$400
and Page 2 is at \$800.
Again the addresses are interleaved in a non-linear fashion.
Lo-res Page 1 is at {\tt \$400} and Page 2 is at {\tt \$800}.
Some amazing effects can be achieved by cycle counting, reading
the floating bus, and racing the beam while toggling graphics
@ -191,10 +198,11 @@ I do all of my coding under Linux, using the nano text editor.
I use the ca65 assembler from the cc65 project, which I find to be a reasonable
tool although many ``real'' Apple II programmers look down on it for some
reason.
I cross-compile the code, construct Apple DOS3.3 disk images using
custom tools I have written, and then do most testing in an emulator.
I cross-compile the code, constructing Apple DOS3.3 disk images using
custom tools I have written.
I test using emulators:
AppleWin (run under the wine emulator) is the easiest to use, but
MESS/MAME has cleaner sound.
until recently MESS/MAME had cleaner sound.
Once the code appears to work, I put it on a USB stick and transfer
to actual hardware using a CFFA3000 disk emulator installed in
@ -260,67 +268,73 @@ well-traveled guinea pig.
An Applesoft BASIC ``HELLO'' program loads the binary automatically at bootup.
This does not count towards the executable size, as you could manually BRUN
the 8k program if you wanted.
the 8k machine-language program if you wanted.
To make the loading time slightly more interesting the binary is loaded at
address \$2000 (hi-res page1) and BASIC is nice enough to enable
graphics mode first so you can watch the display get filled with the random
pattern of the compressed image.
This entirely fills the 8k of the display, or would
if we POKEd the right address to turn off
the 4 lines of text on the bottom of the screen.
To make the loading time slightly more interesting the HELLO program enables
graphics mode and loads the program to address {\tt \$2000} (hi-res page1).
This causes the display to filled with the colorful pattern corresponding
to the compressed image.
This conveniently fills all 8k of the display RAM, or would have
if we had POKEd the right soft-switch to turn off
the bottom 4 lines of text.
Upon loading, execution starts at address \$2000
Upon loading, execution starts at address {\tt \$2000}.
\subsection{DECOMPRESSER}
\subsection{DECOMPRESSION}
The binary is encoded with the LZ4 algorithm.
We flip to hi-res Page 2 and decompress there so the user continues to get
a show of random noise.
We flip to hi-res Page 2 and decompress to this region so the display
now shows the executable code.
The 6502 size-optimized LZ4 decompression code was written by qkumba
(Peter Ferrie).
% http://pferrie.host22.com/misc/appleii.htm
The program and data decompress to around 22k starting at \$4000.
It over-writes parts of DOS3.3, but since we will not be using the disk
any more this is not an issue.
The program and data decompress to around 22k starting at {\tt \$4000}.
This over-writes parts of DOS3.3, but since we are done with the disk
this is not an issue.
If you look carefully at the upper left corner of the screen during
decompress you will see my triangular logo, which is supposed to evoke
my VMW initials (see Figure~\ref{fig:vmw}).
To do this I had to put the proper bit pattern at the interleaved
addresses of \$4000, \$4400, \$4800, and \$4C00.
This turned out to be way more trouble than it was worth.
As an interesting note, the image data at \$4000 is executed as it maps
to (mostly) harmless code.
To do this I had to put the proper bit pattern inside the code
at the interleaved addresses of {\tt \$4000}, {\tt \$4400}, {\tt \$4800},
and {\tt \$4C00}.
The image data at {\tt \$4000} maps to (mostly)
harmless code so it is left in place and executed.
Making this work turned out to be more trouble than it was worth, especially
as the logo is not visible in the youtube capture of the demo (the movie
compression does not handle screens full of seemingly random noise well).
The demo was optimized to fit in 8k, and this is difficult when your program
is compressed.
The demo was optimized to fit in 8k.
Optimizing code inside of a compressed image is much more complicated than
regular size optimization.
Removing instructions sometimes makes the binary {\em larger} as it no longer
compresses as well.
Long runs of values (such as 0 padding) are essentially free.
This mostly turned into an exercise of guess-and-check until everything fit.
\subsection{FADE EFFECT}
\subsection{TITLE SCREEN}
Once decompression is done, execution continues at address {\tt \$4000}.
We switch to low-res mode for the rest of the demo.
\noindent
{\bf FADE EFFECT}:
The title screen fades in from black.
This is a software hack as the Apple II does not have palette support.
The image is loaded to an off-screen buffer and a lookup table is used to
copy in the faded versions on the fly.
\subsection{TITLE SCREEN}
Once decompression is done, execution continues at address \$4000.
We switch to low-res mode for the rest of the demo.
A title screen is loaded, as seen in Figure~\ref{fig:title}.
\noindent
{\bf TITLE GRAPHICS}:
The title screen is shown in Figure~\ref{fig:title}.
The image is run-length encoded (RLE) which is
probably unnecessary when being further LZ4 encoded.
probably unnecessary in light of it being further LZ4 encoded.
(The LZ4 compression was a late addition to this endeavor).
Why not save some space and just load our demo at \$400 and negate the need
Why not save some space and just load our demo at {\tt \$400} and negate
the need
to copy the image in place?
Remember the graphics are 40x48 (shared with the text display region).
It might be easier to think of it as 40x24 characters, with the top / bottom
@ -332,8 +346,10 @@ There are ``holes'' in the address range that are not displayed, and
various pieces of hardware can use these as scratchpad memory.
This means just overwriting the whole 1k with data might not work out well
unless you know what you are doing.
To this end the RLE decompression code skips the holes just to be safe.
To this end our RLE decompression code skips the holes just to be safe.
\noindent
{\bf SCROLL TEXT}:
The title screen has scrolling text at the bottom.
This is nothing fancy, the text is in a buffer off screen and a 40x4
chunk of RAM is copied in every so many cycles.
@ -347,20 +363,23 @@ movie encoding conspire to make this look worse than things look in person.
\subsection{MOCKINGBOARD MUSIC}
No demo is complete without some exciting background music.
I like chiptune music, especially the kind you can find that is made
I like chiptune music, especially the kind written
for AY-3-8910 based systems.
I gained some expertise during the long wait for my Mockingboard to arrive
by building a Raspberry Pi chiptune player that is essentially the same
hardware.
During the long time waiting for my Mockingboard hardware to arrive
I designed and built a Raspberry Pi chiptune player that uses
essentially the same hardware.
This allowed me to build up some expertise with the software/hardware
interface in advance.
The song being played is a stripped down and re-arranged version of
``Electric Wave'' from CC'00 by EA (Ilya Abrosimov).
Most of my sound infrastructure involves YM5 files, a format commonly
used by ZX Spectrum and ATARI ST users.
These are essentially just AY-3-8910 register dumps taken at 50Hz.
To play these back just set up the sound card to interrupt 50 times a second
and then write out the 14 register values from that frame.
used by ZX Spectrum and Atari ST users.
The YM file format is just AY-3-8910 register dumps taken at 50Hz.
To play these back one sets up the sound card to interrupt 50 times a second
and then writes out the 14 register values from each frame in an interrupt
handler.
% To program the Mockingboard, each AY-3-8910 chip has 14 sound related
% registers that control the 3 channels. Each AY chip has a dedicated
@ -381,7 +400,7 @@ and only write to the registers that have changed.
% I have a whole suite of code for manipulating YM sound data, in my
% vmw-meter git repository.
Our code detects a Mockingboard at startup, we are lazy and only support
Our code detects the Mockingboard at startup; we are lazy and only support
finding the card in Slot 4 (which is a fairly typically location).
% The first step for getting this to work is detecting if a Mockingboard is
%% there. This can be in any slot 1-7 on the Apple II, though typically
@ -391,9 +410,9 @@ interrupt at 25Hz.
% (it has to be an on-board timer as the default
% Apple II has no timers).
Why 25Hz and not 50Hz? At 50Hz with 14 registers you use 700 bytes/s.
So a 2 minute song would take 84k of RAM, much more than is available.
To allow the song to fit in memory (without the fancy circular buffer
decompression utilized in my VMW Chiptune Player music-disk demo) we have
So a 2 minute song would take 84k of RAM, which is much more than is available.
To allow the song to fit in memory (without a fancy circular buffer
decompression routine utilized in my VMW Chiptune music-disk demo) we have
to reduce the size.
First the music is changed so it only needs to be updated at 25Hz.
Then the register data is compressed from 14 bytes to 11 bytes by stripping off
@ -404,10 +423,10 @@ acceptably catchy chiptune inside of our 8k payload.
\subsection{MODE7 BACKGROUND}
``Mode7'' is a Super Nintendo (SNES) graphics mode that takes a tiled
background to be transformed by rotation and scaling.
The most common effect was to squash it out to the horizon, giving
background and transforms it by rotating and scaling.
The most common effect squashes the background out to the horizon, giving
a three-dimensional look.
The SNES did these transforms in hardware, but in this demo we implement
The SNES did these transforms in hardware, but our demo must do
them in software.
% As found on Wikipedia, the transform is of the type
@ -415,138 +434,158 @@ them in software.
% [x'] = [a b]([x]-[x0])+[x0]
% [y'] [c d]([y] [y0]) [y0]
% http://www.helixsoft.nl/articles/circle/sincos.htm
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Our algorithm is based on code by Martijn van Iersel.
It iterates through each y line on the screen and calculates based on
the camera location: height ({\em spacez}), x and y coordinates
({\em cx} and {\em cy}) and the {\em angle}.
It iterates through each horizontal line on the screen and calculates the color
to output based on the camera height ({\em spacez}) and {\em angle} as well
as the current x and y coordinates ({\em cx} and {\em cy}).
First calculate the distance
d = (z*yscale)/(y+horizon)
Then calculate the horizontal scale (distance between points on
this line)
h = d/xscale
Then calculate delta x and delta y values
dx = -sin(angle)*h
dy = cos(angle)*h
It then calculates the starting offset of the left side of the line in
the tile lookup:
tilex = cx + (d*cos(angle) - (width/2) * dx;
tiley = cy + (d*sin(angle) - (width/2) * dy;
Now iterate the inner loop, where we lookup the tile color for each pixel
on the horizontal line.
putpixel (x, y, tilelookup(tilex,tiley)
tilex += dx;
tiley += dy;
First the distance {\em d} is calculated based on fixed scale and
distance-to-horizon factors.
Instead of a costly division we use a pre-generated lookup table for this.
\[d = \frac{z \times yscale}{y+horizon}\]
Next calculate the horizontal scale (distance between points on
this line):
\[h = \frac{d}{xscale}\]
Then calculate delta x and delta y values between each block on the line.
We use a pre-computed sine/cosine lookup table.
\[dx = -sin(angle) \times h\]
\[dy = cos(angle) \times h\]
The leftmost position in the tile lookup is calculated:
\[tilex = cx + (d*cos(angle) - (width/2) * dx\]
\[tiley = cy + (d*sin(angle) - (width/2) * dy\]
Then an inner loop happens that adds dx and dy as we lookup the color
from the tilemap (just a wrap-around array lookup) for each block
on the line.
\[color = tilelookup(tilex,tiley)\]
\[plot (x, y) \]
\[tilex += dx, tiley+= dy\]
{\bf Optimizations}
We managed to take this algorithm and speed it up in the following ways:
\begin{itemize}
\item blah
\end{itemize}
For our code, we managed to reduce things to a small number of additions
and subtractions for each pixel on the screen. Of course the 6502 can't
do floating point, so we do fixed point math. We convert as much as we
can to table lookups that are pre-calculated. We also make liberal use
of self-modifying code.
\noindent
{\bf Optimizations:}
The 6502 processor cannot do floating point, so all of our routines use
8.8 fixed point math.
We eliminate all use of division, and convert as much as possible
to table lookups (which involves limiting the heights and angles a bit).
We also save some cycles by using self-modifying code,
most notably hard-coding the height (z) value and modifying the code
whenever this is changed.
The code started out only capable of roughly 4.9fps in 40x20 resolution
and in the end we improved this to 5.7fps in 40x40 resolution.
Care was taken to optimize the innermost loop, as every cycle saved there
results in 1280 cycles saved overall.
\noindent
{\bf Fast Multiply:}
One of the biggest bottlenecks in the mode7 code was the multiply.
Even our optimized algorithm calls for at least seven
16bit x 16bit = 32bit multiplies, something that is {\em really} slow on
the 6502.
A typical implementation takes around 700 cycles
for a 8.8 x 8.8 fixed point multiply.
Despite all of this there are still some cases where we have to do a
16bit x 16bit = 32bit multiply, something that is *really* slow on 6502,
around 700 cycles (for a 8.8 x 8.8 fixed point multiply).
% Note, this is Quarter-square multiplication, apparently an ancient algorithm
% https://en.wikipedia.org/wiki/Multiplication_algorithm#Quarter_square_multiplication
To make this faster we use a method described by Stephen Judd.
We improved this by using the ancient quarter-square
multiply algorithm, first described for 6502 use by Stephen Judd.
The key to note is that $(a+b)^{2} = a^{2}+2ab+b^{2}$
and $(a-b)^{2}=a^{2}-2ab+b^{2}$
and if you add them you can simplify to:
$a\times b =\frac{(a+b)^{2}}{4} - \frac{(a-b)^2}{4}$
This works by noting these factorizations:
\[(a+b)^{2} = a^{2}+2ab+b^{2}\]
\[(a-b)^{2}=a^{2}-2ab+b^{2}\]
If you subtract these you can simplify to
\[a\times b =\frac{(a+b)^{2}}{4} - \frac{(a-b)^2}{4}\]
This is you have a table of squares from 0..511 (all 8-bit a+b and a-b
will fall in this range) then you can convert a multiply into a table
lookup plus a subtract.
For 8-bit values if you create a table of squares from 0 to 511
(all 8-bit a+b and a-b fall in this range) then you can convert a multiply
into two table lookups and a subtraction.
This does have the downside of requiring 2kB of lookup tables
(which can be generated at startup) but it reduces the multiply
cost to the order of 250 cycles or so.
The downsize is you will need 2kB of squares lookup tables (which can
be generated at startup). This reduces the multiply cost to the order
of 200 to 250 cycles.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
By using the fast multiply and a lot of careful optimization you can
generate a Mode7 background in 40x40 graphics mode at about 5 frames/second.
\subsection{BALL ON CHECKERBOARD}
The engine can be parameterized with different tilesets to use, which we
do to provide both a black+white checkerboard background, as well as the
island background from the TFV game.
\subsection{BOUNCING BALL ON CHECKERBOARD}
The first scence starts out viewing an infinite checkerboard.
Any demo would be incomplete without some sort of bouncing geometric solid,
in our case a pink sphere.
This was accomplished with 16 sprites:
the sphere was modeled in OpenGL inside of a 20 year old game engine
and screenshots were taken then reduced in keeping with the size and
color limitations.
Similarly the shadow is also just sprites.
The first Mode7 scene transpires on an infinite checkerboard.
A demo would be incomplete without some sort of bouncing geometric solid,
in this case we have a pink sphere.
The sphere is represented by 16 sprites that were captured from
a 20 year old OpenGL game engine.
Screenshots were taken then reduced to the proper size and color
limitations.
The shadows are also just sprites.
Note that the Apple II has no dedicated sprite hardware, so these
are drawn completely in software.
The clicking noise on bounce is generated by accessing the speaker port
at address \$C030.
This gives some sound for those viewing the demo without a Mockingboard.
at address {\tt \$C030}.
This gives some sound for those viewing the demo without the benefit
of a Mockingboard.
\subsection{TFV SPACESHIP FLYING}
This next scene has a spaceship flying over an island.
The Mode7 graphics code is generic enough that only one copy of the code
is needed to generate both the checkerboard and island scenes.
The spaceship, water splash, and shadows are all sprites.
They are all drawn in software as the Apple II has no sprite hardware.
The path the ship takes is pre-recorded; this is adapted from the
Talbot Fantasy~7 game engine with the keyboard code replaced by a hard-coded
script of actions to take.
\subsection{STARFIELD}
The spaceship takes to the stars.
This is typical starfield code.
Only 16 stars are modeled, and the movement code re-uses the
same fast-multiply routine described previously.
The spaceship now takes to the stars.
This is typical starfield code, where on each iteration the x and y
values are changed by
\[dx=\frac{x}{z}, dy=\frac{y}{z}\]
In order to get a good frame rate and not clutter the lo-res screen
only 16 stars are modeled.
To avoid having to divide, the reciprocal of all possible z values
are stored in a table, and the fast-multiply routine described
previously is used.
The star positions require random number generation, but this is not
fast on the 6502.
The star positions require random number generation, but there is no
easy way to quickly get random data on the Apple II.
Originally we had a 256-byte blob of pre-generated ``random'' values
included in the code.
This wasted space, so now instead we just use our code at address
at \$5000 as if it were a block of random numbers.
This was arbitrarily chosen, and it is not as random as it could be
as seen when the ship enters hyperspace the lower right quadrant has fewer
starts than one could desire.
as seen when the ship enters hyperspace and the lower-right quadrant
is distressingly star-free.
A simple state machine controls star speed, ship movement, hyperspace,
background color (for the blue flash) and the eventual sequence of sprites
as the ship vanishes into the distance.
\subsection{RASTERBARS/CREDITS}
Once the ship has departed, it is time for the credits as the stars
continue to run.
Once the ship has departed, it is time to run the credits as the stars
continue to fly by.
The text is written to the bottom 4 lines of the screen and appears
to be surrounded by low-res graphics blocks.
Mixed graphics/text would generally not be possible on the Apple II, although
The text is written to the bottom four lines of the screen, seemingly
surrounded by graphics blocks.
Mixed graphics/text is generally not be possible on the Apple II, although
with careful cycle counting and mode switching groups such as FrenchTouch
have achieved this effect.
I was lazy and instead used inverse-mode space characters which appear the same
as white graphics blocks.
What we see in this demo is the use of inverse-mode (inverted color)
space characters which appear the same as white graphics blocks.
The rasterbar effect is not really rasterbars, it's just a colorful assortment
The rasterbar effect is not really rasterbars, just a colorful assortment
of horizontal lines drawn at a location determined with a sine lookup table.
Horizontal lines can take a surprising amount of time to draw, so this
was optimized using inlining and a few other methods.
Horizontal lines can take a surprising amount of time to draw, but these
were optimized using inlining and a few other tricks.
The rotating text is done by just rapidly rotating the output string through
the ASCII table, with the clicking effect again by hitting the speaker
at address \$C030.
The list of people to thank ended up being extremely critical to fitting in 8kB,
as unique text strings do not compress well.
The spinning text is done by just rapidly rotating the output string through
the ASCII table, with the clicking effect again generated
by hitting the speaker at address {\tt \$C030}.
The list of people to thank ended up being the primary limitation to
fitting in 8kB, as unique text strings do not compress well.
I apologize to everyone whose moniker got compressed beyond recognition,
and I am still not totally happy with the centering of the text.

24
still_alive/Makefile Normal file
View File

@ -0,0 +1,24 @@
include ../Makefile.inc
DOS33 = ../dos33fs-utils/dos33
all: still_alive.dsk
still_alive.dsk: STILL_ALIVE ./SA.KRW
$(DOS33) -y still_alive.dsk BSAVE -a 0x0C00 STILL_ALIVE
$(DOS33) -y still_alive.dsk SAVE B ./SA.KRW
STILL_ALIVE: still_alive.o
ld65 -o STILL_ALIVE still_alive.o -C ../linker_scripts/apple2_c00.inc
still_alive.o: still_alive.s \
../asm_routines/mockingboard.s \
../asm_routines/dos33_routines.s \
../asm_routines/lz4_decode.s \
../asm_routines/keypress_minimal.s \
interrupt_handler.s \
ascii_art.inc zp.inc
ca65 -o still_alive.o still_alive.s -l still_alive.lst
clean:
rm -f *~ *.o *.lst STILL_ALIVE

View File

@ -0,0 +1,2 @@
initial: 2078
add ascii art: 9142

BIN
still_alive/SA.KRW Normal file

Binary file not shown.

223
still_alive/ascii_art.inc Normal file
View File

@ -0,0 +1,223 @@
aperture:
.asciiz " .,-:;//;:=,"
.asciiz " . :H@@@MM@M#H/.,+%;,"
.asciiz " ,/X+ +M@@M@MM%=,-%HMMM@X/,"
.asciiz " -+@MM; $M@@MH+-,;XMMMM@MMMM@+-"
.asciiz " ;@M@@M- XM@X;. -+XXXXXHHH@M@M#@/."
.asciiz " ,%MM@@MH ,@%= .---=-=:=,."
.asciiz " =@#@@@MX ., -%HX$$%%%+;"
.asciiz " =-./@M@M$ .;@MMMM@MM:"
.asciiz " X@/ -$MM/ .+MM@@@M$"
.asciiz ",@M@H: :@: . =X#@@@@-";
.asciiz ",@@@MMX, . /H- ;@M@M=";
.asciiz ".H@@@@M@+, %MM+..%#$.";
.asciiz " /MMMM@MMH/. XM@MH; =;"
.asciiz " /%+%$XHH@$= , .H@@@@MX,"
.asciiz " .=--------. -%H.,@@@@@MX,"
.asciiz " .%MM@@@HHHXX$$$%+- .:$MMX =M@@MM%."
.asciiz " =XMMM@MM@MM#H;,-+HMM@M+ /MMMX="
.asciiz " =%@M@M#@$-.=$@MM@@@M; %M%="
.asciiz " ,:+$+-,/H#MMMMMMM@= =,"
.asciiz " =++%%%%+/:-."
radioactive:
.asciiz " =+$HM####@H%;,"
.asciiz " /H###############M$,"
.asciiz " ,@################+"
.asciiz " .H##############+"
.asciiz " X############/"
.asciiz " $##########/"
.asciiz " %########/"
.asciiz " /X/;;+X/"
.asciiz " "
.asciiz " -XHHX-"
.asciiz " ,######,"
.asciiz "#############X .M####M. X#############";
.asciiz "##############- -//- -##############";
.asciiz "X##############%, ,+##############X";
.asciiz "-##############X X##############-";
.asciiz " %############% %############%"
.asciiz " %##########; ;##########%"
.asciiz " ;#######M= =M#######;"
.asciiz " .+M###@, ,@###M+."
.asciiz " :XH. .HX:"
atom:
.asciiz " =/;;/-"
.asciiz " +: //"
.asciiz " /; /;"
.asciiz " -X H."
.asciiz ".//;;;:;;-, X= :+ .-;:=;:;%;.";
.asciiz "M- ,=;;;#:, ,:#;;:=, ,@";
.asciiz ":% :%.=/++++/=.$= %=";
.asciiz " ,%; %/:+/;,,/++:+/ ;+."
.asciiz " ,+/. ,;@+, ,%H;, ,/+,"
.asciiz " ;+;;/= @. .H##X -X :///+;"
.asciiz " ;+=;;;.@, .XM@$. =X.//;=%/."
.asciiz " ,;: :@%= =$H: .+%-"
.asciiz " ,%= %;-///==///-// =%,"
.asciiz ";+ :%-;;;:;;;;-X- +:";
.asciiz "@- .-;;;;M- =M/;;;-. -X";
.asciiz " :;;::;;-. %- :+ ,-;;-;:=="
.asciiz " ,X H."
.asciiz " ;/ %="
.asciiz " // +;"
.asciiz " ,////,"
broken_heart:
.asciiz " .,---."
.asciiz " ,/XM#MMMX;,"
.asciiz " -%##########M%,"
.asciiz " -@######% $###@="
.asciiz " .,--, -H#######$ $###M:"
.asciiz " ,;$M###MMX; .;##########$;HM###X=";
.asciiz " ,/@##########H= ;################+";
.asciiz "-+#############M/, %##############+";
.asciiz "%M###############= /##############:";
.asciiz "H################ .M#############;.";
.asciiz "@###############M ,@###########M:."
.asciiz "X################, -$=X#######@:"
.asciiz "/@##################%- +######$-"
.asciiz ".;##################X .X#####+,"
.asciiz " .;H################/ -X####+."
.asciiz " ,;X##############, .MM/"
.asciiz " ,:+$H@M#######M#$- .$$="
.asciiz " .,-=;+$@###X: ;/=."
.asciiz " .,/X$; .::,"
.asciiz " ., .."
explosion:
.asciiz " .+"
.asciiz " /M;"
.asciiz " H#@: ;,"
.asciiz " -###H- -@/"
.asciiz " %####$. -; .%#X"
.asciiz " M#####+;#H :M#M."
.asciiz ".. .+/;%#########X###-"
.asciiz " -/%H%+;-, +##############/"
.asciiz " .:$M###MH$%+############X ,--=;-"
.asciiz " -/H#####################H+=."
.asciiz " .+#################X."
.asciiz " =%M####################H;."
.asciiz " /@###############+;;/%%;,"
.asciiz " -%###################$."
.asciiz " ;H######################M="
.asciiz " ,%#####MH$%;+#####M###-/@####%"
.asciiz " :$H%+;=- -####X.,H# -+M##@-"
.asciiz " . ,###; ; =$##+"
.asciiz " .#H, :XH,"
.asciiz " + .;-";
file:
.asciiz " -$-"
.asciiz " .H##H,"
.asciiz " +######+"
.asciiz " .+#########H."
.asciiz " -$############@."
.asciiz " =H###############@ -X:"
.asciiz " .$##################: @#@-"
.asciiz " ,; .M###################; H###;"
.asciiz " ;@#: @###################@ ,#####:"
.asciiz " -M###. M#################@. ;######H"
.asciiz " M####- +###############$ =@#######X"
.asciiz " H####$ -M###########+ :#########M,"
.asciiz " /####X- =########% :M########@/."
.asciiz " ,;%H@X; .$###X :##MM@%+;:-"
.asciiz " .."
.asciiz " -/;:-,. ,,-==+M########H"
.asciiz " -##################@HX%%+%%$%%%+:,,"
.asciiz " .-/H%%%+%%$H@###############M@+=:/+:";
.asciiz "/XHX%:#####MH%= ,---:;;;;/%%XHM,:###$";
.asciiz "$@#MX %+;- ."
check:
.asciiz " :X-";
.asciiz " :X###"
.asciiz " ;@####@"
.asciiz " ;M######X"
.asciiz " -@########$"
.asciiz " .$##########@"
.asciiz " =M############-";
.asciiz " +##############$";
.asciiz " .H############$=."
.asciiz " ,/: ,M##########M;."
.asciiz " -+@###; =##########M;"
.asciiz " =%M#######; :#########M/"
.asciiz "-$M###########; :#########/"
.asciiz " ,;X###########; =########$."
.asciiz " ;H#########+#######M="
.asciiz " ,+##############+"
.asciiz " /M#########@-"
.asciiz " ;M######%"
.asciiz " +####:"
.asciiz " ,$M-"
black_mesa:
.asciiz " .-;+$XHHHHHHX$+;-."
.asciiz " ,;X@@X%/;=----=:/%X@@X/,"
.asciiz " =$@@%=. .=+H@X:"
.asciiz " -XMX: =XMX="
.asciiz " /@@: =H@+"
.asciiz " %@X, .$@$"
.asciiz " +@X. $@%"
.asciiz "-@@, .@@=";
.asciiz "%@% +@$";
.asciiz "H@: :@H";
.asciiz "H@: :HHHHHHHHHHHHHHHHHHX, =@H";
.asciiz "%@% ;@M@@@@@@@@@@@@@@@@@H- +@$";
.asciiz "=@@, :@@@@@@@@@@@@@@@@@@@@@= .@@:";
.asciiz " +@X :@@@@@@@@@@@@@@@M@@@@@@:%@%"
.asciiz " $@$, ;@@@@@@@@@@@@@@@@@M@@@@@@$."
.asciiz " +@@HHHHHHH@@@@@@@@@@@@@@@@@@@@@@@+"
.asciiz " =X@@@@@@@@@@@@@@@@@@@@@@@@@@@@X="
.asciiz " :$@@@@@@@@@@@@@@@@@@@M@@@@$:"
.asciiz " ,;$@@@@@@@@@@@@@@@@@@X/-"
.asciiz " .-;+$XXHHHHHX$+;-."
cake:
.asciiz " ,:/+/-"
.asciiz " /M/ .,-=;//;-"
.asciiz " .:/= ;MH/, ,=/+%$XH@MM#@:"
.asciiz " -$##@+$###@H@MMM#######H:. -/H#";
.asciiz " .,H@H@ X######@ -H#####@+- -+H###@X";
.asciiz " .,@##H; +XM##M/, =%@###@X;-"
.asciiz "X%- :M##########$. .:%M###@%:"
.asciiz "M##H, +H@@@$/-. ,;$M###@%, -";
.asciiz "M####M=,,---,.-%%H####M$: ,+@##";
.asciiz "@##################@/. :%H##@$-"
.asciiz "M###############H, ;HM##M$="
.asciiz "#################. .=$M##M$="
.asciiz "################H..;XM##M$= .:+";
.asciiz "M###################@%= =+@MH%";
.asciiz "@################M/. =+H#X%="
.asciiz "=+M##############M, -/X#X+;."
.asciiz " .;XM##########H= ,/X#H+:,"
.asciiz " .=+HM######M+/+HM@+=."
.asciiz " ,:/%XM####H/."
.asciiz " ,.:=-."
glados:
.asciiz " #+ @ # # M#@"
.asciiz " . .X X.%##@;# # +@#######X. @#%"
.asciiz " ,==. ,######M+ -#####%M####M- #";
.asciiz " :H##M%:=##+ .M##M,;#####/+#######% ,M#";
.asciiz " .M########= =@#@.=#####M=M#######= X#";
.asciiz " :@@MMM##M. -##M.,#######M#######. = M";
.asciiz " @##..###:. .H####. @@ X,";
.asciiz " ############: ###,/####; /##= @#. M"
.asciiz " ,M## ;##,@#M;/M#M @# X#% X#"
.asciiz ".%= ######M## ##.M#: ./#M ,M #M ,#$"
.asciiz "##/ $## #+;#: #### ;#/ M M- @# :";
.asciiz "#+ #M@MM###M-;M #:$#-##$H# .#X @ + $#. #";
.asciiz " ######/.: #%=# M#:MM./#.-# @#: H#";
.asciiz "+,.= @###: /@ %#,@ ##@X #,-#@.##% .@#";
.asciiz "#####+;/##/ @## @#,+ /#M . X,"
.asciiz " ;###M#@ M###H .#M- ,##M ;@@; ###";
.asciiz " .M#M##H ;####X ,@#######M/ -M###$ -H";
.asciiz " .M###% X####H .@@MM@; ;@#M@"
.asciiz " H#M /@####/ ,++. / ==-,"
.asciiz " ,=/:, .+X@MMH@#H #####$=";

972
still_alive/eightycol.inc Normal file
View File

@ -0,0 +1,972 @@
1 REM PORTAL CLOSING CREDITS APPLESOFT
2 REM BASED ON QBASIC VERSION BY Thomas Moss (spinneretsystems)
3 REM WORDS AND MUSIC BY JONATHAN COULTON
'
' Size Opt: Final Version = 20557
' Move Line 20 to Line 8 = 20182
'
5 TEXT:PRINT CHR$(4)+"PR#3": REM 80 COLUMN MODE
7 HOME:C$=CHR$(13):GOTO 50
'
' SLOWTEXT
'
8 FOR C = 1 TO LEN(T$):PRINT MID$(T$, C, 1);:FOR I = 1 TO 1:NEXT I: NEXT C:POKE 768,F:POKE 769,D:CALL 770:RETURN
'
10 REM SET LEFT WINDOW
11 POKE 32,2:POKE 33,35:POKE 34,1:POKE 35,21
12 RETURN
15 REM SET RIGHT WINDOW
16 POKE 32,39:POKE 33,40:POKE 34,1:POKE 35,23
17 RETURN
'
' Restore Cursor
'
18 X=PEEK(1403):Y=PEEK(37):RETURN
19 POKE 36,X:POKE 37,Y-1:RETURN
'
30 REM FASTTEXT
31 FOR C = 1 TO LEN(T$)
32 PRINT MID$(T$, C, 1);
33 FOR I = 1 TO 25:NEXT I
34 NEXT C
35 RETURN
'
' Assembly Language audio routine
' See http://eightbitsoundandfury.ld8.org/programming.html
50 FOR L = 770 TO 790: READ V: POKE L,V: NEXT L
51 DATA 173,48,192,136,208,5,206,1,3,240,9,202,208,245,174,0,3,76,2,3,96
55 PRINT " ------------------------------------ "
57 FOR I=1 TO 20: PRINT "| |":NEXT I
60 PRINT " ------------------------------------ "
65 GOSUB 10
'
70 HOME
72 T$="Forms FORM-29827281-12:"+C$:GOSUB 30
74 T$="Test Assessment Report"+C$:GOSUB 30
76 PRINT:PRINT
78 FOR I=1 TO 1000: NEXT I
'
' This was a triumph.
'
80 T$="This ":D=54:F=85:GOSUB 8
82 T$="was ":F=91:GOSUB 8
84 T$="a ":F=102:GOSUB 8
86 T$="tri":GOSUB 8
89 T$="umph."+C$:F=91:GOSUB 8
90 FOR I=1 TO 800:NEXT
'
' I'm making a note here:
'
94 T$="I'm ":F=152:GOSUB 8
96 T$="ma":F=85:GOSUB 8
98 T$="king ":F=91:GOSUB 8
100 T$="a ":F=102:GOSUB 8
102 T$="note ":D=108:F=102:GOSUB 8
104 T$ = "here:"+C$:D=54:F=91:GOSUB 8
105 FOR I=1 TO 160: NEXT
'
' HUGE SUCCESS.
'
106 T$ = "HUGE ":D=108:F=114:GOSUB 8
108 T$ = "SUC":D=54:F=102:GOSUB 8
110 T$ = "CESS."+C$:D=108:F=152:GOSUB 8
111 FOR I=1 TO 480: NEXT
'
' It's hard to overstate
'
112 T$="It's ":D=54:F=152:GOSUB 8
114 T$="hard ":D=108:F=102:GOSUB 8
116 T$="to ":D=54:F=91:GOSUB 8
118 T$="o":D=162:F=85:GOSUB 8
120 T$="ver":D=54:F=91:GOSUB 8
122 T$="state"+C$:D=108:F=121:GOSUB 8
'
' my satisfaction.
'
124 T$="my ":D=162:F=114:GOSUB 8
126 T$="sa":D=108:F=102:GOSUB 8
128 T$="tis":D=54:F=152:GOSUB 8
130 T$="fac":D=108:F=152:GOSUB 8
132 T$="tion."+C$:F=91:GOSUB 8
133 FOR I=1 TO 720:NEXT
'
' APERTURE SCIENCE LOGO
134 GOSUB 18:GOSUB 15:HOME:GOSUB 2000:GOSUB 10:GOSUB 19:PRINT
'
' Aperture Science
136 T$="A":D=54:F=85:GOSUB 8
138 T$="per":F=91:GOSUB 8
140 T$="ture ":F=102:GOSUB 8
142 T$="Sci":GOSUB 8
144 T$="ence"+C$:F=91:GOSUB 8
145 FOR I=1 TO 800:NEXT
'
' We do what we must
'
146 T$="We ":F=152:GOSUB 8
148 T$="do ":F=85:GOSUB 8
150 T$="what ":F=91:GOSUB 8
152 T$="we ":F=102:GOSUB 8
154 T$="must"+C$:GOSUB 8
155 FOR I=1 TO 160: NEXT
'
' because we can.
'
156 T$="be":F=91:GOSUB 8
158 T$="cause ":F=114:GOSUB 8
159 FOR I=1 TO 160: NEXT
160 T$="we ":F=102:GOSUB 8
162 T$="can."+C$:D=162:F=152:GOSUB 8
163 FOR I=1 TO 560: NEXT
'
' For the good of all of us.
'
164 T$="For ":D=108:F=102:GOSUB 8
166 T$="the ":D=54:F=91:GOSUB 8
168 T$="good ":D=162:F=85:GOSUB 8
170 T$="of ":D=54:F=102:GOSUB 8
172 T$="all ":D=162:F=121:GOSUB 8
174 T$="of ":D=54:F=114:GOSUB 8
176 T$="us."+C$:F=102:GOSUB 8
'177 FOR I=1 TO 80: NEXT
'
' RADIATION
178 GOSUB 18:GOSUB 15:HOME:GOSUB 2100: GOSUB 10:GOSUB 19:PRINT
'
' Except the ones who are dead.
'
180 T$="Ex":F=152:GOSUB 8
182 T$="cept ":F=114:GOSUB 8
184 T$="the ":F=102:GOSUB 8
186 T$="ones ":F=96:GOSUB 8
188 T$="who ":F=102:GOSUB 8
190 T$="are ":F=114:GOSUB 8
192 T$="dead."+C$:F=128:GOSUB 8
193 FOR I=1 TO 160: NEXT
'
' APERTURE SCIENCE LOGO
194 GOSUB 18:GOSUB 15:HOME:GOSUB 2000: GOSUB 10:GOSUB 19:PRINT
'
' But there's no sense crying\nover every mistake.
'
196 PRINT
198 T$="But ":F=152:GOSUB 8
200 T$="there's ":F=143:GOSUB 8
202 T$="no ":D=108:F=128:GOSUB 8
204 T$="sense ":F=96:GOSUB 8
206 T$="cry":D=54:F=102:GOSUB 8
208 T$="ing"+C$:F=114:GOSUB 8
210 T$="o":GOSUB 8
212 T$="ver ":F=128:GOSUB 8
214 T$="e":F=114:GOSUB 8
216 T$="very ":F=128:GOSUB 8
218 T$="mis":D=108:F=128:GOSUB 8
220 T$="take."+C$:F=128:GOSUB 8
'
' You just keep on trying\ntill you run out of cake.
'
222 T$="You ":D=54:F=152:GOSUB 8
224 T$="just ":F=143:GOSUB 8
226 T$="keep ":D=108:F=128:GOSUB 8
228 T$="on ":F=96:GOSUB 8
230 T$="try":D=54:F=85:GOSUB 8
232 T$="ing"+C$:F=96:GOSUB 8
234 T$="till ":F=102:GOSUB 8
236 T$="you ":F=114:GOSUB 8
238 T$="run ":GOSUB 8
240 T$="out ":F=102:GOSUB 8
242 T$="of ":D=108:F=96:GOSUB 8
244 T$="cake."+C$:F=96:GOSUB 8
'
' ATOM
'
246 GOSUB 18:GOSUB 15:HOME:GOSUB 2200: GOSUB 10:GOSUB 19:PRINT
'
' And the Science gets done.
'
248 T$="And ":D=54:F=85:GOSUB 8
250 T$="the ":F=76:GOSUB 8
252 T$="Sci":F=72:GOSUB 8
254 T$="ence ":GOSUB 8
256 T$="gets ":D=108:F=76:GOSUB 8
258 T$="done."+C$:F=85:GOSUB 8
'
' And you make a neat gun
'
260 T$="And ":D=54:F=96:GOSUB 8
262 T$="you ":F=85:GOSUB 8
264 T$="make ":F=76:GOSUB 8
266 T$="a ":F=76:GOSUB 8
268 T$="neat ":D=108:F=85:GOSUB 8
270 T$="gun."+C$:F=96:GOSUB 8
'
' APERTURE SCIENCE LOGO
272 GOSUB 18:GOSUB 15:HOME:GOSUB 2000: GOSUB 10:GOSUB 19:PRINT
'
' For the people who are
'
274 T$="For ":D=54:F=114:GOSUB 8
276 T$="the ":F=128:GOSUB 8
278 T$="peo":F=114:GOSUB 8
280 T$="ple ":F=96:GOSUB 8
282 T$="who ":GOSUB 8
284 T$="are"+C$:D=108:F=102:GOSUB 8
'
' still alive.
'
286 T$="still ":D=54:F=102:GOSUB 8
288 T$="a":F=91:GOSUB 8
290 T$="live."+C$:D=162:F=91:GOSUB 8
291 FOR I=1 TO 1900: NEXT
'
'
'
292 HOME:C$=CHR$(13):X=FRE(0)
294 T$="Forms FORM-55551-5:"+C$:GOSUB 30
296 T$="Personnel File Addendum:"+C$:GOSUB 30
298 T$=C$+"Dear <<Subject Name Here>>":GOSUB 30
300 PRINT:PRINT
'
' I'm not even angry.
'
302 T$="I'm ":D=54:F=152:GOSUB 8
304 T$="not ":F=85:GOSUB 8
306 T$="e":F=91:GOSUB 8
308 T$="ven ":F=102:GOSUB 8
310 T$="an":GOSUB 8
312 T$="gry."+C$:F=91:GOSUB 8
313 FOR I=1 TO 800: NEXT
'
' I'm being so sincere right now.
'
314 T$="I'm ":F=85:GOSUB 8
316 T$="be":F=91:GOSUB 8
320 T$="ing ":F=102:GOSUB 8
322 T$="so ":D=162:F=102:GOSUB 8
324 T$="sin":D=54:F=91:GOSUB 8
326 T$="cere ":D=108:F=114:GOSUB 8
328 T$="right ":F=102:GOSUB 8
330 T$="now."+C$:F=152:GOSUB 8
331 FOR I=1 TO 560: NEXT
'
' Even though you broke my
'
332 T$="E":F=102:GOSUB 8
334 T$="ven ":D=54:F=91:GOSUB 8
336 T$="though ":D=162:F=85:GOSUB 8
338 T$="you ":D=108:F=102:GOSUB 8
340 T$="broke ":F=121:GOSUB 8
342 T$="my ":D=54:F=114:GOSUB 8
'
' HEART
344 GOSUB 18:GOSUB 15:HOME:GOSUB 2300: GOSUB 10:GOSUB 19:PRINT
345 POKE 36,X
'
' heart.\nAnd killed me.
'
346 T$="heart."+C$:D=162:F=102:GOSUB 8
348 T$="And ":D=54:F=152:GOSUB 8
350 T$="killed ":D=108:F=152:GOSUB 8
352 T$="me."+C$:D=54:F=91:GOSUB 8
353 FOR I=1 TO 720: NEXT
'
' EXPLOSION
'
354 GOSUB 18:GOSUB 15:HOME:GOSUB 2400: GOSUB 10:GOSUB 19:PRINT
'
' And tore me to pieces.
'
356 T$="And ":F=152:GOSUB 8
358 T$="tore ":F=85:GOSUB 8
360 T$="me ":F=91:GOSUB 8
362 T$="to ":F=102:GOSUB 8
364 T$="pie":GOSUB 8
366 T$="ces."+C$:F=91:GOSUB 8
367 FOR I=1 TO 800:NEXT
'
' And threw every peice into
'
368 T$="And ":F=152:GOSUB 8:REM SOUND 220, 4.8
370 T$="threw ":F=85:GOSUB 8
372 T$="ev":F=91:GOSUB 8
374 T$="ery ":F=102:GOSUB 8
376 T$="piece ":GOSUB 8
377 FOR I=1 TO 160: NEXT
378 T$="in":F=91:GOSUB 8
380 T$="to ":F=114:GOSUB 8
'381 FOR I=1 TO 160: NEXT
'
' FIRE
382 GOSUB 18:GOSUB 15:HOME:GOSUB 2500: GOSUB 10:GOSUB 19:PRINT
383 POKE 36,X
'
' a fire.
'
384 T$="a ":F=102:GOSUB 8
386 T$="fire."+C$:D=108:F=152:GOSUB 8
387 FOR I=1 TO 560:NEXT
'
' As they burned it hurt because
'
388 T$="As ":F=102:GOSUB 8
390 T$="they ":D=54:F=91:GOSUB 8
392 T$="burned ":D=162:F=85:GOSUB 8
394 T$="it ":D=108:F=102:GOSUB 8
396 T$="hurt ":F=121:GOSUB 8
398 T$="be":D=54:F=114:GOSUB 8
400 T$="cause"+C$:F=102:GOSUB 8
401 FOR I=1 TO 80: NEXT
'
' I was so happy for you!
'
402 T$="I ":F=152:GOSUB 8:REM SOUND 220, 4.8
404 T$="was ":F=114:GOSUB 8:REM SOUND 293.6, 4.8
406 T$="so ":F=102:GOSUB 8:REM SOUND 329.6, 4.8
408 T$="hap":F=96:GOSUB 8:REM SOUND 349.2, 4.8
410 T$="py ":F=102:GOSUB 8:REM SOUND 329.6, 4.8
412 T$="for ":F=114:GOSUB 8:REM SOUND 293.6, 4.8
414 T$="you!"+C$:F=128:GOSUB 8:REM SOUND 261.6, 14.4
'415 FOR I=1 TO 160: NEXT
'
' CHECK
416 GOSUB 18:GOSUB 15:HOME:GOSUB 2600: GOSUB 10:GOSUB 19:PRINT
'
' Now these points of data\nmake a beautiful line.
'
418 T$="Now ":F=152:GOSUB 8
420 T$="these ":F=143:GOSUB 8
422 T$="points ":D=108:F=128:GOSUB 8
424 T$="of ":F=96:GOSUB 8
426 T$="da":D=54:F=102:GOSUB 8
428 T$="ta"+C$:F=114:GOSUB 8
430 T$="make ":GOSUB 8
432 T$="a ":F=128:GOSUB 8
434 T$="beau":F=114:GOSUB 8
436 T$="ti":F=128:GOSUB 8
438 T$="ful ":D=108:F=128:GOSUB 8
440 T$="line."+C$:F=128:GOSUB 8
'
' And we're out of beta.\nWe're releasing on time.
'
442 T$="And ":D=54:F=152:GOSUB 8
444 T$="we're ":F=143:GOSUB 8
446 T$="out ":D=108:F=128:GOSUB 8
448 T$="of ":F=96:GOSUB 8
450 T$="be":D=54:F=85:GOSUB 8
452 T$="ta."+C$:F=96:GOSUB 8
454 T$="We're ":F=102:GOSUB 8
456 T$="re":F=114:GOSUB 8
458 T$="lea":GOSUB 8
460 T$="sing ":F=102:GOSUB 8
462 T$="on ":D=108:F=96:GOSUB 8
464 T$="time."+C$:F=96:GOSUB 8
'
' EXPLOSION
466 GOSUB 18:GOSUB 15:HOME:GOSUB 2400: GOSUB 10:GOSUB 19:PRINT
'
' So I'm GLaD. I got burned.
'
468 T$="So ":D=54:F=85:GOSUB 8
470 T$="I'm ":F=76:GOSUB 8
472 T$="GLaD. ":F=72:GOSUB 8
474 T$="I ":GOSUB 8
476 T$="got ": D=108:F=76:GOSUB 8
478 T$="burned."+C$:F=85:GOSUB 8
'
' ATOM
'
480 GOSUB 18:GOSUB 15:HOME:GOSUB 2200: GOSUB 10:GOSUB 19:PRINT
'
' Think of all the things we learned
'
482 T$="Think ":D=54:F=96:GOSUB 8
484 T$="of ":F=85:GOSUB 8
486 T$="all ":F=76:GOSUB 8
488 T$="the ":GOSUB 8
490 T$="things ":F=85:GOSUB 8
492 T$="we ":F=96:GOSUB 8
494 T$="learned"+C$:D=108:F=96:GOSUB 8
'
' APERTURE SCIENCE LOGO
'
496 GOSUB 18:GOSUB 15:HOME:GOSUB 2000: GOSUB 10:GOSUB 19:PRINT
'
' for the people who are
'
498 T$="for ":D=54:F=114:GOSUB 8
500 T$="the ":F=128:GOSUB 8
502 T$="peo":F=114:GOSUB 8
504 T$="ple ":F=96:GOSUB 8
506 T$="who ":GOSUB 8
510 T$="are"+C$: D=108:F=102:GOSUB 8
'
' still alive.
'
512 T$="still ":D=54:F=102:GOSUB 8
'
' FIXME: CAN WE DO ALIVE SLOWLY LIKE IN THE VIDEO?
'
513 T$="a":F=91:GOSUB 8
514 T$="live."+C$:D=162:F=91:GOSUB 8
'
' PAGE 3
'
516 HOME:C$=CHR$(13)
517 X=FRE(0)
518 T$="Forms FORM-55551-6:"+C$:GOSUB 30
520 T$="Personnel File Addendum ":GOSUB 30
522 T$="Addendum:"+C$:GOSUB 30
523 PRINT
524 T$="One last thing:"+C$:GOSUB 30
526 PRINT
'
' Go ahead and leave me
'
528 T$="Go ":D=54:F=85:GOSUB 8
530 T$="a":D=27:F=91:GOSUB 8
531 T$="head ":GOSUB 8
532 T$="and ":D=54:F=102:GOSUB 8
534 T$="leave ":D=108:F=102:GOSUB 8
536 T$="me"+C$:D=54:F=91:GOSUB 8
537 FOR I=1 TO 520:NEXT
'
' I think I prefer to stay inside.
'
538 T$="I ":F=152:GOSUB 8
540 T$="think ":F=85:GOSUB 8
542 T$="I ":F=91:GOSUB 8
544 T$="pre":F=102:GOSUB 8
546 T$="fer ":F=102:GOSUB 8
547 FOR I=1 TO 160: NEXT
548 T$="to ":F=91:GOSUB 8
550 T$="stay ":F=114:GOSUB 8
551 FOR I=1 TO 160: NEXT
552 T$="in":F=102:GOSUB 8
554 T$="side."+C$:D=108:F=152:GOSUB 8
555 FOR I=1 TO 560: NEXT
'
' Maybe you'll find someone else
'
556 T$="May":F=102:GOSUB 8
558 T$="be ":D=54:F=91:GOSUB 8
560 T$="you'll ":D=162:F=85:GOSUB 8
562 T$="find ":D=108:F=102:GOSUB 8
564 T$="some":F=121:GOSUB 8
566 T$="one ":D=54:F=114:GOSUB 8
568 T$="else"+C$:D=162:F=102:GOSUB 8
570 T$="to ":D=54:F=152:GOSUB 8
572 T$="help ":D=108:F=152:GOSUB 8
574 T$="you."+C$:D=54:F=91:GOSUB 8
575 FOR I=1 TO 800:NEXT
'
' Black Mesa
'
576 GOSUB 18:GOSUB 15:HOME:GOSUB 2800: GOSUB 10:GOSUB 19:PRINT
'
' Maybe Black Mesa.
'
578 T$="May":F=85:GOSUB 8
580 T$="be ":F=91:GOSUB 8
582 T$="Black ":F=102:GOSUB 8
584 T$="Me":D=108:F=102:GOSUB 8
586 T$="sa.":D=54:F=91:GOSUB 8
587 FOR I=1 TO 800:NEXT I
'
' THAT WAS A JOKE.
'
588 T$=".."+C$:GOSUB 30
590 T$="THAT ":F=85:GOSUB 8
591 T$="WAS ":F=91:GOSUB 8
592 T$="A ":F=102:GOSUB 8
593 T$="JOKE.":F=102:GOSUB 8
594 FOR I=1 TO 160: NEXT
'
' HAHA
'
595 T$=" ":F=91:GOSUB 8
596 T$=" ":F=114:GOSUB 8
597 FOR I=1 TO 160: NEXT
'
' FAT CHANCE.
'
598 T$="FAT ":F=102:GOSUB 8
600 T$="CHANCE."+C$:D=108:F=152:GOSUB 8
601 FOR I=1 TO 560: NEXT
'
' Anyway, this cake is
'
602 T$="A":F=102:GOSUB 8
604 T$="ny":D=54:F=91:GOSUB 8
606 T$="way, ":D=162:F=85:GOSUB 8
608 T$="this ":D=108:F=102:GOSUB 8
610 T$="cake ":F=121:GOSUB 8
612 T$="is ":D=54:F=114:GOSUB 8
'
' CAKE
'
614 GOSUB 18:GOSUB 15:HOME:GOSUB 2900: GOSUB 10:GOSUB 19:PRINT
616 POKE 36,X
'
' great.
'
616 T$="great."+C$:F=102:GOSUB 8
617 FOR I=1 TO 80: NEXT
'
' It's so delicious and moist.
'
618 T$="It's ":F=152:GOSUB 8
620 T$="so ":F=114:GOSUB 8
622 T$="de":F=102:GOSUB 8
624 T$="li":F=96:GOSUB 8
626 T$="cious ":F=102:GOSUB 8
628 T$="and ":F=114:GOSUB 8
630 T$="moist."+C$:F=128:GOSUB 8
631 FOR I=1 TO 160: NEXT
'
' GLaDOS
'
632 GOSUB 18:GOSUB 15:HOME:GOSUB 3000: GOSUB 10:GOSUB 19:PRINT
'
' Look at me still talking.
'
634 T$="Look ":F=152:GOSUB 8
636 T$="at ":F=143:GOSUB 8
638 T$="me ":D=108:F=128:GOSUB 8
640 T$="still ":F=96:GOSUB 8
642 T$="tal":D=54:F=102:GOSUB 8
644 T$="king"+C$:F=114:GOSUB 8
'
' when there's
'
646 T$="when ":F=114:GOSUB 8
648 T$="there's ":F=128:GOSUB 8
'
' RADIATION
650 GOSUB 18:GOSUB 15:HOME:GOSUB 2100: GOSUB 10:GOSUB 19:PRINT
652 POKE 36,X
'
'Science to do.
'
654 T$="Sci":F=114:GOSUB 8
656 T$="ence ":F=128:GOSUB 8
658 T$="to ":D=108:F=128:GOSUB 8
660 T$="do."+C$:F=128:GOSUB 8
'
' APERTURE SCIENCE LOGO
'
662 GOSUB 18:GOSUB 15:HOME:GOSUB 2000: GOSUB 10:GOSUB 19:PRINT
'
' When I look out there
'
664 T$="When ":D=54:F=152:GOSUB 8
666 T$="I ":F=143:GOSUB 8
668 T$="look ":D=108:F=128:GOSUB 8
670 T$="out ":F=96:GOSUB 8
672 T$="there, "+C$:D=54:F=85:GOSUB 8
'
' it makes me GLaD I'm not you."+C$
'
674 T$="it ":F=96:GOSUB 8
676 T$="Makes ":F=102:GOSUB 8
678 T$="me ":F=114:GOSUB 8
680 T$="GLaD ":F=114:GOSUB 8
682 T$="I'm ":F=102:GOSUB 8
684 T$="not ":D=108:F=96:GOSUB 8
686 T$="you."+C$:F=96:GOSUB 8
'
' ATOM
'
688 GOSUB 18:GOSUB 15:HOME:GOSUB 2200: GOSUB 10:GOSUB 19:PRINT
'
' I've experiments to run.
'
690 T$="I've ":D=54:F=85:GOSUB 8
692 T$="ex":F=76:GOSUB 8
694 T$="pe":F=72:GOSUB 8
696 T$="ri":F=72:GOSUB 8
698 T$="ments ":F=76:GOSUB 8
700 T$="to ":F=85:GOSUB 8
702 T$="run."+C$:D=108:F=85:GOSUB 8
'
' EXPLOSION
'
704 GOSUB 18:GOSUB 15:HOME:GOSUB 2400: GOSUB 10:GOSUB 19:PRINT
'
' There is research to be done"
'
706 T$="There ":D=54:F=96:GOSUB 8
708 T$="is ":F=85:GOSUB 8
710 T$="re":F=76:GOSUB 8
712 T$="search ":F=76:GOSUB 8
714 T$="to ":F=85:GOSUB 8
716 T$="be ":F=96:GOSUB 8
718 T$="done."+C$:D=108:F=96:GOSUB 8
'
' APERTURE SCIENCE LOGO
'
720 GOSUB 18:GOSUB 15:HOME:GOSUB 2000: GOSUB 10:GOSUB 19:PRINT
'
' On the people who are
'
722 T$="On ":D=54:F=114:GOSUB 8
724 T$="the ":F=128:GOSUB 8
726 T$="peo":F=114:GOSUB 8
728 T$="ple ":F=96:GOSUB 8
730 T$="who ":F=96:GOSUB 8
732 T$="are"+C$:D=108:F=102:GOSUB 8
'
' still alive.
'
734 T$="still ":D=54:F=102:GOSUB 8
736 T$="a":F=91:GOSUB 8
738 T$="live."+C$:D=162:F=91:GOSUB 8
739 FOR I=1 TO 160: NEXT
'
'
'
740 HOME:PRINT:PRINT:PRINT
'
' PS: And believe me I am\nstill alive.
'
742 T$="PS: And ":D=54:F=76:GOSUB 8
744 T$="be":F=76:GOSUB 8
746 T$="lieve ":F=68:GOSUB 8
748 T$="me ":F=76:GOSUB 8
750 T$="I ":F=91:GOSUB 8
752 T$="am"+C$:D=108:F=114:GOSUB 8
754 T$="still ":D=54:F=102:GOSUB 8
756 T$="a":F=91:GOSUB 8
758 T$="live."+C$:D=162:F=91:GOSUB 8
759 FOR I=1 TO 240:NEXT
'
' PPS: I'm doing Science and I'm\nstill alive.
'
760 T$="PPS: ":GOSUB 30
762 T$="I'm ":D=54:F=76:GOSUB 8
764 T$="do":F=76:GOSUB 8
766 T$="ing ":F=76:GOSUB 8
768 T$="Sci":F=68:GOSUB 8
770 T$="ence ":F=76:GOSUB 8
772 T$="and ":F=91:GOSUB 8
774 T$="I'm"+C$:D=108:F=114:GOSUB 8
776 T$="still ":D=54:F=102:GOSUB 8
778 T$="a":F=91:GOSUB 8
780 T$="live."+C$:D=162:F=91:GOSUB 8
781 FOR I=1 TO 240:NEXT
'
' PPPS: I feel FANTASTIC and I'm\nstill alive
'
782 T$="PPPS: ":GOSUB 30
784 T$="I ":D=54:F=76:GOSUB 8
786 T$="feel ":F=76:GOSUB 8
788 T$="FAN":F=76:GOSUB 8
790 T$="TAS":F=68:GOSUB 8
792 T$="TIC ":F=76:GOSUB 8
794 T$="and ":F=91:GOSUB 8
796 T$="I'm"+C$:D=108:F=114:GOSUB 8
798 T$="still ":D=54:F=102:GOSUB 8
800 T$="a":F=91:GOSUB 8
802 T$="live."+C$:D=162:F=91:GOSUB 8
803 FOR I=1 TO 320:NEXT
804 PRINT
'
' FINAL THOUGHT:
'
806 T$="FINAL THOUGHT:"+C$:GOSUB 30
'
' While you're dying I'll be\nstill alive.
'
808 T$="While ":D=54:F=76:GOSUB 8
810 T$="you're ":F=76:GOSUB 8
812 T$="dy":F=68:GOSUB 8
814 T$="ing ":F=76:GOSUB 8
816 T$="I'll ":F=91:GOSUB 8
818 T$="be"+C$:D=108:F=114:GOSUB 8
820 T$="still ":D=54:F=102:GOSUB 8
822 T$="a":F=91:GOSUB 8
824 T$="live":D=162:F=91:GOSUB 8
825 FOR I=1 TO 240:NEXT
'
' FINAL THOUGHT PS
'
826 T$=C$+C$+"FINAL THOUGHT PS:"+C$:GOSUB 30
'
' And when you're dead I will be\nstill alive
'
828 T$="And ":D=54:F=76:GOSUB 8
830 T$="when ":F=76:GOSUB 8
832 T$="you're ":F=76:GOSUB 8
834 T$="dead ":F=68:GOSUB 8
836 T$="I ":F=76:GOSUB 8
838 T$="will ":F=91:GOSUB 8
840 T$="be"+C$:D=108:F=114:GOSUB 8
842 T$="still ":D=54:F=102:GOSUB 8
844 T$="a":F=91:GOSUB 8
846 T$="live"+C$:D=162:F=91:GOSUB 8
847 FOR I=1 TO 240:NEXT
'
'
'
848 PRINT:PRINT
'
' STILL ALIVE
'
850 T$="STILL ":D=54:F=85:GOSUB 8
851 T$="A":F=76:GOSUB 8
852 T$="LIVE":D=162:F=76:GOSUB 8
853 FOR I=1 TO 240:NEXT
854 PRINT:PRINT
'
' STILL ALIVE
'
855 T$=" ":D=54:F=85:GOSUB 8
856 T$=" ":F=91:GOSUB 8
857 T$=" ":D=162:F=91:GOSUB 8
858 FOR I=1 TO 240:NEXT
'
'
'
860 FOR I=1 TO 500:NEXT I
862 HOME
864 FOR I=1 TO 1000:NEXT I
866 T$="THANK YOU FOR PARTICIPATING"+C$:GOSUB 30
868 T$="IN THIS"+C$:GOSUB 30
870 T$="ENRICHMENT CENTER ACTIVITY!!"+C$:GOSUB 30
872 PRINT:PRINT
874 FOR I=1 TO 3000: NEXT I
1000 PRINT CHR$(4)+"PR#0"
1001 TEXT:HOME
1999 END
'
'
'
2000 REM APERTURE
2001 PRINT " .,-:;//;:=,"
2002 PRINT " . :H@@@MM@M#H/.,+%;,"
2003 PRINT " ,/X+ +M@@M@MM%=,-%HMMM@X/,"
2004 PRINT " -+@MM; $M@@MH+-,;XMMMM@MMMM@+-"
2005 PRINT " ;@M@@M- XM@X;. -+XXXXXHHH@M@M#@/."
2006 PRINT " ,%MM@@MH ,@%= .---=-=:=,."
2007 PRINT " =@#@@@MX ., -%HX$$%%%+;"
2008 PRINT " =-./@M@M$ .;@MMMM@MM:"
2009 PRINT " X@/ -$MM/ .+MM@@@M$"
2010 PRINT ",@M@H: :@: . =X#@@@@-";
2011 PRINT ",@@@MMX, . /H- ;@M@M=";
2012 PRINT ".H@@@@M@+, %MM+..%#$.";
2013 PRINT " /MMMM@MMH/. XM@MH; =;"
2014 PRINT " /%+%$XHH@$= , .H@@@@MX,"
2015 PRINT " .=--------. -%H.,@@@@@MX,"
2016 PRINT " .%MM@@@HHHXX$$$%+- .:$MMX =M@@MM%."
2017 PRINT " =XMMM@MM@MM#H;,-+HMM@M+ /MMMX="
2018 PRINT " =%@M@M#@$-.=$@MM@@@M; %M%="
2019 PRINT " ,:+$+-,/H#MMMMMMM@= =,"
2020 PRINT " =++%%%%+/:-."
2030 RETURN
'
2100 REM RADIOACTIVE
2101 PRINT " =+$HM####@H%;,"
2102 PRINT " /H###############M$,"
2103 PRINT " ,@################+"
2104 PRINT " .H##############+"
2105 PRINT " X############/"
2106 PRINT " $##########/"
2107 PRINT " %########/"
2108 PRINT " /X/;;+X/"
2109 PRINT
2110 PRINT " -XHHX-"
2111 PRINT " ,######,"
2112 PRINT "#############X .M####M. X#############";
2113 PRINT "##############- -//- -##############";
2114 PRINT "X##############%, ,+##############X";
2115 PRINT "-##############X X##############-";
2116 PRINT " %############% %############%"
2117 PRINT " %##########; ;##########%"
2118 PRINT " ;#######M= =M#######;"
2119 PRINT " .+M###@, ,@###M+."
2120 PRINT " :XH. .HX:"
2130 RETURN
'
2200 REM ATOM
2201 PRINT " =/;;/-"
2202 PRINT " +: //"
2203 PRINT " /; /;"
2204 PRINT " -X H."
2205 PRINT ".//;;;:;;-, X= :+ .-;:=;:;%;.";
2206 PRINT "M- ,=;;;#:, ,:#;;:=, ,@";
2207 PRINT ":% :%.=/++++/=.$= %=";
2208 PRINT " ,%; %/:+/;,,/++:+/ ;+."
2209 PRINT " ,+/. ,;@+, ,%H;, ,/+,"
2210 PRINT " ;+;;/= @. .H##X -X :///+;"
2211 PRINT " ;+=;;;.@, .XM@$. =X.//;=%/."
2212 PRINT " ,;: :@%= =$H: .+%-"
2213 PRINT " ,%= %;-///==///-// =%,"
2214 PRINT ";+ :%-;;;:;;;;-X- +:";
2215 PRINT "@- .-;;;;M- =M/;;;-. -X";
2216 PRINT " :;;::;;-. %- :+ ,-;;-;:=="
2217 PRINT " ,X H."
2218 PRINT " ;/ %="
2219 PRINT " // +;"
2220 PRINT " ,////,"
2230 RETURN
'
2300 REM BROKEN HEART
2301 PRINT " .,---."
2302 PRINT " ,/XM#MMMX;,"
2303 PRINT " -%##########M%,"
2304 PRINT " -@######% $###@="
2305 PRINT " .,--, -H#######$ $###M:"
2306 PRINT " ,;$M###MMX; .;##########$;HM###X=";
2307 PRINT " ,/@##########H= ;################+";
2308 PRINT "-+#############M/, %##############+";
2309 PRINT "%M###############= /##############:";
2310 PRINT "H################ .M#############;.";
2311 PRINT "@###############M ,@###########M:."
2312 PRINT "X################, -$=X#######@:"
2313 PRINT "/@##################%- +######$-"
2314 PRINT ".;##################X .X#####+,"
2315 PRINT " .;H################/ -X####+."
2316 PRINT " ,;X##############, .MM/"
2317 PRINT " ,:+$H@M#######M#$- .$$="
2318 PRINT " .,-=;+$@###X: ;/=."
2319 PRINT " .,/X$; .::,"
2320 PRINT " ., .."
2330 RETURN
'
2400 REM EXPLOSION
2401 PRINT " .+"
2402 PRINT " /M;"
2403 PRINT " H#@: ;,"
2404 PRINT " -###H- -@/"
2405 PRINT " %####$. -; .%#X"
2406 PRINT " M#####+;#H :M#M."
2407 PRINT ".. .+/;%#########X###-"
2408 PRINT " -/%H%+;-, +##############/"
2409 PRINT " .:$M###MH$%+############X ,--=;-"
2410 PRINT " -/H#####################H+=."
2411 PRINT " .+#################X."
2412 PRINT " =%M####################H;."
2413 PRINT " /@###############+;;/%%;,"
2414 PRINT " -%###################$."
2415 PRINT " ;H######################M="
2416 PRINT " ,%#####MH$%;+#####M###-/@####%"
2417 PRINT " :$H%+;=- -####X.,H# -+M##@-"
2418 PRINT " . ,###; ; =$##+"
2419 PRINT " .#H, :XH,"
2420 PRINT " + .;-";
2430 RETURN
'
2500 REM FIRE
2501 PRINT " -$-"
2502 PRINT " .H##H,"
2503 PRINT " +######+"
2504 PRINT " .+#########H."
2505 PRINT " -$############@."
2506 PRINT " =H###############@ -X:"
2507 PRINT " .$##################: @#@-"
2508 PRINT " ,; .M###################; H###;"
2509 PRINT " ;@#: @###################@ ,#####:"
2510 PRINT " -M###. M#################@. ;######H"
2511 PRINT " M####- +###############$ =@#######X"
2512 PRINT " H####$ -M###########+ :#########M,"
2513 PRINT " /####X- =########% :M########@/."
2514 PRINT " ,;%H@X; .$###X :##MM@%+;:-"
2515 PRINT " .."
2516 PRINT " -/;:-,. ,,-==+M########H"
2517 PRINT " -##################@HX%%+%%$%%%+:,,"
2518 PRINT " .-/H%%%+%%$H@###############M@+=:/+:";
2519 PRINT "/XHX%:#####MH%= ,---:;;;;/%%XHM,:###$";
2520 PRINT "$@#MX %+;- ."
2530 RETURN
'
2600 REM CHECK
2601 PRINT " :X-";
2602 PRINT " :X###"
2603 PRINT " ;@####@"
2604 PRINT " ;M######X"
2605 PRINT " -@########$"
2606 PRINT " .$##########@"
2607 PRINT " =M############-";
2608 PRINT " +##############$";
2609 PRINT " .H############$=."
2610 PRINT " ,/: ,M##########M;."
2611 PRINT " -+@###; =##########M;"
2612 PRINT " =%M#######; :#########M/"
2613 PRINT "-$M###########; :#########/"
2614 PRINT " ,;X###########; =########$."
2615 PRINT " ;H#########+#######M="
2616 PRINT " ,+##############+"
2617 PRINT " /M#########@-"
2618 PRINT " ;M######%"
2619 PRINT " +####:"
2620 PRINT " ,$M-"
2630 RETURN
'
2800 REM BLACK MESA
2801 PRINT " .-;+$XHHHHHHX$+;-."
2802 PRINT " ,;X@@X%/;=----=:/%X@@X/,"
2803 PRINT " =$@@%=. .=+H@X:"
2804 PRINT " -XMX: =XMX="
2805 PRINT " /@@: =H@+"
2806 PRINT " %@X, .$@$"
2807 PRINT " +@X. $@%"
2808 PRINT "-@@, .@@=";
2809 PRINT "%@% +@$";
2810 PRINT "H@: :@H";
2811 PRINT "H@: :HHHHHHHHHHHHHHHHHHX, =@H";
2812 PRINT "%@% ;@M@@@@@@@@@@@@@@@@@H- +@$";
2813 PRINT "=@@, :@@@@@@@@@@@@@@@@@@@@@= .@@:";
2814 PRINT " +@X :@@@@@@@@@@@@@@@M@@@@@@:%@%"
2815 PRINT " $@$, ;@@@@@@@@@@@@@@@@@M@@@@@@$."
2816 PRINT " +@@HHHHHHH@@@@@@@@@@@@@@@@@@@@@@@+"
2817 PRINT " =X@@@@@@@@@@@@@@@@@@@@@@@@@@@@X="
2818 PRINT " :$@@@@@@@@@@@@@@@@@@@M@@@@$:"
2819 PRINT " ,;$@@@@@@@@@@@@@@@@@@X/-"
2820 PRINT " .-;+$XXHHHHHX$+;-."
2830 RETURN
'
2900 REM CAKE DELICIOUS AND MOIST
2901 PRINT " ,:/+/-"
2902 PRINT " /M/ .,-=;//;-"
2903 PRINT " .:/= ;MH/, ,=/+%$XH@MM#@:"
2904 PRINT " -$##@+$###@H@MMM#######H:. -/H#";
2905 PRINT " .,H@H@ X######@ -H#####@+- -+H###@X";
2906 PRINT " .,@##H; +XM##M/, =%@###@X;-"
2907 PRINT "X%- :M##########$. .:%M###@%:"
2908 PRINT "M##H, +H@@@$/-. ,;$M###@%, -";
2909 PRINT "M####M=,,---,.-%%H####M$: ,+@##";
2910 PRINT "@##################@/. :%H##@$-"
2911 PRINT "M###############H, ;HM##M$="
2912 PRINT "#################. .=$M##M$="
2913 PRINT "################H..;XM##M$= .:+";
2914 PRINT "M###################@%= =+@MH%";
2915 PRINT "@################M/. =+H#X%="
2916 PRINT "=+M##############M, -/X#X+;."
2917 PRINT " .;XM##########H= ,/X#H+:,"
2918 PRINT " .=+HM######M+/+HM@+=."
2919 PRINT " ,:/%XM####H/."
2920 PRINT " ,.:=-."
2930 RETURN
'
3000 REM GLaDOS
3001 PRINT " #+ @ # # M#@"
3002 PRINT " . .X X.%##@;# # +@#######X. @#%"
3003 PRINT " ,==. ,######M+ -#####%M####M- #";
3004 PRINT " :H##M%:=##+ .M##M,;#####/+#######% ,M#";
3005 PRINT " .M########= =@#@.=#####M=M#######= X#";
3006 PRINT " :@@MMM##M. -##M.,#######M#######. = M";
3007 PRINT " @##..###:. .H####. @@ X,";
3008 PRINT " ############: ###,/####; /##= @#. M"
3009 PRINT " ,M## ;##,@#M;/M#M @# X#% X#"
3010 PRINT ".%= ######M## ##.M#: ./#M ,M #M ,#$"
3011 PRINT "##/ $## #+;#: #### ;#/ M M- @# :";
3012 PRINT "#+ #M@MM###M-;M #:$#-##$H# .#X @ + $#. #";
3013 PRINT " ######/.: #%=# M#:MM./#.-# @#: H#";
3014 PRINT "+,.= @###: /@ %#,@ ##@X #,-#@.##% .@#";
3015 PRINT "#####+;/##/ @## @#,+ /#M . X,"
3016 PRINT " ;###M#@ M###H .#M- ,##M ;@@; ###";
3017 PRINT " .M#M##H ;####X ,@#######M/ -M###$ -H";
3018 PRINT " .M###% X####H .@@MM@; ;@#M@"
3019 PRINT " H#M /@####/ ,++. / ==-,"
3020 PRINT " ,=/:, .+X@MMH@#H #####$=";
3030 RETURN

View File

@ -0,0 +1,345 @@
;================================
;================================
; mockingboard interrupt handler
;================================
;================================
; On Apple II/6502 the interrupt handler jumps to address in 0xfffe
; This is in the ROM, which saves the registers
; on older IIe it saved A to $45 (which could mess with DISK II)
; newer IIe doesn't do that.
; It then calculates if it is a BRK or not (which trashes A)
; Then it sets up the stack like an interrupt and calls 0x3fe
TIME_OFFSET EQU 13
interrupt_handler:
pha ; save A ; 3
; Should we save X and Y too?
; inc $0404 ; debug (flashes char onscreen)
bit $C404 ; clear 6522 interrupt by reading T1C-L ; 4
lda DONE_PLAYING ; 3
beq mb_play_music ; if song done, don't play music ; 3/2nt
jmp check_keyboard ; 3
;============
; 13
mb_play_music:
;======================================
; Write frames to Mockingboard
;======================================
; actually plays frame loaded at end of
; last interrupt, so 20ms behind?
mb_write_frame:
ldx #0 ; set up reg count ; 2
;============
; 2
;==================================
; loop through the 14 registers
; reading the value, then write out
;==================================
; inlined "write_ay_both" to save up to 156 (12*13) cycles
; unrolled
mb_write_loop:
lda REGISTER_DUMP,X ; load register value ; 4
cmp REGISTER_OLD,X ; compare with old values ; 4
beq mb_no_write ; 3/2nt
;=============
; typ 11
; special case R13. If it is 0xff, then don't update
; otherwise might spuriously reset the envelope settings
cpx #13 ; 2
bne mb_not_13 ; 3/2nt
cmp #$ff ; 2
beq mb_skip_13 ; 3/2nt
;============
; typ 5
mb_not_13:
; address
stx MOCK_6522_ORA1 ; put address on PA1 ; 4
stx MOCK_6522_ORA2 ; put address on PA2 ; 4
lda #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2
sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4
sta MOCK_6522_ORB2 ; latch_address on PB2 ; 4
lda #MOCK_AY_INACTIVE ; go inactive ; 2
sta MOCK_6522_ORB1 ; 4
sta MOCK_6522_ORB2 ; 4
; value
lda REGISTER_DUMP,X ; load register value ; 4
sta MOCK_6522_ORA1 ; put value on PA1 ; 4
sta MOCK_6522_ORA2 ; put value on PA2 ; 4
lda #MOCK_AY_WRITE ; ; 2
sta MOCK_6522_ORB1 ; write on PB1 ; 4
sta MOCK_6522_ORB2 ; write on PB2 ; 4
lda #MOCK_AY_INACTIVE ; go inactive ; 2
sta MOCK_6522_ORB1 ; 4
sta MOCK_6522_ORB2 ; 4
;===========
; 62
mb_no_write:
inx ; point to next register ; 2
cpx #14 ; if 14 we're done ; 2
bmi mb_write_loop ; otherwise, loop ; 3/2nt
;============
; 7
mb_skip_13:
;=====================================
; Copy registers to old
;=====================================
ldx #13 ; 2
mb_reg_copy:
lda REGISTER_DUMP,X ; load register value ; 4
sta REGISTER_OLD,X ; compare with old values ; 4
dex ; 2
bpl mb_reg_copy ; 2nt/3
;=============
; 171
;===================================
; Load all 14 registers in advance
;===================================
; note, assuming not cross page boundary, not any slower
; then loading from zero page?
mb_load_values:
ldx #0 ; set up reg count ; 2
ldy MB_CHUNK_OFFSET ; get chunk offset ; 3
;=============
; 5
mb_load_loop:
lda (INL),y ; load register value ; 5
sta REGISTER_DUMP,X ; 4
;============
; 9
;====================
; point to next page
;====================
clc ; point to next interleaved ; 2
lda INH ; page by adding CHUNKSIZE (3/1); 3
adc CHUNKSIZE ; 3
sta INH ; 3
inx ; point to next register ; 2
cpx #14 ; if 14 we're done ; 2
bmi mb_load_loop ; otherwise, loop ; 3/2nt
;============
; 18
;=========================================
; if A_COARSE_TONE is $ff then we are done
lda A_COARSE_TONE ; 3
bpl mb_not_done ; 3/2nt
lda #1 ; set done playing ; 2
jmp quiet_exit ; 3
;===========
; typ 6
mb_not_done:
;==============================================
; incremement offset. If 0 move to next chunk
;==============================================
increment_offset:
inc MB_CHUNK_OFFSET ; increment offset ; 5
bne back_to_first_reg ; if not zero, done ; 3/2nt
;=====================
; move to next state
;=====================
clc
rol DECODER_STATE ; next state ; 5
; 20 -> 40 -> 80 -> c+00
bcs wraparound_to_a ; 3/2nt
bit DECODER_STATE ;bit7->N bit6->V
bvs back_to_first_reg ; do nothing on B ; 3/2nt
start_c:
lda #1
sta CHUNKSIZE
; setup next three chunks of song
lda #1 ; start decompressing
sta DECOMPRESS_TIME ; outside of handler
jmp back_to_first_reg
wraparound_to_a:
lda #$3
sta CHUNKSIZE
lda #$20
sta DECODER_STATE
sta COPY_TIME ; start copying
lda DECOMPRESS_TIME
beq blah
lda #1
sta DECODE_ERROR
blah:
;==============================
; After 14th reg, reset back to
; read R0 data
;==============================
back_to_first_reg:
lda #0 ; 2
bit DECODER_STATE ; 3
bmi back_to_first_reg_c ; 2nt/3
bvc back_to_first_reg_a ; 2nt/3
back_to_first_reg_b:
lda #$1 ; offset by 1
back_to_first_reg_a:
clc ; 2
adc #>UNPACK_BUFFER ; in proper chunk 1 or 2 ; 2
jmp update_r0_pointer ; 3
back_to_first_reg_c:
lda #>(UNPACK_BUFFER+$2A00) ; in linear C area ; 2
update_r0_pointer:
sta INH ; update r0 pointer ; 3
;=================================
; Finally done with this interrupt
;=================================
done_interrupt:
;=====================
; Update time counter
;=====================
update_time:
inc FRAME_COUNT ; 5
lda FRAME_COUNT ; 3
cmp #50 ; 3
bne done_time ; 3/2nt
lda #$0 ; 2
sta FRAME_COUNT ; 3
update_second_ones:
inc $7d0+TIME_OFFSET+3 ; 6
inc $bd0+TIME_OFFSET+3 ; 6
lda $bd0+TIME_OFFSET+3 ; 4
cmp #$ba ; one past '9' ; 2
bne done_time ; 3/2nt
lda #'0'+$80 ; 2
sta $7d0+TIME_OFFSET+3 ; 4
sta $bd0+TIME_OFFSET+3 ; 4
update_second_tens:
inc $7d0+TIME_OFFSET+2 ; 6
inc $bd0+TIME_OFFSET+2 ; 6
lda $bd0+TIME_OFFSET+2 ; 4
cmp #$b6 ; 6 (for 60 seconds) ; 2
bne done_time ; 3/2nt
lda #'0'+$80 ; 2
sta $7d0+TIME_OFFSET+2 ; 4
sta $bd0+TIME_OFFSET+2 ; 4
update_minutes:
inc $7d0+TIME_OFFSET ; 6
inc $bd0+TIME_OFFSET ; 6
; we don't handle > 9:59 songs yet
done_time:
;=============
; 90 worst
;=================================
; Moved visualization here as a hack
;=================================
;============================
; Visualization
;============================
check_keyboard:
jsr get_key
lda LASTKEY
beq exit_interrupt
cmp #(' '+$80)
bne key_left
key_space:
lda #$80
eor DONE_PLAYING
jmp quiet_exit
key_left:
cmp #'A'
bne key_right
lda #$40
bne quiet_exit
key_right:
cmp #'D'
bne done_key
lda #$20
bne quiet_exit
done_key:
jmp exit_interrupt
quiet_exit:
sta DONE_PLAYING
jsr clear_ay_both
;=====================================
; clear register area
;=====================================
ldx #13 ; 2
lda #0 ; 2
mb_clear_reg:
sta REGISTER_DUMP,X ; clear register value ; 4
sta REGISTER_OLD,X ; clear old values ; 4
dex ; 2
bpl mb_clear_reg ; 2nt/3
exit_interrupt:
pla ; restore a ; 4
rti ; return from interrupt ; 6
;============
; typical
; ???? cycles
REGISTER_OLD:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0

BIN
still_alive/still_alive.dsk Normal file

Binary file not shown.

558
still_alive/still_alive.s Normal file
View File

@ -0,0 +1,558 @@
; And Believe Me, I'm Still Alive
.include "zp.inc"
; program is ~4k, so from 0xc00 to 0x1C00
LZ4_BUFFER EQU $1C00 ; $1C00 - $5C00, 16k for now
UNPACK_BUFFER EQU $5E00 ; $5E00 - $9600, 14k, $3800
; trying not to hit DOS at $9600
; Reserve 3 chunks plus spare (14k)
NUM_FILES EQU 15
;=============================
; Setup
;=============================
jsr HOME
jsr TEXT
; init variables
lda #0
sta DRAW_PAGE
sta CH
sta CV
sta DONE_PLAYING
sta XPOS
sta MB_CHUNK_OFFSET
sta DECODE_ERROR
lda #0
sta WHICH_FILE
; print detection message
lda #<mocking_message ; load loading message
sta OUTL
lda #>mocking_message
sta OUTH
jsr move_and_print ; print it
jsr mockingboard_detect_slot4 ; call detection routine
cpx #$1
beq mockingboard_found
lda #<not_message ; if not found, print that
sta OUTL
lda #>not_message
sta OUTH
inc CV
jsr move_and_print
jmp forever_loop ; and wait forever
mockingboard_found:
; lda #<found_message ; print found message
; sta OUTL
; lda #>found_message
; sta OUTH
; inc CV
; jsr move_and_print
;============================
; Init the Mockingboard
;============================
jsr mockingboard_init
jsr reset_ay_both
jsr clear_ay_both
;=========================
; Setup Interrupt Handler
;=========================
; Vector address goes to 0x3fe/0x3ff
; FIXME: should chain any existing handler
lda #<interrupt_handler
sta $03fe
lda #>interrupt_handler
sta $03ff
;============================
; Enable 50Hz clock on 6522
;============================
sei ; disable interrupts just in case
lda #$40 ; Continuous interrupts, don't touch PB7
sta $C40B ; ACR register
lda #$7F ; clear all interrupt flags
sta $C40E ; IER register (interrupt enable)
lda #$C0
sta $C40D ; IFR: 1100, enable interrupt on timer one oflow
sta $C40E ; IER: 1100, enable timer one interrupt
lda #$E7
sta $C404 ; write into low-order latch
lda #$4f
sta $C405 ; write into high-order latch,
; load both values into counter
; clear interrupt and start counting
; 4fe7 / 1e6 = .020s, 50Hz
;============================
; Draw title screen
;============================
lda #$4 ; draw page 1
sta DRAW_PAGE
jsr clear_screens ; clear both screens
;==================
; load first song
;==================
jsr new_song
;============================
; Init Background
;============================
;============================
; Enable 6502 interrupts
;============================
cli ; clear interrupt mask
;============================
; Loop forever
;============================
main_loop:
lda DECODE_ERROR
beq check_copy
sei
brk
check_copy:
lda COPY_TIME
beq check_decompress ; if zero, skip
lda #0
sta COPY_OFFSET
check_copy_loop:
jsr page_copy ;6+3621
inc COPY_OFFSET ; (opt: make subtract?) ; 5
lda #14 ; NOT HEX URGH!
cmp COPY_OFFSET
bne check_copy_loop
lda #0 ; we are done
sta COPY_TIME
check_decompress:
lda DECOMPRESS_TIME
beq check_done ; if zero, skip
jsr setup_next_subsong ; decompress
lda MB_CHUNK_OFFSET
sta TIME_TAKEN
lda #0
sta DECOMPRESS_TIME
check_done:
lda #$ff
bit DONE_PLAYING
beq main_loop ; if was all zeros, loop
bmi main_loop ; if high bit set, paused
bvs minus_song ; if bit 6 set, then left pressed
; else, either song finished or
; right pressed
plus_song:
sei ; disable interrupts
jsr increment_file
jmp done_play
minus_song:
sei ; disable interrupts
jsr decrement_file
done_play:
lda #0
sta DONE_PLAYING
lda #0
sta CH
jsr clear_bottoms
jsr new_song
cli ; re-enable interrupts
jmp main_loop
forever_loop:
jmp forever_loop
;=================
; load a new song
;=================
new_song:
;=========================
; Init Variables
;=========================
lda #$0
sta FRAME_COUNT
sta A_VOLUME
sta B_VOLUME
sta C_VOLUME
sta COPY_OFFSET
sta DECOMPRESS_TIME
sta COPY_TIME
sta MB_CHUNK_OFFSET
lda #$20
sta DECODER_STATE
lda #3
sta CHUNKSIZE
;===========================
; Print loading message
;===========================
jsr clear_bottoms ; clear bottom of page 0/1
lda #0 ; print LOADING message
sta CH
lda #21
sta CV
lda #<loading_message
sta OUTL
lda #>loading_message
sta OUTH
jsr print_both_pages
;===========================
; Load in KRW file
;===========================
jsr get_filename
lda #8
sta CH
lda #21
sta CV
lda INL
sta OUTL
lda INH
sta OUTH
jsr print_both_pages
disk_buff EQU LZ4_BUFFER
read_size EQU $4000
jsr read_file ; read KRW file from disk
;=========================
; Print Info
;=========================
jsr clear_bottoms ; clear bottom of page 0/1
lda #>LZ4_BUFFER ; point to LZ4 data
sta OUTH
lda #<LZ4_BUFFER
sta OUTL
ldy #3 ; skip KRW magic at front
; print title
lda #20 ; VTAB 20: HTAB from file
jsr print_header_info
; Print Author
lda #21 ; VTAB 21: HTAB from file
jsr print_header_info
; Print clock
lda #23 ; VTAB 23: HTAB from file
jsr print_header_info
; Print Left Arrow (INVERSE)
lda #'<'
sta $750
sta $B50
lda #'-'
sta $751
sta $B51
; Print Rright Arrow (INVERSE)
lda #'-'
sta $776
sta $B76
lda #'>'
sta $777
sta $B77
; Point LZ4 src at proper place
ldy #0
lda #>(LZ4_BUFFER+3)
sta LZ4_SRC+1
lda #<(LZ4_BUFFER+3)
sta LZ4_SRC
lda (LZ4_SRC),Y ; get header skip
clc
adc LZ4_SRC
sta LZ4_SRC
lda LZ4_SRC+1
adc #0
sta LZ4_SRC+1
lda #<UNPACK_BUFFER ; set input pointer
sta INL
lda #>UNPACK_BUFFER
sta INH
; Decompress first chunks
lda #$0
sta COPY_OFFSET
sta DECOMPRESS_TIME
lda #$3
sta CHUNKSIZE
lda #$20
sta DECODER_STATE
sta COPY_TIME
jsr setup_next_subsong
rts
;=================
; next sub-song
;=================
setup_next_subsong:
ldy #0
lda (LZ4_SRC),Y ; get next size value
sta LZ4_END
iny
lda (LZ4_SRC),Y
sta LZ4_END+1
lda #2 ; increment pointer
clc
adc LZ4_SRC
sta LZ4_SRC
lda LZ4_SRC+1
adc #0
sta LZ4_SRC+1
jsr lz4_decode ; decode
; tail-call?
rts
;===================
; print header info
;===================
; shortcut to print header info
; a = VTAB
print_header_info:
sta CV
iny ; adjust pointer
tya
ldy #0
clc
adc OUTL
sta OUTL
lda OUTH
adc #$0
sta OUTH
lda (OUTL),Y ; get HTAB value
sta CH
inc OUTL ; increment 16-bits
bne bloop22
inc OUTH
bloop22:
jmp print_both_pages ; print, tail call
;==============================================
; plan: takes 256 50Hz to play a chunk
; need to copy 14 256-byte blocks
; PLAY A (copying C)
; PLAY B (copying C)
; PLAY D (decompressing A/B/C)
;========================
; page copy
;========================
; want to copy:
; SRC: chunk_buffer+(2*256)+(COPY_OFFSET*3*256)
; DST: chunk_buffer+$2A00+(COPY_OFFSET*256)
page_copy:
clc ; 2
lda #>(UNPACK_BUFFER+512) ; 3
adc COPY_OFFSET ; 3
adc COPY_OFFSET ; 3
adc COPY_OFFSET ; 3
sta page_copy_loop+2 ; self modify ; 5
lda #>(UNPACK_BUFFER+$2A00) ; 2
adc COPY_OFFSET ; 3
sta page_copy_loop+5 ; self modify ; 5
ldx #$00 ; 2
page_copy_loop:
lda $1000,x ; 4
sta $1000,X ; 5
inx ; 2
bne page_copy_loop ; 2nt/3
rts ; 6
;======================
; 2+14*256+6+29= 3621
;==================
; Get filename
;==================
; WHICH_FILE holds number
; MAX_FILES has max
; Scroll through until find
; point INH:INL to it
get_filename:
ldy #0
ldx WHICH_FILE
lda #<krw_file ; point to filename
sta INL
lda #>krw_file
sta INH
get_filename_loop:
cpx #0
beq filename_found
inner_loop:
iny
lda (INL),Y
bne inner_loop
iny
dex
jmp get_filename_loop
filename_found:
tya
clc
adc INL
sta INL
lda INH
adc #0
sta INH
rts
;===============================
; Increment file we want to load
;===============================
increment_file:
inc WHICH_FILE
lda WHICH_FILE
cmp #NUM_FILES
bne done_increment
lda #0
sta WHICH_FILE
done_increment:
rts
;===============================
; Decrement file we want to load
;===============================
decrement_file:
dec WHICH_FILE
bpl done_decrement
lda #(NUM_FILES-1)
sta WHICH_FILE
done_decrement:
rts
;==========
; filenames
;==========
krw_file:
.asciiz "SA.KRW"
;=========
;routines
;=========
.include "../asm_routines/gr_offsets.s"
.include "../asm_routines/text_print.s"
.include "../asm_routines/mockingboard_a.s"
.include "../asm_routines/gr_fast_clear.s"
.include "../asm_routines/pageflip.s"
.include "../asm_routines/gr_setpage.s"
.include "../asm_routines/dos33_routines.s"
.include "../asm_routines/gr_hlin.s"
.include "../asm_routines/lz4_decode.s"
.include "../asm_routines/keypress_minimal.s"
.include "interrupt_handler.s"
;=========
; strings
;=========
mocking_message: .asciiz "LOOKING FOR MOCKINGBOARD IN SLOT #4"
not_message: .byte "NOT "
found_message: .asciiz "FOUND"
;done_message: .asciiz "DONE PLAYING"
loading_message: .asciiz "LOADING"
.include "ascii_art.inc"

251
still_alive/zp.inc Normal file
View File

@ -0,0 +1,251 @@
.define EQU =
LZ4_SRC EQU $00
LZ4_DST EQU $02
LZ4_END EQU $04
COUNT EQU $06
DELTA EQU $08
;; Zero page monitor routines addresses
WNDLFT EQU $20
WNDWDTH EQU $21
WNDTOP EQU $22
WNDBTM EQU $23
CH EQU $24
CV EQU $25
GBASL EQU $26
GBASH EQU $27
BASL EQU $28
BASH EQU $29
H2 EQU $2C
V2 EQU $2D
MASK EQU $2E
COLOR EQU $30
;INVFLG EQU $32
; dos33 zero page = 26-2f, 35-38, 3e 3f 40-4d
; overlap applesoft 67-6a,6f,70,af,b0,ca-cd,d8
; DOS33: Confirmed kills $68
RWTSL EQU $60
RWTSH EQU $61
DOSBUFL EQU $62
DOSBUFH EQU $63
FILEML EQU $64
FILEMH EQU $65
;TURNING EQU $60
;SCREEN_X EQU $61 ; not used?
;SCREEN_Y EQU $62
;ANGLE EQU $63
;HORIZ_SCALE_I EQU $64
;HORIZ_SCALE_F EQU $65
;FACTOR_I EQU $66
;FACTOR_F EQU $67
;DX_I EQU $68
;DX_F EQU $69
;SPACEX_I EQU $6A
;SPACEX_F EQU $6B
;CX_I EQU $6C
;CX_F EQU $6D
;DY_I EQU $6E
;DY_F EQU $6F
REGISTER_DUMP EQU $70
A_FINE_TONE EQU $70
A_COARSE_TONE EQU $71
B_FINE_TONE EQU $72
B_COARSE_TONE EQU $73
C_FINE_TONE EQU $74
C_COARSE_TONE EQU $75
NOISE EQU $76
ENABLE EQU $77
A_VOLUME EQU $78
B_VOLUME EQU $79
C_VOLUME EQU $7A
ENVELOPE_FINE EQU $7B
ENVELOPE_COARSE EQU $7C
ENVELOPE_SHAPE EQU $7D
COPY_OFFSET EQU $7E
DECODER_STATE EQU $7F
;SPACEY_I EQU $70
;SPACEY_F EQU $71
;CY_I EQU $72
;CY_F EQU $73
;TEMP_I EQU $74
;TEMP_F EQU $75
;DISTANCE_I EQU $76
;DISTANCE_F EQU $77
;SPACEZ_I EQU $78
;SPACEZ_F EQU $79
;DRAW_SPLASH EQU $7A
;SPEED EQU $7B
;SPLASH_COUNT EQU $7C
;OVER_LAND EQU $7D
;NUM1L EQU $7E
;NUM1H EQU $7F
CHUNKSIZE EQU $80
LZ4_DONE EQU $81
DECODE_ERROR EQU $82
A_COLOR EQU $83
B_COLOR EQU $84
C_COLOR EQU $85
COPY_TIME EQU $86
DECOMPRESS_TIME EQU $87
TIME_TAKEN EQU $88
SCREEN_Y EQU $89
WHICH_FILE EQU $8A
;NUM2L EQU $80
;NUM2H EQU $81
;RESULT EQU $82 ; 83,84,85
;NEGATE EQU $86 ; UNUSED?
;LAST_SPACEX_I EQU $87
;LAST_SPACEY_I EQU $88
;LAST_MAP_COLOR EQU $89
;DRAW_SKY EQU $8A
COLOR_MASK EQU $8B
RASTERBARS_ON EQU $8C
;KEY_COUNT EQU $8C
;KEY_OFFSET EQU $8D
;DRAW_BLUE_SKY EQU $8E
RANDOM_POINTER EQU $8F
FRAME_COUNT EQU $90
MB_VALUE EQU $91
;MB_CHUNK EQU $92
MB_ADDRL EQU $91
MB_ADDRH EQU $92
DONE_PLAYING EQU $93
;MB_FRAME_DIFF EQU $94
MB_CHUNK_OFFSET EQU $94
;LZSS_RL EQU $95
;LZSS_RH EQU $96
;LZSS_COUNT EQU $97
;LZSS_MASK EQU $98
;LZSS_ENDL EQU $99
;LZSS_ENDH EQU $9A
;MB_FRAME_DIFF2 EQU $9F
; More zero-page addresses
; we try not to conflict with anything DOS, MONITOR or BASIC related
;COLOR1 EQU $E0
COLOR2 EQU $E1
;MATCH EQU $E2
XX EQU $E3
;YY EQU $E4
;SHIPY EQU $E4
;YADD EQU $E5
;LOOP EQU $E6
;MEMPTRL EQU $E7
;MEMPTRH EQU $E8
;NAMEL EQU $E9
;NAMEH EQU $EA
;NAMEX EQU $EB
;CHAR EQU $EC
DISP_PAGE EQU $ED
DRAW_PAGE EQU $EE
;FIRST EQU $F0
LASTKEY EQU $F1
;PADDLE_STATUS EQU $F2
XPOS EQU $F3
YPOS EQU $F4
TEMP EQU $FA
;RUN EQU $FA
;TEMP2 EQU $FB
TEMPY EQU $FB
INL EQU $FC
INH EQU $FD
OUTL EQU $FE
OUTH EQU $FF
KEYPRESS EQU $C000
KEYRESET EQU $C010
;; SOFT SWITCHES
CLR80COL EQU $C000 ; PAGE0/PAGE1 normal
SET80COL EQU $C001 ; PAGE0/PAGE1 switches PAGE0 in Aux instead
EIGHTYCOL EQU $C00D
SPEAKER EQU $C030
SET_GR EQU $C050
SET_TEXT EQU $C051
FULLGR EQU $C052
TEXTGR EQU $C053
PAGE0 EQU $C054
PAGE1 EQU $C055
LORES EQU $C056 ; Enable LORES graphics
HIRES EQU $C057 ; Enable HIRES graphics
AN3 EQU $C05E ; Annunciator 3
PADDLE_BUTTON0 EQU $C061
PADDL0 EQU $C064
PTRIG EQU $C070
;; BASIC ROUTINES
NORMAL EQU $F273
;; MONITOR ROUTINES
HLINE EQU $F819 ;; HLINE Y,$2C at A
VLINE EQU $F828 ;; VLINE A,$2D at Y
CLRSCR EQU $F832 ;; Clear low-res screen
CLRTOP EQU $F836 ;; clear only top of low-res screen
SETCOL EQU $F864 ;; COLOR=A
TEXT EQU $FB36
TABV EQU $FB5B ;; VTAB to A
BASCALC EQU $FBC1 ;;
VTAB EQU $FC22 ;; VTAB to CV
HOME EQU $FC58 ;; Clear the text screen
WAIT EQU $FCA8 ;; delay 1/2(26+27A+5A^2) us
SETINV EQU $FE80 ;; INVERSE
SETNORM EQU $FE84 ;; NORMAL
COUT EQU $FDED ;; output A to screen
COUT1 EQU $FDF0 ;; output A to screen
COLOR_BLACK EQU 0
COLOR_RED EQU 1
COLOR_DARKBLUE EQU 2
COLOR_PURPLE EQU 3
COLOR_DARKGREEN EQU 4
COLOR_GREY EQU 5
COLOR_MEDIUMBLUE EQU 6
COLOR_LIGHTBLUE EQU 7
COLOR_BROWN EQU 8
COLOR_ORANGE EQU 9
COLOR_GREY2 EQU 10
COLOR_PINK EQU 11
COLOR_LIGHTGREEN EQU 12
COLOR_YELLOW EQU 13
COLOR_AQUA EQU 14
COLOR_WHITE EQU 15
COLOR_BOTH_BLACK EQU $00
COLOR_BOTH_RED EQU $11
COLOR_BOTH_DARKBLUE EQU $22
COLOR_BOTH_DARKGREEN EQU $44
COLOR_BOTH_GREY EQU $55
COLOR_BOTH_MEDIUMBLUE EQU $66
COLOR_BOTH_LIGHTBLUE EQU $77
COLOR_BOTH_BROWN EQU $88
COLOR_BOTH_ORANGE EQU $99
COLOR_BOTH_PINK EQU $BB
COLOR_BOTH_LIGHTGREEN EQU $CC
COLOR_BOTH_YELLOW EQU $DD
COLOR_BOTH_AQUA EQU $EE
COLOR_BOTH_WHITE EQU $FF
AUX_BOTH_MEDIUMBLUE EQU $33 ; 0011 0011
AUX_BOTH_GREY EQU $AA ; 1010 1010