Files
nes/plat.s

1606 lines
25 KiB
ArmAsm
Raw Normal View History

2026-02-14 18:08:10 -05:00
.segment "HEADER"
INES_MAPPER = 0
INES_MIRROR = 1
INES_SRAM = 0
.byte 'N', 'E', 'S', $1A
.byte $02
.byte $01
.byte INES_MIRROR
.byte (INES_MAPPER & %11110000)
.byte $0, $0, $0, $0, $0, $0, $0, $0
.segment "TILES"
.incbin "background.chr"
.incbin "sprite.chr"
.segment "VECTORS"
.word nmi
.word reset
.word irq
.segment "CODE"
reset:
sei
2026-02-17 09:53:46 -05:00
lda #0
2026-02-14 18:08:10 -05:00
sta $2000
2026-02-16 00:27:56 -05:00
lda #0
2026-02-14 18:08:10 -05:00
sta $2001
sta $4015
sta $4010
lda #40
sta $4017
cld
ldx #$FF
txs
bit $2002
:
bit $2002
bpl :-
lda #0
ldx #0
:
sta $0000, X
sta $0100, X
sta $0200, X
sta $0300, X
sta $0400, X
sta $0500, X
sta $0600, X
sta $0700, X
inx
bne :-
lda #255
ldx #0
:
sta oam, X
inx
inx
inx
inx
bne :-
:
bit $2002
bpl :-
2026-02-17 09:53:46 -05:00
lda #%10101000 ; NMI enable, 8x16 sprites, ignored due to 8x16 mode
2026-02-14 18:08:10 -05:00
sta $2000
jmp main
.segment "ZEROPAGE"
nmi_lock: .res 1
nmi_count: .res 1
nmi_ready: .res 1
nmt_update_len: .res 1
scroll_x: .res 1
scroll_y: .res 1
scroll_nmt: .res 1
temp: .res 1
.segment "BSS"
nmt_update: .res 256
palette: .res 32
.segment "OAM"
oam: .res 256
.segment "CODE"
nmi:
pha
txa
pha
tya
pha
lda nmi_lock
beq :+
jmp @nmi_end
:
lda #1
sta nmi_lock
lda nmi_ready
bne :+
jmp @ppu_update_end
:
cmp #2
bne :+
lda #%00000000
sta $2001
ldx #0
stx nmi_ready
jmp @ppu_update_end
:
ldx #0
stx $2003
lda #>oam
sta $4014
2026-02-17 09:53:46 -05:00
lda #%10101000 ; NMI enable, 8x16 sprites, ignored due to 8x16 mode
2026-02-14 18:08:10 -05:00
sta $2000
lda $2002
lda #$3F
sta $2006
stx $2006
ldx #0
:
lda palette, X
sta $2007
inx
cpx #32
bcc :-
ldx #0
cpx nmt_update_len
bcs @scroll
@nmt_update_loop:
lda nmt_update, X
sta $2006
inx
lda nmt_update, X
sta $2006
inx
lda nmt_update, X
sta $2007
cpx nmt_update_len
bcc @nmt_update_loop
lda #0
sta nmt_update_len
@scroll:
lda scroll_nmt
and #%00000011
2026-02-17 09:53:46 -05:00
ora #%10101000
2026-02-14 18:08:10 -05:00
sta $2000
lda scroll_x
sta $2005
lda scroll_y
sta $2005
lda #%00011110
sta $2001
ldx #0
stx nmi_ready
@ppu_update_end:
lda #0
sta nmi_lock
@nmi_end:
pla
tay
pla
tax
pla
rti
.segment "CODE"
irq:
rti
.segment "CODE"
ppu_update:
lda #1
sta nmi_ready
:
lda nmi_ready
bne :-
rts
ppu_skip:
lda nmi_count
:
cmp nmi_count
beq :-
rts
ppu_off:
lda #2
sta nmi_ready
:
lda nmi_ready
bne :-
rts
PAD_A = $01
PAD_B = $02
PAD_SELECT = $04
PAD_START = $08
PAD_U = $10
PAD_D = $20
PAD_L = $40
PAD_R = $80
.segment "ZEROPAGE"
gamepad: .res 1
.segment "CODE"
; gamepad_poll: this reads the gamepad state into the variable labelled "gamepad"
; This only reads the first gamepad, and also if DPCM samples are played they can
; conflict with gamepad reading, which may give incorrect results.
gamepad_poll:
; strobe the gamepad to latch current button state
lda #1
sta $4016
lda #0
sta $4016
; read 8 bytes from the interface at $4016
ldx #8
:
pha
lda $4016
; combine low two bits and store in carry bit
and #%00000011
cmp #%00000001
pla
; rotate carry into gamepad variable
ror
dex
bne :-
sta gamepad
rts
.segment "RODATA"
2026-02-16 00:27:56 -05:00
level:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2026-02-17 22:52:47 -05:00
.byte 0,1,0,0,1,0,0,0,0,1,0,0,2,7,7,3
2026-02-18 20:02:49 -05:00
.byte 0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9
.byte 0,1,0,0,1,7,7,7,7,1,7,7,6,0,0,9
2026-02-17 22:52:47 -05:00
.byte 0,0,1,1,0,0,0,0,0,1,0,0,4,8,8,5
.byte 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
2026-02-16 00:27:56 -05:00
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2026-02-17 09:26:32 -05:00
.byte 0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0
2026-02-16 00:27:56 -05:00
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2026-02-18 15:04:42 -05:00
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,10,10,10,10,10
.byte 0,0,1,0,0,0,0,1,0,0,0,11,11,11,11,11
.byte 0,1,2,3,4,5,6,7,8,9,0,11,11,11,11,11
.byte 0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11
2026-02-16 00:27:56 -05:00
2026-02-19 14:04:29 -05:00
level2:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.byte 0,0,0,0,0,0,0,0,0,0,0,10,10,10,10,10
.byte 0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11
.byte 0,1,7,7,7,7,7,7,7,1,0,11,11,11,11,11
.byte 0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11
2026-02-16 20:33:50 -05:00
metatiles:
.byte 0,0,0,0,0
2026-02-17 22:52:47 -05:00
.byte $14,$15,$16,$17,1 ; Full block
2026-02-18 15:04:42 -05:00
.byte $14,$18,$1B,$00,0 ; up / left
.byte $18,$15,$00,$19,0 ; up / right
.byte $1B,$00,$16,$1A,0 ; down / left
.byte $00,$19,$1A,$17,0 ; down / right
.byte $1B,$00,$1B,$00,0 ; left
.byte $18,$18,$00,$00,0 ; up
.byte $00,$00,$1A,$1A,0 ; down
.byte $00,$19,$00,$19,0 ; right
.byte $10,$11,$12,$13,2
.byte $12,$12,$12,$12,2
2026-02-16 20:33:50 -05:00
2026-02-14 18:08:10 -05:00
example_palette:
2026-02-16 00:27:56 -05:00
.byte $0F,$00,$3D,$20 ; greyscale
2026-02-18 15:04:42 -05:00
.byte $0F,$3D,$30,$00 ; whitescale
2026-02-16 00:27:56 -05:00
.byte $0F,$09,$1A,$16 ; grass
2026-02-14 18:08:10 -05:00
.byte $0F,$15,$26,$37 ; bg0 purple/pink
2026-02-17 11:19:51 -05:00
.byte $0F,$2D,$10,$3D ; reboot bottom
.byte $0F,$2D,$10,$2C ; reboot eye
2026-02-14 18:08:10 -05:00
.byte $0F,$01,$11,$21 ; bg2 blue
.byte $0F,$00,$10,$30 ; bg3 greyscale
2026-02-17 11:19:51 -05:00
; .byte $0F,$18,$28,$38 ; sp0 yellow
; .byte $0F,$14,$24,$34 ; sp1 purple
; .byte $0F,$1B,$2B,$3B ; sp2 teal
; .byte $0F,$12,$22,$32 ; sp3 marine
2026-02-14 18:08:10 -05:00
.segment "ZEROPAGE"
2026-02-16 00:27:56 -05:00
buttons: .res 1
2026-02-17 09:26:32 -05:00
player_pos_x: .res 1
2026-02-19 16:52:08 -05:00
player_nmt_x: .res 1
2026-02-17 09:26:32 -05:00
player_pos_y: .res 1
2026-02-18 15:04:42 -05:00
player_subpos_x: .res 1 ; XXXXYYYY | first 4 bits X subposition, last 4 bits Y
player_subpos_y: .res 1 ; XXXXYYYY | first 4 bits X subposition, last 4 bits Y
player_vel_x: .res 1 ; +PPPSSSS | first bit sign, next 3 pixels, last subpixels
player_vel_y: .res 1 ; in subpixels
2026-02-14 18:08:10 -05:00
2026-02-17 11:19:51 -05:00
player_status: .res 1 ; 76543210 | 0: facing (0 right, 1 left)
2026-02-19 16:52:08 -05:00
; | 1: nametable X
; | 2: nametable Y
2026-02-17 11:19:51 -05:00
; | 7: talking
2026-02-18 15:04:42 -05:00
horizontal_speed: .res 1
2026-02-17 11:19:51 -05:00
2026-02-14 18:08:10 -05:00
cursor_x: .res 1
cursor_y: .res 1
temp_x: .res 1
temp_y: .res 1
2026-02-16 00:27:56 -05:00
temp_mul: .res 1
2026-02-14 18:08:10 -05:00
var_m: .res 1
var_n: .res 1
var_o: .res 1
var_p: .res 1
2026-02-16 20:33:50 -05:00
jump_pressed_last_frame: .res 1
2026-02-14 18:08:10 -05:00
frame_counter: .res 1
2026-02-17 22:52:47 -05:00
last_frame_jumped: .res 1
2026-02-18 16:56:16 -05:00
last_frame_moving: .res 1
2026-02-14 18:08:10 -05:00
.segment "CODE"
main:
ldx #0
:
lda example_palette, X
sta palette, X
inx
cpx #32
bcc :-
jsr setup_background
jsr ppu_update
lda #$40
sta cursor_x
sta cursor_y
lda #0
sta frame_counter
2026-02-17 22:52:47 -05:00
sta last_frame_jumped
2026-02-14 18:08:10 -05:00
jsr init_objects
2026-02-18 15:04:42 -05:00
2026-02-14 18:08:10 -05:00
@loop:
2026-02-18 15:04:42 -05:00
lda $2002
2026-02-14 18:08:10 -05:00
lda frame_counter
clc
adc #1
sta frame_counter
2026-02-16 00:27:56 -05:00
2026-02-19 16:52:08 -05:00
lda scroll_x
adc #1
cmp scroll_x
2026-02-19 13:07:55 -05:00
sta scroll_x
2026-02-19 16:52:08 -05:00
bcs :+
lda scroll_nmt
eor #%00000001
sta scroll_nmt
:
2026-02-18 15:04:42 -05:00
2026-02-16 00:27:56 -05:00
jsr controller
jsr movement
2026-02-18 21:13:38 -05:00
lda player_pos_x
2026-02-16 00:27:56 -05:00
@draw:
2026-02-17 09:26:32 -05:00
jsr draw_player
2026-02-16 00:27:56 -05:00
jsr ppu_update
2026-02-14 18:08:10 -05:00
jmp @loop
2026-02-17 09:26:32 -05:00
draw_player:
lda player_pos_y
sec
2026-02-17 11:19:51 -05:00
sbc #1
sta oam + (4 * 2) + 0
sta oam + (4 * 3) + 0
sec
sbc #16
2026-02-17 09:26:32 -05:00
sta oam + (4 * 0) + 0
sta oam + (4 * 1) + 0
2026-02-19 16:52:08 -05:00
jmp @after
; see if we can skip drawing the player because it's off screen
lda player_pos_x
sec
sbc scroll_x
cmp player_pos_x ; if underflow, nametable bits must be different to continue
bcs :+
lda player_status
clc
ror
eor scroll_nmt
beq @end_position_application
jmp :++
:
; if nothing, nametable bits must be same to continue
lda player_status
clc
ror
eor scroll_nmt
bne @end_position_application
:
@after:
;;;;;;;;;;;;;;;;;;;;;;;;;PUT WHEN VELOCITY IS BEING APPLIED
lda player_pos_x
adc #1
cmp player_pos_x
sta player_pos_x
bcs :+
lda player_status
eor #%00000010
sta player_status
:
;;;;;;;;;;;;;;;;;;;;;;;;;
2026-02-17 11:19:51 -05:00
lda player_status
and #%00000001
cmp #0
bne :+
lda player_pos_x
2026-02-19 13:07:55 -05:00
sec
sbc scroll_x
2026-02-17 11:19:51 -05:00
sta oam + (4 * 1) + 3
sta oam + (4 * 3) + 3
sec
sbc #8
sta oam + (4 * 0) + 3
sta oam + (4 * 2) + 3
jmp :++
:
lda player_pos_x
2026-02-19 13:07:55 -05:00
sec
sbc scroll_x
2026-02-17 11:19:51 -05:00
sta oam + (4 * 0) + 3
sta oam + (4 * 2) + 3
sec
sbc #8
sta oam + (4 * 1) + 3
sta oam + (4 * 3) + 3
:
2026-02-19 16:52:08 -05:00
@end_position_application:
2026-02-17 11:19:51 -05:00
lda player_status
and #%10000000
cmp #0
bne :+
lda #$45
jmp :++
:
lda #$49
:
sta oam + (4 * 0) + 1
clc
adc #2
sta oam + (4 * 1) + 1
lda #$65
sta oam + (4 * 2) + 1
lda #$67
sta oam + (4 * 3) + 1
lda player_status
and #%00000001
cmp #0
beq :+
lda #%01000000
jmp :++
:
lda #%00000000
:
ora #%00000001
sta oam + (4 * 0) + 2
ora #%00000001
sta oam + (4 * 1) + 2
and #%11111100
sta oam + (4 * 2) + 2
and #%11111100
sta oam + (4 * 3) + 2
2026-02-17 09:26:32 -05:00
rts
2026-02-14 18:08:10 -05:00
init_objects:
lda #0
sta var_n
ldx #0
:
lda var_n
clc
adc #8
sta var_n
2026-02-17 09:26:32 -05:00
sta player_pos_y, X ; Set Y position
sta player_pos_x, X ; Set X position
2026-02-14 18:08:10 -05:00
txa
lsr
lsr
sta oam+1, X
inx
inx
inx
inx
cpx #(8*4)
bne :-
2026-02-16 00:27:56 -05:00
lda #0
2026-02-17 09:26:32 -05:00
sta player_vel_x
sta player_vel_y
2026-02-17 11:19:51 -05:00
sta player_status
2026-02-16 00:27:56 -05:00
2026-02-18 20:02:49 -05:00
lda #%00101000
2026-02-18 15:04:42 -05:00
sta horizontal_speed
2026-02-17 22:52:47 -05:00
2026-02-14 18:08:10 -05:00
rts
draw:
2026-02-16 00:27:56 -05:00
@end:
rts
2026-02-14 18:08:10 -05:00
2026-02-16 00:27:56 -05:00
movement:
2026-02-17 11:19:51 -05:00
; Talking
ldx #0
jsr btn_b
cmp #0
beq :+
lda player_status
ora #%10000000
sta player_status
jmp :++
:
lda player_status
and #%01111111
sta player_status
:
2026-02-16 00:27:56 -05:00
; Horizontal velocity
2026-02-14 18:08:10 -05:00
ldx #0
2026-02-16 00:27:56 -05:00
jsr btn_right
cmp #0
beq :+
ldx #1
2026-02-18 15:04:42 -05:00
lda horizontal_speed
2026-02-17 09:26:32 -05:00
sta player_vel_x
2026-02-17 11:19:51 -05:00
lda player_status
and #%11111110
sta player_status
2026-02-18 16:56:16 -05:00
lda frame_counter
sta last_frame_moving
2026-02-16 00:27:56 -05:00
:
jsr btn_left
cmp #0
beq :+
ldx #1
2026-02-18 15:04:42 -05:00
lda horizontal_speed
2026-02-18 16:56:16 -05:00
eor #%11111111
clc
adc #1
2026-02-17 09:26:32 -05:00
sta player_vel_x
2026-02-17 11:19:51 -05:00
lda player_status
ora #%00000001
sta player_status
2026-02-18 16:56:16 -05:00
lda frame_counter
sta last_frame_moving
2026-02-16 00:27:56 -05:00
:
2026-02-18 16:56:16 -05:00
cpx #1 ; skip decay if right or left pressed
2026-02-16 00:27:56 -05:00
beq @end
lda frame_counter
2026-02-18 16:56:16 -05:00
clc
sbc last_frame_moving
and #3
2026-02-16 00:27:56 -05:00
cmp #0
bne @end
2026-02-18 16:56:16 -05:00
lda player_vel_x
and #%01111111
cmp #0
2026-02-17 09:26:32 -05:00
beq @end ; If player_vel_x = 0, skip decay
2026-02-16 00:27:56 -05:00
2026-02-18 16:56:16 -05:00
lda player_vel_x
and #%10000000
; If player_vel_x positive, decrement
2026-02-18 20:02:49 -05:00
bne :++
2026-02-18 15:04:42 -05:00
lda player_vel_x
sec
sbc #16
2026-02-18 16:56:16 -05:00
sta player_vel_x
2026-02-18 20:02:49 -05:00
cmp #0
bpl :+
; negative, clamp to 0
lda #0
sta player_vel_x
:
2026-02-16 00:27:56 -05:00
jmp @end
:
2026-02-17 09:26:32 -05:00
; Else if player_vel_x < 0, increment
2026-02-18 15:04:42 -05:00
lda player_vel_x
clc
adc #16
sta player_vel_x
2026-02-18 20:02:49 -05:00
cmp #0
beq :+
bmi :+
; positive, clamp to 0
lda #0
sta player_vel_x
:
2026-02-16 00:27:56 -05:00
@end:
2026-02-19 16:52:08 -05:00
2026-02-16 00:27:56 -05:00
; Jump
2026-02-16 20:33:50 -05:00
jsr btn_a
2026-02-16 00:27:56 -05:00
cmp #0
2026-02-16 20:33:50 -05:00
beq @fail_jump ; If jump not pressed, forget it
lda jump_pressed_last_frame
cmp #1
beq @fail_jump ; If jump last frame, forget it
; Jump newly pressed this frame
2026-02-17 22:52:47 -05:00
lda #249
2026-02-17 09:26:32 -05:00
sta player_vel_y
2026-02-16 20:33:50 -05:00
2026-02-17 22:52:47 -05:00
lda frame_counter
sta last_frame_jumped
2026-02-16 20:33:50 -05:00
@fail_jump:
jsr btn_a
sta jump_pressed_last_frame
2026-02-16 00:27:56 -05:00
; Gravity
lda frame_counter
2026-02-17 22:52:47 -05:00
sec
sbc last_frame_jumped
and #%00000001
2026-02-16 00:27:56 -05:00
cmp #0
bne :+
2026-02-17 09:26:32 -05:00
lda player_vel_y
2026-02-14 18:08:10 -05:00
clc
adc #1 ; Add 2 to velocity
2026-02-17 09:26:32 -05:00
sta player_vel_y
2026-02-16 00:27:56 -05:00
:
2026-02-14 18:08:10 -05:00
2026-02-16 00:27:56 -05:00
; Apply Y velocity
2026-02-17 09:26:32 -05:00
lda player_pos_y
2026-02-16 00:27:56 -05:00
clc
2026-02-17 09:26:32 -05:00
adc player_vel_y
sta player_pos_y
2026-02-14 18:08:10 -05:00
2026-02-17 22:52:47 -05:00
; Apply X velocity
2026-02-18 15:04:42 -05:00
; Position
lda player_vel_x
and #%10000000
cmp #0
bne :+
; 0: right
lda player_vel_x
2026-02-18 16:56:16 -05:00
and #%01111111
2026-02-18 15:04:42 -05:00
clc
ror
clc
ror
clc
ror
clc
ror
2026-02-18 16:56:16 -05:00
clc
adc player_pos_x
sta player_pos_x ; add pixels
2026-02-18 15:04:42 -05:00
lda player_vel_x
; A contains signed subpixels
clc
adc player_subpos_x ; add subposition and velocity subpixels
and #%00001111
cmp player_subpos_x ; if A (result) is less than current subpos, overflow occurred
2026-02-18 20:02:49 -05:00
sta player_subpos_x
beq @end_add_subpos
bcs @end_add_subpos ; so skip if subpos is smaller than result
2026-02-18 15:04:42 -05:00
ldx player_pos_x
inx
stx player_pos_x
@end_add_subpos:
jmp :++
:
; 1: left
lda player_vel_x
2026-02-18 16:56:16 -05:00
sec
2026-02-18 15:04:42 -05:00
ror
2026-02-18 16:56:16 -05:00
sec
2026-02-18 15:04:42 -05:00
ror
2026-02-18 16:56:16 -05:00
sec
2026-02-18 15:04:42 -05:00
ror
2026-02-18 16:56:16 -05:00
sec
2026-02-18 15:04:42 -05:00
ror
2026-02-18 16:56:16 -05:00
ora #%10000000
2026-02-18 20:02:49 -05:00
clc
adc #1
clc
2026-02-18 16:56:16 -05:00
adc player_pos_x
sta player_pos_x ; add pixels
2026-02-18 15:04:42 -05:00
lda player_vel_x
; A contains signed subpixels
clc
adc player_subpos_x ; add subposition and velocity subpixels
and #%00001111
cmp player_subpos_x ; if A (result) is greater than current subpos, underflow occurred
2026-02-18 20:02:49 -05:00
sta player_subpos_x
beq @end_sub_subpos
bcc @end_sub_subpos ; so skip if subpos is bigger than result
2026-02-18 15:04:42 -05:00
ldx player_pos_x
dex
2026-02-18 20:02:49 -05:00
stx player_pos_x
2026-02-18 15:04:42 -05:00
@end_sub_subpos:
:
2026-02-17 22:52:47 -05:00
; load x pos, filter blocks, check up and down
lda player_vel_y
cmp #0
bmi :+ ; branch if moving up
jsr downward_collision_check
jsr left_collision_check
jsr right_collision_check
jsr upward_collision_check
jmp :++
:
jsr upward_collision_check
jsr left_collision_check
jsr right_collision_check
jsr downward_collision_check
:
rts
2026-02-16 00:27:56 -05:00
; Keep grounded
cmp #200
bcc :+
lda #0
2026-02-17 09:26:32 -05:00
sta player_vel_y
2026-02-16 00:27:56 -05:00
lda #200
2026-02-17 09:26:32 -05:00
sta player_pos_y
2026-02-16 00:27:56 -05:00
:
2026-02-16 20:33:50 -05:00
; Bonk
lda #8
2026-02-17 09:26:32 -05:00
cmp player_pos_y
2026-02-16 20:33:50 -05:00
bcc :+
lda #0
2026-02-17 09:26:32 -05:00
sta player_vel_y
2026-02-16 20:33:50 -05:00
lda #8
2026-02-17 09:26:32 -05:00
sta player_pos_y
2026-02-16 20:33:50 -05:00
:
2026-02-16 00:27:56 -05:00
rts
2026-02-14 18:08:10 -05:00
setup_background:
2026-02-16 20:33:50 -05:00
lda $2002 ; reset latch
lda #$20
sta $2006
lda #$00
sta $2006
; empty nametable
lda #0
ldy #30 ; 30 rows
:
ldx #32 ; 32 columns
:
sta $2007
dex
bne :-
dey
bne :--
2026-02-19 14:04:29 -05:00
; ------------- Nametable 1: level
2026-02-16 20:33:50 -05:00
lda $2002
2026-02-19 14:04:29 -05:00
lda #$20
2026-02-16 20:33:50 -05:00
sta $2006
lda #$00
sta $2006
ldy #0
2026-02-19 14:04:29 -05:00
@row_start_nmt1:
2026-02-16 20:33:50 -05:00
ldx #0
:
txa
pha
; index is (Y * 16) + X
stx temp_x
lda #16
jsr mul_y
clc
adc temp_x
tax
lda level, X
ldx #5
jsr mul_x
tax
lda metatiles+0, X
sta $2007
lda metatiles+1, X
sta $2007
pla
tax
inx
cpx #16
bne :-
; again
ldx #0
:
txa
pha
; index is (Y * 16) + X
stx temp_x
lda #16
jsr mul_y
clc
adc temp_x
tax
lda level, X
ldx #5
jsr mul_x
tax
lda metatiles+2, X
sta $2007
lda metatiles+3, X
sta $2007
pla
tax
inx
cpx #16
bne :-
iny
cpy #15
2026-02-19 14:04:29 -05:00
bne @row_start_nmt1
2026-02-16 20:33:50 -05:00
; clear attributes
2026-02-18 15:04:42 -05:00
;lda #0
;ldx #64 ; 64 bytes
;:
; lda #%11100100
;
; sta $2007
; dex
; bne :-
2026-02-16 20:33:50 -05:00
lda #0
2026-02-18 15:04:42 -05:00
sta $50
2026-02-16 20:33:50 -05:00
2026-02-18 15:04:42 -05:00
ldy #0
:
tya
pha
2026-02-16 20:33:50 -05:00
2026-02-18 15:04:42 -05:00
ldx #0
:
tya
pha
txa
pha
2026-02-16 20:33:50 -05:00
2026-02-18 15:04:42 -05:00
tya
asl
asl
asl
asl
asl
sta temp_y
2026-02-16 20:33:50 -05:00
2026-02-18 15:04:42 -05:00
txa
asl
2026-02-16 20:33:50 -05:00
2026-02-18 15:04:42 -05:00
clc
adc temp_y
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
tax
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
lda level, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
sta temp_x
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
lda level+1, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
adc temp_x
sta temp_x
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
lda level+16, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
asl
asl
adc temp_x
sta temp_x
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
lda level+17, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
asl
asl
asl
asl
adc temp_x
sta $2007
2026-02-16 00:27:56 -05:00
2026-02-18 15:04:42 -05:00
ldx $50
inx
stx $50
2026-02-14 18:08:10 -05:00
2026-02-18 15:04:42 -05:00
sta $60, X
2026-02-14 18:08:10 -05:00
2026-02-18 15:04:42 -05:00
pla
tax
pla
tay
inx
cpx #8
bne :-
2026-02-14 18:08:10 -05:00
2026-02-18 15:04:42 -05:00
pla
tay
iny
cpy #8
bne :--
2026-02-19 14:04:29 -05:00
; ---------------- End nametable 1: Level
; ---------------- Begin nametable 2: Level 2
lda $2002
lda #$24
sta $2006
lda #$00
sta $2006
ldy #0
@row_start_nmt2:
ldx #0
:
txa
pha
2026-02-14 18:08:10 -05:00
2026-02-19 14:04:29 -05:00
; index is (Y * 16) + X
stx temp_x
lda #16
jsr mul_y
clc
adc temp_x
tax
lda level2, X
ldx #5
jsr mul_x
tax
lda metatiles+0, X
sta $2007
lda metatiles+1, X
sta $2007
pla
tax
inx
cpx #16
bne :-
; again
ldx #0
:
txa
pha
; index is (Y * 16) + X
stx temp_x
lda #16
jsr mul_y
clc
adc temp_x
tax
lda level2, X
ldx #5
jsr mul_x
tax
lda metatiles+2, X
sta $2007
lda metatiles+3, X
sta $2007
pla
tax
inx
cpx #16
bne :-
iny
cpy #15
bne @row_start_nmt2
; clear attributes
;lda #0
;ldx #64 ; 64 bytes
;:
; lda #%11100100
;
; sta $2007
; dex
; bne :-
lda #0
sta $50
ldy #0
2026-02-19 13:07:55 -05:00
:
2026-02-19 14:04:29 -05:00
tya
pha
ldx #0
:
tya
pha
txa
pha
tya
asl
asl
asl
asl
asl
sta temp_y
txa
asl
clc
adc temp_y
tax
lda level2, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
sta temp_x
lda level2+1, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
adc temp_x
sta temp_x
lda level2+16, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
asl
asl
adc temp_x
sta temp_x
lda level2+17, X
tay
lda #5
jsr mul_y
tay
lda metatiles+4, Y
asl
asl
asl
asl
asl
asl
adc temp_x
sta $2007
ldx $50
inx
stx $50
sta $60, X
pla
tax
pla
tay
inx
cpx #8
bne :-
pla
tay
iny
cpy #8
bne :--
2026-02-19 13:07:55 -05:00
2026-02-18 15:04:42 -05:00
rts
2026-02-14 18:08:10 -05:00
2026-02-16 00:27:56 -05:00
mul_x:
2026-02-16 20:33:50 -05:00
cmp #0
beq @zero
cpx #0
beq @zero
2026-02-16 00:27:56 -05:00
sta temp_mul
2026-02-16 20:33:50 -05:00
txa
pha
2026-02-16 00:27:56 -05:00
lda #0
:
clc
adc temp_mul
dex
bne :-
2026-02-16 20:33:50 -05:00
sta temp_mul
pla
tax
lda temp_mul
rts
@zero:
lda #0
2026-02-16 00:27:56 -05:00
rts
mul_y:
2026-02-16 20:33:50 -05:00
cmp #0
beq @zero
cpy #0
beq @zero
2026-02-16 00:27:56 -05:00
sta temp_mul
2026-02-16 20:33:50 -05:00
tya
pha
2026-02-16 00:27:56 -05:00
lda #0
:
clc
adc temp_mul
dey
bne :-
2026-02-16 20:33:50 -05:00
sta temp_mul
pla
tay
lda temp_mul
rts
@zero:
lda #0
2026-02-16 00:27:56 -05:00
rts
controller:
lda #1
sta $4016
sta buttons
lda #0
sta $4016
:
lda $4016
lsr
rol buttons
bcc :-
rts
btn_right:
lda buttons
and #%00000001
rts
btn_left:
lda buttons
and #%00000010
lsr
rts
btn_down:
lda buttons
and #%00000100
lsr
lsr
rts
btn_up:
lda buttons
and #%00001000
lsr
lsr
lsr
rts
btn_start:
lda buttons
and #%00010000
lsr
lsr
lsr
lsr
rts
btn_select:
lda buttons
and #%00100000
lsr
lsr
lsr
lsr
lsr
rts
btn_b:
lda buttons
and #%01000000
lsr
lsr
lsr
lsr
lsr
lsr
rts
btn_a:
lda buttons
and #%10000000
lsr
lsr
lsr
lsr
lsr
lsr
lsr
rts
2026-02-17 22:52:47 -05:00
downward_collision_check:
lda #0
sta var_n
@begin_check:
lda player_pos_x
ldx var_n
cpx #0
bne :+
sec
2026-02-18 20:02:49 -05:00
sbc #5
2026-02-17 22:52:47 -05:00
jmp :++
:
clc
2026-02-18 20:02:49 -05:00
adc #4
2026-02-17 22:52:47 -05:00
:
; divide by 16
clc
ror
clc
ror
clc
ror
clc
ror
sta temp_x
lda player_pos_y
; divide by 16
clc
adc #8
clc
ror
clc
ror
clc
ror
clc
ror
tay
lda #16
jsr mul_y
adc temp_x
tax
lda level, X
cmp #0
beq :+
tya
asl
asl
asl
asl
sec
sbc #8
cmp player_pos_y
bcs :+
sta player_pos_y
lda #0
sta player_vel_y
:
ldx var_n
inx
stx var_n
cpx #1
beq @begin_check
rts
upward_collision_check:
lda #0
sta var_n
@begin_check:
lda player_pos_x
ldx var_n
cpx #0
bne :+
sec
2026-02-18 20:02:49 -05:00
sbc #5
2026-02-17 22:52:47 -05:00
jmp :++
:
clc
2026-02-18 20:02:49 -05:00
adc #4
2026-02-17 22:52:47 -05:00
:
; divide by 16
clc
ror
clc
ror
clc
ror
clc
ror
sta temp_x
lda player_pos_y
; divide by 16
sec
sbc #8
clc
ror
clc
ror
clc
ror
clc
ror
tay
lda #16
jsr mul_y
adc temp_x
tax
lda level, X
cmp #0
beq :+
iny
tya
asl
asl
asl
asl
clc
adc #8
cmp player_pos_y
bcc :+
sta player_pos_y
lda #0
sta player_vel_y
:
ldx var_n
inx
stx var_n
cpx #1
beq @begin_check
rts
right_collision_check:
lda #0
sta var_n
@begin_check:
lda player_pos_x
; divide by 16
clc
adc #8
clc
ror
clc
ror
clc
ror
clc
ror
sta temp_x
lda player_pos_y
ldx var_n
cpx #0
bne :+
sec
sbc #7
jmp :++
:
clc
adc #6
:
; divide by 16
clc
ror
clc
ror
clc
ror
clc
ror
tay
lda #16
jsr mul_y
adc temp_x
tax
lda level, X
cmp #0
beq :+
lda temp_x
asl
asl
asl
asl
sec
sbc #8
cmp player_pos_x
bcs :+
sta player_pos_x
lda #0
sta player_vel_x
:
ldx var_n
inx
stx var_n
cpx #1
beq @begin_check
rts
left_collision_check:
lda #0
sta var_n
@begin_check:
lda player_pos_x
; divide by 16
sec
sbc #8
clc
ror
clc
ror
clc
ror
clc
ror
sta temp_x
lda player_pos_y
ldx var_n
cpx #0
bne :+
sec
sbc #7
jmp :++
:
clc
adc #6
:
; divide by 16
clc
ror
clc
ror
clc
ror
clc
ror
tay
lda #16
jsr mul_y
adc temp_x
tax
lda level, X
cmp #0
beq :+
lda temp_x
clc
adc #1
asl
asl
asl
asl
clc
adc #8
cmp player_pos_x
bcc :+
sta player_pos_x
lda #0
sta player_vel_x
:
ldx var_n
inx
stx var_n
cpx #1
beq @begin_check
rts