A.N.A.L.O.G. ISSUE 28 / MARCH 1985 / PAGE 73

TwoGun

16K Cassette or 24K Disk

by Conrad Tatge

All right, you potential Matt Dillons, here’s your chance to walk down the main street of town … into the legends.

TwoGun is a two-player machine language game. It demonstrates two assembly techniques essential on the Atari home computer: color changing and collision detection. VCOUNT ($D40B) is monitored for the majority of the time, to change the color of the players partway down the screen, much like a display list interrupt. Also, the complexity of collision detection becomes apparent, as most of the vertical blank is devoted to this.

Typing it in.

Before typing anything, look at the listings accompanying this article.

Listing 1 is the BASIC data and data checking routine. This listing is used to create both cassette and disk versions of TwoGun. The data statements are listed in hexadecimal (base 16), so the program will fit in 16K cassette systems.

Listing 2 is the assembly language source code for the game of TwoGun, created with the Atari Macro assembler. You don’t have to type this listing to play the game! It is included for those readers interested in assembly language. Follow the instructions below to make either a cassette or disk version of TwoGun.

Cassette instructions.

  1. Type Listing 1 into your computer using the BASIC cartridge and verify your typing with Unicheck (see page 24).
  2. Type RUN and press RETURN. The program will begin and ask:
    MAKE CASSETTE (0) OR DISK (1)? Type 0 and press RETURN. The program will begin checking the DATA statements, printing the line number of each as it goes. It will alert you if it finds any problems. Fix any incorrect (continued on page 74) lines and re-RUN the program, if necessary, until all errors are eliminated.
  3. When all of your DATA lines are correct, the computer will beep twice and prompt you to READY CASSETTE AND PRESS RETURN. Now, insert a blank cassette in your recorder, press RECORD and PLAY simultaneously and hit RETURN. The message WRITING FILE will appear, and the program will create a machine language boot tape version of TwoGun, printing each DATA line number as it goes. When you see the READY prompt, the game is recorded and ready to play. CSAVE the BASIC program onto a separate tape before continuing.
  4. To play the game, rewind the tape created by the BASIC program to the beginning. Turn your computer OFF and remove all cartridges. Press the PLAY button on your recorder and turn ON your computer, holding down the START key. If you have a 600 or 800XL computer, you must hold the START and OPTION keys when you turn on the power. The computer will “beep” once. Hit the RETURN key, and TwoGun will load and run automatically.

Disk instructions.

  1. Type Listing 1 into your computer, using the BASIC cartridge and verify your typing with Unicheck (see page 24).
  2. Type RUN and press RETURN. The program will ask:
    MAKE CASSETTE (0) OR DISK (1)? Type 1 and press RETURN. The program will begin checking the DATA lines, printing the line number of each statement as it goes. It will alert you if it finds any problems. Fix incorrect lines and re-RUN the program, if necessary, until all errors are eliminated.
  3. When all DATA lines are correct, you will be prompted to INSERT DISK WITH DOS, PRESS RETURN. Put a disk containing DOS 2.0S into drive #1 and press RETURN. The message WRITING FILE will appear, and the program will create an AUTORUN.SYS file on the disk, displaying each DATA line number as it goes. When the READY prompt appears, the game is ready to play. Be sure the BASIC program is SAVEd before continuing.
  4. To play the game, insert the disk containing the AUTORUN.SYS file into drive #1. Turn your computer OFF, remove all cartridges and turn the computer back ON. TwoGun will load and run automatically.

How to play.

In TwoGun, shooting your opponent scores a point…and causes him to fall down dead. Bullets can be obtained by touching the flashing gun that appears at random. This also causes a cactus (in your color) to appear in the gun’s position.

Bullets are indicated at the top of the screen next to the score. Your cacti slow down your opponent, as well as stop his bullets. Rocks, on the other hand, ricochet bullets at random. They appear when you’ve shot your opponent’s cactus.

Watch for the players to change color. Flashing grey means the player cannot move; flashing green means he is low on ammunition.

Little gravestones, acting like rocks, will appear after every death — to the tune of Taps. Home on the Range runs throughout the game. Shoot ’em up!

My first game creation, TwoGun was built with APX’s editor. The source code is in macro assembly form.

Practice your draw. TwoGun should keep you in top gunfighting shape just in case the villains ride into town.

Listing 1.

