====== Hyper Duel ======
What is Hyper Duel? Hyper Duel is a game for 2 players only. The idea of the game is very simple, blast your opponent and survive. :-). Here is the source code for the game. If you want the binaries for it, then simply download the whole package from [[http://www.redesign.sk/tnd64/games/Hyper_Duel.zip|here]]. It also includes the source code. :-)
{{base:hd1.png|}}
;--------------------------------------------------
;Hyper Duel V1.4 - 13/02/2008
;
;Written for the Commodore C64/128 by Richard Bayliss
;Copyright 2008 The New Dimension
;
;This game is a weird fun shoot 'em game for only
;two players, written in ACME cross assembler.
;The idea of the game is to fly through the game
;arena blasting hell out of your oppenent and
;score a certain amount of points to win the game
;but the opponents can also fight back.
;Based on Super Dogfight by Terminal Software,
;but set in a weird style.
;
;Simple, but fun. That's what we have to say for
;ourselves.
;Turn all source code + binary data into actual C64 code/routines
;(Best compressed with a packer and cruncher (or Exomizer if
;you prefer)
;Global constants
sync = $0340 ;Synchronize standard data
starcontrol = $0341 ;Delay of the starfield
xpause = $0342 ;Smooth-X for scrolling message in title screen
spincontrol = $0343 ;Spin control ;Useless now, it was for an older title screen
objpos = $0370 ;The virtual sprite position
collision = $03f0 ;Sprite to Sprite collision storage
p1dir = $02 ;Player 1 direction (So we know which direction the player faces)
p1bdir = $03 ;Player 1 bullet direction
p2dir = $04 ;(Same for the previous 2 constants, but for player 2)
p2bdir = $05
p1defaultx = $07 ;Default x position for player 1
p1defaulty = $08 ;Default y position for player 2
p2defaultx = $09 ;(As the previous two constants but for player 2)
p2defaulty = $0a
bouncetime = $0c ;Bounce counter for counting the bounce routine for the score sprites
p1turndelay = $0e ;Delay before player can turn
p2turndelay = $0f ;
p1bull_locked = $11 ;Constant to disable firebutton when bullet is active
p2bull_locked = $12 ;----------------------------------------------------
p1isdead = $13 ;You can guess what this is eh? This is where player 1 is dead.
p2isdead = $14 ;and also the same for player 2. Toasted :D
killpointer = $15 ;Delay routine for the player death animation
colsinepointer = $18 ;Colour sinus routine for the title screen (Something I never tried before)
winpoints = $06f6 ;Screen char in title - setting up the number of points to be won before ending game
gamespeed = $071b ;Screen char in title - setting up slow/fast speed for game play
winscore = $49 ;Storage counter for win
!to "hyper_duel.prg",cbm ;Target of Commodore C64 program!
*= $0801 ;We shall start this as BASIC run.
!byte $0c,$08,$0a,$00,$9e,$31,$34,$34,$33,$36,$00,$00,$00,$00
;^ Data table to form the SYS start address to $3800
;Import Richard's music done in Goat Tracker to $1000
* = $1000-2
!binary "music.dat"
;Import game sprites here
* = $2000
!binary "gamesprites.spr"
;Import game charset here
* = $3000
!binary "charset.chr"
;The starfield char data here. Hell yeah!
;That's what we want :o)
* = $3200
;Shift + * (Blank it)
!byte %00000000 ;Weird eh? Those are for the stars
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
;Shift + A
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00100000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %01000000
;Shift + B
!byte %00000000
!byte %00000000
!byte %00010000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000100
!byte %00000000
;Shift + C
!byte %00000000
!byte %01000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00000000
!byte %00001000
!byte %00000000
;Shift + D
!byte %00000010
!byte %00000000
!byte %00000000
!byte %00010000
!byte %00000000
!byte %00000000
!byte %00000000
Okay, enough of the above bunf. The code below is for the title screen. When assembled the source, and maybe crunched it. If you really want to that is, the result should look something like the screen shot of the actual game. Except when the title is active, you will see nice colour sinus effect and also active options, etc on your C64/emu.
{{base:h2.png|}}
Now for the code
;The game screen
* = $3800 ;Start area
title sei
lda #$37
sta $01 ;Kernal on
lda #$05
jsr $e544
lda #$00
sta $d01a
lda #$81
sta $dc0d
sta $dd0d
cli
lda #$1b
sta $d011
xx lda #0
sta starcontrol
sta spincontrol
sta colsinepointer
sta p1bull_locked
sta p2bull_locked
sta $33
sta $31
sta $38
lda #$02
sta yspeed
lda #$01
sta xspeed
;Clear entire screen
lda #message
sta read+1
stx read+2
ldx #$00
fillchar lda #$00
sta $3000,x
inx
cpx #$08
bne fillchar
;Prepare the bitmap colour set
ldx #$00
colourset lda $8800+0,x
sta $d800+0,x
lda $8800+40,x
sta $d800+40,x
lda $8800+80,x
sta $d800+80,x
lda $8800+120,x
sta $d800+120,x
lda $8800+160,x
sta $d800+160,x
lda $8800+200,x
sta $d800+200,x
lda $8800+240,x
sta $d800+240,x
lda $8800+280,x
sta $d800+280,x
lda $8800+320,x
sta $d800+320,x
lda $8800+360,x
sta $d800+360,x
lda #$00
sta $d800+400,x
inx
cpx #$28
bne colourset
ldx #$00
dark lda #$00
sta $d990,x
sta $da00,x
sta $dae8,x
inx
bne dark
ldx #$00
makescreen lda titlescreentext,x
sta $05e0,x
lda titlescreentext+40,x
sta $05e0+40,x
lda titlescreentext+80,x
sta $05e0+80,x
lda titlescreentext+120,x
sta $05e0+120,x
lda titlescreentext+160,x
sta $05e0+160,x
lda titlescreentext+200,x
sta $05e0+200,x
lda titlescreentext+240,x
sta $05e0+240,x
lda titlescreentext+280,x
sta $05e0+280,x
lda titlescreentext+320,x
sta $05e0+320,x
lda titlescreentext+360,x
sta $05e0+360,x
lda titlescreentext+400,x
sta $05e0+400,x
inx
cpx #$28
bne makescreen
sei
lda #$35
sta $01
lda #$00
sta $d020
sta $d021
sta $d015
lda #irq1
ldy #$00
sta $fffe
stx $ffff
lda #nmi
sta $fffa
stx $fffb
sta $fffc
stx $fffd
lda #$00
sta $d012
lda #$7f
sta $dc0d
lda #$1b
sta $d011
lda #$01
sta $d01a
rol $d019
lda #$00
jsr $1000
cli
titloop lda #$00
sta sync
cmp sync
beq *-3
jsr scrolltext
jsr coleffect
jsr makewinscore
lda $dc00
lsr
bcs tdown1
jsr addround
jmp titloop
tdown1 lsr
bcs tleft1
jsr subround
jmp titloop
tleft1 lsr
bcs tright1
jsr setslow
jmp titloop
tright1 lsr
bcs tfire1
jsr setfast
jmp titloop
tfire1 lsr
bcs tp1
jmp game
tp1 lda $dc01
lsr
bcs tdown2
jsr addround
jmp titloop
tdown2 lsr
bcs tleft2
jsr subround
jmp titloop
tleft2 lsr
bcs tright2
jsr setslow
jmp titloop
tright2 lsr
bcs tfire2
jsr setfast
jmp titloop
tfire2 lsr
bcs nojoyt
jmp game
nojoyt jmp titloop
;Add 1 to the no of rounds
addround inc $38
lda $38
cmp #$08
beq nodelay1
rts
nodelay1 lda #$00
sta $38
inc winpoints
lda winpoints
cmp #$3a
beq resetpoints
rts
resetpoints lda #$39
sta winpoints
rts
;Subtract 1 to the no of rounds
subround inc $38
lda $38
cmp #$08
beq nodelay2
rts
nodelay2 lda #$00
sta $38
dec winpoints
lda winpoints
cmp #$30
beq resetpoints2
rts
resetpoints2 lda #$31
sta winpoints
rts
;Set game mode as slow
setslow ldx #$00
slowtxt lda slow,x
sta gamespeed,x
inx
cpx #$04
bne slowtxt
lda #$02
sta yspeed
lda #$01
sta xspeed
rts
;Set game mode as fast
setfast ldx #$00
fasttxt lda fast,x
sta gamespeed,x
inx
cpx #$04
bne fasttxt
lda #$04
sta yspeed
lda #$02
sta xspeed
rts
;Make the winscore
makewinscore lda winpoints
cmp #$31
bne *+5
jmp setast1
cmp #$32
bne *+5
jmp setast2
cmp #$33
bne *+5
jmp setast3
cmp #$34
bne *+5
jmp setast4
cmp #$35
bne *+5
jmp setast5
cmp #$36
bne *+5
jmp setast6
cmp #$37
bne *+5
jmp setast7
cmp #$38
bne *+5
jmp setast8
cmp #$39
bne *+5
jmp setast9
rts
setast1 lda #$8a
sta winscore
rts
setast2 lda #$8b
sta winscore
rts
setast3 lda #$8c
sta winscore
rts
setast4 lda #$8d
sta winscore
rts
setast5 lda #$8e
sta winscore
rts
setast6 lda #$8f
sta winscore
rts
setast7 lda #$90
sta winscore
rts
setast8 lda #$91
sta winscore
rts
setast9 lda #$92
sta winscore
rts
;Irq interrupts for the title screen.
;Raster 1. The title scrolltext
irq1 pha
tya
pha
txa
pha
inc $d019
lda $dc0d
sta $dd0d
lda #$2e
sta $d012
nop
nop
nop
nop
nop
nop
nop
nop
nop
lda #$1b
sta $d011
lda xpause
sta $d016
lda #$03
sta $dd00
lda #$1c
sta $d018
lda #$01
sta sync
jsr $1003
lda #irq2
sta $fffe
stx $ffff
pla
tax
pla
tay
pla
rti
irq2 pha
tya
pha
txa
pha
inc $d019
lda #$92
sta $d012
lda #$3b
sta $d011
lda #$18
sta $d016
sta $d018
lda #$01
sta $dd00
lda #irq3
sta $fffe
stx $ffff
pla
tax
pla
tay
pla
rti
irq3 pha
tya
pha
txa
pha
inc $d019
lda #$f1
sta $d012
nop
nop
nop
nop
nop
nop
nop
nop
nop
lda #$1b
sta $d011
lda #$08
sta $d016
lda #$1c
sta $d018
lda #$03
sta $dd00
lda #irq1
sta $fffe
stx $ffff
pla
tax
pla
tay
pla
rti
;The actual scroll text code
scrolltext lda xpause
sec
sbc #2
and #7
sta xpause
bcs endscroll
ldx #0
wrapscroll lda $07c1,x
sta $07c0,x
inx
cpx #40
bne wrapscroll
read lda $07e7
cmp #0
bne endpoint
lda #$00
ldx #$64
sta read+1
stx read+2
jmp read
endpoint sta $07e7
inc read+1
bne endscroll
inc read+2
endscroll rts
;Set up the sprite type, colours and positions
titlesprites lda #$80
sta $07f8
sta $07f9
lda #$03
sta $d015
lda #0
sta $d01b
sta $d01d
sta $d01c
sta $d017
lda #$20
sta objpos+0
lda #$52
sta objpos+1
sta objpos+3
lda #$88
sta objpos+2
lda #$02
sta $d027
lda #$0e
sta $d028
rts
;The cool colour sinus effect ;Probably collect fast
coleffect jsr makesine
jsr pastecols
rts
makesine ldx colsinepointer
lda colsinus,x
pha
and #$07
;eor #$d7
;sta $33 ;Temp variable
pla
lsr
lsr
lsr
tay
ldx #$00
makecols lda colours,y
sta $dbc0,x
inx
iny
cpx #$28
bne makecols
inc colsinepointer
inc colsinepointer
rts
pastecols lda $31
sec
sbc #$03
and #$07
sta $31
bcs end
jsr uplift
end rts
uplift ldx #$00
lift lda #0
sta $dbc0-480,x
lda $dbc0-400,x
sta $dbc0-440,x
lda $dbc0-360,x
sta $dbc0-400,x
lda $dbc0-320,x
sta $dbc0-360,x
lda $dbc0-280,x
sta $dbc0-320,x
lda $dbc0-240,x
sta $dbc0-280,x
lda $dbc0-200,x
sta $dbc0-240,x
lda $dbc0-160,x
sta $dbc0-200,x
lda $dbc0-120,x
sta $dbc0-160,x
lda $dbc0-80,x
sta $dbc0-120,x
lda $dbc0-40,x
sta $dbc0-80,x
lda $dbc0-0,x
sta $dbc0-40,x
inx
cpx #$28
bne lift
rts
;---------------------------------------------------------------------------------
Now it is on to the game, which should turn out like the picture below.
{{base:h3.png|}}
game sei
lda #$81
sta $dc0d
sta $dd0d
lda #0
sta $d01a
lda #$37
sta $01
;I do have to admit, for star fields we usually
;use a black frame and black screen, but I
;thought it would be more cool to invert the
;colours for the game screen as black is always
;boring.
lda #$0b
sta $d020
lda #$00
sta $d021
lda #$1c ;Game char
sta $d018
lda #$ff
sta $d015 ;All sprites are on
lda #$35
sta $01
;Build the game background (The strange starfield
;as in the title screen)
ldx #$00
makefield lda gamesfield,x
sta $0400,x
lda gamesfield+$100,x
sta $0500,x
lda gamesfield+$200,x
sta $0600,x
lda gamesfield+$300,x
sta $06e8,x
lda #$04
sta $d800,x
sta $d900,x
sta $da00,x
sta $dae8,x
inx
bne makefield
;
lda #0
sta starcontrol
sta p1isdead
sta p2isdead
;Make a new interrupt ;lda #$35
;sta $01
lda #gameirq
sta $fffe
stx $ffff
lda #$7f
sta $dc0d
lda #$00
sta $d012
sta p1turndelay
sta p2turndelay
lda #$1b
sta $d011
lda #$01
sta $d01a
rol $d019
lda #$01
jsr $1000
cli
;Set default sprite types for the game.
;Player 1 - Face downwards for a start
lda #$84
sta $07f8
sta $07f9
;Set the default value of the direction the
;player is facing, and also the direction for
;which the bullet should fire if on screen.
lda #$04
sta p1dir
sta p1bdir
sta p2dir
sta p2bdir
lda #$20
sta objpos+0
lda #$52
sta objpos+1
sta objpos+3
lda #$8c
sta objpos+2
lda #2
sta $d027
lda #$0e
sta $d028
lda objpos+0
sta p1defaultx
lda objpos+1
sta p1defaulty
lda objpos+2
sta p2defaultx
lda objpos+3
sta p2defaulty
;Set up the sprites for the players bullets
;then zero the position and turn off bullet
;mode
lda #$88
sta $07fe
sta $07ff
lda #2
sta $d02d
lda #$0e
sta $d02e
lda #$00
sta objpos+$0c
sta objpos+$0d
lda #$00
sta objpos+$0e
sta objpos+$0f
;Set up and inititialize the scoreboard and
;energy bars.
lda #$ff
sta $d015
lda #$89
sta $07fa
sta $07fb
lda #$02
sta $d029
lda #$0e
sta $d02a
lda #$10
sta objpos+4
lda #$e0
sta objpos+5
sta objpos+7
lda #$9b
sta objpos+6
main
lda #$95
sta $07fc
sta $07fd
lda #$02
sta $d02b
lda #$0e
sta $d02c
lda #$32
sta objpos+9
sta objpos+11
lda #$14
sta objpos+8
lda #$96
sta objpos+10
lda #$00
sta $22
sta $21
lda #$04
sta p1dir
sta p1bdir
sta p2dir
sta p2bdir
lda #$20
sta objpos+0
lda #$52
sta objpos+1
sta objpos+3
lda #$8c
sta objpos+2
lda #2
sta $d027
lda #$0e
sta $d028
lda objpos+0
sta p1defaultx
lda objpos+1
sta p1defaulty
lda objpos+2
sta p2defaultx
lda objpos+3
sta p2defaulty
lda #0
sta killpointer
sta p1isdead
sta p2isdead
;Synchronized game loop so everything is running smooth
gameloop lda #0
sta sync
cmp sync
beq *-3
jsr expand
jsr starfield
jsr bouncer
lda p1isdead
cmp #$01
bne isp2dead
jsr killplayer1
jmp gameloop
isp2dead lda p2isdead
cmp #$01
bne noplayersdead
jsr killplayer2
jmp gameloop
noplayersdead jsr read_joystick
jsr fire1
jsr fire2
jsr checkp1dir
jsr checkp2dir
jsr checkp1mv
jsr checkp2mv
jsr framecol
jsr bullmove
jsr collision_detect
jmp gameloop
;Main IRQ interrupt to activate the synchronization
;of the game code.
gameirq pha
tya
pha
txa
pha
inc $d019
lda $dc0d
sta $dd0d
lda #0
sta $d012
lda #1
sta sync
jsr $1003
stack3 pla
tax
pla
tay
pla
nmi2 rti
;To make things fun. Let's bounce the score
;sprites.
bouncer ldx bouncetime
lda sinus1+0,x
sta objpos+5
lda sinus2+0,x
sta objpos+7
inx
cpx #100
beq resetbounce
inc bouncetime
rts
resetbounce ldx #0
stx bouncetime
rts
;Read joystick
;=======================================
;Left / Right turn player slightly
;Up = Accellerate
;Down = Decellerate
;Fire = Shoot
;=======================================
read_joystick jsr port2
jsr port1
rts
;=======================================
;The controls for player 1. Read from
;joystick plugged via port 2
port2 lda $dc00 ;Read joystick port 2
lsr ;Joystick up
bcs p1down ;Down
jsr fire1
jsr checkp1mv
jsr p1right
jsr p1left
rts
;Accellerate
rts
p1down lsr
bcs p1left
;Decellerate
jsr fire1
p1left lda $dc00
lsr
lsr
lsr
bcs p1right
jsr p1_anticlockwise
jsr fire1
rts
p1right lda $dc00
lsr
lsr
lsr
lsr
bcs nojoyport2
jsr p1_turnclockwise
jsr fire1
;inc $d020 ;Temporary
nojoyport2 ;sta button1reg
rts
button1reg = $21
button2reg = $22
;Read the fire button for joystick port 2
;isolate to single firebutton taps
fire1 lda $dc00
lsr
lsr
lsr
lsr
lsr
bcs notpressed
inc $21
lda $21
cmp #$08 ;firedelay
bne notpressed
lda #$0e
sta $d028
lda #$00
sta $21
;lsr
;lsr
;lsr
;lsr
;lsr
;and #$10 ;Isolatefirebutton
;beq notpressed
;bcs notpressed
;Because of the fire being pressed. Check that the player's
;bullet is offset (If offset then the p1bull_locked parameter
;is turned off, else terminate routine, until bullet is offset.
lda p1bull_locked
cmp #1
beq notpressed
lda p1dir ;Make value of the direction player 1 is facing
sta p1bdir ;into the direction which the bullet should move
lda objpos+$00 ;
sta objpos+$0c ;Place bullet where player is set
lda objpos+$01
sta objpos+$0d
lda #1
sta p1bull_locked
;inc $d020
notpressed rts
;Check the direction which the player is
;actually facing.
checkp1dir lda p1dir
cmp #0 ;Player faces up
bne notup1
lda #$80 ;Player faces up
sta $07f8
rts
notup1 cmp #1
bne notupleft1
lda #$81 ;Player faces up and left
sta $07f8
rts
notupleft1 cmp #2
bne notleft1
lda #$82 ;Player faces left
sta $07f8
rts
notleft1 cmp #3
bne notdownleft1
lda #$83
sta $07f8
rts
notdownleft1 cmp #4
bne notdown1
lda #$84
sta $07f8
rts
notdown1 cmp #5
bne notdownright1
lda #$85
sta $07f8
rts
notdownright1 cmp #6
bne notright1
lda #$86
sta $07f8
rts
notright1 cmp #7
bne notupright1
lda #$87
sta $07f8
notupright1 rts
;Make the player sprite turn clockwise
p1_turnclockwise
inc p1turndelay
lda p1turndelay
cmp #4
beq nowturnp1
rts
nowturnp1 lda #0
sta p1turndelay
inc p1dir
lda p1dir
cmp #8
beq resetp1face
rts
resetp1face lda #0
sta p1dir
rts
p1_anticlockwise
inc p1turndelay
lda p1turndelay
cmp #4
beq nowturnp1b
rts
nowturnp1b lda #0
sta p1turndelay
dec p1dir
lda p1dir
cmp #255
beq resetp1face2
rts
resetp1face2 lda #7
sta p1dir
rts
;Check the direction player 1 is moving.
checkp1mv lda p1dir
cmp #0
bne notp1up
lda objpos+1
sec
sbc yspeed
sta objpos+1
rts
notp1up cmp #1
bne notp1upright
lda objpos+1
sec
sbc yspeed
sta objpos+1
lda objpos+0
clc
adc xspeed
sta objpos+0
rts
notp1upright cmp #2
bne notp1right
lda objpos+0
clc
adc xspeed
sta objpos+0
rts
notp1right cmp #3
bne notp1downright
lda objpos+0
clc
adc xspeed
sta objpos+0
lda objpos+1
clc
adc yspeed
sta objpos+1
rts
notp1downright cmp #4
bne notp1down
lda objpos+1
clc
adc yspeed
sta objpos+1
rts
notp1down cmp #5
bne notp1downleft
lda objpos+1
clc
adc yspeed
sta objpos+1
lda objpos+0
sec
sbc xspeed
sta objpos+0
rts
notp1downleft cmp #6
bne notp1left
lda objpos+0
sec
sbc xspeed
sta objpos+0
rts
notp1left cmp #7
bne notp1upleft
lda objpos+0
sec
sbc xspeed
sta objpos+0
lda objpos+1
sec
sbc yspeed
sta objpos+1
notp1upleft rts
;=============================================================
;Player 2 properties
;===================
;The controls for player 1. Read from
;joystick plugged via port 2
port1 lda $dc01 ;Read joystick port 2
lsr ;Joystick up
bcs p2down ;Down
jsr fire2
jsr checkp2mv
jsr p2right
jsr p2left
rts
;Accellerate
rts
p2down lsr
bcs p2left
;Decellerate
jsr fire2
p2left lda $dc01
lsr
lsr
lsr
bcs p2right
jsr p2_anticlockwise
jsr fire2
rts
p2right lda $dc01
lsr
lsr
lsr
lsr
bcs nojoyport1
jsr p2_turnclockwise
jsr fire2
;inc $d020 ;Temporary
nojoyport1 rts
;Read the fire button for joystick port 1
fire2 lda $dc01
lsr
lsr
lsr
lsr
lsr
bcs notpressed2
inc $22
lda $22
cmp #$08
bne notpressed2
lda #$02
sta $d027
lda #$00
sta $22
;Because of the fire being pressed. Check that the player's
;bullet is offset (If offset then the p2bull_locked parameter
;is turned off, else terminate routine, until bullet is offset.
;
lda p2bull_locked
cmp #01
beq notpressed2
lda p2dir
sta p2bdir
lda objpos+$02
sta objpos+$0e
lda objpos+$03
sta objpos+$0f
lda #$01
sta p2bull_locked
notpressed2 rts
;Check the direction which the player is
;actually facing.
checkp2dir lda p2dir
cmp #0 ;Player faces up
bne notup2
lda #$80 ;Player faces up
sta $07f9
rts
notup2 cmp #1
bne notupleft2
lda #$81 ;Player faces up and left
sta $07f9
rts
notupleft2 cmp #2
bne notleft2
lda #$82 ;Player faces left
sta $07f9
rts
notleft2 cmp #3
bne notdownleft2
lda #$83
sta $07f9
rts
notdownleft2 cmp #4
bne notdown2
lda #$84
sta $07f9
rts
notdown2 cmp #5
bne notdownright2
lda #$85
sta $07f9
rts
notdownright2 cmp #6
bne notright2
lda #$86
sta $07f9
rts
notright2 cmp #7
bne notupright2
lda #$87
sta $07f9
notupright2 rts
;Make the player sprite turn clockwise
p2_turnclockwise
inc p2turndelay
lda p2turndelay
cmp #4
beq nowturnp2
rts
nowturnp2 lda #0
sta p2turndelay
inc p2dir
lda p2dir
cmp #8
beq resetp2face
rts
resetp2face lda #0
sta p2dir
rts
p2_anticlockwise
inc p2turndelay
lda p2turndelay
cmp #4
beq nowturnp2b
rts
nowturnp2b lda #0
sta p2turndelay
dec p2dir
lda p2dir
cmp #255
beq resetp2face2
rts
resetp2face2 lda #7
sta p2dir
rts
;Check the direction player 1 is moving.
checkp2mv lda p2dir
cmp #0
bne notp2up
lda objpos+3
sec
sbc yspeed
sta objpos+3
rts
notp2up cmp #1
bne notp2upright
lda objpos+3
sec
sbc yspeed
sta objpos+3
lda objpos+2
clc
adc xspeed
sta objpos+2
rts
notp2upright cmp #2
bne notp2right
lda objpos+2
clc
adc xspeed
sta objpos+2
rts
notp2right cmp #3
bne notp2downright
lda objpos+2
clc
adc xspeed
sta objpos+2
lda objpos+3
clc
adc yspeed
sta objpos+3
rts
notp2downright cmp #4
bne notp2down
lda objpos+3
clc
adc yspeed
sta objpos+3
rts
notp2down cmp #5
bne notp2downleft
lda objpos+3
clc
adc yspeed
sta objpos+3
lda objpos+2
sec
sbc xspeed
sta objpos+2
rts
notp2downleft cmp #6
bne notp2left
lda objpos+2
sec
sbc xspeed
sta objpos+2
rts
notp2left cmp #7
bne notp2upleft
lda objpos+2
sec
sbc xspeed
sta objpos+2
lda objpos+3
sec
sbc yspeed
sta objpos+3
notp2upleft rts
;Collision for the player. If it collides into the green frame
;basically if the player is past a certain area, swap the player's
;direction by 180 degrees
framecol jsr p1pos
jsr p2pos
rts
;Check for player 1's position
p1pos lda objpos+0
cmp #$9e
bcc rebound1
lda p1dir
cmp #1
bne *+5
jmp setas7
cmp #2
bne *+5
jmp setas6
cmp #3
bne *+5
jmp setas5
error rts
rebound1 lda objpos+0
cmp #$0e
bcs rebound1b
lda p1dir
cmp #5
bne *+5
jmp setas3
cmp #6
bne *+5
jmp setas2
cmp #7
bne *+5
jmp setas1
rts
rebound1b lda objpos+1
cmp #$32
bcs rebound1c
lda p1dir
cmp #0
bne *+5
jmp setas4
cmp #1
bne *+5
jmp setas3
cmp #7
bne *+5
jmp setas5
rts
rebound1c lda objpos+1
cmp #$ec
bcc norebound
lda p1dir
cmp #3
bne *+5
jmp setas1
cmp #4
bne *+5
jmp setas0
cmp #5
bne *+5
jmp setas7
norebound rts
setas0 lda #0
sta p1dir
rts
setas1 lda #1
sta p1dir
rts
setas2 lda #2
sta p1dir
rts
setas3 lda #3
sta p1dir
rts
setas4 lda #4
sta p1dir
rts
setas5 lda #5
sta p1dir
rts
setas6 lda #6
sta p1dir
rts
setas7 lda #7
sta p1dir
rts
;Check for player 2's position
p2pos lda objpos+2
cmp #$9e
bcc rebound2
lda p2dir
cmp #1
bne *+5
jmp set2as7
cmp #2
bne *+5
jmp set2as6
cmp #3
bne *+5
jmp set2as5
error2 rts
rebound2 lda objpos+2
cmp #$0e
bcs rebound2b
lda p2dir
cmp #5
bne *+5
jmp set2as3
cmp #6
bne *+5
jmp set2as2
cmp #7
bne *+5
jmp set2as1
rts
rebound2b lda objpos+3
cmp #$32
bcs rebound2c
lda p2dir
cmp #0
bne *+5
jmp set2as4
cmp #1
bne *+5
jmp set2as3
cmp #7
bne *+5
jmp set2as5
rts
rebound2c lda objpos+3
cmp #$ec
bcc norebound2
lda p2dir
cmp #3
bne *+5
jmp set2as1
cmp #4
bne *+5
jmp set2as0
cmp #5
bne *+5
jmp set2as7
norebound2 rts
set2as0 lda #0
sta p2dir
rts
set2as1 lda #1
sta p2dir
rts
set2as2 lda #2
sta p2dir
rts
set2as3 lda #3
sta p2dir
rts
set2as4 lda #4
sta p2dir
rts
set2as5 lda #5
sta p2dir
rts
set2as6 lda #6
sta p2dir
rts
set2as7 lda #7
sta p2dir
rts
;Now it is time for the moving bullet
;------------------------------------
bullmove
lda p1bull_locked
cmp #1
bne p1bull_notlocked
jsr checkp1bull
jsr checkp1bullpos
p1bull_notlocked lda p2bull_locked
cmp #1
bne p2bull_notlocked
jsr checkp2bull
jsr checkp2bullpos
p2bull_notlocked rts
;Check the direction of player 1's bullet
checkp1bull lda p1bdir
cmp #0
bne *+5
jmp p1b_up
cmp #1
bne *+5
jmp p1b_up_right
cmp #2
bne *+5
jmp p1b_right
cmp #3
bne *+5
jmp p1b_down_right
cmp #4
bne *+5
jmp p1b_down
cmp #5
bne *+5
jmp p1b_down_left
cmp #6
bne *+5
jmp p1b_left
cmp #7
bne *+5
jmp p1b_up_left
rts
;Move player bullet upwards
p1b_up lda objpos+$0d
sec
sbc #$08
sta objpos+$0d
rts
;Move player bullet up and right (diagonal)
p1b_up_right lda objpos+$0d
sec
sbc #$0a
sta objpos+$0d
lda objpos+$0c
clc
adc #$05
sta objpos+$0c
rts
;Move player 1 bullet right
p1b_right lda objpos+$0c
clc
adc #$05
sta objpos+$0c
rts
;Move player 1 bullet down and right
p1b_down_right lda objpos+$0d
clc
adc #$0a
sta objpos+$0d
lda objpos+$0c
clc
adc #$05
sta objpos+$0c
rts
;Move player 1 bullet down
p1b_down lda objpos+$0d
clc
adc #$0a
sta objpos+$0d
rts
;Move player 1 bullet down and left
p1b_down_left lda objpos+$0d
clc
adc #$0a
sta objpos+$0d
lda objpos+$0c
sec
sbc #$05
sta objpos+$0c
rts
;Move player 1 bullet left
p1b_left lda objpos+$0c
sec
sbc #$05
sta objpos+$0c
rts
;Move player 1 bullet up left
p1b_up_left lda objpos+$0d
sec
sbc #$0a
sta objpos+$0d
lda objpos+$0c
sec
sbc #$05
sta objpos+$0c
rts
;Check to see if player 1's bullet leaves the
;game area. If it does, simply make it stop
;shooting.
checkp1bullpos lda objpos+$0d ;Bullet leaves screen on the top
cmp #$2e
bcs b1_bottom
jsr homebull01
lda #$00
sta p1bull_locked
rts
b1_bottom lda objpos+$0d ;Bullet leaves screen on the bottom
cmp #$f8
bcc b1_left
jsr homebull01
lda #$00
sta p1bull_locked
rts
b1_left lda objpos+$0c ;Bullet leaves screen on the left
cmp #$02
bcs b1_right
jsr homebull01
lda #$00
sta p1bull_locked
rts
b1_right lda objpos+$0c ;Bullet leaves screen on the right
cmp #$b2
bcc b1_error ;Means something wrong with the program
jsr homebull01
lda #$00
sta p1bull_locked
b1_error rts
;Home the player's bullet to the home position
;so that there are no problems. We don't want
;to see the bullet around after it is offset.
homebull01 lda #$00
sta objpos+$0c
sta objpos+$0d
rts
;Check the direction of player 1's bullet
checkp2bull lda p2bdir
cmp #0
bne *+5
jmp p2b_up
cmp #1
bne *+5
jmp p2b_up_right
cmp #2
bne *+5
jmp p2b_right
cmp #3
bne *+5
jmp p2b_down_right
cmp #4
bne *+5
jmp p2b_down
cmp #5
bne *+5
jmp p2b_down_left
cmp #6
bne *+5
jmp p2b_left
cmp #7
bne *+5
jmp p2b_up_left
rts
;Move player bullet upwards
p2b_up lda objpos+$0f
sec
sbc #$0a
sta objpos+$0f
rts
;Move player bullet up and right (diagonal)
p2b_up_right lda objpos+$0f
sec
sbc #$0a
sta objpos+$0f
lda objpos+$0e
clc
adc #$05
sta objpos+$0e
rts
;Move player 2 bullet right
p2b_right lda objpos+$0e
clc
adc #$05
sta objpos+$0e
rts
;Move player 2 bullet down and right
p2b_down_right lda objpos+$0f
clc
adc #$0a
sta objpos+$0f
lda objpos+$0e
clc
adc #$05
sta objpos+$0e
rts
;Move player 2 bullet down
p2b_down lda objpos+$0f
clc
adc #$0a
sta objpos+$0f
rts
;Move player 2 bullet down and left
p2b_down_left lda objpos+$0f
clc
adc #$0a
sta objpos+$0f
lda objpos+$0e
sec
sbc #$05
sta objpos+$0e
rts
;Move player 2 bullet left
p2b_left lda objpos+$0e
sec
sbc #$05
sta objpos+$0e
rts
;Move player 2 bullet up left
p2b_up_left lda objpos+$0f
sec
sbc #$0a
sta objpos+$0f
lda objpos+$0e
sec
sbc #$05
sta objpos+$0e
rts
;Check to see if player 2's bullet leaves the
;game area. If it does, simply make it stop
;shooting.
checkp2bullpos lda objpos+$0f ;Bullet leaves screen on the top
cmp #$2e
bcs b2_bottom
jsr homebull02
lda #$00
sta p2bull_locked
rts
b2_bottom lda objpos+$0f ;Bullet leaves screen on the bottom
cmp #$f8
bcc b2_left
jsr homebull02
lda #$00
sta p2bull_locked
rts
b2_left lda objpos+$0e ;Bullet leaves screen on the left
cmp #$02
bcs b2_right
jsr homebull02
lda #$00
sta p2bull_locked
rts
b2_right lda objpos+$0e ;Bullet leaves screen on the right
cmp #$b2
bcc b2_error ;Means something wrong with the program
jsr homebull02
lda #$00
sta p2bull_locked
b2_error rts
;Home the player's bullet to the home position
;so that there are no problems. We don't want
;to see the bullet around after it is offset.
homebull02 lda #$00
sta objpos+$0e
sta objpos+$0f
rts
;Now it is the collision detection routine
collision_detect jsr p1collision
jsr p2collision
rts
;Set up the collision pointers for player 1's bullet
p1collision lda objpos+$0c ;Player bullet x-position
sec
sbc #$06
sta collision+$00
clc
adc #$0c
sta collision+$01
lda objpos+$0d
sec
sbc #$0c
sta collision+$02
clc
adc #$18
sta collision+$03
;Check if player 1's bullet hits player 2. If at correct position
;then it is a direct hit. Else if not then no collision is made
lda objpos+$02
cmp collision+$00
bcc nop2col
cmp collision+$01
bcs nop2col
lda objpos+$03
cmp collision+$02
bcc nop2col
cmp collision+$03
bcs nop2col
;Direct Hit
lda #$00
sta objpos+$0c
sta objpos+$0d
jsr p2_shield_down
lda #$00
sta p1bull_locked
lda #$03
sta $d028
nop2col rts
;Player 2's shield goes down (Hit)
p2_shield_down inc $07fd
lda $07fd
cmp #$9b
beq p2_dies
rts
p2_dies lda #$9c
sta $07fc
lda #$9f
sta $07f9
lda #$01
sta p2isdead
rts
;Player 2's bullet collision registers
p2collision lda objpos+$0e
sec
sbc #$06
sta collision+$04
clc
adc #$0c
sta collision+$05
lda objpos+$0f
sec
sbc #$0c
sta collision+$06
clc
adc #$18
sta collision+$07
;Check whether or not player 2's bullet hits player 1
lda objpos+$00
cmp collision+$04
bcc nop1col
cmp collision+$05
bcs nop1col
lda objpos+$01
cmp collision+$06
bcc nop1col
cmp collision+$07
bcs nop1col
lda #$07
sta $d027
lda #$00
sta objpos+$0e
sta objpos+$0f
jsr p1_shield_down
lda #$00
sta p2bull_locked
nop1col rts
p1_shield_down inc $07fc
lda $07fc
cmp #$9b
beq p1dead
rts
p1dead lda #$9c
sta $07fd
lda #$9f
sta $07f8
lda #$01
sta p1isdead
rts
;Because player 1 has been defeated. Time for the kill player 1 effect.
killplayer1 lda killpointer
cmp #$08
beq delayoff1
inc killpointer
rts
delayoff1 lda #0
sta killpointer
inc $07f8
lda $07f8
cmp #$a5
beq enddeath1
rts
enddeath1 inc $07fb ;1 point to player2
lda $07fb
cmp winscore
beq enditall
jmp main
enditall lda #$93
sta $07fb
lda #$94
sta $07fa
jmp enditall3
killplayer2 lda killpointer
cmp #$08
beq delayoff2
inc killpointer
rts
delayoff2 lda #0
sta killpointer
inc $07f9
lda $07f9
cmp #$a5
beq enddeath2
rts
enddeath2 inc $07fa ;1 point to player1
lda $07fa
cmp winscore
beq enditall2
jmp main
enditall2 lda #$93
sta $07fa
lda #$94
sta $07fb
jmp enditall3
waittime = $19
enditall3 lda #$9e
sta $07fc
sta $07fd
lda #0
sta waittime
sta waittime+1
sta objpos+0
sta objpos+1
sta objpos+2
sta objpos+3
sta objpos+$0c
sta objpos+$0d
sta objpos+$0e
sta objpos+$0f
lda #$02
jsr $1000
sync2 lda #0
sta sync
cmp sync
beq *-3
jsr expand
jsr starfield
jsr bouncer
jsr waitend
jmp sync2
waitend inc waittime
lda waittime
cmp #$08
beq nextwait
rts
nextwait lda #0
sta waittime
;inc $d020
inc waittime+1
lda waittime+1
cmp #$30
beq titletime
rts
titletime lda #$31
sta $0314
lda #$ea
sta $0315
lda #$81
sta $dc0d
lda #$00
sta $d01a
cli
jmp $3800
jmp $5000
;Expand sprite areas
expand ldx #$00
expandloop lda objpos+$01,x
sta $d001,x
lda objpos+$00,x
asl
ror $d010
sta $d000,x
inx
inx
cpx #$10
bne expandloop
rts
;Starfield
starfield inc starcontrol
lda starcontrol
cmp #$03
beq doscroll
rts
doscroll lda #0
sta starcontrol
ldx #0
jsr starscroll
jsr starscroll
ldx #1
jsr starscroll
ldx #2
jsr starscroll
jsr starscroll
jsr starscroll
ldx #3
jsr starscroll
ldx #4
jsr starscroll
jsr starscroll
jsr starscroll
ldx #5
jsr starscroll
jsr starscroll
ldx #6
jsr starscroll
ldx #7
jsr starscroll
jsr starscroll
rts
starscroll lda $3220,x
rol $3208,x
rol $3210,x
rol $3218,x
rol $3220,x
sta $3208,x
rts
nmi rti
p1limit !byte $93
p2limit !byte $93
;Now for the byte tables to finish the game & title off.
* = $5000
gamesfield !scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!scr"BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDA"
!scr"CDABCDABCDABCDABCDABCDABCDABCDABCDABCDAB"
!scr"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
!scr"DABCDABCDABCDABCDABCDABCDABCDABCDABCDABC"
!byte 0,0,0,0,00,0
sinus1
!byte $d0,$d0,$d0,$d0,$d1,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db
!byte $dc,$dd,$de,$df,$e0,$e0,$e1,$e1,$e1,$e1,$e1,$e1,$e1,$e0,$e0,$df
!byte $de,$dd,$dc,$db,$da,$d9,$d8,$d7,$d6,$d5,$d4,$d3,$d2,$d1,$d1,$d0
!byte $d0,$d0,$d0,$d0,$d0,$d0,$d1,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9
!byte $da,$db,$dc,$dd,$de,$df,$e0,$e0,$e1,$e1,$e1,$e1,$e1,$e1,$e1,$e0
!byte $e0,$df,$de,$dd,$dc,$db,$da,$d9,$d8,$d7,$d6,$d5,$d4,$d3,$d2,$d1
!byte $d1,$d0,$d0,$d0
!byte 0,0,0,0
sinus2
!byte $e0,$e0,$e0,$e0,$e0,$df,$de,$de,$dd,$dc,$db,$da,$d9,$d8,$d7,$d6
!byte $d5,$d4,$d3,$d3,$d2,$d1,$d1,$d1,$d1,$d1,$d1,$d1,$d1,$d1,$d2,$d3
!byte $d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db,$dc,$dd,$de,$de,$df,$e0,$e0
!byte $e0,$e0,$e0,$e0,$e0,$e0,$e0,$df,$de,$de,$dd,$dc,$db,$da,$d9,$d8
!byte $d7,$d6,$d5,$d4,$d3,$d3,$d2,$d1,$d1,$d1,$d1,$d1,$d1,$d1,$d1,$d1
!byte $d2,$d3,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db,$dc,$dd,$de,$de,$df
!byte $e0,$e0,$e0,$e0
!byte 0,0,0,0
yspeed !byte $02
xspeed !byte $01
;Sinus table for the colour sinus
colsinus
!byte $00,$00,$00,$00,$00,$00,$01,$01,$02,$03,$03,$04,$05,$06,$07,$08
!byte $09,$0b,$0c,$0d,$0f,$10,$12,$13,$15,$17,$19,$1b,$1d,$1f,$21,$23
!byte $25,$27,$2a,$2c,$2e,$31,$33,$36,$39,$3b,$3e,$41,$43,$46,$49,$4c
!byte $4f,$52,$55,$58,$5b,$5e,$61,$64,$67,$6a,$6d,$70,$73,$77,$7a,$7d
!byte $80,$83,$86,$89,$8d,$90,$93,$96,$99,$9c,$9f,$a2,$a5,$a8,$ab,$ae
!byte $b1,$b4,$b7,$ba,$bc,$bf,$c2,$c5,$c7,$ca,$cc,$cf,$d1,$d4,$d6,$d8
!byte $da,$dd,$df,$e1,$e3,$e5,$e7,$e9,$ea,$ec,$ee,$ef,$f1,$f2,$f4,$f5
!byte $f6,$f7,$f8,$f9,$fa,$fb,$fc,$fd,$fd,$fe,$fe,$ff,$ff,$ff,$ff,$ff
!byte $ff,$ff,$ff,$ff,$ff,$ff,$fe,$fe,$fd,$fc,$fc,$fb,$fa,$f9,$f8,$f7
!byte $f6,$f4,$f3,$f2,$f0,$ef,$ed,$ec,$ea,$e8,$e6,$e4,$e2,$e0,$de,$dc
!byte $da,$d8,$d5,$d3,$d1,$ce,$cc,$c9,$c6,$c4,$c1,$be,$bc,$b9,$b6,$b3
!byte $b0,$ad,$aa,$a7,$a4,$a1,$9e,$9b,$98,$95,$92,$8f,$8c,$88,$85,$82
!byte $7f,$7c,$79,$76,$72,$6f,$6c,$69,$66,$63,$60,$5d,$5a,$57,$54,$51
!byte $4e,$4b,$48,$45,$43,$40,$3d,$3a,$38,$35,$33,$30,$2e,$2b,$29,$27
!byte $25,$22,$20,$1e,$1c,$1a,$18,$16,$15,$13,$11,$10,$0e,$0d,$0b,$0a
!byte $09,$08,$07,$06,$05,$04,$03,$02,$02,$01,$01,$00,$00,$00,$00,$00
!byte $00
;Colours for the title screen colour SINUS
;max 64 bytes
colours !byte $09,$09,$02,$02,$08,$08,$0a,$0a
!byte $07,$07,$01,$01,$01,$01,$01,$01
!byte $01,$01,$01,$01,$01,$01,$07,$07
!byte $0a,$0a,$08,$08,$02,$02,$09,$09
!byte $0b,$0c,$0f,$07,$07,$0f,$0c,$0b
!byte $06,$06,$04,$04,$0e,$0e,$05,$05
!byte $0d,$0d,$01,$01,$01,$01,$01,$01
!byte $01,$01,$01,$01,$01,$01,$0d,$0d
!byte $05,$05,$0e,$0e,$04,$04,$06,$06
!byte $0b,$05,$03,$0d,$0d,$03,$05,$0b
!byte $00
* = $6200
;The actual title screen
titlescreen
titlescreentext
!scr" "
!scr" programming .........richard bayliss "
!scr" graphics ............richard bayliss "
!scr" logo ................michael koslowski "
!scr" music ...............richard bayliss "
!scr" "
!scr" points to win game ................. 9 "
!scr" game speed ...................... slow "
!scr" "
!scr"press fire or spacebar to start toasting"
!scr" "
slow !scr "slow" ;Text we paste into the title screen
fast !scr "fast"
message * = $6400-2
!binary "scrolltext.prg" ;Game title scroll text
* = $8400-2
!binary "vidram.prg" ;Game title logo video RAM data
* = $8800-2
!binary "colram.prg" ;Game title logo colour RAM data
* = $a000-2
!binary "bitmap.prg" ; Game title bitmap data