This repository was archived by the owner on Mar 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.asm
724 lines (671 loc) · 10.2 KB
/
game.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
.MEMORYMAP
SLOTSIZE $4000
DEFAULTSLOT 0
SLOT 0 $0000
SLOT 1 $4000
SLOT 2 $8000 SIZE $2000 "VRAM"
SLOT 3 $C000 SIZE $1000 "WRAM"
SLOT 4 $FF80 SIZE $80 "HRAM"
.ENDME
.ROMBANKMAP
BANKSTOTAL 2
BANKSIZE $4000
BANKS 2
.ENDRO
.STRUCT OAMSPRITE
Y DB
X DB
IDX DB
FLAGS DB
.ENDST
; POINT WITH 8.8 FIXED POINT COORDINATES
.STRUCT POINT88
XL DB
XH DB
YL DB
YH DB
.ENDST
.ENUM $FE00
SPRITES INSTANCEOF OAMSPRITE 40
.ENDE
.ENUM $80
; INITALIZED HRAM VARIABLES HERE
; HRAM DMA ROUTINE HERE
; WE SAY IT IS DB BUT IT HAS VARIABLE LENGTH
; WHICH MEANS IT MUST BE AT THE END OF THIS SECTION
HRAMDMA DB
.ENDE
; BSS SECTION
.ENUM $C000
; 1 = VBLANK INTR OCCURRED
STATICFLAGS DB
; 01,02,04,08 = A,B,SEL,START
; 10,20,40,80 = R,L,U,D
; PREVINPUTFLAGS SHOULD BE AFTER INPUTFLAGS
; TO DO TRICKS LIKE THIS
;
; LD A,(HL+) ; MOVE INPUT TO PREV
; LD (HL-),A
INPUTFLAGS DB
PREVINPUTFLAGS DB
; BULLET VARIABLES (TODO: REMOVE MAGIC NUMBER)
BULLETPOS INSTANCEOF POINT88 16
BULLETOAMADDRS DS 16
NBULLETS DB
.ENDE
; DATA SECTION
.ENUM $C800
; OAM SHADOW BUFFER FOR DMA ON VBLANK
OAMSHADOW INSTANCEOF OAMSPRITE 40
PLAYERPOS INSTANCEOF POINT88
.ENDE
; MEM* RST ROUTINES
; THESE ARE VERY COMMON SO MAKE THEM RST ROUTINES
; THERE ARE 256-BYTE BLOCK AND BYTE MEM ROUTINES
; COUNTS ARE NON-ZERO AND IF THE COUNT IS 256, USE 0 INSTEAD
; THEY'RE DESIGNED TO PERFORM THE FOLLOWING MEM ROUTINES
;
; LD HL,ADDR
; XOR A
; LD BC,$1234
; RST $8 ; MEMSETLNZ
; RST $0 ; MEMSETHNZ
;
; NOTE THAT THE BYTE ROUTINES DO NOT TOUCH THE B REGISTER,
; SO YOU DO NOT HAVE TO PUSH THAT REGISTER ONTO THE STACK
; BEFORE CALLING THESE RST FUNCTIONS. SOME CODE RELIES ON THIS.
; MEMSETHNZ = RST $0
; HL = DEST
; A = DATA
; B = NONZERO # OF 256-BYTE BLOCKS
.ORG $0
MEMSETHNZ:
LD C,0
MEMSETHNZLOOP:
RST $8
DEC B
JR NZ, MEMSETHNZLOOP
RET
; MEMSETLNZ = RST $8
; HL = DEST
; A = DATA
; C = NONZERO # OF BYTES
.ORG $8
MEMSETLNZ:
LD (HL+),A
DEC C
JR NZ, MEMSETLNZ
RET
; MEMCPYHNZ = RST $10
; HL = DEST
; DE = SRC
; C = NONZERO # OF 256-BYTE BLOCKS
.ORG $10
MEMCPYHNZ:
LD C,0
MEMCPYHNZLOOP:
RST $18
DEC B
JR NZ, MEMCPYHNZLOOP
.ORG $18
; MEMCPYLNZ = RST $18
; HL = DEST
; DE = SRC
; C = NONZERO # OF BYTES
MEMCPYLNZ:
LD A,(DE)
LD (HL+),A
INC DE
DEC C
JR NZ,MEMCPYLNZ
RET
; ADD16 = RST $20
; HL = ADDRESS OF 16-BIT LHS OP AND RESULT
; DE = 16-BIT RHS OP
; ALL REGISTERS PRESERVED EXCEPT AF
.ORG $20
ADD16:
LD A,E
ADD (HL)
LD (HL+),A
LD A,D
ADC (HL)
LD (HL-),A
RET
; SUB16 = RST $28
; HL = ADDRESS OF 16-BIT LHS OP AND RESULT
; DE = 16-BIT RHS OP
; ALL REGISTERS PRESERVED EXCEPT AF
.ORG $28
SUB16:
LD A,(HL)
SUB E
LD (HL+),A
LD A,(HL)
SBC D
LD (HL-),A
RET
.ORG $30
RET
.ORG $38
RET
.ORG $40
VBLANKTHUNK:
PUSH BC
PUSH DE
PUSH HL
PUSH AF
JR VBLANKINTR
.ORG $68
VBLANKINTR:
; SET VBLANK FLAG
LD HL,STATICFLAGS
SET $0,(HL)
; MOVE INPUTFLAGS TO PREVINPUTFLAGS
LD HL,INPUTFLAGS
LD A,(HL+)
LD (HL-),A
LD A,$10
; SET INPUT FLAGS
; READ ACTION BUTTONS FIRST
CALL READINPUT
LD (HL),A
; READ DIRECTIONAL BUTTONS SECOND
LD A,$20
CALL READINPUT
; PUT DIRECTIONS IN HIGH NIBBLE
; LEAVE ACTIONS IN LOW NIBBLE
SWAP A
OR (HL)
LD (HL),A
CALL $FF00+HRAMDMA
INTRPROLOG:
POP AF
POP HL
POP DE
POP BC
RETI
; INTERNAL VBLANK ROUTINE TO READ INPUT
; A REGISTER CONTAINS SELECTION TO WRITE TO P1 PORT
; CLOBBERS: C,A
; RETAINS: DE,HL
; RETURNS: INPUTS FROM P1 IN A REGISTER (TOP NIBBLE ZERO)
READINPUT:
LD C,0
LDH (C),A
LD E,4
INPUTLOOP:
LDH A,(C)
DEC E
JR NZ,INPUTLOOP
XOR $0F
AND $0F
RET
.ORG $100
JP START
NOP
.GBHEADER
NAME "SPACESHIP"
LICENSEECODENEW "1A"
CARTRIDGETYPE 1
RAMSIZE 0
ROMDMG
COUNTRYCODE 1
DESTINATIONCODE 1
NINTENDOLOGO
VERSION $01
.ENDGB
.ORG $150
START:
; DISABLE INTERRUPTS FOR ANY INITIAL PROCESSING
DI
; MEMSET BSS TO 0 AND SET SP
LD SP,$D000
LD HL,$C000
LD B,$1
XOR A
RST $0
; MEMSET HRAM TO 0
LD HL,$FF80
LD C,$80
RST $8
; COPY SPRITE SECTION
; ZERO OUT THE REST OF THE BYTES OF OAM
LD HL,OAMSHADOW
LD C,$10
LD DE,SPRITESECTION
RST $18
LD C,$90
XOR A
RST $8
; COPY DATA SECTION
LD C,$4
RST $18
; COPY HRAM SECTION
LD HL,$FF80
LD C,HRAMSECTIONEND-HRAMSECTION
RST $18
; SET MASTER SOUND REGISTERS TO INITIAL VALUES
; RESET APU
LD C,$24
XOR A
LDH (C),A
LD A,$80
LDH (C),A
; BLAST AT FULL VOLUME
LD C,$24
LD A,$FF
LDH (C),A
; MIX ONLY CHANNEL 1 FOR NOW
INC C
LD A,$11
LDH (C),A
; RE-ENABLE INTERRUPTS
EI
; ENABLE INTERRUPTS WE WANT (VBLANK)
LD A,1
LDH ($FF),A
; WAIT FOR VBLANK, TURN OFF PPU, THEN CONTROL PPU
; DISABLE PPU FOR NOW
CALL VBLANKINTRWAIT
LD A,0
LDH ($40),A
LD HL,$8000
LD B,$20
RST $0
; ZERO OAM
LD HL,$FE00
LD C,$A0
RST $8
; LOAD 1 BPP TILE DATA (TILE 0 = EMPTY TILE)
LD HL,$8010
LD DE,BPP1TILEDATA
LD C,$3
CALL BPP1TILECPY
; LOAD INITIAL OBJ PALETTES
LD A,$9C
LDH ($48),A
; RE-ENABLE PPU, ENABLE OBJS
LD A,$82
LDH ($40),A
MAINLOOP:
CALL VBLANKINTRWAIT
; TODO: IMPLEMENT PAUSING
; CALL THESE WHEN THE GAME IS NOT PAUSED
CALL UPDATEFROMINPUT
CALL UPDATEENTITIES
; ALWAYS CALL THIS REGARDLESS IF THE GAME IS PAUSED
CALL UPDATEOAM
JR MAINLOOP
UPDATEENTITIES:
LD A,(NBULLETS)
OR A
JR Z,UPDATEBULLETSDONE
; C = ITERATOR
LD C,A
UPDATEBULLETS:
LD A,C
DEC A
ADD A
ADD A
LD DE,$0327
LD HL,BULLETPOS+2
ADD A,L
LD L,A
RST $28
INC HL
LD A,(HL)
LD B,160
CP B
PUSH BC
CALL NC,DESPAWNBULLET
POP BC
DEC C
JR NZ, UPDATEBULLETS
UPDATEBULLETSDONE:
RET
; UPDATE BASED ON INPUT
UPDATEFROMINPUT:
LD DE, $0102
LD HL, PLAYERPOS
LD A,(INPUTFLAGS)
LD B,A
; MOVE X POSITION
MOVESHIPLEFT:
BIT $5,B
JR Z,MOVESHIPRIGHT
RST $28
MOVESHIPRIGHT:
BIT $4,B
JR Z,MOVESHIPDOWN
RST $20
; INC HL BY 2 TO MOVE Y POSITION
MOVESHIPDOWN:
INC HL
INC HL
BIT $7,B
JR Z,MOVESHIPUP
RST $20
MOVESHIPUP:
BIT $6,B
JR Z,MOVESHIPDONE
RST $28
; SHOOT BULLETS!
; WE WANT TO DO THIS ON A BUTTON PRESS
; SO COMPUTE NEW FLAGS USING PREVINPUTFLAGS
MOVESHIPDONE:
LD A,(PREVINPUTFLAGS)
CPL
OR B
LD B,A
BIT $1,B
RET NZ
; ONLY SPAWN A BULLET IF WE HAVE ROOM (16 BULLETS)
; FALLTHROUGH TO SPAWN BULLET
LD D,H
LD E,L
LD HL,NBULLETS
LD A,$15
CP (HL)
RET C
LD H,D
LD L,E
; LOAD MODIFIED XY INTO DE TO USE FOR SPAWN BULLET
INC HL
LD A,(HL-)
SUB A,$2
LD E,A
DEC HL
LD A,(HL-)
ADD A,$4
LD D,A
; OTHER ENTITIES CAN USE THIS TOO FOR
; SPAWNING BULLETS, NOT JUST THE SHIP
; DE = XY POSITION
; ALL REGISTERS CLOBBERED EXCEPT B REGISTER
SPAWNBULLET:
LD A,(NBULLETS)
ADD A
ADD A
LD HL,BULLETPOS
ADD A,L
LD L,A
XOR A
LD (HL+),A
LD (HL),D
INC HL
LD (HL+),A
LD (HL),E
INC HL
LD C,$1
CALL OAMALLOC
; SAVE OAM ADDR AND ADD ONE TO NBULLETS
PUSH HL
LD HL,NBULLETS
INC (HL)
; RESTORE OAM ADDR AND STORE IT
LD A,(HL)
POP DE
LD HL,BULLETOAMADDRS-1
ADD A,L
LD L,A
LD (HL),E
LD L,E
LD H,D
; OAM FLAGS = 0, OAM TILE = 3
INC L
INC L
LD A,$03
LD (HL+),A
XOR A
LD (HL),A
; PLAY BULLET SOUND IN NR1 REGISTERS
PLAYBULLETSOUND:
LD HL,$FF10
LD DE,BULLETSOUND
LD C,$5
JP MEMCPYLNZ
; C = BULLET INDEX + 1
DESPAWNBULLET:
; DEC 1 FROM NBULLETS AND STORE IN B
DEC C
LD HL,NBULLETS
DEC (HL)
LD B,(HL)
; COPY BULLET POSITIONS USING MEMCPY
LD DE,BULLETPOS
PUSH DE
LD A,B
ADD A
ADD A
ADD A,E
LD E,A
LD A,C
ADD A
ADD A
POP HL
ADD A,L
LD L,A
PUSH BC
LD C,$4
RST $18
POP BC
; NOW FETCH THE ONE WE WANT TO REMOVE
; AND REPLACE IT WITH THE LAST
LD DE,BULLETOAMADDRS
LD H,D
LD L,E
LD A,B
ADD A,L
LD L,A
LD B,(HL)
LD A,C
ADD A,E
LD E,A
LD A,(DE)
LD L,A
LD A,B
LD (DE),A
LD C,$1
JP OAMFREE
UPDATEOAM:
; UPDATE OTHER ENTITIES HERE EVENTUALLY
; EVENTUALLY, THE SHIP SHOUD BE AN ENTITY JUST LIKE
; ANYTHING ELSE, BUT HARDCODED AT INDEX 0
; REFLECT UPDATES TO BULLETS IN OAM
LD A,(NBULLETS)
OR A
JR Z,UPDATEBULLETSOAMDONE
; C = ITERATOR
LD C,A
UPDATEBULLETSOAM:
; LOAD OAM ADDR FIRST
LD A,C
DEC A
LD HL,BULLETOAMADDRS
ADD A,L
LD L,A
LD E,(HL)
LD D,OAMSHADOW/256
; NOW LOAD BULLET POSITION
LD A,C
DEC A
ADD A
ADD A
LD HL,BULLETPOS+3
ADD A,L
LD L,A
; NOW STORE BULLET POSITION IN OAM
LD A,(HL-)
LD (DE),A
DEC HL
INC DE
LD A,(HL-)
LD (DE),A
DEC C
JR NZ, UPDATEBULLETSOAM
UPDATEBULLETSOAMDONE:
; REFLECT UPDATES TO SHIP IN OAM
; WHOSE SPRITES ARE AT SPRITE 0
UPDATESHIPOAM:
LD HL,PLAYERPOS+3
LD E,(HL)
DEC HL
DEC HL
LD D,(HL)
LD HL,OAMSHADOW
LD BC,$0202
CALL UPDATEOAMPOS
RET
BULLETSOUND:
.DB $00, $8F, $F0, $6E, $C3
; HL = OAM SPRITES LOCATION
; DE = XY POSITION
; BC = WH DIMENSIONS
UPDATEOAMPOS:
UPDATEOAMYLOOP:
LD A,D
PUSH BC
UPDATEOAMXLOOP:
LD (HL),E
INC HL
LD (HL+),A
INC HL
INC HL
ADD $8
DEC B
JR NZ,UPDATEOAMXLOOP
POP BC
LD A,E
ADD $8
LD E,A
DEC C
JR NZ,UPDATEOAMYLOOP
RET
; OAM MEMORY MANAGEMENT
; OAM MEMORY IS FREE IF TILE IDX = 0, ALLOCATED OTHERWISE
; ALLOC MEMORY FROM OAM
; C = NUMBER OF OAM SPRITES
; ALL REGISTERS CLOBBERED EXCEPT B
; RETURN ADDRESS OF OAM IN HL
OAMALLOC:
LD HL,OAMSHADOW+160
OAMSEARCH:
LD D,C
OAMSEARCHLOOP:
DEC L
DEC L
LD A,(HL-)
DEC L
OR A
JR NZ,OAMSEARCH
DEC D
JR NZ,OAMSEARCHLOOP
RET
; FREE MEMORY FROM OAM
; L = LOW BYTE OF OAM INDEX
; C = NUMBER OF OAM SPRITES
OAMFREE:
LD H,OAMSHADOW/256
XOR A
OAMFREELOOP:
INC L
INC L
LD (HL+),A
INC L
DEC C
JR NZ,OAMFREELOOP
RET
; WAIT FOR VBLANK TO PASS
VBLANKINTRWAIT:
LD HL,STATICFLAGS
RES $0,(HL)
VBLANKINTRWAITLOOP:
HALT
BIT $0,(HL)
JR Z, VBLANKINTRWAITLOOP
RET
LD C,$41
LD D,$1
LD E,$3
VBLANKINTRWAITLOOPEXIT:
LDH A,[C]
AND E
CP D
JR Z,VBLANKINTRWAITLOOPEXIT
VBLANKINTRWAITLOOPENTER:
LDH A,[C]
AND E
CP D
JR NZ,VBLANKINTRWAITLOOPEXIT
RET
; SIMILAR TO MEMCPY BUT WITH A STRIDE OF 2
; TO COMPRESS CERTAIN TILES IN ROM TO 1BPP
; HL = DST
; DE = SRC
; B = # OF TILES IN TILESET (OR 0 FOR 256 TILES)
BPP1TILECPY:
LD C,8
BPP1TILECPYINNERLOOP:
LD A,(DE)
INC DE
LD (HL+),A
INC HL
DEC C
JR NZ,BPP1TILECPYINNERLOOP
DEC B
JR NZ,BPP1TILECPY
RET
BPP1TILEDATA:
SPACESHIPHALFTILES:
.DB $00,$00,$01,$01,$03,$03,$07,$07,$07,$07,$0F,$0F,$0F,$0F,$0F,$0F
BULLETTILES:
.DB $00,$00,$00,$18,$18,$00,$00,$00
; INITIALIZED DATA SECTIONS
; COPY THESE IN ORDER TO OPTIMIZE MEMCPY ROUTINES
SPRITESECTION:
.DSTRUCT PLAYERTLSPRITE INSTANCEOF OAMSPRITE VALUES
Y: .DB 48
X: .DB 48
IDX: .DB 1
FLAGS: .DB $0
.ENDST
.DSTRUCT PLAYERTRSPRITE INSTANCEOF OAMSPRITE VALUES
Y: .DB 48
X: .DB 56
IDX: .DB 1
FLAGS: .DB $20
.ENDST
.DSTRUCT PLAYERBLSPRITE INSTANCEOF OAMSPRITE VALUES
Y: .DB 56
X: .DB 48
IDX: .DB 2
FLAGS: .DB $0
.ENDST
.DSTRUCT PLAYERBRSPRITE INSTANCEOF OAMSPRITE VALUES
Y: .DB 56
X: .DB 56
IDX: .DB 2
FLAGS: .DB $20
.ENDST
DATASECTION:
.DSTRUCT PLAYERPOSSTART INSTANCEOF POINT88 VALUES
XL: .DB 0
XH: .DB $48
YL: .DB 0
YH: .DB $48
.ENDST
HRAMSECTION:
; THIS FUNCTION SHOULD ALWAYS BE AT THE END OF THE HRAM SECTION
; BECAUSE IT HAS VARIABLE LENGTH WHICH COULD SHIFT VARIABLES
HRAMROUTINEDMA:
LD A,$C8 ; OAMSHADOW
LDH ($46),A
LD A,$40
DMAWAIT:
DEC A
JR NZ,DMAWAIT
RET
HRAMSECTIONEND:
; HRAM < 256 BYTES, SO YOU CAN INDEED DO THIS
; LD C, (HRAMSECTIONEND - HRAMSECTION)