10 REM *** TWOGUN ***
20 TRAP 20:? "MAKE CASSETTE (0), OR DISK (1)";:INPUT DSK:IF DSK>1 THEN 20
30 TRAP 40000:DATA 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15
40 DIM DAT$(91),HEX(22):FOR X=0 TO 22:READ N:HEX(X)=N:NEXT X:LINE=990:RESTORE 1000:TRAP 120:? "CHECKING DATA"
50 LINE=LINE+10:? "LINE:";LINE:READ DAT$:IF LEN(DAT$)<>90 THEN 220
60 DATLIN=PEEK(183)+PEEK(184)*256:IF DATLIN<>LINE THEN ? "LINE ";LINE;" MISSING!":END 
70 FOR X=1 TO 89 STEP 2:D1=ASC(DAT$(X,X))-48:D2=ASC(DAT$(X+1,X+1))-48:BYTE=HEX(D1)*16+HEX(D2)
80 IF PASS=2 THEN PUT #1,BYTE:NEXT X:READ CHKSUM:GOTO 50
90 TOTAL=TOTAL+BYTE:IF TOTAL>999 THEN TOTAL=TOTAL-1000
100 NEXT X:READ CHKSUM:IF TOTAL=CHKSUM THEN 50
110 GOTO 220
120 IF PEEK(195)<>6 THEN 220
130 IF PASS=0 THEN 170
140 IF  NOT DSK THEN 160
150 PUT #1,224:PUT #1,2:PUT #1,225:PUT #1,2:PUT #1,0:PUT #1,32:CLOSE #1:END 
160 FOR X=1 TO 97:PUT #1,0:NEXT X:CLOSE #1:END 
170 IF  NOT DSK THEN 200
180 ? "INSERT DISK WITH DOS, PRESS RETURN";:DIM IN$(1):INPUT IN$:OPEN #1,8,0,"D:AUTORUN.SYS"
190 PUT #1,255:PUT #1,255:PUT #1,0:PUT #1,32:PUT #1,246:PUT #1,40:GOTO 210
200 ? "READY CASSETTE AND PRESS RETURN";:OPEN #1,8,128,"C:":RESTORE 230:FOR X=1 TO 40:READ N:PUT #1,N:NEXT X
210 ? :? "WRITING FILE":PASS=2:LINE=990:RESTORE 1000:TRAP 120:GOTO 50
220 ? "BAD DATA: LINE ";LINE:END 
230 DATA 0,19,216,31,255,31,169,0,141,47,2,169,60,141,2,211,169,0,141,231,2,133,14,169,56,141,232,2
240 DATA 133,15,169,0,133,10,169,32,133,11,24,96
1000 DATA 2065E420E92220DE22A9D38D3002A9288D3102A92E8D2F02A9388D07D4A9038D1DD0A9008D0CD0A9188D6F02A9,606
1010 DATA 008D08D2A9068DC602A9AA8DC702A200BD00E09D0030BD00E19D0031E8D0F1A9308DF402A248BDCB279D0830CA,927
1020 DATA 10F7A900A27F9580CA10FBA2079D00D0CA10FAA9008583A223A000A906205CE4A212BD8C26BC9F26990038CA10,72
1030 DATA F4A20FA058BD832899003A8899003A88CA10F2A207A058BDD32799803A99813A99823A99833ABDDB2799003B99,285
1040 DATA 013B99023B99033B88888888CA10DBA9038D08D08D09D08D0AD0A9368DC002A9C28DC102A9068DC202A9788D00,200
1050 DATA D0A9A88D01D0A9488D02D0A94A8D2327A9018D6D27A9018589A220ADC40248ADC5028DC402688DC502A9108585,287
1060 DATA A585D0FCCAD0E720E922A9078581A9008583A2079D00D2CA10FAAD0AD20901858EA9008D08D08D09D085908594,980
1070 DATA 8D1527858B858A85918592A9028D00D2A9AA8D03D2A9FF858685878588A213BD78269DDC38CA10F7A681A51409,639
1080 DATA 079DC002E002B00729F0090A9DC402AD1FD02901D0E720E92220DE22AD1FD02901F0F9A9F28DC802A9BA8DC702,935
1090 DATA A201A91A9DC002BDC72709049DC402BDC92795AA95AEA93095AC95B0A90095A4959A95A295BE95A695A8A90395,761
1100 DATA 9CCA10D18D1ED0A9018583A9008584858AA580F0FCA584F0034C1C21A9008580A201B5AC18691E9596BDC72709,164
1110 DATA 069598A590F012B5A4F004A9049598B59CC902B004A9CA9598CA10D9A201AD0BD48D0AD4D596D00748B5989D12,8
1120 DATA D068CA10F2C97090E6A201BD04D03DC02648D5A0F0129010B59AD00CB5A2D008A92D95A4A91085886895A0BD04,886
1130 DATA D02908F022A9108588A482BDB8269914388D1ED0AD0AD22903090118759C959CAD0AD20940858EA58ED00EAD0A,686
1140 DATA D2D02EA482A900991438F0E7C68ED02120B022F011293FC902F00BC982F0F1A900991438F0EA8482A9C1991438,488
1150 DATA A9108588CA30034C27224CD321AD0AD2C9C8B0F9A8B91438600A0A858D0A0A18658D601875B84A4A4A20BC2285,18
1160 DATA 8DB5B61869014A4A4A18658DA860A2F0A9009DFF37CAD0FA60A27FA9009D80399D003A9D803A9D003B9D803BCA,318
1170 DATA 10EE60A9018580C685A589F03CCE6D27AD6D27D01AEE2327AD2327C94A9005A9018D2327AABD6D278D6D27A90A,284
1180 DATA 858CAE2327BD23278D06D2A5852901D00BC68CA58C300509A08D07D2A583D0034C7526C6911033A91F8591A592,144
1190 DATA 49108592A59049018590AD0AD20906CDC702F0F68DC702A5861012A5A425A5D00CA690BDE6268D00D2A908858B,465
1200 DATA A58BF00FC68BA58610F6A58B09808D01D2300BA5863007C686290F8D01D2A5873010C687A687BDF4268D03D2BD,880
1210 DATA E8268D02D2A5883010C688A6888A09408D05D2BDFD268D04D2AC1527D00AA58A1022A9018589D02BA9008589CE,45
1220 DATA 1C271013B91C278D1C27B915278D06D2A910858ACE1527A5852901D009C68AA58A09A08D07D2A201B59AF012A9,579
1230 DATA 019D08D0D69AD009A94095A2A9009D08D0B5A2F002D6A2B5A4F008D6A4D004A92095A2BCBC26A905858FB59C95,630
1240 DATA 9EB59EC904B00C186984990038A900959EF00CA988990038B59E38E904959EC8C68FD0DDBD0CD03DC026F00BB5,273
1250 DATA AE95AAB5B095AC4C7724B5AA95AEB5AC95B0BC7802B9C62695B21875AAC998B00C858DB5A815A4D004A58D95AA,582
1260 DATA B9D62695B41875ACC940B00C858DB5A815A4D004A58D95ACB5A8F042BD8402F03DB5B215B4D006854D95A8F031,630
1270 DATA B59CF0F6B59A15A4D027D69CA90195A6A90095A8A9188586B5AA18690395B6B5AC95B8B5B20A0A95BAB5B40A95,755
1280 DATA BC4CFD24BD8402D008B5A6D004A90195A8BD08D03DC026F06BA90095A6A90F20C622A989990038BCBE26B99A00,138
1290 DATA F006A9A095A4D04FA9008D1C27A9068D1527A9B0999A00A9A899A400F8B5BE186901D895BE48BCBA26290F1DB6,427
1300 DATA 26990038684A4A4A4A1DB62699FF37290FC90190158681BCBE26A90099C002A9008583A90185844C6726B5AA18,864
1310 DATA 69309D00D08A48BDB2268595BDB4268594A9B08593B5A4D01BA5928593B5A8F013BD7802C90FF00CB59CF008BC,923
1320 DATA 7802B9B7278593B5AC186928A8B59AF004A9A08593A59318690FAABD1328919488CAE49310F568AAB5A6D017B5,784
1330 DATA B818691FA8B980393DC426998039A9009D04D04C6126BD00D03DC026F011A90720C622A983991438A91085884C,492
1340 DATA 5B26BD00D02904F01DA90A8587AD0AD2290FA8B9C62619D626F0F2B9C6260A95BAB9D62695BCB5B61875BAC99E,165
1350 DATA B03295B61869309D04D0B5B818691FA8B980393DC426998039B5B81875BCC950B01295B818691FA8B980391DC2,387
1360 DATA 269980394C6126A90095A695A8CA30034C06248D1ED0AD1FD02901D004A90185844CD1E7B0B2A5B3B300F3F4E1,731
1370 DATA F2F400B4AF00A2A5A7A9AE34772F67356E6279636F6E7261647461746765293D5165798D3F4042434445464749,433
1380 DATA 4A4B4C4D3A3A0080105002420113020D01000201030CFCF3000000000001010100FFFFFF000000000000000000,460
1390 DATA 01FF000001FF000001FF000A102818100C0A09080A0F161040ACADAEAFADAAA6A2A00A0B0A090B0A0807090C0D,135
1400 DATA 0A0605080A0F100F0A06070A0A0051607960797900400810400810006C6C5148405155603C3C3C3C3C35515151,366
1410 DATA 5551486C6C5148405155603C3C3C3C3C40485155514851353C40484048515151515551486C6C5148405155603C,837
1420 DATA 3C3C3C3C4048515551485100101010102008081808102008081808101010104010101010200808180810200808,189
1430 DATA 180810180810403018081030101808101010104010101010200808180810200808180810101010800000000000,101
1440 DATA 2030400050607000809000703010880041CF7FF0F8E000181B1BDBDFD8F8180000307C72FEFF1F000000FF00FF,572
1450 DATA 0000008080FF80FF800000A0A0FFA0FFA00000A8A8FFA8FFA80000AAAAFFAAFFAA0000183C18183C7E7E00287C,724
1460 DATA 547C387CBABABA792828680C0000143E2A3E1C3E5D5D5D9E141416300004147C68743878BCBAB9782828282C60,293
1470 DATA 04147C69763C78B8B8B8782828282C6004147C6874387FB8B8B8782828282C6020283E162E1C1E3D5D9D1E1414,900
1480 DATA 14340620283E966E3C1E1D1D1D1E141414340620283E162E1CFE1D1D1D1E141414340604147C6874387EBABABA,524
1490 DATA 7A2828282C6020287E566E5C7E1D1D1D1E141414340600000000000000000000103BBBFF000000143E2A3E1C3E,546
1500 DATA 5D5D5D5D1414143600707070470038070707070707070707070741D32800000000000000000000000000000000,888

