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.

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