246 lines
4.2 KiB
NASM
246 lines
4.2 KiB
NASM
;;; -*- Mode: asm; indent-tabs-mode: t; tab-width: 8 -*-
|
|
.include "c64.inc"
|
|
.include "enum.asm"
|
|
|
|
VMBASE = $0400
|
|
|
|
.org PROGSTART
|
|
|
|
.include "init.asm" ;must come first
|
|
.include "utilities.asm"
|
|
|
|
;; Start screen, waits for space key to be pressed.
|
|
titlescreen:
|
|
;; More visually interesting sprite positioning for
|
|
;; the title screen. Overrides default from init.
|
|
lda #$82
|
|
sta SPRITE_0Y
|
|
|
|
ldx #%01111111
|
|
ldy #%00010000
|
|
jsr keydown
|
|
bne @dontstart
|
|
;; Start the game here.
|
|
jsr loadgamefield ;set the background
|
|
lda #mode::MainGame ;don't forget that #
|
|
sta gamemode ;set the game mode to MainGame
|
|
@dontstart:
|
|
rts
|
|
|
|
|
|
;; Wait and highlight the score change for half a second.
|
|
;; Happens every time a player scores or whatever it's called in tennis
|
|
scorewait:
|
|
;; While waiting we play a buzz
|
|
lda #$0f
|
|
sta SIDFMV
|
|
lda #$08
|
|
sta SIDAD1
|
|
lda #$68
|
|
sta SIDSR1
|
|
|
|
lda #$45
|
|
sta SIDF1L
|
|
lda #$1d
|
|
sta SIDF1H
|
|
|
|
lda #$11
|
|
sta SIDCR1
|
|
|
|
dec timer
|
|
bne @dontresume
|
|
;; Reset gamemode
|
|
lda #mode::MainGame
|
|
sta gamemode
|
|
;; Reset background color
|
|
lda #0
|
|
sta BGCOL0
|
|
;; Stop sound
|
|
lda #$10
|
|
sta SIDCR1
|
|
@dontresume:
|
|
rts
|
|
|
|
|
|
;; Call after a player scores to highlight the win
|
|
highlightscore:
|
|
lda #mode::ScoreHighlight
|
|
sta gamemode
|
|
lda #25
|
|
sta timer
|
|
lda #2
|
|
sta BGCOL0
|
|
rts
|
|
|
|
.include "gameloop.asm"
|
|
|
|
|
|
;; "Victory" mode when 100 points has been reached.
|
|
win:
|
|
dec timer
|
|
bne @skip
|
|
dec timer2
|
|
bne @continue
|
|
;; After five seconds (10 half-seconds) we reset the game
|
|
jmp PROGSTART
|
|
@continue:
|
|
lda #25
|
|
sta timer
|
|
lda BGCOL0
|
|
eor #8
|
|
sta BGCOL0
|
|
@skip:
|
|
rts
|
|
|
|
winstop:
|
|
lda #25
|
|
sta timer
|
|
lda #10
|
|
sta timer2
|
|
lda #$0d
|
|
sta BGCOL0
|
|
lda #mode::Win ;DO NOT FORGET THE #
|
|
sta gamemode
|
|
rts
|
|
|
|
ball_x_inc:
|
|
inc ball_x
|
|
bne @done
|
|
;; If ball_x incremented to zero we have either looped around
|
|
;; the screen (shouldn't happen) or crossed the bit 8 boundry.
|
|
;; So we set the MSB to one, since we're going right.
|
|
lda #%00000100
|
|
ora SPRITE_X_MSB
|
|
sta SPRITE_X_MSB
|
|
@done:
|
|
rts
|
|
|
|
ball_x_dec:
|
|
dec ball_x
|
|
lda ball_x
|
|
cmp #$ff
|
|
bne @done
|
|
;; If ball_x incremented to zero we have either looped around
|
|
;; the screen (shouldn't happen) or crossed the bit 8 boundry.
|
|
;; So we set the MSB to one, since we're going right.
|
|
lda #%11111011
|
|
and SPRITE_X_MSB
|
|
sta SPRITE_X_MSB
|
|
@done:
|
|
rts
|
|
|
|
ball_bounce_vert:
|
|
jsr color_change
|
|
lda #%10000000
|
|
eor balldata
|
|
sta balldata
|
|
rts
|
|
|
|
ball_bounce_hori:
|
|
jsr color_change
|
|
lda #%01000000
|
|
eor balldata
|
|
sta balldata
|
|
rts
|
|
|
|
reset_ball:
|
|
jsr ball_bounce_hori
|
|
lda #$90
|
|
sta ball_y
|
|
lda #$c0
|
|
sta ball_x
|
|
lda #%11111011
|
|
and SPRITE_X_MSB
|
|
sta SPRITE_X_MSB
|
|
rts
|
|
|
|
color_change:
|
|
inc bordercol
|
|
lda bordercol
|
|
and #$0f
|
|
cmp #2
|
|
bcs @fine
|
|
lda #2
|
|
sta bordercol
|
|
@fine:
|
|
lda bordercol
|
|
sta BORDER
|
|
rts
|
|
|
|
handle_collision:
|
|
jsr ball_bounce_hori ;obvious, flip the ball's horizontal direction
|
|
lda #$00
|
|
sta col ;clear the collision flag
|
|
rts
|
|
|
|
;; Cheap trick to make a hexprinted number look decimal.
|
|
;; Score comes in the A register, clamped score returned in A
|
|
clampscore:
|
|
tax
|
|
and #%00001111
|
|
cmp #$0a
|
|
bcc @noclamplower
|
|
;; yes clamp, inc upper nybble, ex. $19 -> $20
|
|
txa
|
|
and #%11110000
|
|
clc
|
|
adc #$10
|
|
tax
|
|
@noclamplower:
|
|
txa
|
|
and #%11110000
|
|
cmp #$a0
|
|
bcc @noclamp
|
|
;; over 99? just stop at that point, we'll flash some colors then reset
|
|
jsr winstop
|
|
pla
|
|
pla
|
|
@noclamp:
|
|
txa
|
|
rts
|
|
|
|
modedispatch:
|
|
jsr jumpwithtable
|
|
.addr titlescreen
|
|
.addr game ;normal gameplay
|
|
.addr scorewait
|
|
.addr win
|
|
|
|
|
|
;; Main IRQ subroutine. CPU gets sent here by the interrupts from the
|
|
;; VIC-II's raster and collision interrupts, and is responsible for
|
|
;; calling everything else. Since the game is interrupt-driven, you
|
|
;; could add a RTS to the init code and have the game run together
|
|
;; with BASIC. Would be pretty stupid but you *can* do it. That does
|
|
;; give me an idea though...
|
|
irq:
|
|
lda SSCOL ;need to do this for collision checking to work
|
|
|
|
lda #%00000100 ;check if irq is for collision or not
|
|
and VICINT
|
|
beq @nocol
|
|
;; Collision
|
|
sta col ;set the collision flag
|
|
lda #$7f
|
|
and VICINT
|
|
sta VICINT
|
|
jmp @skipgame
|
|
@nocol:
|
|
lda gamemode
|
|
jsr modedispatch
|
|
@skipgame:
|
|
lda #$7f
|
|
and VICINT
|
|
sta VICINT
|
|
|
|
jmp $ea31
|
|
|
|
.include "variables.asm"
|
|
|
|
BALLVERT = %10000000
|
|
BALLHORI = %01000000
|
|
BALLVSPEED = %00000010
|
|
BALLHSPEED = %00000001
|
|
|
|
.include "graphics.asm"
|
|
.include "zeropage.asm"
|