Assembly listing.

        TITLE 'TWOGUN - A Shootout'
        SUBTTL 'By Conrad Tatge 84'

CONSOL  EQU $D01F ;Console switch
RANDOM  EQU $D20A ;random byte
HPOSP0  EQU $D000 ;horizontal
M0PF    EQU $D000 ;collisions
M0PL    EQU $D008
P0PF    EQU $D004

        ORG $80 ;Page zero

VBIDO   DS 1 ;vertical blank shake
WINNER  DS 1 ;starts glow
LOOT    DS 1 ;where loot is
ENABLE  DS 1 ;VBI allowance
DOCPU   DS 1 ;game over flag
TIMER   DS 1 ;inc'ed every VBI
SND1    DS 1 ;firing sound
SND2    DS 1 ;ricochet
SND3    DS 1 ;fwooop
DOHOME  DS 1 ;flag for little music
VOLUME  DS 1 ;taps note volume
VOL2    DS 1 ;footstep volume
SUSTAI  DS 1 ;tune volume
TEMP    DS 1 ;work
NOLOOT  DS 1 ;countdown
COUNT   DS 1 ;counter
ONOFF   DS 1 ;foot switch
STEPTM  DS 1 ;time for next step
STEP    DS 1 ;step pointer
PICTUR  DS 1 ;frame
PIC     DS 2 ;Page zero PM point
CHANGE  DS 2 ;where to change color
NEWCOL  DS 2 ;what color to change
DEAD    DS 2 ;dead flag
AMMOS   DS 2 ;bullets
AMMOS2  DS 2 ;for displaying
PLPF2   DS 2
NOCOL   DS 2 ;after a collision
NOMOVE  DS 2 ;after a shot
MISSLF  DS 2 ;1 = shooting
PRESSF  DS 2 ;1 = aiming
HORIZ   DS 2 ;cowboy position
VERT    DS 2
HORIZ2  DS 2 ;previously
VERT2   DS 2
DIRX    DS 2 ;aim direction
DIRY    DS 2
SHORIZ  DS 2 ;shot position
SHVERT  DS 2
SHDIRX  DS 2 ;shot direction
SHDIRY  DS 2
SCORE   DS 2 ;BCD player score

        ASSERT * < $100 ;page zero!

PMHORZ  =  $30 ;For screen
PMVERT  =  $28 ;offsets
PMTITL  =  PMVERT+$30 ;for title page
AMMO    =  1 ;character codes
CACTUS  =  2
ROCK    =  3
CHAMMO  =  4 ;bullets character
GRAVE   =  9 ;gravestone
HOMES   =  74 ;length of song
CHRSET  EQU $3000 ;memory space
PMAREA  EQU $3800
DISP    EQU PMAREA ;screen memory
MIS     EQU PMAREA+$180
PL0     EQU PMAREA+$200
PL1     EQU PMAREA+$280
PL2     EQU PMAREA+$300
PL3     EQU PMAREA+$380
PLAREA  EQU DISP+20 ;play area

        ORG $2000

