diff options
Diffstat (limited to 'engine/overworld/map_sprites.asm')
-rwxr-xr-x | engine/overworld/map_sprites.asm | 684 |
1 files changed, 306 insertions, 378 deletions
diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm index 05588321..43b44946 100755 --- a/engine/overworld/map_sprites.asm +++ b/engine/overworld/map_sprites.asm @@ -8,433 +8,361 @@ ; fields, respectively, within loops. The X is the loop index. ; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y* ; denote fields of the sprite slots interated over in the inner loop. -InitMapSprites: +_InitMapSprites: call InitOutsideMapSprites ret c ; return if the map is an outside map (already handled by above call) ; if the map is an inside map (i.e. mapID >= $25) - ld hl,wSpriteStateData1 - ld de,wSpriteStateData2 + $0d -; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns. -.copyPictureIDLoop - ld a,[hl] ; $C1X0 (picture ID) - ld [de],a ; $C2XD - ld a,$10 - add e - ld e,a - ld a,$10 - add l - ld l,a - jr nz,.copyPictureIDLoop - -; This is used for both inside and outside maps, since it is called by -; InitOutsideMapSprites. -; Loads tile pattern data for sprites into VRAM. -LoadMapSpriteTilePatterns: - ld a,[wNumSprites] - and a ; are there any sprites? - jr nz,.spritesExist - ret -.spritesExist - ld c,a ; c = [wNumSprites] - ld b,$10 ; number of sprite slots - ld hl,wSpriteStateData2 + $0d - xor a - ld [hFourTileSpriteCount],a -.copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE - ld a,[hli] ; $C2XD (sprite picture ID) - ld [hld],a ; $C2XE - ld a,l - add a,$10 - ld l,a - dec b - jr nz,.copyPictureIDLoop - ld hl,wSpriteStateData2 + $1e -.loadTilePatternLoop - ld de,wSpriteStateData2 + $1d -; Check if the current picture ID has already had its tile patterns loaded. -; This done by looping through the previous sprite slots and seeing if any of -; their picture ID's match that of the current sprite slot. -.checkIfAlreadyLoadedLoop - ld a,e - and a,$f0 - ld b,a ; b = offset of the wSpriteStateData2 sprite slot being checked against - ld a,l - and a,$f0 ; a = offset of current wSpriteStateData2 sprite slot - cp b ; done checking all previous sprite slots? - jr z,.notAlreadyLoaded - ld a,[de] ; picture ID of the wSpriteStateData2 sprite slot being checked against - cp [hl] ; do the picture ID's match? - jp z,.alreadyLoaded - ld a,e - add a,$10 - ld e,a - jr .checkIfAlreadyLoadedLoop -.notAlreadyLoaded - ld de,wSpriteStateData2 + $0e - ld b,$01 -; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot -; this is done in order to find the first free VRAM slot available -.findNextVRAMSlotLoop - ld a,e - add a,$10 - ld e,a - ld a,l - cp e ; reached current slot? - jr z,.foundNextVRAMSlot - ld a,[de] ; $C2YE (VRAM slot) - cp a,11 ; is it one of the first 10 slots? - jr nc,.findNextVRAMSlotLoop - cp b ; compare the slot being checked to the current max - jr c,.findNextVRAMSlotLoop ; if the slot being checked is less than the current max -; if the slot being checked is greater than or equal to the current max - ld b,a ; store new max VRAM slot - jr .findNextVRAMSlotLoop -.foundNextVRAMSlot - inc b ; increment previous max value to get next VRAM tile pattern slot - ld a,b ; a = next VRAM tile pattern slot - push af - ld a,[hl] ; $C2XE (sprite picture ID) - ld b,a ; b = current sprite picture ID - cp a,SPRITE_BALL ; is it a 4-tile sprite? - jr c,.notFourTileSprite - pop af - ld a,[hFourTileSpriteCount] - add a,11 - jr .storeVRAMSlot -.notFourTileSprite - pop af -.storeVRAMSlot - ld [hl],a ; store VRAM slot at $C2XE - ld [hVRAMSlot],a ; used to determine if it's 4-tile sprite later - ld a,b ; a = current sprite picture ID - dec a - add a - add a - push bc - push hl - ld hl,SpriteSheetPointerTable - jr nc,.noCarry - inc h -.noCarry - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - push hl - call ReadSpriteSheetData - push af - push de - push bc - ld hl,vNPCSprites ; VRAM base address - ld bc,$c0 ; number of bytes per VRAM slot - ld a,[hVRAMSlot] - cp a,11 ; is it a 4-tile sprite? - jr nc,.fourTileSpriteVRAMAddr - ld d,a - dec d -; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM -; slot and adding the result to $8000 (the VRAM base address). -.calculateVRAMAddrLoop - add hl,bc - dec d - jr nz,.calculateVRAMAddrLoop - jr .loadStillTilePattern -.fourTileSpriteVRAMAddr - ld hl,vSprites + $7c0 ; address for second 4-tile sprite - ld a,[hFourTileSpriteCount] - and a - jr nz,.loadStillTilePattern -; if it's the first 4-tile sprite - ld hl,vSprites + $780 ; address for first 4-tile sprite - inc a - ld [hFourTileSpriteCount],a -.loadStillTilePattern - pop bc - pop de - pop af - push hl - push hl - ld h,d - ld l,e - pop de - ld b,a - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.skipFirstLoad ; if so, skip loading data into the lower half - ld a,b - ld b,0 - call FarCopyData2 ; load tile pattern data for sprite when standing still -.skipFirstLoad - pop de - pop hl - ld a,[hVRAMSlot] - cp a,11 ; is it a 4-tile sprite? - jr nc,.skipSecondLoad ; if so, there is no second block - push de - call ReadSpriteSheetData - push af - ld a,$c0 - add e - ld e,a - jr nc,.noCarry3 - inc d -.noCarry3 - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.loadWhileLCDOn - pop af - pop hl - set 3,h ; add $800 to hl - push hl - ld h,d - ld l,e - pop de - call FarCopyData2 ; load tile pattern data for sprite when walking - jr .skipSecondLoad -; When reloading the upper half of tile patterns after diplaying text, the LCD -; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must -; be used instead of FarCopyData2. -.loadWhileLCDOn - pop af - pop hl - set 3,h ; add $800 to hl - ld b,a - swap c - call CopyVideoData ; load tile pattern data for sprite when walking -.skipSecondLoad - pop hl - pop bc - jr .nextSpriteSlot -.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded - inc de - ld a,[de] ; a = VRAM slot for the current picture ID (from $C2YE) - ld [hl],a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE) -.nextSpriteSlot - ld a,l - add a,$10 - ld l,a - dec c - jp nz,.loadTilePatternLoop - ld hl,wSpriteStateData2 + $0d - ld b,$10 -; the pictures ID's stored at $C2XD are no longer needed, so zero them -.zeroStoredPictureIDLoop - xor a - ld [hl],a ; $C2XD - ld a,$10 - add l - ld l,a - dec b - jr nz,.zeroStoredPictureIDLoop - ret - -; reads data from SpriteSheetPointerTable -; INPUT: -; hl = address of sprite sheet entry -; OUTPUT: -; de = pointer to sprite sheet -; bc = length in bytes -; a = ROM bank -ReadSpriteSheetData: - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - ld c,a - xor a - ld b,a - ld a,[hli] + call LoadSpriteSetFromMapHeader + call LoadMapSpriteTilePatterns + call Func_14150 ret ; Loads sprite set for outside maps (cities and routes) and sets VRAM slots. ; sets carry if the map is a city or route, unsets carry if not InitOutsideMapSprites: - ld a,[wCurMap] - cp a,REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)? + ld a, [wCurMap] + cp a, REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)? ret nc ; if not, return - ld hl,MapSpriteSets - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - ld a,[hl] ; a = spriteSetID - cp a,$f0 ; does the map have 2 sprite sets? - call nc,GetSplitMapSpriteSetID ; if so, choose the appropriate one - ld b,a ; b = spriteSetID - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.loadSpriteSet ; if so, forcibly reload the sprite set - ld a,[wSpriteSetID] + call GetSplitMapSpriteSetID +; if so, choose the appropriate one + ld b, a ; b = spriteSetID + ld a, [wFontLoaded] + bit 0, a ; reloading upper half of tile patterns after displaying text? + jr nz, .loadSpriteSet ; if so, forcibly reload the sprite set + ld a, [wSpriteSetID] cp b ; has the sprite set ID changed? - jr z,.skipLoadingSpriteSet ; if not, don't load it again + jr z, .skipLoadingSpriteSet ; if not, don't load it again .loadSpriteSet - ld a,b - ld [wSpriteSetID],a + ld a, b + ld [wSpriteSetID], a dec a - ld b,a - sla a - ld c,a - sla a - sla a - add c - add b ; a = (spriteSetID - 1) * 11 - ld de,SpriteSets -; add a to de to get offset of sprite set - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - ld hl,wSpriteStateData2 + $0d - ld a,SPRITE_RED - ld [hl],a - ld bc,wSpriteSet -; Load the sprite set into RAM. -; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A -; with picture ID's. This is done so that LoadMapSpriteTilePatterns will -; load tile patterns for all sprite pictures in the sprite set. -.loadSpriteSetLoop - ld a,$10 - add l - ld l,a - ld a,[de] ; sprite picture ID from sprite set - ld [hl],a ; $C2XD (sprite picture ID) - ld [bc],a - inc de - inc bc - ld a,l - cp a,$bd ; reached 11th sprite slot? - jr nz,.loadSpriteSetLoop - ld b,4 ; 4 remaining sprite slots -.zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots - ld a,$10 - add l - ld l,a - xor a - ld [hl],a ; $C2XD (sprite picture ID) - dec b - jr nz,.zeroRemainingSlotsLoop - ld a,[wNumSprites] - push af ; save number of sprites - ld a,11 ; 11 sprites in sprite set - ld [wNumSprites],a + ld c, a + ld b, 0 + ld a, (wSpriteSetID - wSpriteSet) + ld hl, SpriteSets + call AddNTimes ; get sprite set offset + ld de, wSpriteSet + ld bc, (wSpriteSetID - wSpriteSet) + call CopyData ; copy it to wSpriteSet call LoadMapSpriteTilePatterns - pop af - ld [wNumSprites],a ; restore number of sprites - ld hl,wSpriteStateData2 + $1e - ld b,$0f -; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the -; order of the map's sprite set, not the order of the actual sprites loaded -; for the current map. So, they are not needed and are zeroed by this loop. -.zeroVRAMSlotsLoop - xor a - ld [hl],a ; $C2XE (VRAM slot) - ld a,$10 - add l - ld l,a - dec b - jr nz,.zeroVRAMSlotsLoop .skipLoadingSpriteSet - ld hl,wSpriteStateData1 + $10 + call Func_14150 + scf + ret + +LoadSpriteSetFromMapHeader: ; This loop stores the correct VRAM tile pattern slots according the sprite ; data from the map's header. Since the VRAM tile pattern slots are filled in ; the order of the sprite set, in order to find the VRAM tile pattern slot ; for a sprite slot, the picture ID for the sprite is looked up within the -; sprite set. The index of the picture ID within the sprite set plus one -; (since the Red sprite always has the first VRAM tile pattern slot) is the -; VRAM tile pattern slot. +; sprite set. The index of the picture ID within the sprite set plus two +; (since the Red sprite always has the first VRAM tile pattern slot and the +; Pikachu sprite reserves the second slot) is the VRAM tile pattern slot. + ld hl, wSpriteSet + ld bc, (wSpriteSetID - wSpriteSet) + xor a + call FillMemory + ld a, SPRITE_PIKACHU ; load Pikachu separately + ld [wSpriteSet], a + ld hl, wSprite01SpriteStateData1 + ld a, 14 .storeVRAMSlotsLoop - ld c,0 - ld a,[hl] ; $C1X0 (picture ID) (zero if sprite slot is not used) + push af + ld a, [hl] ; $C1X0 (picture ID) (zero if sprite slot is not used) and a ; is the sprite slot used? - jr z,.skipGettingPictureIndex ; if the sprite slot is not used - ld b,a ; b = picture ID - ld de,wSpriteSet -; Loop to find the index of the sprite's picture ID within the sprite set. -.getPictureIndexLoop - inc c - ld a,[de] + jr z, .continue ; if the sprite slot is not used + ld c, a + call CheckForFourTileSprite ; is this a four tile sprite? + jr nc, .isFourTileSprite +; loop through the space reserved for four tile picture IDs + ld de, wSpriteSet + 9 + ld b, 2 + call CheckIfPictureIDAlreadyLoaded + jr .continue + +.isFourTileSprite +; loop through the space reserved for regular picture IDs + ld de, wSpriteSet + ld b, 9 + call CheckIfPictureIDAlreadyLoaded +.continue + ld de, wSprite02SpriteStateData1 - wSprite01SpriteStateData1 + add hl, de + pop af + dec a + jr nz, .storeVRAMSlotsLoop + ret + +CheckIfPictureIDAlreadyLoaded: +; Check if the current picture ID has already had its tile patterns loaded. +; This done by looping through the previous sprite slots and seeing if any of +; their picture ID's match that of the current sprite slot. +.loop + ld a, [de] + and a ; is sprite set slot not taken up yet? + jr z, .spriteSlotNotTaken ; if so, load it as it signifies we've reached + ; the end of data for the last sprite set + + cp c ; is the tile pattern already loaded? + ret z ; don't redundantly load + dec b ; have we reached the end of the sprite set? + jr z, .spriteNotAlreadyLoaded ; if so, we're done here inc de - cp b ; does the picture ID match? - jr nz,.getPictureIndexLoop - inc c -.skipGettingPictureIndex - push hl - inc h - ld a,$0e - add l - ld l,a - ld a,c ; a = VRAM slot (zero if sprite slot is not used) - ld [hl],a ; $C2XE (VRAM slot) - pop hl - ld a,$10 - add l - ld l,a + jr .loop + +.spriteSlotNotTaken + ld a, c + ld [de], a + ret +.spriteNotAlreadyLoaded + scf + ret + +CheckForFourTileSprite: +; Checks for a sprite added in yellow +; Returns no carry if the sprite is Pikachu, as its sprite is handled separately +; Else, returns carry if the sprite uses 4 tiles + cp SPRITE_PIKACHU ; is this the Pikachu Sprite? + ret z ; return if yes + + cp SPRITE_BALL ; is this a four tile sprite? + jr nc, .notYellowSprite ; set carry if yes +; regular sprite and a - jr nz,.storeVRAMSlotsLoop + ret + +.notYellowSprite scf ret +LoadMapSpriteTilePatterns: + ld a, 0 +.loop + ld [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadStillTilePattern + call LoadWalkingTilePattern + jr .continue + +.fourTileSprite + call LoadStillTilePattern +.continue + ld a, [hVRAMSlot] + inc a + cp 11 + jr nz, .loop + ret + +ReloadWalkingTilePatterns: + xor a +.loop + ld [hVRAMSlot], a + cp 9 + jr nc, .fourTileSprite + call LoadWalkingTilePattern +.fourTileSprite + ld a, [hVRAMSlot] + inc a + cp 11 + jr nz, .loop + ret + +LoadStillTilePattern: + ld a, [wFontLoaded] + bit 0, a ; reloading upper half of tile patterns after displaying text? + ret nz ; if so, skip loading data into the lower half + call ReadSpriteSheetData + ret nc + call GetSpriteVRAMAddress + call CopyVideoDataAlternate ; new yellow function + ret + +LoadWalkingTilePattern: + call ReadSpriteSheetData + ret nc + ld hl, $c0 + add hl, de + ld d, h + ld e, l + call GetSpriteVRAMAddress + set 3, h ; add $800 to hl + call CopyVideoDataAlternate + ret + +GetSpriteVRAMAddress: + push bc + ld a, [hVRAMSlot] + ld c, a + ld b, 0 + ld hl, SpriteVRAMAddresses + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + pop bc + ret + +SpriteVRAMAddresses: +; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM +; slot and adding the result to $8000 (the VRAM base address). + dw vChars0 + $0c0 + dw vChars0 + $180 + dw vChars0 + $240 + dw vChars0 + $300 + dw vChars0 + $3c0 + dw vChars0 + $480 + dw vChars0 + $540 + dw vChars0 + $600 + dw vChars0 + $6c0 + dw vChars0 + $780 ; 4-tile sprites + dw vChars0 + $7c0 ; 4-tile sprites + +ReadSpriteSheetData: + ld a, [hVRAMSlot] + ld e, a + ld d, 0 + ld hl, wSpriteSet + add hl, de + ld a, [hl] + and a + ret z + + dec a + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, SpriteSheetPointerTable + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld c, [hl] + swap c ; get the number of tiles, not the raw byte length + ; this is because of the use of CopyVideoDataAlternate + inc hl + ld b, [hl] + inc hl + scf + ret + +Func_14150: + ld a, $1 + ld [wPlayerSpriteImageBaseOffset], a ; vram slot for player + ld a, $2 + ld [wPikachuSpriteImageBaseOffset], a ; vram slot for Pikachu + ld a, $e + ld hl, wSprite01SpriteStateData1 +.loop + ld [hVRAMSlot], a ; store current sprite set slot as a counter + ld a, [hl] ; $c1x0 (picture ID) + and a ; is the sprite unused? + jr z, .spriteUnused + call Func_14179 + push hl + ld de, (wPlayerSpriteImageBaseOffset) - (wSpriteStateData1) ; $10e + add hl, de ; get $c2xe (sprite image base offset) + ld [hl], a ; write offset + pop hl +.spriteUnused + ld de, wSprite02SpriteStateData1 - wSprite01SpriteStateData1 + add hl, de + ld a, [hVRAMSlot] + dec a + jr nz, .loop + ret + +Func_14179: + push de + push bc + ld c, a ; c = picture ID + ld b, 11 + ld de, wSpriteSet +.findSpriteImageBaseOffsetLoop + ld a, [de] ; a = sprite set picture ID + cp c ; have we found a match? + jr z, .foundSpritePictureID ; if so, get the sprite image base offset and return + inc de + dec b ; have we looped through all entries in wSpriteSet? + jr nz, .findSpriteImageBaseOffsetLoop ; continue looping if not + ld a, $1 ; assume slot one if this ever happens + jr .done +.foundSpritePictureID + ld a, 13 + sub b ; get sprite image base offset +.done + pop bc + pop de + ret + +GetSplitMapSpriteSetID: + ld e, a + ld d, 0 + ld hl, MapSpriteSets + add hl, de + ld a, [hl] ; a = spriteSetID + cp a, $f0 ; does the map have 2 sprite sets? + ret c ; Chooses the correct sprite set ID depending on the player's position within ; the map for maps with two sprite sets. -GetSplitMapSpriteSetID: - cp a,$f8 - jr z,.route20 - ld hl,SplitMapSpriteSets - and a,$0f + cp a, $f8 + jr z, .route20 + ld hl, SplitMapSpriteSets + and a, $0f dec a - sla a - sla a + add a + add a add l - ld l,a - jr nc,.noCarry + ld l, a + jr nc, .noCarry inc h .noCarry - ld a,[hli] ; determines whether the map is split East/West or North/South - cp a,$01 - ld a,[hli] ; position of dividing line - ld b,a - jr z,.eastWestDivide + ld a, [hli] ; determines whether the map is split East/West or North/South + cp a, $01 + ld a, [hli] ; position of dividing line + ld b, a + jr z, .eastWestDivide .northSouthDivide - ld a,[wYCoord] + ld a, [wYCoord] jr .compareCoord + .eastWestDivide - ld a,[wXCoord] + ld a, [wXCoord] .compareCoord cp b - jr c,.loadSpriteSetID + jr c, .loadSpriteSetID ; if in the East side or South side inc hl .loadSpriteSetID - ld a,[hl] + ld a, [hl] ret ; Uses sprite set $01 for West side and $0A for East side. ; Route 20 is a special case because the two map sections have a more complex ; shape instead of the map simply being split horizontally or vertically. .route20 - ld hl,wXCoord - ld a,[hl] - cp a,$2b - ld a,$01 + ld hl, wXCoord + ld a, [hl] + cp a, $2b + ld a, $01 ret c - ld a,[hl] - cp a,$3e - ld a,$0a + ld a, [hl] + cp a, $3e + ld a, $0a ret nc - ld a,[hl] - cp a,$37 - ld b,$08 - jr nc,.next - ld b,$0d + ld a, [hl] + cp a, $37 + ld b, $08 + jr nc, .next + ld b, $0d .next - ld a,[wYCoord] + ld a, [wYCoord] cp b - ld a,$0a + ld a, $0a ret c - ld a,$01 + ld a, $01 ret INCLUDE "data/sprite_sets.asm" |