-
Notifications
You must be signed in to change notification settings - Fork 0
/
pong.asm
767 lines (637 loc) · 10.4 KB
/
pong.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.inesprg 1
.ineschr 1
.inesmap 0
.inesmir 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; VARIABLES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.rsset $0000
gamestate .rs 1
ball_x .rs 1
ball_y .rs 1
ball_u .rs 1
ball_r .rs 1
ball_x_speed .rs 1
ball_y_speed .rs 1
paddle_1_y .rs 1
paddle_2_y .rs 1
paddle_1_u .rs 1
paddle_2_u .rs 1
ctrl_1 .rs 1
ctrl_2 .rs 1
score_1 .rs 1
score_2 .rs 1
rand_seed .rs 1
pointerLo .rs 1
pointerHi .rs 1
STATE_TITLE = $00
STATE_PLAYING = $01
STATE_GAMEOVER = $02
RWALL = $F4
UWALL = $20
DWALL = $E0
LWALL = $04
PADDLE_1_X = $20
PADDLE_2_X = $E0
PADDLE_1_H = $18
PADDLE_2_H = $18
PADDLE_SPEED= $02
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PROGRAM - MAIN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.bank 0
.org $C000
vblankwait:
bit $2002
bpl vblankwait
rts
; update random num
prng:
ldx #$08
lda rand_seed+0
prng_1:
asl A
rol rand_seed+1
bcc prng_2
eor #$2D
prng_2:
dex
bne prng_1
sta rand_seed+0
cmp #$00 ; reload flags
rts
LoadBG:
lda $2002
lda #$20 ; remember top row doesn't get rendered
sta $2006
lda #$00
sta $2006
ldx #$00
ldy #$00
; Load entire BG
LoadBGLoop:
lda [pointerLo], y ; can only be used with y
sta $2007
iny
bne LoadBGLoop
inc pointerHi
inx
cpx #$04
bne LoadBGLoop
rts
; ===================
; === START RESET ===
RESET:
; disable irq
sei
cld
ldx #%01000000
stx $4017
; set up stack
ldx #$FF
txs
ldx #$00
stx $2000 ; disable NMI
stx $2001 ; disable rendering
stx $4010 ; disable dmc
; 1st vblank
jsr vblankwait
ldx #$00
clrmem:
lda #$00
sta $0000, x
sta $0100, x
sta $0300, x
sta $0400, x
sta $0500, x
sta $0600, x
sta $0700, x
lda #$FE
sta $0300, x
inx
bne clrmem ; loop until x overflows
; 2nd vblank
jsr vblankwait
LoadSprites:
ldx #$00
LoadSpritesLoop:
lda sprites, x
sta $0200, x
inx
cpx #$24
bne LoadSpritesLoop
LoadPalette:
lda $2002
lda #$3F
sta $2006
lda #$00
sta $2006
ldx #$00
LoadPaletteLoop:
lda palette, x
sta $2007
inx
cpx #$20
bne LoadPaletteLoop
; bg to title
lda #LOW(title_bg)
sta pointerLo
lda #HIGH(title_bg)
sta pointerHi
jsr LoadBG
; set ball init
lda #$80
sta ball_x
sta ball_y
lda #$01
sta ball_r
lda #$01
sta ball_x_speed
lda #$01
sta ball_y_speed
; set paddles init
lda #$80
sta paddle_1_y
sta paddle_2_y
; set init state
lda #STATE_TITLE
sta gamestate
; set seed
lda #$66
sta rand_seed
; set ppu
lda #%10010000
sta $2000
lda #%00011110
sta $2001
Forever:
jmp Forever
; === END RESET ===
; =================
; ===========================
; === START NMI INTERRUPT ===
NMI:
; set RAM address to 0200
lda #$00
sta $2003
lda #$02
sta $4014
; ppu clean up
lda #%10010000
sta $2000 ; set PPUCTRL
lda #%00011110
sta $2001 ; set PPUMASK
lda #%00000000
sta $2005 ; disable PPU scrolling
sta $2005
; read controllers
jsr ReadCtrl1
jsr ReadCtrl2
; GAME ENGINE
GameEngine:
;jmp GameEngineDone
lda gamestate
cmp #STATE_TITLE
beq RunTitle
lda gamestate
cmp #STATE_PLAYING
beq RunPlaying
lda gamestate
cmp #STATE_GAMEOVER
beq RunGameOver
GameEngineDone:
jsr UpdateSprites
rti
RunTitle:
; Running title
; disable sprites
lda #%00001110
sta $2001 ; set PPUMASK
; check for start pressed
lda ctrl_1
and #%00010000
beq GameEngineDone
; start game
lda #STATE_PLAYING
sta gamestate
lda #%00010000 ; disable NMI
sta $2000
lda #%00000000 ; disable rendering
sta $2001
; load bg
; NOTE: don't load BG on every NMI interrupt
lda #LOW(arena_bg)
sta pointerLo
lda #HIGH(arena_bg)
sta pointerHi
jsr LoadBG
lda #%10010000
sta $2000
lda #%00011110
sta $2001
jmp GameEngineDone
RunGameOver:
; Running game over screen
; disable sprites
lda #%00001110
sta $2001 ; set PPUMASK
; check for start pressed
lda ctrl_1
and #%00010000
beq GameEngineDone
; play again
jmp RESET
jmp GameEngineDone
RunPlaying:
; Running main game
; update ball location
; move ball vert
lda ball_u
beq MoveBallDown
lda ball_y
sec
sbc ball_y_speed
sta ball_y
jmp MoveBallVertDone
MoveBallDown:
lda ball_y
clc
adc ball_y_speed
sta ball_y
MoveBallVertDone:
; move ball hori
lda ball_r
beq MoveBallLeft
lda ball_x
clc
adc ball_x_speed
sta ball_x
jmp MoveBallHoriDone
MoveBallLeft:
lda ball_x
sec
sbc ball_x_speed
sta ball_x
MoveBallHoriDone:
; move paddle locations
MovePaddle1:
; hit up wall
lda paddle_1_y
sec
sbc #$08
cmp #UWALL
bcc MovePaddle1UpDone
; move paddle up
lda ctrl_2
and #%0001000
beq MovePaddle1UpDone
lda paddle_1_y
sec
sbc #PADDLE_SPEED
sta paddle_1_y
lda #$01
sta paddle_1_u
MovePaddle1UpDone:
; hit down wall
lda paddle_1_y
clc
adc #$08
cmp #DWALL
bcs MovePaddle1DownDone
; move paddle down
lda ctrl_2
and #%0000100
beq MovePaddle1DownDone
lda paddle_1_y
clc
adc #PADDLE_SPEED
sta paddle_1_y
lda #$00
sta paddle_1_u
MovePaddle1DownDone:
; same as paddle 1
MovePaddle2:
lda paddle_2_y
sec
sbc #$08
cmp #UWALL
bcc MovePaddle2UpDone
lda ctrl_1
and #%0001000
beq MovePaddle2UpDone
lda paddle_2_y
sec
sbc #PADDLE_SPEED
sta paddle_2_y
lda #$01
sta paddle_2_u
MovePaddle2UpDone:
lda paddle_2_y
clc
adc #$08
cmp #DWALL
bcs MovePaddle2DownDone
lda ctrl_1
and #%0000100
beq MovePaddle2DownDone
lda paddle_2_y
clc
adc #PADDLE_SPEED
sta paddle_2_y
lda #$00
sta paddle_2_u
MovePaddle2DownDone:
; wall bounces
BounceRightWall:
lda ball_x
cmp #RWALL
bcc RightWallDone
jsr ScorePointPaddle1
jsr RespawnBall
jmp GameEngineDone
RightWallDone:
BounceLeftWall:
lda ball_x
cmp #LWALL
bcs LeftWallDone
jsr ScorePointPaddle2
jsr RespawnBall
jmp GameEngineDone
LeftWallDone:
BounceUpWall:
lda ball_y
cmp #UWALL
bcs UpWallDone
lda #$00
sta ball_u
UpWallDone:
BounceDownWall:
lda ball_y
cmp #DWALL
bcc DownWallDone
lda #$01
sta ball_u
DownWallDone:
; paddle bounces
BouncePaddle1:
lda #PADDLE_1_X
clc
adc #$03
cmp ball_x
bcc BouncePaddle1Done
lda #PADDLE_1_X
sec
sbc #$03
cmp ball_x
bcs BouncePaddle1Done
lda paddle_1_y
sec
sbc #$0B ; 08 for paddle and 03 for ball
cmp ball_y
bcs BouncePaddle1Done
lda paddle_1_y
clc
adc #$0B
cmp ball_y
bcc BouncePaddle1Done
lda #$01
sta ball_r
; apply prng to paddle
jsr prng
jsr PRNGPaddleX
jsr prng
jsr PRNGPaddleY_1
BouncePaddle1Done:
BouncePaddle2:
lda #PADDLE_2_X
sec
sbc #$03
cmp ball_x
bcs BouncePaddle2Done
lda #PADDLE_2_X
clc
adc #$03
cmp ball_x
bcc BouncePaddle2Done
lda paddle_2_y
sec
sbc #$0B
cmp ball_y
bcs BouncePaddle2Done
lda paddle_2_y
clc
adc #$0B
cmp ball_y
bcc BouncePaddle2Done
lda #$00
sta ball_r
; apply prng to paddle
jsr prng
jsr PRNGPaddleX
jsr prng
jsr PRNGPaddleY_2
BouncePaddle2Done:
jmp GameEngineDone
; END GAME ENGINE
; read controllers
ReadCtrl1:
lda #$01
sta $4016
lda #$00
sta $4016
ldx #$08
ReadCtrl1Loop:
lda $4016
lsr A
rol ctrl_1
dex
bne ReadCtrl1Loop
rts
ReadCtrl2:
lda #$01
sta $4016
lda #$00
sta $4016
ldx #$08
ReadCtrl2Loop:
lda $4017
lsr A
rol ctrl_2
dex
bne ReadCtrl2Loop
rts
; update sprites
UpdateSprites:
lda ball_y
sta $0218
lda ball_x
sta $021B
; paddle 1 movement
lda paddle_1_y
sta $0204
sec
sbc #$08
sta $0200
clc
adc #$0F
sta $0208
; paddle 2 movement
lda paddle_2_y
sta $0210
sec
sbc #$08
sta $020C
clc
adc #$0F
sta $0214
; Score
lda score_1
clc
adc #$02 ; offset to get to 0 sprite
sta $0221
lda score_2
clc
adc #$02
sta $021D
rts
ScorePointPaddle1:
lda score_1
clc
adc #$01
sta score_1
; TEMP check for win
lda score_1
cmp #$07
bne Score1Done
lda #STATE_GAMEOVER
sta gamestate
jsr LoadGameOver
Score1Done:
rts
ScorePointPaddle2:
lda score_2
clc
adc #$01
sta score_2
; TEMP check for win
lda score_2
cmp #$07
bne Score2Done
lda #STATE_GAMEOVER
sta gamestate
jsr LoadGameOver
Score2Done:
rts
RespawnBall:
jsr prng
and #$02
beq RespawnRight
RespawnLeft:
lda #$00
sta ball_r
jmp RespawnDirDone
RespawnRight:
lda #$01
sta ball_r
RespawnDirDone:
jsr prng
and #$01
clc
adc #$01
sta ball_x_speed
jsr prng
and #$01
clc
adc #$01
sta ball_y_speed
lda #$80
sta ball_x
sta ball_y
rts
; apply prng to paddle
; do prng first!
; fix slope of ball!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
PRNGPaddleX:
and #$01
clc
adc #$01
sta ball_x_speed
rts
PRNGPaddleY_1:
and #$01
clc
adc #$01
sta ball_y_speed
lda paddle_1_u
sta ball_u
rts
PRNGPaddleY_2:
and #$01
clc
adc #$01
sta ball_y_speed
lda paddle_2_u
sta ball_u
rts
LoadGameOver:
; load game over
lda #%00010000 ; disable NMI
sta $2000
lda #%00000000 ; disable rendering
sta $2001
; load bg
; NOTE: don't load BG on every NMI interrupt
lda #LOW(game_over_bg)
sta pointerLo
lda #HIGH(game_over_bg)
sta pointerHi
jsr LoadBG
lda #%10010000
sta $2000
lda #%00011110
sta $2001
rts
; === END NMI INTERRUPT ===
; =========================
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PROGRAM - INTERRUPTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.bank 1
.org $E000
sprites:
; Paddle 1
.db $78,$01,$00,$20 ; 00
.db $80,$01,$00,$20 ; 04
.db $88,$01,$00,$20 ; 08
; Paddle 2
.db $78,$01,$00,$E0 ; 0C
.db $80,$01,$00,$E0 ; 10
.db $88,$01,$00,$E0 ; 14
; Ball 1
.db $80,$00,$00,$80 ; 18
; Score 2
.db $10,$02,$00,$A0 ; 1C
; Score 1
.db $10,$02,$00,$60 ; 20
palette:
.db $0F,$17,$28,$39, $0F,$17,$28,$39, $0F,$17,$28,$39, $0F,$17,$28,$39
.db $0F,$17,$28,$39, $0F,$17,$28,$39, $0F,$17,$28,$39, $0F,$17,$28,$39
title_bg:
.incbin "title.nam"
arena_bg:
.incbin "arena.nam"
game_over_bg:
.incbin "game_over.nam"
.org $FFFA
.dw NMI
.dw RESET
.dw 0 ; no irq interrupt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CHARACTER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.bank 2
.org $0000
.incbin "graphics.chr"