INIT    JSR $E465 ;init sound
        JSR PMCLR ;clear buffer
        JSR CLDISP ;clear screen
        LDA #LOW DLIST
        STA $230
        LDA #HIGH DLIST
        STA $231
        LDA #$2E
        STA $22F ;P/M
        LDA #HIGH PMAREA
        STA $D407
        LDA #3
        STA $D01D ;GRACTL
        LDA #0
        STA $D00C ;SIZEM
        LDA #$18
        STA $26F ;PRIOR
        LDA #0
        STA $D208 ;init
        LDA #$06 ;light grey
        STA $2C6 ;rocks
        LDA #$AA
        STA $2C7 ;bullets

        LDX #0
MOVEIT  LDA $E000,X ;move ROM set 
        STA CHRSET,X
        LDA $E100,X
        STA CHRSET+$100,X
        INX
        BNE MOVEIT
        LDA #HIGH CHRSET
        STA 756 ;point to new one
        LDX #$48 ;move 9 characters
NEWCHR  LDA NEWSET,X ;and copy new
        STA CHRSET+8,X
        DEX 
        BPL NEWCHR
        LDA #0
        LDX #$7F
CLPZER  STA $80,X ;zero variables
        DEX
        BPL CLPZER
        LDX #7
ZHORIZ  STA HPOSP0,X ;horizontals
        DEX
        BPL ZHORIZ

        LDA #0
        STA ENABLE ;Not yet
        LDX #HIGH VBLANK ;Set up
        LDY #LOW VBLANK ;NMI
        LDA #6
        JSR $E45C

        LDX #18 ;19 characters
PRINT   LDA CHRS,X
        LDY CHRPOS,X
        STA DISP,Y ;put to screen
        DEX
        BPL PRINT

        LDX #$F
        LDY #PMTITL
DOMAN   LDA THEMAN,X
        STA PL0,Y
        DEY
        STA PL0,Y
        DEY
        DEX
        BPL DOMAN
        LDX #$7
        LDY #PMTITL
DOCAC   LDA NEWSET+8,X ;display dudes
        STA PL1,Y
        STA PL1+1,Y
        STA PL1+2,Y
        STA PL1+3,Y
        LDA NEWSET+$10,X
        STA PL2,Y
        STA PL2+1,Y
        STA PL2+2,Y
        STA PL2+3,Y
        DEY
        DEY
        DEY
        DEY
        DEX
        BPL DOCAC

        LDA #3
        STA $D008 ;x4 width
        STA $D009
        STA $D00A
        LDA #$36 ;red cowboy
        STA $2C0
        LDA #$C2 ;green cactus
        STA $2C1
        LDA #$06 ;grey rocks
        STA $2C2
        LDA #$78 ;horizontals
        STA $D000
        LDA #$A8
        STA $D001
        LDA #$48
        STA $D002
        LDA #HOMES ;set it up...
        STA HOMEON
        LDA #1 ;and
        STA DURAT2
        LDA #1 ;start the tune...
        STA DOHOME

        LDX #32
AGAIN   LDA $2C4 ;switch $2C4 & $2C5
        PHA
        LDA $2C5
        STA $2C4
        PLA
        STA $2C5
        LDA #16 ;quarter of a second
        STA TIMER
TWAITA  LDA TIMER
        BNE TWAITA
        DEX
        BNE AGAIN
        JSR PMCLR ;clear PM title
        LDA #7 ;glow title
        STA WINNER
START   LDA #0
        STA ENABLE
        LDX #7
NOSNDS  STA $D200,X
        DEX
        BPL NOSNDS
        LDA RANDOM
        ORA #1 ;at least one
        STA NOLOOT ;set up timer
        LDA #0
        STA $D008
        STA $D009
        sta ONOFF
        STA PIC
        STA TAPS
        STA VOL2
        STA VOLUME
        STA STEPTM
        STA STEP
        LDA #2 ;Sound freq'
        STA $D200 ;AUDF1
        LDA #$AA
        STA $D203 ;sound ctrl 2
        LDA #$FF
        STA SND1
        STA SND2
        STA SND3

        LDX #19
PRESS   LDA PRESSM,X ;write message
        STA DISP+220,X
        DEX
        BPL PRESS

        LDX WINNER
DOWN    LDA $14 ;Glow
        ORA #7
        STA $2C0,X
        CPX #2
        BCS DOGAME
        AND #$F0
        ORA #$A
        STA $2C4,X
DOGAME  LDA CONSOL
        AND #1 ;START?
        BNE DOWN
        JSR PMCLR
        JSR CLDISP

UP      LDA CONSOL
        AND #1 ;Let go yet?
        BEQ UP

        LDA #$F2 ;brown
        STA $2C8
        LDA #$BA ;color of loot
        STA $2C7
        LDX #1 ;Set up game
SETUP   LDA #$1A ;fleshy
        STA $2C0,X ;COLPM0
        LDA TCOLOR,X
        ORA #4
        STA $2C4,X ;COLPF0
        LDA THORIZ,X
        STA HORIZ,X
        STA HORIZ2,x ;old
        LDA #$30
        STA VERT,X
        STA VERT2,X ;old
        LDA #0
        STA NOMOVE,X
        STA DEAD,X
        STA NOCOL,X
        STA SCORE,X
        STA MISSLF,X
        STA PRESSF,X ;etc...
        LDA #3 ;give him some!
        STA AMMOS,X
        DEX
        BPL SETUP
        STA $D01E ;HITCLR
        LDA #1 ;Now it can
        STA ENABLE
        LDA #0
        STA DOCPU
        STA VOLUME ;quiet!

* CPU moves the random gun, checks
* for it's collision, and does color

CPU     PROC
        LDA VBIDO ;wait for VBI
        BEQ CPU
        LDA DOCPU ;end game?
        BEQ :CPU.2
        JMP START ;do it again!
