map_sprites.asm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. ; Loads tile patterns for map's sprites.
  2. ; For outside maps, it loads one of several fixed sets of sprites.
  3. ; For inside maps, it loads each sprite picture ID used in the map header.
  4. ; This is also called after displaying text because loading
  5. ; text tile patterns overwrites half of the sprite tile pattern data.
  6. ; Note on notation:
  7. ; $C1X* and $C2X* are used to denote wSpriteStateData1-wSpriteStateData1 + $ff and wSpriteStateData2 + $00-wSpriteStateData2 + $ff sprite slot
  8. ; fields, respectively, within loops. The X is the loop index.
  9. ; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y*
  10. ; denote fields of the sprite slots iterated over in the inner loop.
  11. InitMapSprites:
  12. call InitOutsideMapSprites
  13. ret c ; return if the map is an outside map (already handled by above call)
  14. ; if the map is an inside map (i.e. mapID >= $25)
  15. ld hl, wSpriteStateData1
  16. ld de, wSpriteStateData2 + $0d
  17. ; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns.
  18. .copyPictureIDLoop
  19. ld a, [hl] ; $C1X0 (picture ID)
  20. ld [de], a ; $C2XD
  21. ld a, $10
  22. add e
  23. ld e, a
  24. ld a, $10
  25. add l
  26. ld l, a
  27. jr nz, .copyPictureIDLoop
  28. ; This is used for both inside and outside maps, since it is called by
  29. ; InitOutsideMapSprites.
  30. ; Loads tile pattern data for sprites into VRAM.
  31. LoadMapSpriteTilePatterns:
  32. ld a, [wNumSprites]
  33. and a ; are there any sprites?
  34. jr nz, .spritesExist
  35. ret
  36. .spritesExist
  37. ld c, a ; c = [wNumSprites]
  38. ld b, $10 ; number of sprite slots
  39. ld hl, wSpriteStateData2 + $0d
  40. xor a
  41. ld [hFourTileSpriteCount], a
  42. .copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE
  43. ld a, [hli] ; $C2XD (sprite picture ID)
  44. ld [hld], a ; $C2XE
  45. ld a, l
  46. add $10
  47. ld l, a
  48. dec b
  49. jr nz, .copyPictureIDLoop
  50. ld hl, wSpriteStateData2 + $1e
  51. .loadTilePatternLoop
  52. ld de, wSpriteStateData2 + $1d
  53. ; Check if the current picture ID has already had its tile patterns loaded.
  54. ; This done by looping through the previous sprite slots and seeing if any of
  55. ; their picture ID's match that of the current sprite slot.
  56. .checkIfAlreadyLoadedLoop
  57. ld a, e
  58. and $f0
  59. ld b, a ; b = offset of the wSpriteStateData2 sprite slot being checked against
  60. ld a, l
  61. and $f0 ; a = offset of current wSpriteStateData2 sprite slot
  62. cp b ; done checking all previous sprite slots?
  63. jr z, .notAlreadyLoaded
  64. ld a, [de] ; picture ID of the wSpriteStateData2 sprite slot being checked against
  65. cp [hl] ; do the picture ID's match?
  66. jp z, .alreadyLoaded
  67. ld a, e
  68. add $10
  69. ld e, a
  70. jr .checkIfAlreadyLoadedLoop
  71. .notAlreadyLoaded
  72. ld de, wSpriteStateData2 + $0e
  73. ld b, $01
  74. ; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot
  75. ; this is done in order to find the first free VRAM slot available
  76. .findNextVRAMSlotLoop
  77. ld a, e
  78. add $10
  79. ld e, a
  80. ld a, l
  81. cp e ; reached current slot?
  82. jr z, .foundNextVRAMSlot
  83. ld a, [de] ; $C2YE (VRAM slot)
  84. cp 11 ; is it one of the first 10 slots?
  85. jr nc, .findNextVRAMSlotLoop
  86. cp b ; compare the slot being checked to the current max
  87. jr c, .findNextVRAMSlotLoop ; if the slot being checked is less than the current max
  88. ; if the slot being checked is greater than or equal to the current max
  89. ld b, a ; store new max VRAM slot
  90. jr .findNextVRAMSlotLoop
  91. .foundNextVRAMSlot
  92. inc b ; increment previous max value to get next VRAM tile pattern slot
  93. ld a, b ; a = next VRAM tile pattern slot
  94. push af
  95. ld a, [hl] ; $C2XE (sprite picture ID)
  96. ld b, a ; b = current sprite picture ID
  97. cp SPRITE_BALL ; is it a 4-tile sprite?
  98. jr c, .notFourTileSprite
  99. pop af
  100. ld a, [hFourTileSpriteCount]
  101. add 11
  102. jr .storeVRAMSlot
  103. .notFourTileSprite
  104. pop af
  105. .storeVRAMSlot
  106. ld [hl], a ; store VRAM slot at $C2XE
  107. ld [hVRAMSlot], a ; used to determine if it's 4-tile sprite later
  108. ld a, b ; a = current sprite picture ID
  109. dec a
  110. add a
  111. add a
  112. push bc
  113. push hl
  114. ld hl, SpriteSheetPointerTable
  115. jr nc, .noCarry
  116. inc h
  117. .noCarry
  118. add l
  119. ld l, a
  120. jr nc, .noCarry2
  121. inc h
  122. .noCarry2
  123. push hl
  124. call ReadSpriteSheetData
  125. push af
  126. push de
  127. push bc
  128. ld hl, vNPCSprites ; VRAM base address
  129. ld bc, $c0 ; number of bytes per VRAM slot
  130. ld a, [hVRAMSlot]
  131. cp 11 ; is it a 4-tile sprite?
  132. jr nc, .fourTileSpriteVRAMAddr
  133. ld d, a
  134. dec d
  135. ; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM
  136. ; slot and adding the result to $8000 (the VRAM base address).
  137. .calculateVRAMAddrLoop
  138. add hl, bc
  139. dec d
  140. jr nz, .calculateVRAMAddrLoop
  141. jr .loadStillTilePattern
  142. .fourTileSpriteVRAMAddr
  143. ld hl, vSprites + $7c0 ; address for second 4-tile sprite
  144. ld a, [hFourTileSpriteCount]
  145. and a
  146. jr nz, .loadStillTilePattern
  147. ; if it's the first 4-tile sprite
  148. ld hl, vSprites + $780 ; address for first 4-tile sprite
  149. inc a
  150. ld [hFourTileSpriteCount], a
  151. .loadStillTilePattern
  152. pop bc
  153. pop de
  154. pop af
  155. push hl
  156. push hl
  157. ld h, d
  158. ld l, e
  159. pop de
  160. ld b, a
  161. ld a, [wFontLoaded]
  162. bit 0, a ; reloading upper half of tile patterns after displaying text?
  163. jr nz, .skipFirstLoad ; if so, skip loading data into the lower half
  164. ld a, b
  165. ld b, 0
  166. call FarCopyData2 ; load tile pattern data for sprite when standing still
  167. .skipFirstLoad
  168. pop de
  169. pop hl
  170. ld a, [hVRAMSlot]
  171. cp 11 ; is it a 4-tile sprite?
  172. jr nc, .skipSecondLoad ; if so, there is no second block
  173. push de
  174. call ReadSpriteSheetData
  175. push af
  176. ld a, $c0
  177. add e
  178. ld e, a
  179. jr nc, .noCarry3
  180. inc d
  181. .noCarry3
  182. ld a, [wFontLoaded]
  183. bit 0, a ; reloading upper half of tile patterns after displaying text?
  184. jr nz, .loadWhileLCDOn
  185. pop af
  186. pop hl
  187. set 3, h ; add $800 to hl
  188. push hl
  189. ld h, d
  190. ld l, e
  191. pop de
  192. call FarCopyData2 ; load tile pattern data for sprite when walking
  193. jr .skipSecondLoad
  194. ; When reloading the upper half of tile patterns after displaying text, the LCD
  195. ; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must
  196. ; be used instead of FarCopyData2.
  197. .loadWhileLCDOn
  198. pop af
  199. pop hl
  200. set 3, h ; add $800 to hl
  201. ld b, a
  202. swap c
  203. call CopyVideoData ; load tile pattern data for sprite when walking
  204. .skipSecondLoad
  205. pop hl
  206. pop bc
  207. jr .nextSpriteSlot
  208. .alreadyLoaded ; if the current picture ID has already had its tile patterns loaded
  209. inc de
  210. ld a, [de] ; a = VRAM slot for the current picture ID (from $C2YE)
  211. ld [hl], a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE)
  212. .nextSpriteSlot
  213. ld a, l
  214. add $10
  215. ld l, a
  216. dec c
  217. jp nz, .loadTilePatternLoop
  218. ld hl, wSpriteStateData2 + $0d
  219. ld b, $10
  220. ; the pictures ID's stored at $C2XD are no longer needed, so zero them
  221. .zeroStoredPictureIDLoop
  222. xor a
  223. ld [hl], a ; $C2XD
  224. ld a, $10
  225. add l
  226. ld l, a
  227. dec b
  228. jr nz, .zeroStoredPictureIDLoop
  229. ret
  230. ; reads data from SpriteSheetPointerTable
  231. ; INPUT:
  232. ; hl = address of sprite sheet entry
  233. ; OUTPUT:
  234. ; de = pointer to sprite sheet
  235. ; bc = length in bytes
  236. ; a = ROM bank
  237. ReadSpriteSheetData:
  238. ld a, [hli]
  239. ld e, a
  240. ld a, [hli]
  241. ld d, a
  242. ld a, [hli]
  243. ld c, a
  244. xor a
  245. ld b, a
  246. ld a, [hli]
  247. ret
  248. ; Loads sprite set for outside maps (cities and routes) and sets VRAM slots.
  249. ; sets carry if the map is a city or route, unsets carry if not
  250. InitOutsideMapSprites:
  251. ld a, [wCurMap]
  252. cp REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)?
  253. ret nc ; if not, return
  254. ld hl, MapSpriteSets
  255. add l
  256. ld l, a
  257. jr nc, .noCarry
  258. inc h
  259. .noCarry
  260. ld a, [hl] ; a = spriteSetID
  261. cp $f0 ; does the map have 2 sprite sets?
  262. call nc, GetSplitMapSpriteSetID ; if so, choose the appropriate one
  263. ld b, a ; b = spriteSetID
  264. ld a, [wFontLoaded]
  265. bit 0, a ; reloading upper half of tile patterns after displaying text?
  266. jr nz, .loadSpriteSet ; if so, forcibly reload the sprite set
  267. ld a, [wSpriteSetID]
  268. cp b ; has the sprite set ID changed?
  269. jr z, .skipLoadingSpriteSet ; if not, don't load it again
  270. .loadSpriteSet
  271. ld a, b
  272. ld [wSpriteSetID], a
  273. dec a
  274. ld b, a
  275. sla a
  276. ld c, a
  277. sla a
  278. sla a
  279. add c
  280. add b ; a = (spriteSetID - 1) * 11
  281. ld de, SpriteSets
  282. ; add a to de to get offset of sprite set
  283. add e
  284. ld e, a
  285. jr nc, .noCarry2
  286. inc d
  287. .noCarry2
  288. ld hl, wSpriteStateData2 + $0d
  289. ld a, SPRITE_RED
  290. ld [hl], a
  291. ld bc, wSpriteSet
  292. ; Load the sprite set into RAM.
  293. ; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A
  294. ; with picture ID's. This is done so that LoadMapSpriteTilePatterns will
  295. ; load tile patterns for all sprite pictures in the sprite set.
  296. .loadSpriteSetLoop
  297. ld a, $10
  298. add l
  299. ld l, a
  300. ld a, [de] ; sprite picture ID from sprite set
  301. ld [hl], a ; $C2XD (sprite picture ID)
  302. ld [bc], a
  303. inc de
  304. inc bc
  305. ld a, l
  306. cp $bd ; reached 11th sprite slot?
  307. jr nz, .loadSpriteSetLoop
  308. ld b, 4 ; 4 remaining sprite slots
  309. .zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots
  310. ld a, $10
  311. add l
  312. ld l, a
  313. xor a
  314. ld [hl], a ; $C2XD (sprite picture ID)
  315. dec b
  316. jr nz, .zeroRemainingSlotsLoop
  317. ld a, [wNumSprites]
  318. push af ; save number of sprites
  319. ld a, 11 ; 11 sprites in sprite set
  320. ld [wNumSprites], a
  321. call LoadMapSpriteTilePatterns
  322. pop af
  323. ld [wNumSprites], a ; restore number of sprites
  324. ld hl, wSpriteStateData2 + $1e
  325. ld b, $0f
  326. ; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the
  327. ; order of the map's sprite set, not the order of the actual sprites loaded
  328. ; for the current map. So, they are not needed and are zeroed by this loop.
  329. .zeroVRAMSlotsLoop
  330. xor a
  331. ld [hl], a ; $C2XE (VRAM slot)
  332. ld a, $10
  333. add l
  334. ld l, a
  335. dec b
  336. jr nz, .zeroVRAMSlotsLoop
  337. .skipLoadingSpriteSet
  338. ld hl, wSpriteStateData1 + $10
  339. ; This loop stores the correct VRAM tile pattern slots according the sprite
  340. ; data from the map's header. Since the VRAM tile pattern slots are filled in
  341. ; the order of the sprite set, in order to find the VRAM tile pattern slot
  342. ; for a sprite slot, the picture ID for the sprite is looked up within the
  343. ; sprite set. The index of the picture ID within the sprite set plus one
  344. ; (since the Red sprite always has the first VRAM tile pattern slot) is the
  345. ; VRAM tile pattern slot.
  346. .storeVRAMSlotsLoop
  347. ld c, 0
  348. ld a, [hl] ; $C1X0 (picture ID) (zero if sprite slot is not used)
  349. and a ; is the sprite slot used?
  350. jr z, .skipGettingPictureIndex ; if the sprite slot is not used
  351. ld b, a ; b = picture ID
  352. ld de, wSpriteSet
  353. ; Loop to find the index of the sprite's picture ID within the sprite set.
  354. .getPictureIndexLoop
  355. inc c
  356. ld a, [de]
  357. inc de
  358. cp b ; does the picture ID match?
  359. jr nz, .getPictureIndexLoop
  360. inc c
  361. .skipGettingPictureIndex
  362. push hl
  363. inc h
  364. ld a, $0e
  365. add l
  366. ld l, a
  367. ld a, c ; a = VRAM slot (zero if sprite slot is not used)
  368. ld [hl], a ; $C2XE (VRAM slot)
  369. pop hl
  370. ld a, $10
  371. add l
  372. ld l, a
  373. and a
  374. jr nz, .storeVRAMSlotsLoop
  375. scf
  376. ret
  377. ; Chooses the correct sprite set ID depending on the player's position within
  378. ; the map for maps with two sprite sets.
  379. GetSplitMapSpriteSetID:
  380. cp $f8
  381. jr z, .route20
  382. ld hl, SplitMapSpriteSets
  383. and $0f
  384. dec a
  385. sla a
  386. sla a
  387. add l
  388. ld l, a
  389. jr nc, .noCarry
  390. inc h
  391. .noCarry
  392. ld a, [hli] ; determines whether the map is split East/West or North/South
  393. cp $01
  394. ld a, [hli] ; position of dividing line
  395. ld b, a
  396. jr z, .eastWestDivide
  397. .northSouthDivide
  398. ld a, [wYCoord]
  399. jr .compareCoord
  400. .eastWestDivide
  401. ld a, [wXCoord]
  402. .compareCoord
  403. cp b
  404. jr c, .loadSpriteSetID
  405. ; if in the East side or South side
  406. inc hl
  407. .loadSpriteSetID
  408. ld a, [hl]
  409. ret
  410. ; Uses sprite set $01 for West side and $0A for East side.
  411. ; Route 20 is a special case because the two map sections have a more complex
  412. ; shape instead of the map simply being split horizontally or vertically.
  413. .route20
  414. ld hl, wXCoord
  415. ld a, [hl]
  416. cp $2b
  417. ld a, $01
  418. ret c
  419. ld a, [hl]
  420. cp $3e
  421. ld a, $0a
  422. ret nc
  423. ld a, [hl]
  424. cp $37
  425. ld b, $08
  426. jr nc, .next
  427. ld b, $0d
  428. .next
  429. ld a, [wYCoord]
  430. cp b
  431. ld a, $0a
  432. ret c
  433. ld a, $01
  434. ret
  435. INCLUDE "data/sprite_sets.asm"