mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-09-09 09:51:34 -07:00
40902ffe24
This was discussed in #706 It also uncovered some off-by-one issues with defining some constants. A few structs now use rsreset/_RS to define their offset constants, as discussed in #739
672 lines
8.9 KiB
NASM
672 lines
8.9 KiB
NASM
GetEmote2bpp:
|
|
ld a, $1
|
|
ldh [rVBK], a
|
|
call Get2bpp
|
|
xor a
|
|
ldh [rVBK], a
|
|
ret
|
|
|
|
_UpdatePlayerSprite::
|
|
call GetPlayerSprite
|
|
ld a, [wUsedSprites]
|
|
ldh [hUsedSpriteIndex], a
|
|
ld a, [wUsedSprites + 1]
|
|
ldh [hUsedSpriteTile], a
|
|
call GetUsedSprite
|
|
ret
|
|
|
|
_RefreshSprites: ; mobile
|
|
ld hl, wSpriteFlags
|
|
ld a, [hl]
|
|
push af
|
|
res 7, [hl]
|
|
set 6, [hl]
|
|
call LoadUsedSpritesGFX
|
|
pop af
|
|
ld [wSpriteFlags], a
|
|
ret
|
|
|
|
_ClearSprites: ; mobile
|
|
ld hl, wSpriteFlags
|
|
ld a, [hl]
|
|
push af
|
|
set 7, [hl]
|
|
res 6, [hl]
|
|
call LoadUsedSpritesGFX
|
|
pop af
|
|
ld [wSpriteFlags], a
|
|
ret
|
|
|
|
RefreshSprites::
|
|
call .Refresh
|
|
call LoadUsedSpritesGFX
|
|
ret
|
|
|
|
.Refresh:
|
|
xor a
|
|
ld bc, wUsedSpritesEnd - wUsedSprites
|
|
ld hl, wUsedSprites
|
|
call ByteFill
|
|
call GetPlayerSprite
|
|
call AddMapSprites
|
|
call LoadAndSortSprites
|
|
ret
|
|
|
|
GetPlayerSprite:
|
|
; Get Chris or Kris's sprite.
|
|
ld hl, ChrisStateSprites
|
|
ld a, [wPlayerSpriteSetupFlags]
|
|
bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a
|
|
jr nz, .go
|
|
ld a, [wPlayerGender]
|
|
bit PLAYERGENDER_FEMALE_F, a
|
|
jr z, .go
|
|
ld hl, KrisStateSprites
|
|
|
|
.go
|
|
ld a, [wPlayerState]
|
|
ld c, a
|
|
.loop
|
|
ld a, [hli]
|
|
cp c
|
|
jr z, .good
|
|
inc hl
|
|
cp -1
|
|
jr nz, .loop
|
|
|
|
; Any player state not in the array defaults to Chris's sprite.
|
|
xor a ; ld a, PLAYER_NORMAL
|
|
ld [wPlayerState], a
|
|
ld a, SPRITE_CHRIS
|
|
jr .finish
|
|
|
|
.good
|
|
ld a, [hl]
|
|
|
|
.finish
|
|
ld [wUsedSprites + 0], a
|
|
ld [wPlayerSprite], a
|
|
ld [wPlayerObjectSprite], a
|
|
ret
|
|
|
|
INCLUDE "data/sprites/player_sprites.asm"
|
|
|
|
AddMapSprites:
|
|
call GetMapEnvironment
|
|
call CheckOutdoorMap
|
|
jr z, .outdoor
|
|
call AddIndoorSprites
|
|
ret
|
|
|
|
.outdoor
|
|
call AddOutdoorSprites
|
|
ret
|
|
|
|
AddIndoorSprites:
|
|
ld hl, wMap1ObjectSprite
|
|
ld a, 1
|
|
.loop
|
|
push af
|
|
ld a, [hl]
|
|
call AddSpriteGFX
|
|
ld de, MAPOBJECT_LENGTH
|
|
add hl, de
|
|
pop af
|
|
inc a
|
|
cp NUM_OBJECTS
|
|
jr nz, .loop
|
|
ret
|
|
|
|
AddOutdoorSprites:
|
|
ld a, [wMapGroup]
|
|
dec a
|
|
ld c, a
|
|
ld b, 0
|
|
ld hl, OutdoorSprites
|
|
add hl, bc
|
|
add hl, bc
|
|
ld a, [hli]
|
|
ld h, [hl]
|
|
ld l, a
|
|
ld c, MAX_OUTDOOR_SPRITES
|
|
.loop
|
|
push bc
|
|
ld a, [hli]
|
|
call AddSpriteGFX
|
|
pop bc
|
|
dec c
|
|
jr nz, .loop
|
|
ret
|
|
|
|
LoadUsedSpritesGFX:
|
|
ld a, MAPCALLBACK_SPRITES
|
|
call RunMapCallback
|
|
call GetUsedSprites
|
|
call LoadMiscTiles
|
|
ret
|
|
|
|
LoadMiscTiles:
|
|
ld a, [wSpriteFlags]
|
|
bit 6, a
|
|
ret nz
|
|
|
|
ld c, EMOTE_SHADOW
|
|
farcall LoadEmote
|
|
call GetMapEnvironment
|
|
call CheckOutdoorMap
|
|
ld c, EMOTE_GRASS_RUSTLE
|
|
jr z, .outdoor
|
|
ld c, EMOTE_BOULDER_DUST
|
|
.outdoor
|
|
farcall LoadEmote
|
|
ret
|
|
|
|
SafeGetSprite:
|
|
push hl
|
|
call GetSprite
|
|
pop hl
|
|
ret
|
|
|
|
GetSprite:
|
|
call GetMonSprite
|
|
ret c
|
|
|
|
ld hl, OverworldSprites + SPRITEDATA_ADDR
|
|
dec a
|
|
ld c, a
|
|
ld b, 0
|
|
ld a, NUM_SPRITEDATA_FIELDS
|
|
call AddNTimes
|
|
; load the address into de
|
|
ld a, [hli]
|
|
ld e, a
|
|
ld a, [hli]
|
|
ld d, a
|
|
; load the length into c
|
|
ld a, [hli]
|
|
swap a
|
|
ld c, a
|
|
; load the sprite bank into both b and h
|
|
ld b, [hl]
|
|
ld a, [hli]
|
|
; load the sprite type into l
|
|
ld l, [hl]
|
|
ld h, a
|
|
ret
|
|
|
|
GetMonSprite:
|
|
; Return carry if a monster sprite was loaded.
|
|
|
|
cp SPRITE_POKEMON
|
|
jr c, .Normal
|
|
cp SPRITE_DAY_CARE_MON_1
|
|
jr z, .BreedMon1
|
|
cp SPRITE_DAY_CARE_MON_2
|
|
jr z, .BreedMon2
|
|
cp SPRITE_VARS
|
|
jr nc, .Variable
|
|
jr .Icon
|
|
|
|
.Normal:
|
|
and a
|
|
ret
|
|
|
|
.Icon:
|
|
sub SPRITE_POKEMON
|
|
ld e, a
|
|
ld d, 0
|
|
ld hl, SpriteMons
|
|
add hl, de
|
|
ld a, [hl]
|
|
jr .Mon
|
|
|
|
.BreedMon1
|
|
ld a, [wBreedMon1Species]
|
|
jr .Mon
|
|
|
|
.BreedMon2
|
|
ld a, [wBreedMon2Species]
|
|
|
|
.Mon:
|
|
ld e, a
|
|
and a
|
|
jr z, .NoBreedmon
|
|
|
|
farcall LoadOverworldMonIcon
|
|
|
|
ld l, WALKING_SPRITE
|
|
ld h, 0
|
|
scf
|
|
ret
|
|
|
|
.Variable:
|
|
sub SPRITE_VARS
|
|
ld e, a
|
|
ld d, 0
|
|
ld hl, wVariableSprites
|
|
add hl, de
|
|
ld a, [hl]
|
|
and a
|
|
jp nz, GetMonSprite
|
|
|
|
.NoBreedmon:
|
|
ld a, WALKING_SPRITE
|
|
ld l, WALKING_SPRITE
|
|
ld h, 0
|
|
and a
|
|
ret
|
|
|
|
_DoesSpriteHaveFacings::
|
|
; Checks to see whether we can apply a facing to a sprite.
|
|
; Returns carry unless the sprite is a Pokemon or a Still Sprite.
|
|
cp SPRITE_POKEMON
|
|
jr nc, .only_down
|
|
|
|
push hl
|
|
push bc
|
|
ld hl, OverworldSprites + SPRITEDATA_TYPE
|
|
dec a
|
|
ld c, a
|
|
ld b, 0
|
|
ld a, NUM_SPRITEDATA_FIELDS
|
|
call AddNTimes
|
|
ld a, [hl]
|
|
pop bc
|
|
pop hl
|
|
cp STILL_SPRITE
|
|
jr nz, .only_down
|
|
scf
|
|
ret
|
|
|
|
.only_down
|
|
and a
|
|
ret
|
|
|
|
_GetSpritePalette::
|
|
ld a, c
|
|
call GetMonSprite
|
|
jr c, .is_pokemon
|
|
|
|
ld hl, OverworldSprites + SPRITEDATA_PALETTE
|
|
dec a
|
|
ld c, a
|
|
ld b, 0
|
|
ld a, NUM_SPRITEDATA_FIELDS
|
|
call AddNTimes
|
|
ld c, [hl]
|
|
ret
|
|
|
|
.is_pokemon
|
|
xor a
|
|
ld c, a
|
|
ret
|
|
|
|
LoadAndSortSprites:
|
|
call LoadSpriteGFX
|
|
call SortUsedSprites
|
|
call ArrangeUsedSprites
|
|
ret
|
|
|
|
AddSpriteGFX:
|
|
; Add any new sprite ids to a list of graphics to be loaded.
|
|
; Return carry if the list is full.
|
|
|
|
push hl
|
|
push bc
|
|
ld b, a
|
|
ld hl, wUsedSprites + 2
|
|
ld c, SPRITE_GFX_LIST_CAPACITY - 1
|
|
.loop
|
|
ld a, [hl]
|
|
cp b
|
|
jr z, .exists
|
|
and a
|
|
jr z, .new
|
|
inc hl
|
|
inc hl
|
|
dec c
|
|
jr nz, .loop
|
|
|
|
pop bc
|
|
pop hl
|
|
scf
|
|
ret
|
|
|
|
.exists
|
|
pop bc
|
|
pop hl
|
|
and a
|
|
ret
|
|
|
|
.new
|
|
ld [hl], b
|
|
pop bc
|
|
pop hl
|
|
and a
|
|
ret
|
|
|
|
LoadSpriteGFX:
|
|
; Bug: b is not preserved, so it's useless as a next count.
|
|
; Uncomment the lines below to fix.
|
|
|
|
ld hl, wUsedSprites
|
|
ld b, SPRITE_GFX_LIST_CAPACITY
|
|
.loop
|
|
ld a, [hli]
|
|
and a
|
|
jr z, .done
|
|
push hl
|
|
call .LoadSprite
|
|
pop hl
|
|
ld [hli], a
|
|
dec b
|
|
jr nz, .loop
|
|
|
|
.done
|
|
ret
|
|
|
|
.LoadSprite:
|
|
; push bc
|
|
call GetSprite
|
|
; pop bc
|
|
ld a, l
|
|
ret
|
|
|
|
SortUsedSprites:
|
|
; Bubble-sort sprites by type.
|
|
|
|
; Run backwards through wUsedSprites to find the last one.
|
|
|
|
ld c, SPRITE_GFX_LIST_CAPACITY
|
|
ld de, wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2
|
|
.FindLastSprite:
|
|
ld a, [de]
|
|
and a
|
|
jr nz, .FoundLastSprite
|
|
dec de
|
|
dec de
|
|
dec c
|
|
jr nz, .FindLastSprite
|
|
.FoundLastSprite:
|
|
dec c
|
|
jr z, .quit
|
|
|
|
; If the length of the current sprite is
|
|
; higher than a later one, swap them.
|
|
|
|
inc de
|
|
ld hl, wUsedSprites + 1
|
|
|
|
.CheckSprite:
|
|
push bc
|
|
push de
|
|
push hl
|
|
|
|
.CheckFollowing:
|
|
ld a, [de]
|
|
cp [hl]
|
|
jr nc, .loop
|
|
|
|
; Swap the two sprites.
|
|
|
|
ld b, a
|
|
ld a, [hl]
|
|
ld [hl], b
|
|
ld [de], a
|
|
dec de
|
|
dec hl
|
|
ld a, [de]
|
|
ld b, a
|
|
ld a, [hl]
|
|
ld [hl], b
|
|
ld [de], a
|
|
inc de
|
|
inc hl
|
|
|
|
; Keep doing this until everything's in order.
|
|
|
|
.loop
|
|
dec de
|
|
dec de
|
|
dec c
|
|
jr nz, .CheckFollowing
|
|
|
|
pop hl
|
|
inc hl
|
|
inc hl
|
|
pop de
|
|
pop bc
|
|
dec c
|
|
jr nz, .CheckSprite
|
|
|
|
.quit
|
|
ret
|
|
|
|
ArrangeUsedSprites:
|
|
; Get the length of each sprite and space them out in VRAM.
|
|
; Crystal introduces a second table in VRAM bank 0.
|
|
|
|
ld hl, wUsedSprites
|
|
ld c, SPRITE_GFX_LIST_CAPACITY
|
|
ld b, 0
|
|
.FirstTableLength:
|
|
; Keep going until the end of the list.
|
|
ld a, [hli]
|
|
and a
|
|
jr z, .quit
|
|
|
|
ld a, [hl]
|
|
call GetSpriteLength
|
|
|
|
; Spill over into the second table after $80 tiles.
|
|
add b
|
|
cp $80
|
|
jr z, .loop
|
|
jr nc, .SecondTable
|
|
|
|
.loop
|
|
ld [hl], b
|
|
inc hl
|
|
ld b, a
|
|
|
|
; Assumes the next table will be reached before c hits 0.
|
|
dec c
|
|
jr nz, .FirstTableLength
|
|
|
|
.SecondTable:
|
|
; The second tile table starts at tile $80.
|
|
ld b, $80
|
|
dec hl
|
|
.SecondTableLength:
|
|
; Keep going until the end of the list.
|
|
ld a, [hli]
|
|
and a
|
|
jr z, .quit
|
|
|
|
ld a, [hl]
|
|
call GetSpriteLength
|
|
|
|
; There are only two tables, so don't go any further than that.
|
|
add b
|
|
jr c, .quit
|
|
|
|
ld [hl], b
|
|
ld b, a
|
|
inc hl
|
|
|
|
dec c
|
|
jr nz, .SecondTableLength
|
|
|
|
.quit
|
|
ret
|
|
|
|
GetSpriteLength:
|
|
; Return the length of sprite type a in tiles.
|
|
|
|
cp WALKING_SPRITE
|
|
jr z, .AnyDirection
|
|
cp STANDING_SPRITE
|
|
jr z, .AnyDirection
|
|
cp STILL_SPRITE
|
|
jr z, .OneDirection
|
|
|
|
ld a, 12
|
|
ret
|
|
|
|
.AnyDirection:
|
|
ld a, 12
|
|
ret
|
|
|
|
.OneDirection:
|
|
ld a, 4
|
|
ret
|
|
|
|
GetUsedSprites:
|
|
ld hl, wUsedSprites
|
|
ld c, SPRITE_GFX_LIST_CAPACITY
|
|
|
|
.loop
|
|
ld a, [wSpriteFlags]
|
|
res 5, a
|
|
ld [wSpriteFlags], a
|
|
|
|
ld a, [hli]
|
|
and a
|
|
jr z, .done
|
|
ldh [hUsedSpriteIndex], a
|
|
|
|
ld a, [hli]
|
|
ldh [hUsedSpriteTile], a
|
|
|
|
bit 7, a
|
|
jr z, .dont_set
|
|
|
|
ld a, [wSpriteFlags]
|
|
set 5, a ; load VBank0
|
|
ld [wSpriteFlags], a
|
|
|
|
.dont_set
|
|
push bc
|
|
push hl
|
|
call GetUsedSprite
|
|
pop hl
|
|
pop bc
|
|
dec c
|
|
jr nz, .loop
|
|
|
|
.done
|
|
ret
|
|
|
|
GetUsedSprite:
|
|
ldh a, [hUsedSpriteIndex]
|
|
call SafeGetSprite
|
|
ldh a, [hUsedSpriteTile]
|
|
call .GetTileAddr
|
|
push hl
|
|
push de
|
|
push bc
|
|
ld a, [wSpriteFlags]
|
|
bit 7, a
|
|
jr nz, .skip
|
|
call .CopyToVram
|
|
|
|
.skip
|
|
pop bc
|
|
ld l, c
|
|
ld h, $0
|
|
rept 4
|
|
add hl, hl
|
|
endr
|
|
pop de
|
|
add hl, de
|
|
ld d, h
|
|
ld e, l
|
|
pop hl
|
|
|
|
ld a, [wSpriteFlags]
|
|
bit 5, a
|
|
jr nz, .done
|
|
bit 6, a
|
|
jr nz, .done
|
|
|
|
ldh a, [hUsedSpriteIndex]
|
|
call _DoesSpriteHaveFacings
|
|
jr c, .done
|
|
|
|
ld a, h
|
|
add HIGH(vTiles1 - vTiles0)
|
|
ld h, a
|
|
call .CopyToVram
|
|
|
|
.done
|
|
ret
|
|
|
|
.GetTileAddr:
|
|
; Return the address of tile (a) in (hl).
|
|
and $7f
|
|
ld l, a
|
|
ld h, 0
|
|
rept 4
|
|
add hl, hl
|
|
endr
|
|
ld a, l
|
|
add LOW(vTiles0)
|
|
ld l, a
|
|
ld a, h
|
|
adc HIGH(vTiles0)
|
|
ld h, a
|
|
ret
|
|
|
|
.CopyToVram:
|
|
ldh a, [rVBK]
|
|
push af
|
|
ld a, [wSpriteFlags]
|
|
bit 5, a
|
|
ld a, $1
|
|
jr z, .bankswitch
|
|
ld a, $0
|
|
|
|
.bankswitch
|
|
ldh [rVBK], a
|
|
call Get2bpp
|
|
pop af
|
|
ldh [rVBK], a
|
|
ret
|
|
|
|
LoadEmote::
|
|
; Get the address of the pointer to emote c.
|
|
ld a, c
|
|
ld bc, EMOTE_LENGTH
|
|
ld hl, Emotes
|
|
call AddNTimes
|
|
; Load the emote address into de
|
|
ld e, [hl]
|
|
inc hl
|
|
ld d, [hl]
|
|
; load the length of the emote (in tiles) into c
|
|
inc hl
|
|
ld c, [hl]
|
|
swap c
|
|
; load the emote pointer bank into b
|
|
inc hl
|
|
ld b, [hl]
|
|
; load the VRAM destination into hl
|
|
inc hl
|
|
ld a, [hli]
|
|
ld h, [hl]
|
|
ld l, a
|
|
; if the emote has a length of 0, do not proceed (error handling)
|
|
ld a, c
|
|
and a
|
|
ret z
|
|
call GetEmote2bpp
|
|
ret
|
|
|
|
INCLUDE "data/sprites/emotes.asm"
|
|
|
|
INCLUDE "data/sprites/sprite_mons.asm"
|
|
|
|
INCLUDE "data/maps/outdoor_sprites.asm"
|
|
|
|
INCLUDE "data/sprites/sprites.asm"
|