:CPU.2  LDA #0
        STA VBIDO
        LDX #1
setvp   LDA VERT,X
        CLC
        ADC #30 ;where to change
        STA CHANGE,X
        LDA TCOLOR,X
        ORA #6
        STA NEWCOL,X
        LDA ONOFF ;alternate
        BEQ SETVP3 ;natural color
        LDA NOMOVE,X
        BEQ SETVP2
        LDA #4
        STA NEWCOL,X ;darken him!
SETVP2  LDA AMMOS,X
        CMP #2
        BCS SETVP3
        LDA #$CA ;embarassment
        STA NEWCOL,X
SETVP3  DEX
        BPL SETVP
KERNEL  LDX #1
        LDA $D40B
        STA $D40A ;WSYNC
CKVP    CMP CHANGE,X ;time to change?
        BNE nochan
        PHA
        LDA NEWCOL,X ;get new color
        STA $D012,X
        PLA
nochan  DEX
        BPL CKVP
        CMP #$70
        BCC KERNEL

        LDX #1
:CPU1   LDA P0PF,X ;have we run into
        AND MISHIT,X ;a cactus?
        PHA ;hold on to
        CMP PLPF2,X
        BEQ :CPU1.2
        BCC :CPU1.2
        LDA DEAD,X ;O.K. if dead...
        BNE :CPU1.2
        LDA NOCOL,X ;or already hit
        BNE :CPU1.2
        LDA #45 ;.75 seconds
        STA NOMOVE,X ;stop there
        LDA #$10 ;start boing
        STA SND3
:CPU1.2 PLA
        STA PLPF2,X ;remember it
        LDA P0PF,X
        AND #8 ;got the loot?
        BEQ :CPU3
        LDA #$10
        STA SND3 ;boing
        LDY LOOT
        LDA GOTIT,X ;make a cactus
        STA PLAREA,Y
        STA $D01E ;HITCLR
        LDA RANDOM
        AND #3
        ORA #1
        CLC     
        ADC AMMOS,X
        STA AMMOS,X
loottm  LDA RANDOM ;wait a little
        ORA #$40 ;not zero
        STA NOLOOT
:CPU3   LDA NOLOOT ;waiting?
        BNE lootdn
        LDA RANDOM ;chance it
        BNE :CPU3.1
        LDY LOOT ;erase old one
        LDA #0
        STA DISP+20,y
        BEQ LOOTTM    
LOOTDN  DEC NOLOOT
        BNE :CPU3.1
:CPU2   JSR RANDY ;hide loot
        BEQ DOLOOT
        AND #$3F ;remove color
        CMP #CACTUS
        BEQ DOLOOT
        CMP #LOOT ;the loot?
        BEQ :CPU2
        LDA #0 ;erase it
        STA PLAREA,Y
        BEQ :CPU2 ;now try again
DOLOOT  STY LOOT ;use this value
        LDA #AMMO OR $C0 ;PF3
        STA PLAREA,Y
        LDA #$10
        STA SND3 ;boing
:CPU3.1 DEX
        BMI RECPU
        JMP :CPU1
RECPU   JMP CPU

        SUBTTL 'Subroutines'

RANDY   LDA RANDOM ;find a random
        CMP #200 ;byte on screen
        BCS RANDY
        TAY ;and get its contents
        LDA PLAREA,Y
        RTS
                 
* Multiply by 20 for screen plotting

MULT20  ASL A ;*2
        ASL A ;*4
        STA TEMP
        ASL A ;*8
        ASL A ;*16
        CLC
        ADC TEMP ;*20
        RTS

* Finds screen location from a missle

PMDISP  CLC ;offset is on A
        ADC SHVERT,X ;get horizontal
        LSR A
        LSR A
        LSR A ;/8
        JSR MULT20 ;times 20
        STA TEMP ;hold
        LDA SHORIZ,X
        CLC
        ADC #1
        LSR A
        LSR A
        LSR A ;/8
        CLC
        ADC TEMP ;add on to
        TAY ;and put in Y
        RTS

CLDISP  LDX #240 ;Clear screen
        LDA #0
CLEAR   STA DISP-1,X
        DEX
        BNE CLEAR
        RTS

PMCLR   LDX #$7F ;clear out P/M
        LDA #0
ZPLYR   STA MIS,X
        STA PL0,X
        STA PL1,X
        STA PL2,X
        STA PL3,X
        DEX
        BPL ZPLYR
        RTS

        SUBTTL 'The Vertical Blank'

* Vertical BLANK does everything else

VBLANK  PROC
        LDA #1 ;VBI call flag
        STA VBIDO
        DEC TIMER
        
        LDA DOHOME ;Home on the range
        BEQ CKENAB
        DEC DURAT2 ;count it down
        LDA DURAT2
        BNE DONOTE
        INC HOMEON ;next note
        LDA HOMEON
        CMP #HOMES ;done yet?
        BCC NEWDUR
        LDA #1 ;yes, start again
        STA HOMEON
NEWDUR  TAX ;note getter
        LDA DURAT2,X
        STA DURAT2        
        LDA #$A ;start volume
        STA SUSTAI
DONOTE  LDX HOMEON
        LDA HOMEON,X ;play the note
        STA $D206
        LDA TIMER ;decrease volume?
        AND #1
        BNE CKENAB
        DEC SUSTAI ;a little softer
        LDA SUSTAI
        BMI CKENAB ;not too much!
        ORA #$A0 ;adjust sound
        STA $D207
CKENAB  LDA ENABLE ;should we?
        BNE :L1
        JMP LOOP6
:L1     DEC STEPTM
        BPL DOSNDS
        LDA #$1F ;wait for next
        STA STEPTM
        LDA STEP ;take a step!
        EOR #$10
        STA STEP
        LDA ONOFF
        EOR #1
        STA ONOFF
