Simple SNES shoot-'em-up game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

880 lines
18 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. .INCLUDE "header.asm"
  2. .INCLUDE "init.asm"
  3. .INCLUDE "registers.asm"
  4. .INCLUDE "memory.asm"
  5. ; Sets A to 8-bit (& enables 8-bit "B" register).
  6. .MACRO SetA8Bit
  7. sep #%00100000 ; 8-bit A/B.
  8. .ENDM
  9. ; Sets A to 16-bit.
  10. .MACRO SetA16Bit
  11. rep #%00100000 ; 16-bit A.
  12. .ENDM
  13. ; Sets X/Y to 16-bit.
  14. .MACRO SetXY16Bit
  15. rep #%00010000 ; 16-bit X/Y.
  16. .ENDM
  17. ; Stores result to A.
  18. ; Assumes 16-bit X & 8-bit A.
  19. ; Modifies X.
  20. ; Updates randomBytePtr.
  21. .MACRO GetRandomByte
  22. ldx randomBytePtr
  23. lda $028000, X ; $028000: beginning of ROM bank 2.
  24. inx
  25. cpx #$8000 ; This is the size of the entire ROM bank.
  26. bne +++
  27. ldx #0
  28. +++
  29. stx randomBytePtr
  30. .ENDM
  31. .BANK 0 SLOT 0
  32. .ORG 0
  33. .SECTION "MainCode"
  34. Start:
  35. InitSNES
  36. ; By default we assume 16-bit X/Y and 8-bit A.
  37. ; If any code wants to change this, it's expected to do so itself,
  38. ; and to change them back to the defaults before returning.
  39. SetXY16Bit
  40. SetA8Bit
  41. jsr LoadPaletteAndTileData
  42. jsr InitSpriteTables
  43. jsr InitWorld
  44. ; Set screen mode: 16x16 tiles for backgrounds, mode 1.
  45. lda #%11000001
  46. sta BGMODE
  47. ; Set sprite size to 16x16 (small) and 32x32 (large).
  48. lda #%01100000
  49. sta OAMSIZE
  50. ; Main screen: enable sprites & BG3.
  51. lda #%00010100
  52. sta MSENABLE
  53. ; Turn on the screen.
  54. ; Format: x000bbbb
  55. ; x: 0 = screen on, 1 = screen off, bbbb: Brightness ($0-$F)
  56. lda #%00001111
  57. sta INIDISP
  58. jmp MainLoop
  59. LoadPaletteAndTileData:
  60. ; For more details on DMA, see:
  61. ; http://wiki.superfamicom.org/snes/show/Grog%27s+Guide+to+DMA+and+HDMA+on+the+SNES
  62. ; http://wiki.superfamicom.org/snes/show/Making+a+Small+Game+-+Tic-Tac-Toe
  63. ;
  64. ; A lot of the graphics-related registers are explained in Qwertie's doc:
  65. ; http://emu-docs.org/Super%20NES/General/snesdoc.html
  66. ; ... but be careful, because there are some errors in this doc.
  67. ;
  68. ; bazz's tutorial (available from http://wiki.superfamicom.org/snes/) is
  69. ; quite helpful with palette / sprites / DMA, especially starting at
  70. ; http://wiki.superfamicom.org/snes/show/Working+with+VRAM+-+Loading+the+Palette
  71. ; Initialize the palette memory in a loop.
  72. ; We could also do this with a DMA transfer (like we do with the tile data
  73. ; below), but it seems overkill for just a few bytes. :)
  74. ; TODO(mcmillen): do it with a DMA transfer.
  75. ; First, sprite palette data:
  76. ldx #0
  77. lda #128 ; Palette entries for sprites start at 128.
  78. sta CGADDR
  79. -
  80. lda.l SpritePalette, X
  81. sta CGDATA
  82. inx
  83. cpx #32 ; 32 bytes of palette data.
  84. bne -
  85. ; Now, BG3 palette data.
  86. ; Palette entries for BG3 start at 0.
  87. ldx #0
  88. lda #0
  89. sta CGADDR
  90. -
  91. lda.l TilePalette, X
  92. sta CGDATA
  93. inx
  94. cpx #8 ; 8 bytes of palette data.
  95. bne -
  96. ; TODO(mcmillen): make the "DMA stuff into VRAM" a macro or function.
  97. ; Set VMADDR to where we want the DMA to start. We'll store sprite data
  98. ; at the beginning of VRAM.
  99. ldx #$0000
  100. stx VMADDR
  101. ; DMA 0 source address & bank.
  102. ldx #SpriteData
  103. stx DMA0SRC
  104. lda #:SpriteData
  105. sta DMA0SRCBANK
  106. ; DMA 0 transfer size. Equal to the size of sprites32.pic.
  107. ldx #2048
  108. stx DMA0SIZE
  109. ; DMA 0 control register.
  110. ; Transfer type 001 = 2 addresses, LH.
  111. lda #%00000001
  112. sta DMA0CTRL
  113. ; DMA 0 destination.
  114. lda #$18 ; The upper byte is assumed to be $21, so this is $2118 & $2119.
  115. sta DMA0DST
  116. ; Enable DMA channel 0.
  117. lda #%00000001
  118. sta DMAENABLE
  119. ; Store background tile data at byte $2000 of VRAM.
  120. ; (VMADDR is a word address, so multiply by 2 to get the byte address.)
  121. ldx #$1000
  122. stx VMADDR
  123. ; DMA 0 source address & bank.
  124. ldx #TileData
  125. stx DMA0SRC
  126. lda #:TileData
  127. sta DMA0SRCBANK
  128. ; DMA 0 transfer size. Equal to the size of tiles.pic.
  129. ldx #512
  130. stx DMA0SIZE
  131. ; DMA 0 control register.
  132. ; Transfer type 001 = 2 addresses, LH.
  133. lda #%00000001
  134. sta DMA0CTRL
  135. ; DMA 0 destination.
  136. lda #$18 ; The upper byte is assumed to be $21, so this is $2118 & $2119.
  137. sta DMA0DST
  138. ; Enable DMA channel 0.
  139. lda #%00000001
  140. sta DMAENABLE
  141. ; Tell the system that the BG3 tilemap starts at $4000.
  142. lda #%00100000
  143. sta BG3TILEMAP
  144. ; ... and that the background tile data for BG3 starts at $2000.
  145. lda #%00000001
  146. sta BG34NBA
  147. ; Set up the BG3 tilemap.
  148. ; VRAM write mode: increments the address every time we write a word.
  149. lda #%10000000
  150. sta VMAIN
  151. ; Set word address for accessing VRAM.
  152. ldx #$2000 ; BG 3 tilemap starts here. (Byte address $4000.)
  153. stx VMADDR
  154. ; Now write entries into the tile map.
  155. ldy #0
  156. -
  157. GetRandomByte
  158. sta $00
  159. ldx #$0000 ; This is a blank tile.
  160. ; 1 in 8 chance that we choose a non-blank tile.
  161. bit #%00000111
  162. bne +
  163. ldx #$0002
  164. bit #%10000000
  165. bne +
  166. ldx #$8002 ; Flip vertically.
  167. +
  168. stx VMDATA
  169. iny
  170. ; The tile map is 32x32 (1024 entries).
  171. cpy #1024
  172. bne -
  173. rts
  174. InitSpriteTables: ; TODO(mcmillen): why do we need this?
  175. SetA16Bit
  176. ldx #$0000
  177. ; Fill sprite table 1.
  178. lda #$01
  179. -
  180. sta spriteTableStart, X
  181. .rept 4
  182. inx
  183. .endr
  184. cpx #spriteTable1Size
  185. bne -
  186. SetA8Bit
  187. rts
  188. InitWorld:
  189. ; Start the background color as a dark blue.
  190. lda #4
  191. sta backgroundBlue
  192. ; Player's initial starting location.
  193. lda #(256 / 4)
  194. sta playerX
  195. lda #((224 - 32) / 2)
  196. sta playerY
  197. ; (x-velocity, y-velocity) of 4 different player shot patterns.
  198. lda #6
  199. sta shotVelocityTable
  200. lda #0
  201. sta shotVelocityTable + 1
  202. lda #3
  203. sta shotVelocityTable + 2
  204. lda #3
  205. sta shotVelocityTable + 3
  206. lda #0
  207. sta shotVelocityTable + 4
  208. lda #6
  209. sta shotVelocityTable + 5
  210. lda #-3
  211. sta shotVelocityTable + 6
  212. lda #3
  213. sta shotVelocityTable + 7
  214. lda #-6
  215. sta shotVelocityTable + 8
  216. lda #0
  217. sta shotVelocityTable + 9
  218. lda #-3
  219. sta shotVelocityTable + 10
  220. lda #-3
  221. sta shotVelocityTable + 11
  222. lda #0
  223. sta shotVelocityTable + 12
  224. lda #-6
  225. sta shotVelocityTable + 13
  226. lda #3
  227. sta shotVelocityTable + 14
  228. lda #-3
  229. sta shotVelocityTable + 15
  230. rts
  231. MainLoop:
  232. lda #%10000001 ; Enable NMI interrupt & auto joypad read.
  233. sta NMITIMEN
  234. wai ; Wait for interrupt.
  235. lda #%00000001 ; Disable NMI interrupt while processing.
  236. sta NMITIMEN
  237. jsr JoypadRead
  238. jsr JoypadHandler
  239. jsr UpdateWorld
  240. jsr UpdateSprites
  241. jsr FillSecondarySpriteTable
  242. jsr SetBackgroundColor
  243. bra MainLoop
  244. JoypadRead:
  245. ; Load joypad registers into RAM for easy inspection & manipulation.
  246. -
  247. lda HVBJOY
  248. bit #$01 ; If auto-joypad read is happening, loop.
  249. bne -
  250. ldx JOY1L
  251. stx joy1
  252. ldx JOY2L
  253. stx joy2
  254. rts
  255. JoypadHandler:
  256. JoypadUp:
  257. lda joy1 + 1
  258. bit #$08 ; Up
  259. beq JoypadDown ; Button not pressed.
  260. lda playerY
  261. cmp #0
  262. beq JoypadDown ; Value saturated.
  263. dec playerY
  264. dec playerY
  265. JoypadDown:
  266. lda joy1 + 1
  267. bit #$04 ; Down
  268. beq JoypadLeft ; Button not pressed.
  269. lda playerY
  270. cmp #(224 - 32)
  271. beq JoypadLeft ; Value saturated.
  272. inc playerY
  273. inc playerY
  274. JoypadLeft:
  275. lda joy1 + 1
  276. bit #$02 ; Left
  277. beq JoypadRight ; Button not pressed.
  278. lda playerX
  279. cmp #0
  280. beq JoypadRight ; Value saturated.
  281. dec playerX
  282. dec playerX
  283. JoypadRight:
  284. lda joy1 + 1
  285. bit #$01 ; Right
  286. beq JoypadStart ; Button not pressed.
  287. lda playerX
  288. cmp #(256 - 32)
  289. beq JoypadStart ; Value saturated.
  290. inc playerX
  291. inc playerX
  292. JoypadStart:
  293. lda joy1 + 1
  294. bit #$10 ; Start
  295. beq JoypadSelect ; Button not pressed.
  296. lda backgroundRed
  297. cmp #31
  298. beq JoypadSelect ; Value saturated.
  299. inc backgroundRed
  300. JoypadSelect:
  301. lda joy1 + 1
  302. bit #$20 ; Select
  303. beq JoypadY ; Button not pressed.
  304. lda backgroundRed
  305. cmp #0
  306. beq JoypadY ; Value saturated.
  307. dec backgroundRed
  308. JoypadY:
  309. lda joy1 + 1
  310. bit #$40 ; Y
  311. beq JoypadX ; Button not pressed.
  312. lda backgroundGreen
  313. cmp #0
  314. beq JoypadX ; Value saturated.
  315. dec backgroundGreen
  316. JoypadX:
  317. lda joy1
  318. bit #$40 ; X
  319. beq JoypadL ; Button not pressed.
  320. lda backgroundGreen
  321. cmp #31
  322. beq JoypadL ; Value saturated.
  323. inc backgroundGreen
  324. JoypadL:
  325. lda joy1
  326. bit #$20 ; L
  327. beq JoypadR ; Button not pressed.
  328. lda backgroundBlue
  329. cmp #0
  330. beq JoypadR ; Value saturated.
  331. dec backgroundBlue
  332. JoypadR:
  333. lda joy1
  334. bit #$10 ; R
  335. beq JoypadB ; Button not pressed.
  336. lda backgroundBlue
  337. cmp #31
  338. beq JoypadB ; Value saturated.
  339. inc backgroundBlue
  340. JoypadB:
  341. lda joy1 + 1
  342. bit #$80 ; B
  343. beq JoypadDone
  344. jsr MaybeShoot
  345. JoypadDone:
  346. rts
  347. MaybeShoot:
  348. ; If the cooldown timer is non-zero, don't shoot.
  349. lda shotCooldown
  350. cmp #0
  351. bne MaybeShootDone
  352. ; Find the first empty spot in the shots array.
  353. ldx #playerShotArray
  354. -
  355. lda 0, X
  356. cmp #0
  357. beq +
  358. .rept shotSize
  359. inx
  360. .endr
  361. ; If we went all the way to the end, bail out.
  362. cpx #(playerShotArray + playerShotArrayLength * shotSize)
  363. beq MaybeShootDone
  364. bra -
  365. +
  366. ; Enable shot; set its position based on player position.
  367. ; TODO(mcmillen): it might be easier/faster to keep N arrays: one for each
  368. ; field of shot (shotSpriteArray, shotXArray, shotYArray, ...)
  369. lda #8 ; Sprite number.
  370. sta 0, X
  371. lda playerX
  372. clc
  373. adc #20
  374. sta 1, X
  375. lda playerY
  376. sta 2, X
  377. ; Get x- and y-velocity out of shotVelocityTable.
  378. lda nextShotState
  379. and #%00000111 ; 8 possibilities.
  380. ldy #0
  381. -
  382. cmp #0
  383. beq +
  384. .rept 2
  385. iny
  386. .endr
  387. dec A
  388. bra -
  389. +
  390. inc nextShotState
  391. ; x-velocity.
  392. lda shotVelocityTable, Y
  393. sta 3, X
  394. ; y-velocity.
  395. lda shotVelocityTable + 1, Y
  396. sta 4, X
  397. ; Set cooldown timer.
  398. lda #8
  399. sta shotCooldown
  400. MaybeShootDone:
  401. rts
  402. UpdateWorld:
  403. jsr UpdateShotCooldown
  404. jsr SpawnEnemyShots
  405. jsr UpdateShotPositions
  406. jsr UpdateBackgroundScroll
  407. rts
  408. UpdateShotCooldown:
  409. ; Update shot cooldown.
  410. lda shotCooldown
  411. cmp #0
  412. beq +
  413. dec A
  414. sta shotCooldown
  415. +
  416. rts
  417. SpawnEnemyShots:
  418. lda vBlankCounter
  419. bit #%00001111
  420. beq +
  421. rts
  422. +
  423. ldy #0
  424. -
  425. lda enemyShotArray, Y
  426. cmp #0
  427. beq +
  428. .rept 6
  429. iny
  430. .endr
  431. cpy #(enemyShotArrayLength * shotSize)
  432. bne -
  433. rts ; Too many shots; bail.
  434. +
  435. lda #12 ; Sprite number.
  436. sta enemyShotArray, Y
  437. lda #254
  438. sta enemyShotArray + 1, Y ; x.
  439. lda #((224 - 32) / 2)
  440. and #%01111111
  441. sta enemyShotArray + 2, Y ; y.
  442. lda #-4
  443. sta enemyShotArray + 3, Y ; x-velocity.
  444. GetRandomByte
  445. and #%00000111 ; [0, 7]
  446. clc
  447. adc #-3 ; [-3, 4]
  448. cmp #4
  449. bne +
  450. lda #0 ; [-3, 3] with 2x chance of zero.
  451. +
  452. sta enemyShotArray + 4, Y ; y-velocity.
  453. rts
  454. UpdateShotPositions:
  455. ldx #0
  456. UpdateShot: ; Updates position of one shot.
  457. lda playerShotArray, X
  458. cmp #0
  459. beq ShotDone
  460. ; Add to the x-coordinate. If the carry bit is set, we went off the edge
  461. ; of the screen, so disable the shot.
  462. lda playerShotArray + 3, X ; x-velocity.
  463. sta $00
  464. bit #%10000000 ; Check whether the velocity is negative.
  465. bne UpdateShotWithNegativeXVelocity
  466. lda playerShotArray + 1, X
  467. clc
  468. adc $00
  469. bcs DisableShot
  470. sta playerShotArray + 1, X ; Store new x-coord.
  471. bra UpdateShotY
  472. UpdateShotWithNegativeXVelocity:
  473. ; TODO(mcmillen): wrap sprites when they go negative here, like we do
  474. ; with y-velocities.
  475. lda playerShotArray + 1, X ; Current x.
  476. clc
  477. adc $00
  478. bcc DisableShot
  479. sta playerShotArray + 1, X
  480. UpdateShotY:
  481. ; Add to the y-coordinate.
  482. lda playerShotArray + 4, X ; y-velocity.
  483. sta $00
  484. bit #%10000000 ; Check whether the velocity is negative.
  485. bne UpdateShotWithNegativeYVelocity
  486. lda playerShotArray + 2, X
  487. clc
  488. adc $00
  489. cmp #224
  490. bcs DisableShot
  491. sta playerShotArray + 2, X ; Store new y-coord.
  492. bra ShotDone
  493. UpdateShotWithNegativeYVelocity:
  494. lda playerShotArray + 2, X ; Current y.
  495. cmp #224
  496. bcs + ; If the shot was "off the top" before moving, maybe we'll reap it.
  497. adc $00 ; Otherwise, just update it,
  498. sta playerShotArray + 2, X ; save the result,
  499. bra ShotDone ; and we know it shouldn't be reaped.
  500. +
  501. clc
  502. adc $00
  503. cmp #224
  504. bcc DisableShot ; If it's now wrapped around, reap it.
  505. sta playerShotArray + 2, X
  506. bra ShotDone
  507. DisableShot:
  508. stz playerShotArray, X
  509. ShotDone:
  510. ; TODO(mcmillen): in places where we .rept inx (etc), is it faster to use
  511. ; actual addition?
  512. .rept shotSize
  513. inx
  514. .endr
  515. cpx #(playerShotArrayLength * enemyShotArrayLength * shotSize)
  516. bne UpdateShot
  517. rts
  518. UpdateBackgroundScroll:
  519. ; Make the background scroll. Horizontal over time; vertical depending on
  520. ; player's y-coordinate.
  521. lda vBlankCounter
  522. sta BG3HOFS
  523. lda vBlankCounter + 1
  524. sta BG3HOFS
  525. lda playerY
  526. .rept 3
  527. lsr
  528. .endr
  529. sta BG3VOFS
  530. stz BG3VOFS
  531. rts
  532. UpdateSprites:
  533. ; This page is a good reference on SNES sprite formats:
  534. ; http://wiki.superfamicom.org/snes/show/SNES+Sprites
  535. ; It uses the same approach we're using, in which we keep a buffer of the
  536. ; sprite tables in RAM, and DMA the sprite tables to the system's OAM
  537. ; during VBlank.
  538. ; Sprite table 1 has 4 bytes per sprite, laid out as follows:
  539. ; Byte 1: xxxxxxxx x: X coordinate
  540. ; Byte 2: yyyyyyyy y: Y coordinate
  541. ; Byte 3: cccccccc c: Starting tile #
  542. ; Byte 4: vhoopppc v: vertical flip h: horizontal flip o: priority bits
  543. ; p: palette #
  544. ; Sprite table 2 has 2 bits per sprite, like so:
  545. ; bits 0,2,4,6 - High bit of the sprite's x-coordinate.
  546. ; bits 1,3,5,7 - Toggle Sprite size: 0 - small size 1 - large size
  547. ; Setting all the high bits keeps the sprites offscreen.
  548. ; Zero out the scratch space for the secondary sprite table.
  549. ldx #0
  550. -
  551. stz spriteTableScratchStart, X
  552. inx
  553. cpx #numSprites
  554. bne -
  555. ldx #0 ; Index into sprite table 1.
  556. ldy #0 ; Index into sprite table 2.
  557. ; Copy player coords into sprite table.
  558. lda playerX
  559. sta spriteTableStart, X
  560. lda playerY
  561. sta spriteTableStart + 1, X
  562. lda #0
  563. sta spriteTableStart + 2, X
  564. ; Set priority bits so that the sprite is drawn in front.
  565. lda #%00110000
  566. sta spriteTableStart + 3, X
  567. lda #%11000000 ; Enable large sprite.
  568. sta spriteTableScratchStart, Y
  569. .rept 4
  570. inx
  571. .endr
  572. iny
  573. ; Now add shots.
  574. sty $00 ; Save sprite table 2 index.
  575. ldy #0 ; Index into playerShotArray.
  576. -
  577. lda playerShotArray, Y
  578. cmp #0
  579. beq + ; If not enabled, skip to next shot.
  580. ; Update sprite table 1.
  581. sta spriteTableStart + 2, X ; sprite number
  582. lda playerShotArray + 1, Y
  583. sta spriteTableStart, X ; x
  584. lda playerShotArray + 2, Y
  585. sta spriteTableStart + 1, X ; y
  586. ; Update secondary sprite table.
  587. phy ; Save playerShotArray index.
  588. ldy $00
  589. lda #%11000000
  590. sta spriteTableScratchStart, Y
  591. iny
  592. sty $00
  593. ply ; Restore playerShotArrayIndex.
  594. .rept 4
  595. inx
  596. .endr
  597. +
  598. .rept shotSize
  599. iny
  600. .endr
  601. cpy #((playerShotArrayLength + enemyShotArrayLength) * shotSize)
  602. bne -
  603. ; Now clear out the unused entries in the sprite table.
  604. -
  605. cpx #spriteTable1Size
  606. beq +
  607. lda #1
  608. sta spriteTableStart, X
  609. .rept 4
  610. inx
  611. .endr
  612. +
  613. rts
  614. FillSecondarySpriteTable:
  615. ; The secondary sprite table wants 2 bits for each sprite: one to set the
  616. ; sprite's size, and one that's the high bit of the sprite's x-coordinate.
  617. ; It's annoying to deal with bitfields when thinking about business logic,
  618. ; so the spriteTableScratch array contains one byte for each sprite, in
  619. ; which the two most significant bits are the "size" and "upper x" bits.
  620. ; This function is meant to be called after UpdateWorld, and packs those
  621. ; bytes into the actual bitfield that the OAM wants for the secondary
  622. ; sprite table.
  623. ;
  624. ; The expected format of every byte in the scratch sprite table is:
  625. ; sx------ s = size (0 = small, 1 = large)
  626. ; x = flipped high x-coordinate (so 1 behaves like "enable").
  627. ldx #0 ; Index into input table.
  628. ldy #0 ; Index into output table.
  629. -
  630. stz $00 ; Current byte; filled out by a set of 4 input table entries.
  631. .rept 4
  632. ; For each byte, the lower-order bits correspond to the lower-numbered
  633. ; sprites; therefore we insert the current sprite's bits "at the top"
  634. ; and shift them right for each successive sprite.
  635. lsr $00
  636. lsr $00
  637. lda spriteTableScratchStart, X
  638. ora $00
  639. sta $00
  640. inx
  641. .endr
  642. lda $00
  643. eor #%01010101
  644. sta spriteTable2Start, Y
  645. iny
  646. cpx #numSprites
  647. bne -
  648. rts
  649. SetBackgroundColor:
  650. ; The background-color bytes are (R, G, B), each ranging from [0-31].
  651. ; The palette color format is 15-bit: [0bbbbbgg][gggrrrrr]
  652. ; Set the background color.
  653. ; Entry 0 corresponds to the SNES background color.
  654. stz CGADDR
  655. ; Compute and the low-order byte and store it in CGDATA.
  656. lda backgroundGreen
  657. .rept 5
  658. asl
  659. .endr
  660. ora backgroundRed
  661. sta CGDATA
  662. ; Compute the high-order byte and store it in CGDATA.
  663. lda backgroundBlue
  664. .rept 2
  665. asl
  666. .endr
  667. sta $00
  668. lda backgroundGreen
  669. .rept 3
  670. lsr
  671. .endr
  672. ora $00
  673. sta CGDATA
  674. rts
  675. VBlankHandler:
  676. jsr VBlankCounter
  677. jsr DMASpriteTables
  678. rti
  679. VBlankCounter:
  680. ; Increment a counter of how many VBlanks we've done.
  681. ; This is a 24-bit counter. At 60 vblanks/second, this will take
  682. ; 77 hours to wrap around; that's good enough for me :)
  683. inc vBlankCounter
  684. bne +
  685. inc vBlankCounter + 1
  686. bne +
  687. inc vBlankCounter + 2
  688. +
  689. rts
  690. DMASpriteTables:
  691. ; Store at the base OAM address.
  692. ldx #$0000
  693. stx OAMADDR
  694. ; Default DMA control; destination $2104 (OAM data register).
  695. stz DMA0CTRL
  696. lda #$04
  697. sta DMA0DST
  698. ; Our sprites start at $0100 in bank 0 and are #$220 bytes long.
  699. ldx #spriteTableStart
  700. stx DMA0SRC
  701. stz DMA0SRCBANK
  702. ldx #spriteTableSize
  703. stx DMA0SIZE
  704. ; Kick off the DMA transfer.
  705. lda #%00000001
  706. sta DMAENABLE
  707. rts
  708. .ENDS
  709. ; Bank 1 is used for our graphics assets.
  710. .BANK 1 SLOT 0
  711. .ORG 0
  712. .SECTION "GraphicsData"
  713. SpriteData:
  714. .INCBIN "sprites32.pic"
  715. SpritePalette:
  716. .INCBIN "sprites32.clr"
  717. TileData:
  718. .INCBIN "tiles.pic"
  719. TilePalette:
  720. .INCBIN "tiles.clr"
  721. .ENDS
  722. ; Fill an entire bank with random numbers.
  723. .SEED 1
  724. .BANK 2 SLOT 0
  725. .ORG 0
  726. .SECTION "RandomBytes"
  727. .DBRND 32 * 1024, 0, 255
  728. .ENDS