diff options
| -rw-r--r-- | engine/oam_dma.asm | 25 | ||||
| -rw-r--r-- | engine/overworld/oam.asm | 178 | ||||
| -rwxr-xr-x | main.asm | 180 | 
3 files changed, 205 insertions, 178 deletions
| diff --git a/engine/oam_dma.asm b/engine/oam_dma.asm new file mode 100644 index 00000000..6421a1b8 --- /dev/null +++ b/engine/oam_dma.asm @@ -0,0 +1,25 @@ +WriteDMACodeToHRAM: +; Since no other memory is available during OAM DMA, +; DMARoutine is copied to HRAM and executed there. +	ld c, $ff80 % $100 +	ld b, DMARoutineEnd - DMARoutine +	ld hl, DMARoutine +.copy +	ld a, [hli] +	ld [$ff00+c], a +	inc c +	dec b +	jr nz, .copy +	ret + +DMARoutine: +	; initiate DMA +	ld a, $c3 +	ld [$ff46], a + +	; wait for DMA to finish +	ld a, $28 +.wait	dec a +	jr nz, .wait +	ret +DMARoutineEnd: diff --git a/engine/overworld/oam.asm b/engine/overworld/oam.asm new file mode 100644 index 00000000..040513b1 --- /dev/null +++ b/engine/overworld/oam.asm @@ -0,0 +1,178 @@ +PrepareOAMData: +; Determine OAM data for currently visible +; sprites and write it to wOAMBuffer. + +	ld a, [$cfcb] +	dec a +	jr z, .asm_4b1e + +	cp 0 - 1 +	ret nz +	ld [$cfcb], a +	jp HideSprites + +.asm_4b1e +	xor a +	ld [$ff90], a +.asm_4b21 +	ld [$ff8f], a + +	ld d, wSpriteStateData1 / $100 +	ld a, [$ff8f] +	ld e, a +	ld a, [de] ; c1x0 +	and a +	jp z, .asm_4bad + +	inc e +	inc e +	ld a, [de] ; c1x2 (facing/anim) +	ld [$d5cd], a +	cp $ff ; off-screen (don't draw) +	jr nz, .visible + +	call Func_4bd1 +	jr .asm_4bad + +.visible +	cp $a0 +	jr c, .usefacing +	and $f +	add $10 +	jr .asm_4b48 + +.usefacing +	and $f +.asm_4b48 +	ld l, a + +	push de +	inc d +	ld a, e +	add $5 +	ld e, a +	ld a, [de] ; c2x7 +	and $80 +	ld [$ff94], a ; temp store sprite priority +	pop de + +	ld h, 0 +	ld bc, SpriteFacingAndAnimationTable +	add hl, hl +	add hl, hl +	add hl, bc + +	ld a, [hli] +	ld c, a +	ld a, [hli] +	ld b, a +	ld a, [hli] +	ld h, [hl] +	ld l, a + +	call Func_4bd1 + +	ld a, [$ff90] +	ld e, a +	ld d, wOAMBuffer / $100 +.tile +	ld a, [$ff92]            ; temp for sprite Y position +	add $10                  ; Y=16 is top of screen (Y=0 is invisible) +	add [hl]                 ; add Y offset from table +	ld [de], a               ; write new sprite OAM Y position +	inc hl +	ld a, [$ff91]            ; temp for sprite X position +	add $8                   ; X=8 is left of screen (X=0 is invisible) +	add [hl]                 ; add X offset from table +	inc e +	ld [de], a               ; write new sprite OAM X position +	inc e +	ld a, [bc]               ; read pattern number offset (accomodates orientation (offset 0,4 or 8) and animation (offset 0 or $80)) +	inc bc +	push bc +	ld b, a + +	ld a, [$d5cd]            ; temp copy of c1x2 +	swap a                   ; high nybble determines sprite used (0 is always player sprite, next are some npcs) +	and $f + +	; Sprites $a and $b have one face (and therefore 4 tiles instead of 12). +	; As a result, sprite $b's tile offset is less than normal. +	cp $b +	jr nz, .offset +	ld a, $a * 12 + 4 +	jr .gotoffset + +.offset +	; a *= 12 +	sla a +	sla a +	ld c, a +	sla a +	add c +.gotoffset +	add b ; which frame +	pop bc +	ld [de], a ; tile id +	inc hl +	inc e +	ld a, [hl] +	bit 1, a ; sprite priority +	jr z, .fg +	ld a, [$ff94] ; facing priority +	or [hl] +.fg +	inc hl +	ld [de], a +	inc e +	bit 0, a ; OAMFLAG_ENDOFDATA +	jr z, .tile + +	ld a, e +	ld [$ff90], a + +.asm_4bad +	ld a, [$ff8f] +	add $10 +	cp $100 % $100 +	jp nz, .asm_4b21 + +	; Clear unused OAM. +	ld a, [$ff90] +	ld l, a +	ld h, wOAMBuffer / $100 +	ld de, $4 +	ld b, $a0 +	ld a, [$d736] +	bit 6, a +	ld a, $a0 +	jr z, .clear +	ld a, $90 +.clear +	cp l +	ret z +	ld [hl], b +	add hl, de +	jr .clear + +Func_4bd1: ; 4bd1 (1:4bd1) +	inc e +	inc e +	ld a, [de] ; c1x4 +	ld [$ff92], a +	inc e +	inc e +	ld a, [de] ; c1x6 +	ld [$ff91], a +	ld a, $4 +	add e +	ld e, a +	ld a, [$ff92] +	add $4 +	and $f0 +	ld [de], a ; c1xa (y) +	inc e +	ld a, [$ff91] +	and $f0 +	ld [de], a  ; c1xb (x) +	ret @@ -139,184 +139,8 @@ UnusedNames: ; 4a92 (1:4a92)  	db "マスター@"  	db "エクセレント" -; calculates the OAM data for all currently visible sprites and writes it to wOAMBuffer -PrepareOAMData: ; 4b0f (1:4b0f) -	ld a, [$cfcb] -	dec a -	jr z, .asm_4b1e -	cp $ff -	ret nz -	ld [$cfcb], a -	jp HideSprites -.asm_4b1e -	xor a -	ld [$ff90], a -.asm_4b21 -	ld [$ff8f], a -	ld d, $c1 -	ld a, [$ff8f] -	ld e, a -	ld a, [de]         ; c1x0 -	and a -	jp z, .asm_4bad -	inc e -	inc e -	ld a, [de]         ; c1x2 read combined orientation and animation info -	ld [$d5cd], a -	cp $ff -	jr nz, .spriteVisible   ; $ff -> offscreen, don't draw -	call Func_4bd1 -	jr .asm_4bad -.spriteVisible -	cp $a0 -	jr c, .considerOrientation ; if >= $a0, ignore the sprite orientation and animation (by using a different conversion table) -	and $f -	add $10 -	jr .asm_4b48 -.considerOrientation -	and $f                     ; the lower nybble contains orientation and animation info -.asm_4b48 -	ld l, a -	push de -	inc d -	ld a, e -	add $5 -	ld e, a -	ld a, [de]         ; c2x7 -	and $80 -	ld [$ff94], a          ; temp store bit 7 for later use in OAM flags (draws sprite behind background (used for grass)) -	pop de -	ld h, $0 -	ld bc, SpriteFacingAndAnimationTable -	add hl, hl -	add hl, hl -	add hl, bc                 ; skip to the table location determined by orientation and animation -	ld a, [hli] -	ld c, a -	ld a, [hli] -	ld b, a -	ld a, [hli] -	ld h, [hl] -	ld l, a -	call Func_4bd1 -	ld a, [$ff90] -	ld e, a -	ld d, $c3                ; wOAMBuffer+x is buffer for OAM data -.spriteTilesLoop             ; loops 4 times for the 4 tiles a sprite consists of -	ld a, [$ff92]        ; temp for sprite Y position -	add $10                  ; Y=16 is top of screen (Y=0 is invisible) -	add [hl]                 ; add Y offset from table -	ld [de], a               ; write new sprite OAM Y position -	inc hl -	ld a, [$ff91]        ; temp for sprite X position -	add $8                   ; X=8 is left of screen (X=0 is invisible) -	add [hl]                 ; add X offset from table -	inc e -	ld [de], a               ; write new sprite OAM X position -	inc e -	ld a, [bc]               ; read pattern number offset (accomodates orientation (offset 0,4 or 8) and animation (offset 0 or $80)) -	inc bc -	push bc -	ld b, a -	ld a, [$d5cd]            ; temp copy of c1x2 -	swap a                   ; high nybble determines sprite used (0 is always player sprite, next are some npcs) -	and $f -	cp $b                    ; sprites $a and $b have no orientation or animation and therefore only 4 tiles -	jr nz, .calcTileOffset   ; (instead of 12), so tile b's offset is a special case -	ld a, $7c                ; = $a * 12 + 4 -	jr .doneCalcTileOffset -.calcTileOffset -	sla a -	sla a -	ld c, a -	sla a -	add c                    ; a *= 12 (each sprite consists of 12 tiles) -.doneCalcTileOffset -	add b                    ; add orientation and animation offset -	pop bc -	ld [de], a               ; write OAM sprite pattern number -	inc hl -	inc e -	ld a, [hl] -	bit 1, a                 ; bit 1 is ignored for OAM, it's used here as an "always in foregroud" flag. -	jr z, .alwaysInForeground -	ld a, [$ff94]        ; load bit 7 (set to $80 if sprite is in grass and should be drawn behind it) -	or [hl] -.alwaysInForeground -	inc hl -	ld [de], a               ; write OAM sprite flags -	inc e -	bit 0, a                 ; test for OAMFLAG_ENDOFDATA -	jr z, .spriteTilesLoop -	ld a, e -	ld [$ff90], a -.asm_4bad -	ld a, [$ff8f] -	add $10 -	cp $0 -	jp nz, .asm_4b21 -	ld a, [$ff90] -	ld l, a -	ld h, $c3 -	ld de, $4 -	ld b, $a0 -	ld a, [$d736] -	bit 6, a -	ld a, $a0 -	jr z, .clearUnusedOAMEntriesLoop -	ld a, $90 -.clearUnusedOAMEntriesLoop -	cp l -	ret z -	ld [hl], b -	add hl, de -	jr .clearUnusedOAMEntriesLoop - -Func_4bd1: ; 4bd1 (1:4bd1) -	inc e -	inc e -	ld a, [de]            ; c1x4 -	ld [$ff92], a -	inc e -	inc e -	ld a, [de]            ; c1x6 -	ld [$ff91], a -	ld a, $4 -	add e -	ld e, a -	ld a, [$ff92] -	add $4 -	and $f0 -	ld [de], a            ; c1xa (sprite Y pos (snapped to whole steps (?)) -	inc e -	ld a, [$ff91] -	and $f0 -	ld [de], a            ; c1xb (sprite X pos (snapped to whole steps (?)) -	ret - -; copies DMA routine to HRAM. By GB specifications, all DMA needs to be done in HRAM (no other memory section is available during DMA) -WriteDMACodeToHRAM: ; 4bed (1:4bed) -	ld c, $80 -	ld b, $a -	ld hl, DMARoutine -.copyLoop -	ld a, [hli] -	ld [$ff00+c], a -	inc c -	dec b -	jr nz, .copyLoop -	ret - -; this routine is copied to HRAM and executed there on every VBlank -DMARoutine: ; 4bfb (1:4bfb) -	ld a, $c3 -	ld [$ff46], a   ; start DMA -	ld a, $28 -.waitLoop               ; wait for DMA to finish -	dec a -	jr nz, .waitLoop -	ret - +INCLUDE "engine/overworld/oam.asm" +INCLUDE "engine/oam_dma.asm"  PrintWaitingText:  	FuncCoord 3, 10 | 