NEWAMO  LDA RANDOM
        ORA #6
        CMP $2C7
        BEQ NEWAMO
        STA $2C7 ;new ammo color
        LDA SND1 ;not during a shot!
        BPL DOSNDS
        LDA NOMOVE ;if not moving...
        AND NOMOVE+1
        BNE DOSNDS
        LDX ONOFF
        LDA FEET,X ;make footsteps
        STA $D200
        LDA #8
        STA VOL2
DOSNDS  LDA VOL2
        BEQ DOSND1
        DEC VOL2
        LDA SND1
        BPL DOSNDS
        LDA VOL2
        ORA #$80 ;decrease volume
        STA $D201
        BMI CKSND2
DOSND1  LDA SND1 ;gunshot
        BMI CKSND2
        DEC SND1
        AND #$F
        STA $D201
CKSND2  LDA SND2
        BMI CKSND3
        DEC SND2
        LDX SND2
        LDA CONT2,X
        STA $D203
        LDA FREQ2,X
        STA $D202
CKSND3  LDA SND3 ;boing
        BMI CKTAPS
        DEC SND3
        LDX SND3
        TXA ;use pointer as volume
        ORA #$40
        STA $D205 ;AUDC3
        LDA FREQ3,X
        STA $D204 ;AUDF3
CKTAPS  LDY TAPS
        BNE DOTAPS
        LDA VOLUME ;of last note?
        BPL TAPS2
        LDA #1 ;we're done!
        STA DOHOME
        BNE LOOP
DOTAPS  LDA #0 ;reset flag
        STA DOHOME
        DEC DURAT ;note length
        BPL TAPS2
        LDA DURAT,Y
        STA DURAT
        LDA TAPS,Y ;new note
        STA $D206 ;AUDF4
        LDA #$10 ;new volume
        STA VOLUME
        DEC TAPS ;next note
TAPS2   LDA TIMER
        AND #1
        BNE LOOP
        DEC VOLUME
        LDA VOLUME
        ORA #$A0
        STA $D207
LOOP    LDX #1
LOOP1   LDA DEAD,X ;6 feet under?
        BEQ ALIVE1
        LDA #1 ;elongate him
        STA $D008,X
        DEC DEAD,X ;and decrement
        BNE ALIVE1
        LDA #$40
        STA NOCOL,X
        LDA #0 ;back to normal
        STA $D008,X
ALIVE1  LDA NOCOL,X
        BEQ DECMOV
        DEC NOCOL,X
DECMOV  LDA NOMOVE,X ;movement?
        BEQ SHOAMM
        DEC NOMOVE,X
        BNE SHOAMM
        LDA #$20
        STA NOCOL,X
SHOAMM  LDY WHERE2,X ;get posit'
        LDA #5
        STA COUNT
        LDA AMMOS,X ;replicate
        STA AMMOS2,X
SHOAM1  LDA AMMOS2,X ;ammo left
        CMP #4
        BCS SHOAM2 ;full four?
        CLC ;partial
        ADC #CHAMMO OR $80
        STA DISP,Y
        LDA #0 ;no more
        STA AMMOS2,X
        BEQ SHOAM3
SHOAM2  LDA #CHAMMO+4 OR $80
        STA DISP,Y
        LDA AMMOS2,X
        SEC
        SBC #4
        STA AMMOS2,X
SHOAM3  INY ;go right one
        DEC COUNT
        BNE SHOAM1
        LDA $D00C,X
        AND MISHIT,X ;other guy?
        BEQ safety
        LDA HORIZ2,X ;move back!
        STA HORIZ,X
        LDA VERT2,X
        STA VERT,X
        JMP GETSTK
safety  LDA HORIZ,X ;safe place!
        STA HORIZ2,X
        LDA VERT,X
        STA VERT2,X
GETSTK  LDY $278,X ;Y is STICK
        LDA TDIRX,Y
        STA DIRX,X ;hold direction
        CLC
        ADC HORIZ,X ;new HORIZ
        CMP #$98 ;off of screen?
        BCS CKVERT
        STA TEMP ;no...could use
        LDA PRESSF,X ;unless aiming
        ORA NOMOVE,X
        BNE CKVERT
        LDA TEMP
        STA HORIZ,X ;update it
        
CKVERT  LDA TDIRY,Y ;same for VERT
        STA DIRY,X
        CLC
        ADC VERT,X
        CMP #$40
        BCS CKPRES
        STA TEMP
        LDA PRESSF,X
        ORA NOMOVE,X
        BNE CKPRES
        LDA TEMP
        STA VERT,X

* Joystick fire button code:
*   test for ammos then
*   if not strig then set PRESSF
*   if strig and PRESSF then fire

CKPRES  LDA PRESSF,X ;already?
        BEQ CKBUTT
        LDA $284,X ;letting go?
        BEQ CKBUTT
        LDA DIRX,X
        ORA DIRY,X
        BNE FIRE ;any direction?
NOFLIP  STA 77   ;stop attract
        STA PRESSF,X ;not pressing
        BEQ CKBUTT
FIRE    LDA AMMOS,X ;any bullets?
        BEQ NOFLIP
        LDA DEAD,X ;if dead
        ORA NOMOVE,X ;or immobile...
        BNE CKBUTT ;don't shoot!
        DEC AMMOS,X ;use a bullet
        LDA #1 ;he's shooting
        STA MISSLF,X
        LDA #0
        STA PRESSF,X
        LDA #$18 ;fire sound
        STA SND1
        LDA HORIZ,X ;make a bullet
        CLC
        ADC #3 ;center it
        STA SHORIZ,X
        LDA VERT,X
        STA SHVERT,X
        LDA DIRX,X
        ASL A ;4 times as fast
        ASL A
        STA SHDIRX,X
        LDA DIRY,X
        ASL A ;twice as fast
        STA SHDIRY,X
        JMP LOOP2
CKBUTT  LDA $284,X ;now button?
        BNE LOOP2
        LDA MISSLF,X ;or shoot?
        BNE LOOP2
        LDA #1
        STA PRESSF,X ;pressed...
