mminer-apple2/src/apple2/tiles.inc

449 lines
16 KiB
PHP

;-----------------------------------------------------------------------------
; tiles.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"
;-----------------------------------------------------------------------------
.proc tilesPrepForLevel
jsr tilesMakeInstances ; copy tile data to instance area
lda monochrome ; see if the game should render for monochrome
beq color ; no, apply all masks
mono:
ldy #(DATA_COLLAPSE / $10) - 1 ; apply color mask only to the conveyor tile
ldx #((DATA_COLLAPSE / $10) -1) * TILE_BYTES
lda #1
bne mask
color:
ldy #0
ldx #0
lda #TILES_PER_LEVEL
mask:
jsr tilesColorInstances ; color instance tiles by applying appropriate color masks
jsr tilesPrepKeysTiles ; make animated keys from the key tile
jmp tilesPrepConveyorTiles ; Make rotated conveyor tiles into conveyorAnimTiles
.endproc
;-----------------------------------------------------------------------------
.proc tilesMakeInstances
numTiles = sizeL
iLevelTile = sizeH
iWrite = dstPtrL
tileMemL = srcPtrL
tileMemH = srcPtrH
lda #TILES_PER_LEVEL ; for all tiles used in a level
sta numTiles
lda #TILE_BYTES - 1 ; start at the end of tile memory
sta iWrite
ldx currLevel ; find index into tile table
lda mult8, x ; 8 tiles per level
sta iLevelTile ; gives entry for the 1st tile
loop:
lda #0 ; set the hi for reading tile memory to 0
sta tileMemH
ldx iLevelTile ; get the index into the table
lda levelTiles, x ; and get the id for the tile from the table
asl ; mult tile offset * 16 (width of a tile)
asl
asl
rol tileMemH
asl
rol tileMemH ; offset of tile start (from background) now in tileMem ptr
adc #<tiles ; add tiles base address
sta tileMemL
lda #>tiles
adc tileMemH
sta tileMemH ; tileMem pointer now points at memory for the tile
ldy #TILE_BYTES - 1 ; 0 based, copy all the bytes of the tile
ldx iWrite
:
lda (tileMemL), y ; get the tile byte
sta tilesInstances, x ; and save it to instance 0
dex ; back up the tile write pointer
dey ; and completed one byte
bpl :- ; do for all bytes of a tile
dec numTiles ; done a tile
beq copyDone ; see if all tiles done
lda iWrite ; more tiles to do, adjust the tile write ptr
clc
adc #TILE_BYTES ; by moving it to the end of the next tile
sta iWrite
inc iLevelTile ; and advance the index into the table to the next tile
bne loop ; BRA to do the next tile
copyDone:
rts
.endproc
.proc tilesColorCollapsing
rts
.endproc
;-----------------------------------------------------------------------------
; Color tile instances
; IN: a - number of tiles to color
; y - index of first tile to color
; x - write address of first tile data (16 * y)
.proc tilesColorInstances
numTiles = sizeL
iLevelTile = sizeH
colMaskL = dstPtrL + 0
colMaskR = dstPtrL + 1
tileMemL = srcPtrL
tileMemH = srcPtrH
sta numTiles ; save the register parameters
sty iLevelTile
ldy currLevel ; get the offset of the tiles in the level tile table
lda mult8, y
clc
adc iLevelTile ; and add the parameter offset (0 for color and 3 for mono)
sta iLevelTile
loop:
ldy iLevelTile ; get the index
lda levelMasks, y ; and extract the masks for this tile
tay
lda masksLeft, y
sta colMaskL
lda masksRight, y
sta colMaskR
ldy #(TILE_BYTES / 2) ; 2 masks at one time, so bytes / 2
:
lda colMaskL ; instance 0 mask the left side with a left mask
and tilesInstances, x
sta tilesInstances, x
inx ; next byte
lda colMaskR ; instance 0 mask the right side with a right mask
and tilesInstances, x
sta tilesInstances, x
inx ; next byte
dey ; one more column done
bne :- ; keep going till all columns done
inc iLevelTile ; go to the next table entry
dec numTiles ; done one more tile
bne loop ; keep going till all tiles done
rts
.endproc
;-----------------------------------------------------------------------------
.proc tilesPrepKeysTiles
keyByte = tmpBot + 0
lda #4 ; init the key animation to frame 4
sta keysFrameNum
ldy #0 ; start at the 1st key byte
maskLoop:
lda tilesInstances + DATA_KEY - TILE_BYTES, y
sta keyByte ; get a byte and save it
clc
ldx #4 ; make 4 color variations
colorLoopLeft:
lda keyByte ; start with the white key byte
and masksLeft, x ; mask it for left
sta keyAnimTiles, y ; and save it to the first key frame instance 0
tya ; move y along to the next key instance
adc #TILE_BYTES
tay
dex ; and do the next color for that instance
bne colorLoopLeft ; repeat for all 4 color frames
tya ; move Y back 63 bytes, to the next white key byte
sec
sbc #63
tay
lda tilesInstances + DATA_KEY - TILE_BYTES, y
sta keyByte ; get the second (right hand byte)
clc
ldx #4 ; repeat the above but swap color masks
colorLoopRight:
lda keyByte
and masksRight, x
sta keyAnimTiles, y
tya
adc #TILE_BYTES
tay
dex
bne colorLoopRight
tya
sec
sbc #63
tay ; y is now pointing at the next left byte
cpy #TILE_BYTES ; see if the whole key has been processes
bne maskLoop
rts
.endproc
;-----------------------------------------------------------------------------
; Makes animated copies of the conveyor tile. Instead of making full tile
; copies, this should really just do the two lines affected (so use 1 tile
; of memory, not 7 * TILE_BYTES)
.proc tilesPrepConveyorTiles
frame = sizeL
count = sizeH
dir = tmpBot + 0
carry = tmpBot + 1
lda #6 ; init the conveyor frame counter
sta conveyorFrameNum
ldx currLevel
lda conveyorDirections, x ; get a local copy of the conveyor direction
sta dir
clc ; point srcPtr at the conveyor tile
lda #DATA_CONVEYOR - TILE_BYTES
sta srcPtrL
lda #>tilesInstances
sta srcPtrH
lda #<conveyorAnimTiles ; point dstPtr at the first animated tile
sta dstPtrL
lda #>conveyorAnimTiles
sta dstPtrH
ldy #TILE_BYTES - 1 ; copy the tile to the animated tiles
:
lda (srcPtrL), y
and #$7F ; clear the MSB, will be fixed later
sta (dstPtrL), y
dey
bpl :-
ldy #CONVEYOR_FRAMES - 1 ; set a counter for how many frames to process
processTile:
sty frame
clc ; move srcPtr to dstPtr (the new src)
lda dstPtrL ; and move dstPtr to the next frame to animate
sta srcPtrL
adc #TILE_BYTES
sta dstPtrL
lda dstPtrH
sta srcPtrH
bcc :+
inc dstPtrH
:
ldy #TILE_BYTES - 1 ; process a tile's bytes (0 based)
:
lda (srcPtrL), y ; copy the source
sta (dstPtrL), y ; save to the dest
dey ; copy the whole tile
bpl :-
lda dir ; different algorithm for each direction
cmp #2
beq left
right:
ldy #0 ; top row
jsr shiftLeft ; move "left" which is "wrong", the processing is going 0..CONVEYOR_FRAMES
ldy #4 ; 3rd row down, 0 based (2) * 2 byes/row is 4
jsr shiftRight ; but the animation plays back CONVEYOR_FRAMES..0
jmp nextFrame ; so this is all reversed
left:
ldy #0
jsr shiftRight
ldy #4
jsr shiftLeft
nextFrame:
ldy frame
dey ; another frame processed
bne processTile ; have all tiles been animated (0 is original the rest shifted)
jmp finalFix ; fix the MSB
shiftRight:
lda (dstPtrL), y ; left byte scroll right (apple pixels are reversed, so asl)
asl ; shift msb away, bit 0 clear
asl ; shift 1/2 a pixel, bit 1 and 0 clear
sta (dstPtrL), y ; save left shifted. carry has a pixel bit that needs to move
iny
lda (dstPtrL), y
rol ; shift right byte once, carry goes in, MSB bit out in carry
asl ; shift second time, bit 0 is now a zero, carry bit needs moving left
sta (dstPtrL), y
dey
lda #0 ; start fresh
rol ; move carry into bit 0
asl ; carry into bit 1, carry clear, bit 0 now 0
ora (dstPtrL), y ; add bit 1 to the left byte
sta (dstPtrL), y ; save the left byte
and #$80 ; extract bit 8 left that should be in right bit0
asl ; put bit 8 in carry and acc now clear
rol ; put bit 8 in bit 0
iny
ora (dstPtrL), y ; add it to the right byte
sta (dstPtrL), y ; store the right byte
and #$80 ; extract bit 8 right which should be bit 0 left
asl ; move into carry
rol ; move carry into bit 0, carry now clear
dey
ora (dstPtrL), y ; add to bit0 of left byte
sta (dstPtrL), y ; and save
rts
shiftLeft:
ldx #1
lda (dstPtrL), y ; get left byte
:
lsr ; move bit out
sta (dstPtrL), y ; save byte
lda #0 ; move bit in for next byte to bit 6
ror
lsr
sta carry
iny
lda (dstPtrL), y
ror ; move right byte one over (carry needs to go left now)
ora carry ; add bit from left
sta (dstPtrL), y ; save
lda #0 ; start fresh
ror ; move carry to bit 6
lsr
dey
ora (dstPtrL), y ; add to left byte
dex
bpl :-
sta (dstPtrL), y ; save
rts
finalFix:
ldy #(CONVEYOR_FRAMES * TILE_BYTES) - 1
lda tilesInstances + (DATA_CONVEYOR - TILE_BYTES)
and #$80 ; load a byte from original
beq clear ; and see if color bit is set
:
lda #$80 ; if set, set color on for all frames
ora conveyorAnimTiles, y
sta conveyorAnimTiles, y
dey
bpl :-
bmi done
clear:
lda #$7f ; if not set, make sure color isn't on for all
and conveyorAnimTiles, y
sta conveyorAnimTiles, y
dey
bpl clear
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Copy a pre-animated key tile into the tilesInstances so it looks as
; though the key is animating
.proc tilesAnimateKeys
ldx keysFrameNum ; get the frame
dex ; step
bpl :+ ; underflow
ldx #3 ; reset - frames are 0 to 6, but go to render + 1
:
stx keysFrameNum ; save the new frame
inx ; go one frame past
lda mult16, x ; get the byte offset to the frame
tax ; put it in x
dex ; and go to the last byte of the frame needed
ldy #TILE_BYTES - 1 ; set y to copy a whole tile
:
lda keyAnimTiles, x ; read the frame and write to key tile
sta tilesInstances + DATA_KEY - TILE_BYTES, y
dex
dey
bpl :-
rts
.endproc
;-----------------------------------------------------------------------------
; Copy a pre-animated conveyor lines over the lines in the conveyor frame tile,
; in the tilesInstances area
.proc tilesAnimateConveyor
ldx conveyorFrameNum ; get the frame
dex ; step
bpl :+ ; underflow
ldx #6 ; reset - frames are 0 to 6, but go to render + 1
:
stx conveyorFrameNum ; save the new frame
lda mult16, x ; get the byte offset to the frame
tax ; put it in x
lda conveyorAnimTiles, x ; copy the 4 animated bytes for
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES
inx
lda conveyorAnimTiles, x ; instance 0 over
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 1
inx ; to the tile area 0
inx
inx
lda conveyorAnimTiles, x
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 4
inx
lda conveyorAnimTiles, x
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 5
rts
.endproc