385 lines
13 KiB
PHP
385 lines
13 KiB
PHP
;-----------------------------------------------------------------------------
|
|
; sprite.inc
|
|
; Part of manic miner, the zx spectrum game, made for Apple II
|
|
;
|
|
; Stefan Wessels, 2020
|
|
; This is free and unencumbered software released into the public domain.
|
|
|
|
;-----------------------------------------------------------------------------
|
|
.segment "CODE"
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Copy bytes from srcPtr to dstPtr
|
|
; IN: - srcPtr - start of copy
|
|
; dstPtr - start of non-overlapping destination
|
|
; size - number of bytes to copy
|
|
; Clobbers: a, y
|
|
.proc spriteCopyMemSrcToDst
|
|
|
|
ldy #0
|
|
hiCopy:
|
|
dec sizeH
|
|
bmi lowCopy
|
|
:
|
|
lda (srcPtrL), y
|
|
sta (dstPtrL), y
|
|
dey
|
|
bne :-
|
|
inc srcPtrH
|
|
inc dstPtrH
|
|
bne hiCopy
|
|
|
|
lowCopy:
|
|
ldy sizeL
|
|
dey
|
|
bmi done
|
|
:
|
|
lda (srcPtrL), y
|
|
sta (dstPtrL), y
|
|
dey
|
|
bpl :-
|
|
|
|
done:
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Look up the color, and apply those masks to the frames
|
|
; IN: x = start frame
|
|
; y = num frames
|
|
; a = color index
|
|
; Clobbers: a, y
|
|
.proc spriteApplyMaskToFrames
|
|
|
|
instanceIdx = tmpBot + 0
|
|
colMaskL = tmpBot + 1
|
|
colMaskR = tmpBot + 2
|
|
numFrames = tmpBot + 3
|
|
|
|
sty numFrames ; save y
|
|
tay ; put color index in y
|
|
|
|
lda masksLeft, y ; look up the masks for the color
|
|
sta colMaskL
|
|
lda masksRight, y
|
|
sta colMaskR
|
|
|
|
lda mult64L, x ; build a pointer to the frame
|
|
sta srcPtrL
|
|
lda mult64H, x
|
|
adc #>spriteInstances
|
|
sta srcPtrH
|
|
|
|
ldy numFrames ; convert frames to bytes
|
|
lda mult64H, y
|
|
sta sizeH
|
|
lda mult64L, y
|
|
sta sizeL
|
|
|
|
ldy #0 ; do blocks of 256
|
|
hiPass:
|
|
dec sizeH ; see if there's a hi block to do
|
|
bmi lowPass ; if none (remain) to do, move on
|
|
:
|
|
lda (srcPtrL), y ; do a left hand byte
|
|
and colMaskL
|
|
sta (srcPtrL), y
|
|
dey
|
|
lda (srcPtrL), y ; then a right hand byte
|
|
and colMaskR
|
|
sta (srcPtrL), y
|
|
dey
|
|
bne :- ; for 256 bytes
|
|
inc dstPtrH ; advance the dest ptr Hi
|
|
bne hiPass ; BRA
|
|
|
|
lowPass:
|
|
ldy sizeL ; do bytes remaining lt 256
|
|
dey
|
|
bmi done ; keep going till all done
|
|
:
|
|
lda (srcPtrL), y
|
|
and colMaskL
|
|
sta (srcPtrL), y
|
|
dey
|
|
lda (srcPtrL), y
|
|
and colMaskR
|
|
sta (srcPtrL), y
|
|
dey
|
|
bpl :-
|
|
|
|
done:
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Copy one frame to another
|
|
; IN:
|
|
; originalFrame = tmpBot + 4
|
|
; newFrame = tmpBot + 5
|
|
; Clobbers: a, x, y
|
|
.proc spriteCopyFrameToFrame
|
|
|
|
originalFrame = tmpBot + 4
|
|
newFrame = tmpBot + 5
|
|
|
|
clc
|
|
|
|
ldx originalFrame ; point srcPtr at the original frame
|
|
lda mult64L, x
|
|
sta srcPtrL
|
|
lda mult64H, x
|
|
adc #>spriteInstances
|
|
sta srcPtrH
|
|
|
|
ldx newFrame ; point dstPtr at the target frame
|
|
lda mult64L, x
|
|
sta dstPtrL
|
|
lda mult64H, x
|
|
adc #>spriteInstances
|
|
sta dstPtrH
|
|
|
|
lda #0 ; 256 or less bytes (no Hi)
|
|
sta sizeH
|
|
lda #64 ; just 64 bytes to copy
|
|
sta sizeL
|
|
jsr spriteCopyMemSrcToDst ; use copymem to copy a 64 byte frame
|
|
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Invert the pixels of a frame
|
|
; IN:
|
|
; x = frame number
|
|
.proc spriteInvertFrame
|
|
|
|
clc
|
|
lda mult64L, x ; make srcPtr point at the frame
|
|
sta srcPtrL
|
|
lda mult64H, x
|
|
adc #>spriteInstances
|
|
sta srcPtrH
|
|
|
|
ldy #SPRITE_BYTES - 1 ; do for a whole frame (0 based)
|
|
:
|
|
lda (srcPtrL), y ; get the frame byte
|
|
eor #%01111111 ; invert except for the MSB
|
|
sta (srcPtrL), y ; and save the byte
|
|
dey ; one less byte to do
|
|
bpl :- ; do for all bytes
|
|
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Clear all the pixels of a frame
|
|
; IN:
|
|
; x = frame number
|
|
; y = number of frames to clear
|
|
.proc spriteClearFrames
|
|
|
|
count = sizeL
|
|
|
|
lda mult64L, y ; turn the number of frames into num bytes
|
|
sta count ; save as a count
|
|
|
|
clc ; and clear carry
|
|
lda mult64L, x ; make srcPtr point at the
|
|
sta srcPtrL
|
|
lda mult64H, x
|
|
adc #>spriteInstances
|
|
sta srcPtrH
|
|
|
|
ldy count ; how many bytes to clear
|
|
dey ; make zero based
|
|
lda #0 ; value to write
|
|
:
|
|
sta (srcPtrL), y ; write 0 to frame
|
|
dey ; previous byte in frame
|
|
bpl :- ; do for all, incl. zero'th byte
|
|
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Make an instance of the bitmap (index in a) into the spriteInstance buffer
|
|
; while expanding the bitmap from 32 byte 1bpp into 64 byte 2bpp and masking
|
|
; the instance for the required color.
|
|
; IN:
|
|
; a - bitmapIdx
|
|
; x - instanceIdx
|
|
.proc spriteInstanceSpriteFrames
|
|
|
|
; count = tmpBot + 0
|
|
; spriteIdx = tmpBot + 1
|
|
instanceIdx = tmpBot + 2
|
|
srcIdx = tmpBot + 3
|
|
dstIdx = tmpBot + 4
|
|
colMaskL = tmpBot + 5
|
|
colMaskR = tmpBot + 6
|
|
|
|
ldy #0
|
|
sty srcPtrH
|
|
sty dstPtrH
|
|
|
|
ldy #5 ; mult * 32 (shl 5 times) since each src frame is 32 bytes
|
|
:
|
|
asl ; shift the low
|
|
rol srcPtrH ; and the hi, and move carry into hi if needed
|
|
dey ; do for all 6 iterations
|
|
bne :-
|
|
|
|
adc #<sprite08 ; add the memory offset off the non-willy src sprites
|
|
sta srcPtrL
|
|
lda #>sprite08
|
|
adc srcPtrH
|
|
sta srcPtrH ; src ptr now points at the 1st frame
|
|
|
|
lda spriteFramesIdx, x ; get the sprite dest frame
|
|
ldy #6 ; mult * 64 (shl 6 times) since each frame is 64 bytes
|
|
:
|
|
asl ; shift the lo
|
|
rol dstPtrH ; and the hi, and move carry into hi if needed
|
|
dey ; do for all 6 iterations
|
|
bne :-
|
|
sta dstPtrL ; save the lo
|
|
lda dstPtrH ; get the hi
|
|
adc #>spriteInstances ; and make relative to the buffer
|
|
sta dstPtrH ; and save the hi
|
|
|
|
lda #1 ; assume 4 frames = 256 bytes
|
|
sta sizeH
|
|
lda spriteClass, x ; get the class
|
|
bit bit1Mask ; CLASS_FOUR_FRAME is it 4 frames
|
|
bne :+ ; yes, all set
|
|
inc sizeH ; 8 frames = 512 bytes = 2 Hi
|
|
|
|
:
|
|
ldy instanceIdx ; get the instance
|
|
lda spriteColor, y ; and get the color for the instance
|
|
tay ; put the color index in y
|
|
lda masksLeft, y ; get the color mask
|
|
sta colMaskL
|
|
lda masksRight, y ; do the same for the right
|
|
sta colMaskR ; SQW - look at comments but save for second (inverse) buffer
|
|
|
|
ldy #0
|
|
sty dstIdx ; set the src and dst indices to start at 0
|
|
sty srcIdx ; srcIndex moves at 1/2 of dstIndex
|
|
|
|
copyFrames:
|
|
ldy srcIdx ; get the source index
|
|
lda (srcPtrL), y ; get a (left) src byte at the source index
|
|
pha ; save so the right nibble can be expanded later
|
|
lsr ; make the left nibble the low nibble
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tax ; put the value in x
|
|
lda binDouble, x ; look up the "pixel doubled" value
|
|
ora #$80 ; and set the color msb "on"
|
|
and colMaskL ; mask it with appropriate color
|
|
ldy dstIdx ; get the destination offset
|
|
sta (dstPtrL), y ; and save to instance destination
|
|
iny ; move the destination along one
|
|
pla ; get the source byte
|
|
and #$0f ; mask so only right nibble
|
|
tax ; put it in x
|
|
lda binDouble, x ; and look up the "doubled" pixel values
|
|
sec ; set carry so a rotate will be equiv to or #$80
|
|
ror ; and rotate, making it a "right" byte
|
|
and colMaskR ; mask it with appropriate color
|
|
sta (dstPtrL), y ; and save to instance destination
|
|
iny ; move the dest index along again
|
|
sty dstIdx ; and save the index
|
|
bne :+ ; if the index rolled over
|
|
inc dstPtrH ; move the hi byte along
|
|
dec sizeH ; check if moved all required 4 * 32 src byte blocks
|
|
beq done
|
|
:
|
|
inc srcIdx ; move the src index along
|
|
bne copyFrames ; do max 256 bytes = 8 * 32 byte src frames
|
|
|
|
done:
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Copy the door frame, invert the copy, mask both and combine
|
|
.proc spriteDoorSetup
|
|
|
|
originalFrame = tmpBot + 4
|
|
newFrame = tmpBot + 5
|
|
|
|
ldx numSprites ; numSprites is the door sprite index
|
|
lda spriteFramesIdx, x
|
|
tax
|
|
stx originalFrame
|
|
inx
|
|
stx newFrame
|
|
jsr spriteCopyFrameToFrame ; make a copy y = instanceIdx, a = srcFrame, x = dstFrame
|
|
|
|
ldx newFrame
|
|
jsr spriteInvertFrame ; invert the instance frame bits (leave msb alone)
|
|
|
|
ldx currLevel
|
|
lda door_color1, x
|
|
beq :+
|
|
ldx originalFrame
|
|
ldy #1
|
|
jsr spriteApplyMaskToFrames
|
|
|
|
ldx currLevel
|
|
lda door_color2, x
|
|
beq :+
|
|
ldx newFrame
|
|
ldy #1
|
|
jmp spriteApplyMaskToFrames
|
|
|
|
:
|
|
rts
|
|
|
|
.endproc
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Make 4 copies of Eugene frame 0 into frames 1-4 and apply a different
|
|
; color mask to the additional frames
|
|
.proc spriteEugeneSetup
|
|
|
|
originalFrame = tmpBot + 4
|
|
newFrame = tmpBot + 5
|
|
count = tmpBot + 6
|
|
|
|
ldx numSprites
|
|
dex ; eugene is sprite before the door
|
|
|
|
lda spriteFramesIdx, x ; get the frame where eugene is
|
|
tax ; put in x
|
|
stx originalFrame ; and call it the original
|
|
inx ; and go to the next frame
|
|
stx newFrame ; and call it the new frame
|
|
ldx #3 ; and set the loop count to 3
|
|
stx count
|
|
:
|
|
jsr spriteCopyFrameToFrame ; make a copy of eugene, x = ori, y = new
|
|
|
|
lda count ; get the count in a (as a color mask index)
|
|
ldx newFrame ; the frame in x
|
|
ldy #1 ; and the number of frames to process in Y
|
|
jsr spriteApplyMaskToFrames ; mask the new eugene to the "count" color
|
|
|
|
inc newFrame ; go up a frame
|
|
dec count ; and dec the loop counter
|
|
bne :- ; and do for the number of loops (3)
|
|
|
|
rts ; there are now 4 eugenes, White, Green, Orange & Purple
|
|
|
|
.endproc
|