LOOP2   LDA M0PL,X
        AND MISHIT,X ;player hit?
        BEQ MOVEM
        LDA #0 ;stop shooting
        STA MISSLF,X
        LDA #$F ;offset
        JSR PMDISP ;find where
        LDA #GRAVE OR $80
        STA DISP,Y ;put on screen
        LDY OPPON,X
        LDA DEAD,Y ;already dead?
        BEQ KILLEM
        LDA #$A0 ;slow shooter
        STA NOMOVE,x
        BNE MOVEM ;JMP
killem  LDA #0 ;play taps
        STA DURAT
        LDA #6
        STA TAPS
        LDA #$B0 ;kill him
        STA DEAD,Y
        LDA #$A8
        STA NOMOVE,Y
        SED
        LDA SCORE,X
        CLC
        ADC #1 ;Give him 1 point
        CLD
        STA SCORE,X
        PHA ;And display his score
        LDY WHERE,X
        AND #$F
        ORA COLSCO,X
        STA DISP,Y
        PLA
        LSR A
        LSR A
        LSR A
        LSR A
        ORA COLSCO,X
        STA DISP-1,Y
        AND #$F
        CMP #1 ;20 points wins
        BCC MOVEM
        STX WINNER
        LDY OPPON,X
        LDA #0 ;darken loser
        STA $2C0,Y
        LDA #0
        STA ENABLE
        LDA #1
        STA DOCPU
        JMP LOOP4 ;Remember who

MOVEM   LDA HORIZ,X
        CLC
        ADC #PMHORZ ;Small adjust
        STA HPOSP0,X ;horizontal
        TXA
        PHA
        LDA PLOFF1,X ;Set up PM
        STA PIC+1 ;pointers for
        LDA PLOFF2,X ;players
        STA PIC
        LDA #$B0 ;hold him still
        STA PICTUR
        LDA NOMOVE,X
        BNE :L2
        LDA STEP ;now animate
        STA PICTUR
        LDA PRESSF,X ;aiming?
        BEQ :L2
        LDA $278,X
        CMP #15 ;stick centered?
        BEQ :L2
        LDA AMMOS,X ;or out?
        BEQ :L2
        LDY $278,X
        LDA PICOFF,Y ;According
        STA PICTUR ;to STICK0
:L2     LDA VERT,X
        CLC
        ADC #PMVERT
        TAY ;No more Y!
        LDA DEAD,X
        BEQ ALIVE
        LDA #$A0 ;draw dead guy
        STA PICTUR
ALIVE   LDA PICTUR
        CLC 
        ADC #$F ;16 bytes
        TAX ;X is saved on stack
DRAW    LDA SHAPE,X ;draw him!
        STA (PIC),Y
        DEY
        DEX
        CPX PICTUR ;done yet?
        BPL DRAW
        PLA
        TAX ;restore player X
        LDA MISSLF,X ;Should we
        BNE MVHORZ ;kill missle?
        LDA SHVERT,X ;Y not stick
        CLC
        ADC #PMVERT-9
        TAY
        LDA MIS,Y
        AND BITSOF,X ;Out bits
        STA MIS,Y
        LDA #0
        STA $D004,X ;Zero HPOSM0
        JMP LOOP3
MVHORZ  LDA M0PF,X ;have we hit
        AND MISHIT,X ;a cactus?
        BEQ HORZ1 ;no collision
        LDA #7 ;offset
        JSR PMDISP ;figure out where
        LDA #ROCK OR $80
        STA DISP+20,Y ;make rock
        LDA #$10 ;make boing
        STA SND3
        JMP KILMSL ;kill missle
HORZ1:  LDA M0PF,X ;have we hit a
        AND #4 ;PF2 rock?
        BEQ HORZ3
        LDA #10 ;ricochet
        STA SND2
HORZ2:  LDA RANDOM ;new direc'
        AND #$F
        TAY
        LDA TDIRX,Y
        ORA TDIRY,Y
        BEQ HORZ2 ;some delta
        LDA TDIRX,Y
        ASL A ;a little slower
        STA SHDIRX,X
        LDA TDIRY,Y
        STA SHDIRY,X

HORZ3:  LDA SHORIZ,X ;update
        CLC
        ADC SHDIRX,X
        CMP #$9E ;off screen?
        BCS KILMSL
        STA SHORIZ,X
        CLC
        ADC #PMHORZ ;Compensate
        STA $D004,X

        LDA SHVERT,X ;Remove old
        CLC
        ADC #PMVERT-9
        TAY
        LDA MIS,Y
        AND BITSOF,X
        STA MIS,Y
        LDA SHVERT,X ;Now update
        CLC
        ADC SHDIRY,X
        CMP #$50 ;off screen?
        BCS KILMSL
        STA SHVERT,X
        CLC
        ADC #PMVERT-9 ;Compensate
        TAY
        LDA MIS,Y
        ORA BITSON,X ;Turn on bit
        STA MIS,Y
        JMP LOOP3
KILMSL  LDA #0 ;kill this missle
        STA MISSLF,X
        STA PRESSF,X
LOOP3   DEX ;Next player
        BMI LOOP4 ;end part of VBI
        JMP LOOP1
LOOP4   STA $D01E
        LDA CONSOL
        AND #1
        BNE LOOP6
        LDA #1
        STA DOCPU

LOOP6   JMP $E7D1 ;Exit VBI

        SUBTTL 'Data Tables'

* Various tables

PRESSM  DB $B0,$B2,$A5,$B3,$B3,0
        DB $F3,$F4,$E1,$F2,$F4,0
        DB $B4,$AF,0,$A2,$A5,$A7
        DB $A9,$AE ;press start...
CHRS    DB $34,$77,$2f,$67,$35,$6E
        DB 'byconradtatge'
CHRPOS  DB 41,61,81,101,121,141
        DB 63,64,66,67,68,69,70,71
        DB 73,74,75,76,77 ;position
PLOFF1  DB HIGH PL0 ;PM pointers
        DB HIGH PL1
PLOFF2  DB LOW PL0
        DB LOW PL1
