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.

941 lines
14 KiB

2 years ago
2 years ago
  1. INCLUDE "game.inc"
  2. INCLUDE "hardware.inc"
  3. INCLUDE "util.inc"
  4. SECTION "Map Data", WRAM0
  5. DEF ROW_BUFFER_SIZE EQUS "SCRN_X_B + 4"
  6. DEF COL_BUFFER_SIZE EQUS "SCRN_Y_B + 4"
  7. PENDING_ROW_PTR:: DW ; Where to write pending row data (0 = no write)
  8. PENDING_ROW_DATA:: DS ROW_BUFFER_SIZE ; Row to be written
  9. PENDING_COL_PTR:: DW ; Where to write pending column data (0 = no write)
  10. PENDING_COL_DATA: DS COL_BUFFER_SIZE ; Column to be written
  11. CURRENT_DATA_START::
  12. CURRENT_TILE_PTR:: DW ; Location of tile data
  13. CURRENT_TILE_SIZE:: DB ; Length of tile data (num_tiles * 8)
  14. CURRENT_MAP_PTR:: DW ; Location of map data
  15. CURRENT_MAP_COLLISION:: DW ; Location of map collision data
  16. CURRENT_MAP_WIDTH:: DB ; Width of map in tiles
  17. CURRENT_MAP_HEIGHT:: DB ; Height of map in tiles
  18. CURRENT_SPAWN_X:: DB ; X coordinate to spawn player at
  19. CURRENT_SPAWN_Y:: DB ; Y coordinate to spawn player at
  20. CURRENT_CAMERA_X:: DB ; X coordinate of camera (top left of viewport)
  21. CURRENT_CAMERA_Y:: DB ; Y coordinate of camera (top left of viewport)
  22. CURRENT_DATA_END::
  23. SECTION "Map Code", ROM0
  24. DEF INIT_SCX EQUS "((SCRN_VX - SCRN_X) / 2)"
  25. DEF INIT_SCY EQUS "((SCRN_VY - SCRN_Y) / 2)"
  26. ; Loads a map
  27. ; @param hl Pointer to map metadata
  28. Map_Load::
  29. ; Initialize scroll state
  30. ld a, INIT_SCX
  31. ld [rSCX], a
  32. ld a, INIT_SCY
  33. ld [rSCY], a
  34. ; Store metadata
  35. ld bc, CURRENT_DATA_START
  36. ld d, CURRENT_DATA_END - CURRENT_DATA_START
  37. call memcpy
  38. ; Move player to spawn point
  39. ld a, [CURRENT_CAMERA_X]
  40. ld b, a
  41. ld a, [CURRENT_SPAWN_X]
  42. sub b
  43. sla a
  44. sla a
  45. sla a
  46. ld [PLAYER_X], a
  47. ld a, [CURRENT_CAMERA_Y]
  48. ld b, a
  49. ld a, [CURRENT_SPAWN_Y]
  50. sub b
  51. sla a
  52. sla a
  53. sla a
  54. ld [PLAYER_Y], a
  55. ; Write tiles to VRAM
  56. ld hl, CURRENT_TILE_PTR
  57. ld a, [hl+]
  58. ld c, a
  59. ld a, [hl+]
  60. ld b, a
  61. ld a, [CURRENT_TILE_SIZE]
  62. ld d, a
  63. ld hl, _VRAM + TILE_INDEX_BACKGROUND * TILE_SIZE
  64. MEMCPY hl, bc, d
  65. ; Write initial map data
  66. ld hl, _SCRN0
  67. ld a, [CURRENT_CAMERA_X]
  68. sub INIT_SCX / 8
  69. ld b, a
  70. ld a, [CURRENT_CAMERA_Y]
  71. sub INIT_SCY / 8
  72. ld c, a
  73. ld d, SCRN_VY_B
  74. .write_rows:
  75. call write_map_row
  76. inc c
  77. ld a, SCRN_VX_B
  78. ADD16 hl
  79. dec d
  80. jr nz, .write_rows
  81. ret
  82. ; Scroll the map upwards
  83. ; @param d The amount to scroll by (0 < d < 8)
  84. ;
  85. ; SCY_T = SCY % 8;
  86. ; if CAMERA_Y = 0 {
  87. ; if SCY_T != 0 {
  88. ; SCY -= MIN(D, SCY_T);
  89. ; }
  90. ; return;
  91. ; }
  92. ; SCY -= D;
  93. ; if SCY_T - D < 0 {
  94. ; CAMERA_Y -= 1;
  95. ; Map_ScrollRow(CAMERA_X - 2, CAMERA_Y - 2);
  96. ; }
  97. Map_ScrollUp::
  98. ld a, [rSCY]
  99. and %111
  100. add sp, -1
  101. ld hl, sp + 0
  102. ld [hl], a
  103. ld a, [CURRENT_CAMERA_Y]
  104. or a
  105. jr nz, .scroll
  106. ld hl, sp + 0
  107. ld a, [hl]
  108. or a
  109. jr z, .done
  110. ld b, d
  111. call min
  112. ld d, a
  113. ld a, [rSCY]
  114. sub d
  115. ld [rSCY], a
  116. jr .done
  117. .scroll:
  118. ld a, [rSCY]
  119. sub d
  120. ld [rSCY], a
  121. ; Check SCY_T - D < 0
  122. ld hl, sp + 0
  123. ld a, [hl]
  124. sub d
  125. jr nc, .done
  126. ; CAMERA_Y -= 1
  127. ld a, [CURRENT_CAMERA_Y]
  128. dec a
  129. ld [CURRENT_CAMERA_Y], a
  130. ; B = CAMERA_X - 2
  131. ld a, [CURRENT_CAMERA_X]
  132. sub 2
  133. ld b, a
  134. ; C = CAMERA_Y - 2
  135. ld a, [CURRENT_CAMERA_Y]
  136. sub 2
  137. ld c, a
  138. ; MAP Y = SCY/8 - 2
  139. ld a, [rSCY]
  140. srln a, 3
  141. sub 2
  142. add sp, 1
  143. jr Map_ScrollRow
  144. .done:
  145. add sp, 1
  146. ret
  147. ; Map_ScrollDown(D)
  148. ;
  149. ; SCY_T = SCY % 8;
  150. ; if CAMERA_Y + 18 = MAP_HEIGHT {
  151. ; if SCY_T != 0 {
  152. ; SCY += MIN(D, 8 - SCY_T);
  153. ; }
  154. ; return;
  155. ; }
  156. ; SCY += D;
  157. ; if SCY_T + D >= 8 {
  158. ; CAMERA_Y += 1;
  159. ; Map_ScrollRow(CAMERA_X - 2, CAMERA_Y + 18 + 1);
  160. ; }
  161. Map_ScrollDown::
  162. ld a, [rSCY]
  163. and %111
  164. add sp, -1
  165. ld hl, sp + 0
  166. ld [hl], a
  167. ld a, [CURRENT_CAMERA_Y]
  168. add SCRN_Y_B
  169. ld hl, CURRENT_MAP_HEIGHT
  170. cp [hl]
  171. jr nz, .scroll
  172. ld hl, sp + 0
  173. ld a, [hl]
  174. or a
  175. jr z, .done
  176. sub 8
  177. cpl
  178. ld b, d
  179. call min
  180. ld d, a
  181. ld a, [rSCY]
  182. add d
  183. ld [rSCY], a
  184. jr .done
  185. .scroll:
  186. ld a, [rSCY]
  187. add d
  188. ld [rSCY], a
  189. ; Check SCY_T + D < 8
  190. ld hl, sp + 0
  191. ld a, [hl]
  192. add d
  193. cp 8
  194. jr c, .done
  195. ; CAMERA_Y += 1
  196. ld a, [CURRENT_CAMERA_Y]
  197. inc a
  198. ld [CURRENT_CAMERA_Y], a
  199. ; B = CAMERA_X - 2
  200. ld a, [CURRENT_CAMERA_X]
  201. sub 2
  202. ld b, a
  203. ; C = CAMERA_Y + 18 + 1
  204. ld a, [CURRENT_CAMERA_Y]
  205. add SCRN_Y_B + 1
  206. ld c, a
  207. ; MAP Y = SCY/8 + SCRN_Y_B + 1
  208. ld a, [rSCY]
  209. srln a, 3
  210. add SCRN_Y_B + 1
  211. add sp, 1
  212. jr Map_ScrollRow
  213. .done:
  214. add sp, 1
  215. ret
  216. ; Scroll in a new row
  217. ; @param a Map VRAM Y-coordinate
  218. ; @param b Data X-coordinate
  219. ; @param c Data Y-coordinate
  220. Map_ScrollRow:
  221. and %11111
  222. call get_row_ptr
  223. ld a, [rSCX]
  224. sub 16
  225. srl a
  226. srl a
  227. srl a
  228. ld e, a
  229. ld d, 0
  230. add hl, de
  231. call enqueue_row_write
  232. ret
  233. Map_ScrollLeft::
  234. ld a, [rSCX]
  235. and %111
  236. add sp, -1
  237. ld hl, sp + 0
  238. ld [hl], a
  239. ld a, [CURRENT_CAMERA_X]
  240. or a
  241. jr nz, .scroll
  242. ld hl, sp + 0
  243. ld a, [hl]
  244. or a
  245. jr z, .done
  246. ld b, d
  247. call min
  248. ld d, a
  249. ld a, [rSCX]
  250. sub d
  251. ld [rSCX], a
  252. jr .done
  253. .scroll:
  254. ld a, [rSCX]
  255. sub d
  256. ld [rSCX], a
  257. ; Check SCX_T - D < 0
  258. ld hl, sp + 0
  259. ld a, [hl]
  260. sub d
  261. jr nc, .done
  262. ld a, [CURRENT_CAMERA_X]
  263. dec a
  264. ld [CURRENT_CAMERA_X], a
  265. ld a, [rSCY]
  266. sub 16
  267. srl a
  268. srl a
  269. srl a
  270. call get_row_ptr
  271. ; B = CAMERA_X - 2
  272. ld a, [CURRENT_CAMERA_X]
  273. sub 2
  274. ld b, a
  275. ; E = VRAM + (SCX/8 - 2)
  276. ld a, [rSCX]
  277. srln a, 3
  278. sub 2
  279. ADD16 hl
  280. add sp, 1
  281. jr Map_ScrollColumn
  282. .done:
  283. add sp, 1
  284. ret
  285. Map_ScrollRight::
  286. ld a, [rSCX]
  287. and %111
  288. add sp, -1
  289. ld hl, sp + 0
  290. ld [hl], a
  291. ld a, [CURRENT_CAMERA_X]
  292. add SCRN_X_B
  293. ld hl, CURRENT_MAP_WIDTH
  294. cp [hl]
  295. jr nz, .scroll
  296. ld hl, sp + 0
  297. ld a, [hl]
  298. or a
  299. jr z, .done
  300. sub 8
  301. cpl
  302. ld b, d
  303. call min
  304. ld d, a
  305. ld a, [rSCX]
  306. add d
  307. ld [rSCX], a
  308. jr .done
  309. .scroll:
  310. ld a, [rSCX]
  311. add d
  312. ld [rSCX], a
  313. ; Check SCX_T + D < 8
  314. ld hl, sp + 0
  315. ld a, [hl]
  316. add d
  317. cp 8
  318. jr c, .done
  319. ; CAMERA_X += 1
  320. ld a, [CURRENT_CAMERA_X]
  321. inc a
  322. ld [CURRENT_CAMERA_X], a
  323. ld a, [rSCY]
  324. sub 16
  325. srl a
  326. srl a
  327. srl a
  328. call get_row_ptr
  329. ; B = CAMERA_X + 20 + 1
  330. ld a, [CURRENT_CAMERA_X]
  331. add SCRN_X_B + 1
  332. ld b, a
  333. ; E = VRAM + SCX/8 + SCRN_X_B + 1
  334. ld a, [rSCX]
  335. srl a
  336. srl a
  337. srl a
  338. add SCRN_X_B + 1
  339. and %11111
  340. ADD16 hl
  341. add sp, 1
  342. jr Map_ScrollColumn
  343. .done:
  344. add sp, 1
  345. ret
  346. Map_ScrollColumn:
  347. ; C = CAMERA_Y - 2
  348. ld a, [CURRENT_CAMERA_Y]
  349. sub 2
  350. ld c, a
  351. call enqueue_col_write
  352. ret
  353. Map_Update::
  354. ; Skip row update if PENDING_ROW_PTR is 0
  355. ld a, [PENDING_ROW_PTR]
  356. ld c, a
  357. ld a, [PENDING_ROW_PTR + 1]
  358. ld b, a
  359. or c
  360. jr z, .update_col
  361. ld hl, PENDING_ROW_DATA
  362. ld d, ROW_BUFFER_SIZE
  363. .copy_row:
  364. ld a, [hl+]
  365. ld [bc], a
  366. inc bc
  367. ; if BC % 32 == 0 (we just crossed a row boundary)
  368. ld a, c
  369. and %11111
  370. jr nz, .copy_row1
  371. ; BC -= 32 (reset back to beginning of row)
  372. ld a, c
  373. sub 32
  374. ld c, a
  375. ld a, b
  376. sbc 0
  377. ld b, a
  378. .copy_row1:
  379. dec d
  380. jr nz, .copy_row
  381. ; Reset PENDING_ROW_PTR
  382. xor a
  383. ld [PENDING_ROW_PTR], a
  384. ld [PENDING_ROW_PTR + 1], a
  385. .update_col:
  386. ; Skip column update if PENDING_COL_PTR is 0
  387. ld a, [PENDING_COL_PTR]
  388. ld c, a
  389. ld a, [PENDING_COL_PTR + 1]
  390. ld b, a
  391. or c
  392. ret z
  393. ld d, COL_BUFFER_SIZE
  394. ld hl, PENDING_COL_DATA
  395. .update_col_loop:
  396. ld a, [hl+]
  397. ld [bc], a
  398. ld a, SCRN_VX_B
  399. ADD16 bc
  400. ; If BC = 9c00, set BC = 9800
  401. CP16 bc, _SCRN0 + SCRN_VY_B * SCRN_VX_B
  402. jr nz, .update_col_loop_next
  403. ld b, HIGH(_SCRN0)
  404. .update_col_loop_next:
  405. dec d
  406. jr nz, .update_col_loop
  407. ; Reset PENDING_COL_PTR
  408. xor a
  409. ld [PENDING_COL_PTR], a
  410. ld [PENDING_COL_PTR + 1], a
  411. ret
  412. ; Computes the offset into map RAM
  413. ; @param a The map RAM y-coordinate
  414. ; @return hl Pointer into map RAM
  415. get_row_ptr:
  416. push de
  417. ld d, 0
  418. ld e, a
  419. REPT 5
  420. SLA16 de
  421. ENDR
  422. ld hl, _SCRN0
  423. add hl, de
  424. pop de
  425. ret
  426. ; Write a row of map data into row buffer
  427. ; @param b Map X coordinate (signed)
  428. ; @param c Map Y coordinate (signed)
  429. ; @param hl Where to write the row in map VRAM
  430. ; @destroy All registers
  431. enqueue_row_write:
  432. ; PENDING_ROW_PTR = HL
  433. ld a, l
  434. ld [PENDING_ROW_PTR], a
  435. ld a, h
  436. ld [PENDING_ROW_PTR + 1], a
  437. ; If Y < 0, write 0s
  438. bit 7, c
  439. jr nz, .zero_row
  440. ; If Y >= MAP_HEIGHT, write 0s
  441. ld a, [CURRENT_MAP_HEIGHT]
  442. dec a
  443. cp c
  444. jr c, .zero_row
  445. ; HL = CURRENT_MAP_PTR
  446. ld a, [CURRENT_MAP_PTR]
  447. ld l, a
  448. ld a, [CURRENT_MAP_PTR + 1]
  449. ld h, a
  450. ; HL = CURRENT_MAP_PTR + Y * MAP_WIDTH
  451. ld d, 0
  452. ld a, [CURRENT_MAP_WIDTH]
  453. ld e, a
  454. ld a, c
  455. .get_map_row_ptr:
  456. or a
  457. jr z, .copy_map_row
  458. add hl, de
  459. dec a
  460. jr .get_map_row_ptr
  461. .copy_map_row:
  462. ; C = BYTES_LEFT
  463. ld c, ROW_BUFFER_SIZE
  464. ld de, PENDING_ROW_DATA
  465. ; If X > 0, increment map pointer by X
  466. bit 7, b
  467. jr nz, .pad_left
  468. ld a, b
  469. ADD16 hl
  470. jr .copy_middle
  471. .pad_left:
  472. ; Check X < 0
  473. bit 7, b
  474. jr z, .copy_middle
  475. ; Check BYTES_LEFT > 0
  476. ld a, c
  477. or a
  478. ret z
  479. ; *ROW++ = 0
  480. ld a, TILE_INDEX_BACKGROUND
  481. ld [de], a
  482. inc de
  483. ; X++, BYTES_LEFT--
  484. inc b
  485. dec c
  486. jr .pad_left
  487. .copy_middle:
  488. ; Check X < MAP_WIDTH
  489. ld a, [CURRENT_MAP_WIDTH]
  490. dec a
  491. cp b
  492. jr c, .pad_right
  493. ; Check BYTES_LEFT > 0
  494. ld a, c
  495. or a
  496. ret z
  497. ; *ROW++ = *MAP++
  498. ld a, [hl+]
  499. add TILE_INDEX_BACKGROUND
  500. ld [de], a
  501. inc de
  502. ; X++, BYTES_LEFT--
  503. inc b
  504. dec c
  505. jr .copy_middle
  506. .pad_right:
  507. ; Check BYTES_LEFT > 0
  508. ld a, c
  509. or a
  510. ret z
  511. ; *ROW++ = 0
  512. ld a, TILE_INDEX_BACKGROUND
  513. ld [de], a
  514. inc de
  515. ; X++, BYTES_LEFT--
  516. inc b
  517. dec c
  518. jr .pad_right
  519. .zero_row:
  520. ld hl, PENDING_ROW_DATA
  521. xor a
  522. ld c, ROW_BUFFER_SIZE
  523. .zero_row_loop:
  524. ld [hl+], a
  525. dec c
  526. jr nz, .zero_row_loop
  527. ret
  528. ; NOTE: This works by enqueueing a row to write, and then immediately flushing
  529. ; the queue. The subroutine could be sped up by writing to map RAM directly, but
  530. ; this is simpler to write and saves on code size.
  531. ;
  532. ; Write a row of map data into map RAM.
  533. ; @param b Map X coordinate (signed)
  534. ; @param c Map Y coordinate (signed)
  535. ; @param hl Pointer into map VRAM
  536. write_map_row:
  537. push bc
  538. push de
  539. push hl
  540. call init_row_write
  541. pop hl
  542. pop de
  543. pop bc
  544. ret
  545. ; Write a column of map data into column buffer
  546. ; @param b Map X coordinate (signed)
  547. ; @param c Map Y coordinate (signed)
  548. ; @param hl Where to write the column in map VRAM
  549. ; @destroy All registers
  550. enqueue_col_write:
  551. ; PENDING_COL_PTR = HL
  552. ld a, l
  553. ld [PENDING_COL_PTR], a
  554. ld a, h
  555. ld [PENDING_COL_PTR + 1], a
  556. ; If X < 0, write 0s
  557. bit 7, b
  558. jr nz, .zero_row
  559. ; If X >= MAP_WIDTH, write 0s
  560. ld a, [CURRENT_MAP_WIDTH]
  561. dec a
  562. cp b
  563. jr c, .zero_row
  564. ; HL = CURRENT_MAP_PTR + X
  565. ld a, [CURRENT_MAP_PTR]
  566. ld l, a
  567. ld a, [CURRENT_MAP_PTR + 1]
  568. ld h, a
  569. ld a, b
  570. ADD16 hl
  571. ; B = BYTES_LEFT
  572. ld b, COL_BUFFER_SIZE
  573. ld de, PENDING_COL_DATA
  574. .pad_left:
  575. ; Check Y < 0
  576. bit 7, c
  577. jr z, .adjust_hl
  578. ; Check BYTES_LEFT > 0
  579. ld a, b
  580. or a
  581. ret z
  582. ; *ROW++ = 0
  583. ld a, TILE_INDEX_BACKGROUND
  584. ld [de], a
  585. inc de
  586. ; Y++, BYTES_LEFT--
  587. inc c
  588. dec b
  589. jr .pad_left
  590. .adjust_hl:
  591. push de
  592. ; HL += Y * MAP_WIDTH
  593. ld d, 0
  594. ld a, [CURRENT_MAP_WIDTH]
  595. ld e, a
  596. ld a, c
  597. .get_map_col_ptr:
  598. or a
  599. jr z, .done_get_col_map_ptr
  600. add hl, de
  601. dec a
  602. jr .get_map_col_ptr
  603. .done_get_col_map_ptr:
  604. pop de
  605. .copy_middle:
  606. ; Check Y < MAP_HEIGHT
  607. ld a, [CURRENT_MAP_HEIGHT]
  608. dec a
  609. cp c
  610. jr c, .pad_right
  611. ; Check BYTES_LEFT > 0
  612. ld a, b
  613. or a
  614. ret z
  615. ; *ROW++ = *MAP
  616. ld a, [hl]
  617. add TILE_INDEX_BACKGROUND
  618. ld [de], a
  619. inc de
  620. ; MAP += MAP_WIDTH
  621. ld a, [CURRENT_MAP_WIDTH]
  622. ADD16 hl
  623. ; Y++, BYTES_LEFT--
  624. inc c
  625. dec b
  626. jr .copy_middle
  627. .pad_right:
  628. ; Check BYTES_LEFT > 0
  629. ld a, b
  630. or a
  631. ret z
  632. ; *ROW++ = 0
  633. ld a, TILE_INDEX_BACKGROUND
  634. ld [de], a
  635. inc de
  636. ; X++, BYTES_LEFT--
  637. inc c
  638. dec b
  639. jr .pad_right
  640. .zero_row:
  641. ld hl, PENDING_COL_DATA
  642. xor a
  643. ld c, COL_BUFFER_SIZE
  644. .zero_row_loop:
  645. ld [hl+], a
  646. dec c
  647. jr nz, .zero_row_loop
  648. ret
  649. ; Basically enqueue_col_write but for entire row, used during map load
  650. ; TODO: Deduplicate
  651. ; @param b Map X coordinate (signed)
  652. ; @param c Map Y coordinate (signed)
  653. ; @param hl Where to write the column in map VRAM
  654. ; @destroy All registers
  655. init_row_write:
  656. ; If Y < 0, write 0s
  657. bit 7, c
  658. jr nz, .zero_row
  659. ; If Y >= MAP_HEIGHT, write 0s
  660. ld a, [CURRENT_MAP_HEIGHT]
  661. dec a
  662. cp c
  663. jr c, .zero_row
  664. ; DE = HL
  665. ld d, h
  666. ld e, l
  667. ; HL = CURRENT_MAP_PTR
  668. ld a, [CURRENT_MAP_PTR]
  669. ld l, a
  670. ld a, [CURRENT_MAP_PTR + 1]
  671. ld h, a
  672. push de
  673. ; HL = CURRENT_MAP_PTR + Y * MAP_WIDTH
  674. ld d, 0
  675. ld a, [CURRENT_MAP_WIDTH]
  676. ld e, a
  677. ld a, c
  678. .get_map_row_ptr:
  679. or a
  680. jr z, .copy_map_row
  681. add hl, de
  682. dec a
  683. jr .get_map_row_ptr
  684. .copy_map_row:
  685. pop de
  686. ; C = BYTES_LEFT
  687. ld c, SCRN_VX_B
  688. ; If X > 0, increment map pointer by X
  689. ; TODO: Remove this branch by adding X before copy_middle
  690. bit 7, b
  691. jr nz, .pad_left
  692. ld a, b
  693. ADD16 hl
  694. jr .copy_middle
  695. .pad_left:
  696. ; Check X < 0
  697. bit 7, b
  698. jr z, .copy_middle
  699. ; Check BYTES_LEFT > 0
  700. ld a, c
  701. or a
  702. ret z
  703. ; *ROW++ = 0
  704. ld a, TILE_INDEX_BACKGROUND
  705. ld [de], a
  706. inc de
  707. ; X++, BYTES_LEFT--
  708. inc b
  709. dec c
  710. jr .pad_left
  711. .copy_middle:
  712. ; Check X < MAP_WIDTH
  713. ld a, [CURRENT_MAP_WIDTH]
  714. dec a
  715. cp b
  716. jr c, .pad_right
  717. ; Check BYTES_LEFT > 0
  718. ld a, c
  719. or a
  720. ret z
  721. ; *ROW++ = *MAP++
  722. ld a, [hl+]
  723. add TILE_INDEX_BACKGROUND
  724. ld [de], a
  725. inc de
  726. ; X++, BYTES_LEFT--
  727. inc b
  728. dec c
  729. jr .copy_middle
  730. .pad_right:
  731. ; Check BYTES_LEFT > 0
  732. ld a, c
  733. or a
  734. ret z
  735. ; *ROW++ = 0
  736. ld a, TILE_INDEX_BACKGROUND
  737. ld [de], a
  738. inc de
  739. ; X++, BYTES_LEFT--
  740. inc b
  741. dec c
  742. jr .pad_right
  743. .zero_row:
  744. xor a
  745. ld c, SCRN_VX_B
  746. .zero_row_loop:
  747. ld [hl+], a
  748. dec c
  749. jr nz, .zero_row_loop
  750. ret