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