COLSCO  DB $10,$50 ;masks
GOTIT   DB CACTUS OR $00 ;PF0
        DB CACTUS OR $40 ;PF1
WHERE   DB 1,19 ;score posit'
WHERE2  DB 2,13 ;ammo position
OPPON   DB 1,0 ;opponent
MISHIT  DB 2,1 ;collision checks
BITSON  DB 3,$C ;ORA turn ons
BITSOF  DB $FC,$F3 ;AND turn offs
TDIRX   DB 0,0,0,0,0,1,1,1 ;stick
        DB 0,$FF,$FF,$FF,0 ;deltas
        DB 0,0,0
TDIRY   DB 0,0,0,0,0,1,$FF
        DB 0,0,1,$FF,0,0
        DB 1,$FF,0
FEET    DB 10,16 ;footsteps
FREQ2   DB 40,24,16,12,10,9,8,10
        DB 15,22,16,64 ;ricochet
CONT2   DB $AC,$AD,$AE,$AF,$AD,$AA
        DB $A6,$A2,$A0
FREQ3   DB 10,11,10,9,11,10,8 ;boing
        DB 7,9,12,13,10,6,5,8,10
        DB 15,16,15,10,6,7,10,10
TAPS    DB 0
        DB $51,$60,$79 ;notes
        DB $60,$79,$79
DURAT   DB 0
        DB 64,8,16,64,8,16 ;durations
HOMEON  DB 0 ;Home, home on the...
        DB 108,108,81,72,64 ;Oh give
        DB 81,85,96,60,60,60
        DB 60,60,53,81,81,81,85,81,72
        DB 108,108,81,72,64 ;where
        DB 81,85,96,60,60,60
        DB 60,60,64,72,81,85,81,72,81
        DB 53,60,64,72,64 ;Home, home
        DB 72,81,81,81,81,85,81,72
        DB 108,108,81,72,64 ;where
        DB 81,85,96,60,60,60
        DB 60,60,64,72,81,85,81,72,81
DURAT2  DB 0
        DB 16,16,16,16,32
        DB 8,8,24,8,16,32
        DB 8,8,24,8,16,16,16,16,64
        DB 16,16,16,16,32
        DB 8,8,24,8,16,32
        DB 8,8,24,8,16,24,8,16,64
        DB 48,24,8,16,48
        DB 16,24,8,16,16,16,16,64
        DB 16,16,16,16,32
        DB 8,8,24,8,16,32
        DB 8,8,24,8,16,16,16,16,128
PICOFF  DB 0,0,0,0,0,$20,$30,$40
        DB 0,$50,$60,$70,0,$80
        DB $90,0
TCOLOR  DB $70,$30 ;player colors
THORIZ  DB $10,$88 ;and positions

* Alternate character set

NEWSET  DB 0,$41,$CF,$7F ;ammo dump
        DB $F0,$F8,$E0,0

        DB $18,$1B,$1B ;cactus
        DB $DB,$DF,$D8,$F8,$18

        DB 0,0,$30,$7C,$72
        DB $FE,$FF,$1F ;rock

        DB 0,0,0,$FF ;empty
        DB 0,$FF,0,0
        DB 0,$80,$80,$FF ;1
        DB $80,$FF,$80,0
        DB 0,$A0,$A0,$FF ;2
        DB $A0,$FF,$A0,0
        DB 0,$A8,$A8,$FF ;3
        DB $A8,$FF,$A8,0
        DB 0,$AA,$AA,$FF ;4
        DB $AA,$FF,$AA,0

        DB 0,$18,$3C,$18 ;a grave
        DB $18,$3C,$7E,$7E

* Cowboy shape table

SHAPE   DB $00,$28,$7C,$54 ;+1
        DB $7C,$38,$7C,$BA
        DB $BA,$BA,$79,$28
        DB $28,$68,$0C,$00

        DB $00,$14,$3E,$2A ;+2
        DB $3E,$1C,$3E,$5D
        DB $5D,$5D,$9E,$14
        DB $14,$16,$30,$00

        DB $04,$14,$7C,$68 ;
        DB $74,$38,$78,$BC
        DB $BA,$B9,$78,$28
        DB $28,$28,$2C,$60

        DB $04,$14,$7C,$69 ;
        DB $76,$3C,$78,$B8
        DB $B8,$B8,$78,$28
        DB $28,$28,$2C,$60

        DB $04,$14,$7C,$68 ;
        DB $74,$38,$7F,$B8
        DB $B8,$B8,$78,$28
        DB $28,$28,$2C,$60

        DB $20,$28,$3E,$16 ;
        DB $2E,$1C,$1E,$3D
        DB $5D,$9D,$1E,$14
        DB $14,$14,$34,$06

        DB $20,$28,$3E,$96 ;
        DB $6E,$3C,$1E,$1D
        DB $1D,$1D,$1E,$14
        DB $14,$14,$34,$06

THEMAN  DB $20,$28,$3E,$16 ;
        DB $2E,$1C,$FE,$1D
        DB $1D,$1D,$1E,$14
        DB $14,$14,$34,$06

        DB $04,$14,$7C,$68 ;
        DB $74,$38,$7E,$BA
        DB $BA,$BA,$7A,$28
        DB $28,$28,$2C,$60

        DB $20,$28,$7E,$56 ;
        DB $6E,$5C,$7E,$1D
        DB $1D,$1D,$1E,$14
        DB $14,$14,$34,$06

        DB 0,0,0,0,0,0,0,0,0,0 ;DEAD
        DB $10,$3B,$BB,$FF,0,0

        DB $00,$14,$3E,$2A ;NOMOVE
        DB $3E,$1C,$3E,$5D
        DB $5D,$5D,$5D,$14
        DB $14,$14,$36,$00

* The display list is 12 graphic 2's

DLIST   DB $70,$70,$70
        DB $47
        DW DISP
        DB 7,7,7,7,7,7,7,7,7,7,7
        DB $41
        DW DLIST

        ;and that's all she wrote!

        END INIT