8bitworkshop/presets/examples/adventure.a

248 lines
6.5 KiB
Plaintext

processor 6502
include "vcs.h"
include "macro.h"
org $f000
; Now, we'll finally put everything together and
; make a little person with a hat that can move
; back and forth and throw rocks. We'll use one player
; to generate a 8x16 sprite and one missile.
;
; We have two tables for the sprite, a bitmap table and
; a color table. We'll lookup from both of these tables on
; each scanline.
;
; Because VCS programming is all about thrift, we'll
; reuse the machine code for our program as the backdrop
; for the playfield, just to show we can fit it all on
; a scanline.
;
; Note: the Y coordinate goes bottom-top, not top-bottom
; as in the next section.
counter equ $81 ; increments each frame
yplyr equ $82 ; player y pos
yrock equ $83 ; rock y pos
animofs equ $84 ; sprite data offset, used for animation
; Initialize and set initial offsets of objects.
start CLEAN_START
lda #5
sta yplyr
lda #70
ldx #0
jsr SetHorizPos ; set player 0 horiz. pos
sta WSYNC
sta HMOVE
; Next frame loop
nextframe
VERTICAL_SYNC
; in case the rock is on screen
lda ColorFrame0 ; load 1st entry of color data
sta COLUP0 ; set sprite 0 color
; 37 lines of VBLANK
ldx #37
lvblank sta WSYNC
dex
bne lvblank
; set some colors
lda #$80
sta COLUBK ; set the background color
lda #1
sta CTRLPF ; playfield reflection
; Draw 192 scanlines with our sprite/missile kernel
ldx #192
lvscan
; Draw sprite?
txa
sec ; make sure carry is set (meaning no borrow for subtraction)
sbc yplyr ; get offset into sprite for this line
cmp #SpriteHeight ; sprite is 16 pixels high + padding on either side
bcc insprite
lda #SpriteHeight-1 ; draw the padding
insprite
tay
lda ColorFrame0,y ; load color data
pha ; push color data onto stack
clc ; clear carry flag
adc animofs ; add animation offset (not for color though)
lda Frame0,y ; load bitmap data
sta WSYNC ; wait for next scanline (as late as possible!)
sta GRP0 ; set sprite 0 pixels
pla ; pull bitmap data from stack
sta COLUP0 ; set sprite 0 color
lda start,x ; store some random garbage into the playfield
sta PF0
sta PF1
sta PF2
; Draw rock? Player 0 and missile 0 share a color register,
; so they will have the same colors on the same scanline
lda #%00000000
cpx yrock
bne norock
lda #%00000010 ; for ENAM0 the 2nd bit is enable
norock
sta ENAM0 ; enable missile 0
dex
bne lvscan ; repeat next scanline until finished
; End of scanline loop
; Clear all colors to black before overscan
stx COLUBK
stx COLUP0
stx COLUP1
stx COLUPF
; 30 lines of overscan
ldx #29
lvover sta WSYNC
dex
bne lvover
; Joystick movement
; For up and down, we INC or DEC the Y Position
lda #%00010000 ;Up?
bit SWCHA
bne SkipMoveUp
inc yplyr
SkipMoveUp
lda #%00100000 ;Down?
bit SWCHA
bne SkipMoveDown
dec yplyr
SkipMoveDown
; Note that the horizontal position is not contained in RAM,
; but inaccessibly inside the TIA's registers! Some games can
; get away with this if they use the collision registers.
ldx #0 ; assume speed is 0 if no movement
lda #%01000000 ;Left?
bit SWCHA
bne SkipMoveLeft
ldx #$10 ;a 1 in the left nibble means go left
SkipMoveLeft
lda #%10000000 ;Right?
bit SWCHA
bne SkipMoveRight
ldx #$F0 ;a -1 in the left nibble means go right...
SkipMoveRight
stx HMP0 ;set the move for plyr 0
sta WSYNC
sta HMOVE
; Throw a rock when fire button pressed
lda #0
sta animofs
ldy #%00000000 ; use later to enable/disable missile lock on player
lda INPT4 ;read button input
bmi ButtonNotPressed ;skip if button not pressed
lda yplyr
sta yrock ; set rock vert pos to player's vert
lda #SpriteHeight
sta animofs ; while button pressed, use alternate player bitmap
ldy #%00000010 ; for RESMP0 the 2nd bit is the enable bit
ButtonNotPressed
sty RESMP0 ; reset missile 0 to player 0's horiz position
inc yrock ; rock moves no matter what (actually a boomerang)
; Goto next frame
jmp nextframe
; SetHorizPos - Sets the horizontal position of an object.
; The X register contains the index of the desired object:
; X=0: player 0
; X=1: player 1
; X=2: missile 0
; X=3: missile 1
; X=4: ball
; This routine does a WSYNC and HMOVE before executing,
; so whatever you do here will not take effect until you
; call the routine again or do your own WSYNC and HMOVE.
SetHorizPos
sta WSYNC ; start a new line
sta HMOVE ; apply the previous fine position(s)
sta HMCLR ; reset the old horizontal position(s)
sec ; set carry flag
DivideLoop
sbc #15 ; subtract 15
bcs DivideLoop ; branch until negative
eor #7 ; calculate fine offset
asl
asl
asl
asl
sta RESP0,x ; fix coarse position
sta HMP0,x ; set fine offset
rts ; return to caller
; Height of our sprite in lines
SpriteHeight equ 18
; Bitmap data "standing" position
Frame0
.byte #0
.byte #%01101100;$F6
.byte #%00101000;$86
.byte #%00101000;$86
.byte #%00111000;$86
.byte #%10111010;$C2
.byte #%10111010;$C2
.byte #%01111100;$C2
.byte #%00111000;$C2
.byte #%00111000;$16
.byte #%01000100;$16
.byte #%01111100;$16
.byte #%01111100;$18
.byte #%01010100;$18
.byte #%01111100;$18
.byte #%11111110;$F2
.byte #%00111000;$F4
; Bitmap data "throwing" position
Frame1
.byte #0
.byte #%01101100;$F6
.byte #%01000100;$86
.byte #%00101000;$86
.byte #%00111000;$86
.byte #%10111010;$C2
.byte #%10111101;$C2
.byte #%01111101;$C2
.byte #%00111001;$C2
.byte #%00111000;$16
.byte #%01101100;$16
.byte #%01111100;$16
.byte #%01111100;$18
.byte #%01010100;$18
.byte #%01111100;$18
.byte #%11111110;$F2
.byte #%00111000;$F4
; Color data for each line of sprite
ColorFrame0
.byte #$FF ; rock color if not sharing line with player sprite
.byte #$F6;
.byte #$86;
.byte #$86;
.byte #$86;
.byte #$C2;
.byte #$C2;
.byte #$C2;
.byte #$C2;
.byte #$16;
.byte #$16;
.byte #$16;
.byte #$18;
.byte #$18;
.byte #$18;
.byte #$F2;
.byte #$F4;
; Epilogue
org $fffc
.word start
.word start