prog8/examples/tehtriz.p8

654 lines
20 KiB
Plaintext
Raw Normal View History

2019-03-06 21:11:16 +00:00
; TehTriz - a Tetris clone.
2019-03-10 19:17:58 +00:00
;
; features:
; holding area
; wall kick rotations
; shows next piece
; staged speed increase
; some simple sound effects
2019-03-07 01:28:01 +00:00
2020-06-30 18:42:13 +00:00
; TODO fix crash when piece reaches bottom.
; TODO fix wrong behavior when compiled without optimizations.
2019-07-29 21:11:13 +00:00
main {
const ubyte boardOffsetX = 14
const ubyte boardOffsetY = 3
const ubyte boardWidth = 10
const ubyte boardHeight = 20
2019-02-14 01:23:59 +00:00
const ubyte startXpos = boardOffsetX + 3
const ubyte startYpos = boardOffsetY - 2
2019-03-09 11:52:02 +00:00
uword lines
2019-03-07 22:29:23 +00:00
uword score
ubyte xpos
ubyte ypos
ubyte nextBlock
2019-03-10 18:24:11 +00:00
ubyte speedlevel
2019-03-10 19:17:58 +00:00
ubyte holding
ubyte holdingAllowed
2019-03-07 22:29:23 +00:00
sub start() {
2019-02-14 01:23:59 +00:00
@(650) = 128 ; set all keys to repeat
sound.init()
2019-03-07 22:29:23 +00:00
newGame()
drawBoard()
gameOver()
2019-03-07 22:29:23 +00:00
newgame:
newGame()
drawBoard()
2019-02-14 01:23:59 +00:00
spawnNextBlock()
2019-02-14 01:23:59 +00:00
waitkey:
2020-03-12 23:50:50 +00:00
check_eval_stack()
2019-03-10 04:24:07 +00:00
if c64.TIME_LO>=(60-4*speedlevel) {
2019-02-14 01:23:59 +00:00
c64.TIME_LO = 0
2019-02-21 00:31:33 +00:00
2019-03-09 11:52:02 +00:00
drawBlock(xpos, ypos, 32) ; hide block
if blocklogic.noCollision(xpos, ypos+1) {
2019-03-07 01:28:01 +00:00
; slowly move the block down
ypos++
2019-03-09 11:52:02 +00:00
drawBlock(xpos, ypos, 160) ; show block on new position
2019-02-14 01:23:59 +00:00
} else {
; block can't move further down!
; check if the game area is full, if not, spawn the next block at the top.
2019-03-07 01:28:01 +00:00
if blocklogic.isGameOver(xpos, ypos) {
2019-03-07 22:29:23 +00:00
gameOver()
goto newgame
2019-02-14 01:23:59 +00:00
} else {
2019-03-10 18:24:11 +00:00
sound.blockrotate()
2019-03-09 11:52:02 +00:00
checkForLines()
2019-02-14 01:23:59 +00:00
spawnNextBlock()
2019-03-10 18:24:11 +00:00
score++
2019-02-14 01:23:59 +00:00
}
}
2019-03-09 11:52:02 +00:00
drawScore()
}
2019-03-07 22:29:23 +00:00
ubyte key=c64.GETIN()
2019-03-09 11:52:02 +00:00
if key==0 goto waitkey
2019-02-14 01:23:59 +00:00
2019-03-10 02:53:17 +00:00
keypress(key)
goto waitkey
}
2019-07-09 21:39:03 +00:00
sub move_left() {
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos-1, ypos) {
xpos--
2019-02-14 01:23:59 +00:00
}
2019-07-09 21:39:03 +00:00
drawBlock(xpos, ypos, 160)
}
sub move_right() {
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos+1, ypos) {
xpos++
}
2019-07-09 21:39:03 +00:00
drawBlock(xpos, ypos, 160)
}
sub move_down_faster() {
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos, ypos+1) {
ypos++
2019-02-14 01:23:59 +00:00
}
2019-07-09 21:39:03 +00:00
drawBlock(xpos, ypos, 160)
}
sub drop_down_immediately() {
drawBlock(xpos, ypos, 32)
ubyte dropypos
for dropypos in ypos+1 to boardOffsetY+boardHeight-1 {
if not blocklogic.noCollision(xpos, dropypos) {
dropypos-- ; the furthest down that still fits
break
2019-03-09 11:52:02 +00:00
}
2019-02-14 01:23:59 +00:00
}
2019-07-09 21:39:03 +00:00
if dropypos>ypos {
ypos = dropypos
sound.blockdrop()
drawBlock(xpos, ypos, 160)
2019-07-09 21:39:03 +00:00
checkForLines()
spawnNextBlock()
score++
drawScore()
2019-02-14 01:23:59 +00:00
}
2019-07-09 21:39:03 +00:00
}
sub keypress(ubyte key) {
when key {
157, ',' -> move_left()
29, '/' -> move_right()
17, '.' -> move_down_faster()
145, ' ' -> drop_down_immediately()
2019-07-09 21:39:03 +00:00
'z' -> {
; no joystick equivalent (there is only 1 fire button)
; rotate counter clockwise
drawBlock(xpos, ypos, 32)
if blocklogic.canRotateCCW(xpos, ypos) {
blocklogic.rotateCCW()
sound.blockrotate()
}
else if blocklogic.canRotateCCW(xpos-1, ypos) {
xpos--
blocklogic.rotateCCW()
sound.blockrotate()
}
else if blocklogic.canRotateCCW(xpos+1, ypos) {
xpos++
blocklogic.rotateCCW()
sound.blockrotate()
}
drawBlock(xpos, ypos, 160)
}
2019-07-09 21:39:03 +00:00
'x' -> {
; rotate clockwise
drawBlock(xpos, ypos, 32)
if blocklogic.canRotateCW(xpos, ypos) {
blocklogic.rotateCW()
sound.blockrotate()
}
else if blocklogic.canRotateCW(xpos-1, ypos) {
xpos--
blocklogic.rotateCW()
sound.blockrotate()
}
else if blocklogic.canRotateCW(xpos+1, ypos) {
xpos++
blocklogic.rotateCW()
sound.blockrotate()
}
drawBlock(xpos, ypos, 160)
2019-02-21 00:31:33 +00:00
}
2019-07-09 21:39:03 +00:00
'c' -> {
; hold
if holdingAllowed {
sound.swapping()
if holding<7 {
drawBlock(xpos, ypos, 32)
ubyte newholding = blocklogic.currentBlockNum
swapBlock(holding)
holding = newholding
holdingAllowed = false
} else {
holding = blocklogic.currentBlockNum
drawBlock(xpos, ypos, 32)
spawnNextBlock()
}
drawHoldBlock()
2019-03-10 19:17:58 +00:00
}
}
}
2019-02-14 01:23:59 +00:00
}
2019-03-09 11:52:02 +00:00
sub checkForLines() {
; check if line(s) are full -> flash/clear line(s) + add score + move rest down
ubyte[boardHeight] complete_lines
ubyte num_lines=0
ubyte linepos
2019-03-09 11:52:02 +00:00
memset(complete_lines, len(complete_lines), 0)
for linepos in boardOffsetY to boardOffsetY+boardHeight-1 {
2019-03-09 11:52:02 +00:00
if blocklogic.isLineFull(linepos) {
complete_lines[num_lines]=linepos
num_lines++
ubyte x
for x in boardOffsetX to boardOffsetX+boardWidth-1
2019-03-09 11:52:02 +00:00
c64scr.setcc(x, linepos, 160, 1)
}
}
if num_lines {
2019-03-10 18:24:11 +00:00
if num_lines>3
sound.lineclear_big()
else
sound.lineclear()
2019-03-09 11:52:02 +00:00
c64.TIME_LO=0
while c64.TIME_LO<20 {
; slight delay to flash the line
}
c64.TIME_LO=0
for linepos in complete_lines
2019-03-09 11:52:02 +00:00
if linepos and blocklogic.isLineFull(linepos)
blocklogic.collapse(linepos)
lines += num_lines
uword[] scores = [10, 25, 50, 100] ; can never clear more than 4 lines
2019-03-09 11:52:02 +00:00
score += scores[num_lines-1]
2019-03-10 04:24:07 +00:00
speedlevel = 1+lsb(lines/10)
2019-03-09 11:52:02 +00:00
drawScore()
}
}
2019-03-07 22:29:23 +00:00
sub gameOver() {
sound.gameover()
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 7)
2019-03-07 01:28:01 +00:00
c64.CHROUT('U')
c64scr.print("────────────────────────")
c64.CHROUT('I')
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 8)
2019-03-07 01:28:01 +00:00
c64scr.print("│*** g a m e o v e r ***│")
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 9)
2019-03-07 01:28:01 +00:00
c64.CHROUT('J')
c64scr.print("────────────────────────")
c64.CHROUT('K')
2019-03-07 22:29:23 +00:00
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 18)
2019-03-07 22:29:23 +00:00
c64.CHROUT('U')
c64scr.print("────────────────────────")
c64.CHROUT('I')
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 19)
2019-03-07 22:29:23 +00:00
c64scr.print("│ f1 for new game │")
2019-03-21 21:36:46 +00:00
c64scr.plot(7, 20)
2019-03-07 22:29:23 +00:00
c64.CHROUT('J')
c64scr.print("────────────────────────")
c64.CHROUT('K')
2020-03-14 16:11:10 +00:00
while c64.GETIN()!=133 {
2019-03-07 22:29:23 +00:00
; endless loop until user presses F1 to restart the game
2019-03-07 01:28:01 +00:00
}
}
2019-03-07 22:29:23 +00:00
sub newGame() {
lines = 0
score = 0
xpos = startXpos
ypos = startYpos
2019-03-10 18:24:11 +00:00
speedlevel = 1
2019-03-07 22:29:23 +00:00
nextBlock = rnd() % 7
2019-03-10 19:17:58 +00:00
holding = 255
holdingAllowed = true
2019-03-07 22:29:23 +00:00
}
2019-03-10 19:17:58 +00:00
sub swapBlock(ubyte newblock) {
2019-02-14 01:23:59 +00:00
c64.TIME_LO = 0
2019-03-10 19:17:58 +00:00
blocklogic.newCurrentBlock(newblock)
2019-02-14 01:23:59 +00:00
xpos = startXpos
ypos = startYpos
drawBlock(xpos, ypos, 160)
}
2019-03-10 19:17:58 +00:00
sub spawnNextBlock() {
swapBlock(nextBlock)
nextBlock = (rnd() + c64.RASTER) % 7
drawNextBlock()
holdingAllowed = true
}
sub drawBoard() {
c64.CLEARSCR()
2019-02-14 01:23:59 +00:00
c64.COLOR = 7
2019-03-21 21:36:46 +00:00
c64scr.plot(1,1)
2019-02-14 01:23:59 +00:00
c64scr.print("irmen's")
2019-03-21 21:36:46 +00:00
c64scr.plot(2,2)
c64scr.print("teh▁triz")
2019-03-10 19:17:58 +00:00
c64.COLOR = 5
2019-03-21 21:36:46 +00:00
c64scr.plot(6,4)
2019-03-10 19:17:58 +00:00
c64scr.print("hold:")
2019-03-21 21:36:46 +00:00
c64scr.plot(2,22)
2019-03-10 02:53:17 +00:00
c64scr.print("speed: ")
2019-03-21 21:36:46 +00:00
c64scr.plot(28,3)
2019-02-14 01:23:59 +00:00
c64scr.print("next:")
2019-03-21 21:36:46 +00:00
c64scr.plot(28,10)
2019-02-14 01:23:59 +00:00
c64scr.print("lines:")
2019-03-21 21:36:46 +00:00
c64scr.plot(28,14)
2019-02-14 01:23:59 +00:00
c64scr.print("score:")
c64.COLOR = 12
2019-03-21 21:36:46 +00:00
c64scr.plot(27,18)
2019-02-14 01:23:59 +00:00
c64scr.print("controls:")
c64.COLOR = 11
2019-03-21 21:36:46 +00:00
c64scr.plot(28,19)
2019-03-10 18:24:11 +00:00
c64scr.print(",/ move")
2019-03-21 21:36:46 +00:00
c64scr.plot(28,20)
2019-03-10 18:24:11 +00:00
c64scr.print("zx rotate")
2019-03-21 21:36:46 +00:00
c64scr.plot(29,21)
2019-03-10 18:24:11 +00:00
c64scr.print(". descend")
2019-03-21 21:36:46 +00:00
c64scr.plot(27,22)
2019-03-10 18:24:11 +00:00
c64scr.print("spc drop")
2019-03-21 21:36:46 +00:00
c64scr.plot(29,23)
2019-03-10 19:17:58 +00:00
c64scr.print("c hold")
2019-02-14 01:23:59 +00:00
2019-02-21 00:31:33 +00:00
c64scr.setcc(boardOffsetX-1, boardOffsetY-2, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX-1, boardOffsetY-3, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-2, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-3, 255, 0) ; invisible barrier
2019-02-14 01:23:59 +00:00
c64scr.setcc(boardOffsetX-1, boardOffsetY-1, 108, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-1, 123, 12)
2019-02-21 00:31:33 +00:00
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-1, 123, 12)
c64scr.setcc(boardOffsetX-1, boardOffsetY+boardHeight, 124, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY+boardHeight, 126, 12)
ubyte i
2020-03-11 19:47:42 +00:00
for i in boardOffsetX+boardWidth-1 downto boardOffsetX {
2019-02-21 00:31:33 +00:00
c64scr.setcc(i, boardOffsetY-3, 255, 0) ; invisible barrier
c64scr.setcc(i, boardOffsetY+boardHeight, 69, 11)
2019-02-21 00:31:33 +00:00
}
2020-03-11 19:47:42 +00:00
for i in boardOffsetY+boardHeight-1 downto boardOffsetY {
c64scr.setcc(boardOffsetX-1, i, 89, 11)
c64scr.setcc(boardOffsetX+boardWidth, i, 84, 11)
}
2019-02-14 01:23:59 +00:00
ubyte[] colors = [6,8,7,5,4]
2020-03-11 19:47:42 +00:00
for i in len(colors)-1 downto 0 {
ubyte x
2020-03-11 19:47:42 +00:00
for x in 5 downto 0 {
c64scr.setcc(6+x-i, 11+2*i, 102, colors[i])
2019-03-10 19:17:58 +00:00
}
2019-02-14 01:23:59 +00:00
}
drawScore()
}
2019-02-14 01:23:59 +00:00
sub drawScore() {
c64.COLOR=1
2019-03-21 21:36:46 +00:00
c64scr.plot(30,11)
2019-03-09 11:52:02 +00:00
c64scr.print_uw(lines)
2019-03-21 21:36:46 +00:00
c64scr.plot(30,15)
2019-02-14 01:23:59 +00:00
c64scr.print_uw(score)
2019-03-21 21:36:46 +00:00
c64scr.plot(9,22)
2019-03-10 04:24:07 +00:00
c64scr.print_ub(speedlevel)
2019-02-14 01:23:59 +00:00
}
sub drawNextBlock() {
2019-03-10 02:53:17 +00:00
const ubyte nextBlockXpos = 29
2019-03-10 19:17:58 +00:00
const ubyte nextBlockYpos = 5
ubyte x
2020-03-11 19:47:42 +00:00
for x in nextBlockXpos+3 downto nextBlockXpos {
2019-03-10 19:17:58 +00:00
c64scr.setcc(x, nextBlockYpos, ' ', 0)
c64scr.setcc(x, nextBlockYpos+1, ' ', 0)
2019-02-14 01:23:59 +00:00
}
; reuse the normal block draw routine (because we can't manipulate array pointers yet)
ubyte prev = blocklogic.currentBlockNum
blocklogic.newCurrentBlock(nextBlock)
2019-03-10 19:17:58 +00:00
drawBlock(nextBlockXpos, nextBlockYpos, 160)
blocklogic.newCurrentBlock(prev)
2019-02-14 01:23:59 +00:00
}
2019-03-10 19:17:58 +00:00
sub drawHoldBlock() {
const ubyte holdBlockXpos = 7
const ubyte holdBlockYpos = 6
ubyte x
2020-03-11 19:47:42 +00:00
for x in holdBlockXpos+3 downto holdBlockXpos {
2019-03-10 19:17:58 +00:00
c64scr.setcc(x, holdBlockYpos, '@', 0)
c64scr.setcc(x, holdBlockYpos+1, '@', 0)
}
if holding < 7 {
; reuse the normal block draw routine (because we can't manipulate array pointers yet)
ubyte prev = blocklogic.currentBlockNum
blocklogic.newCurrentBlock(holding)
drawBlock(holdBlockXpos, holdBlockYpos, 160)
blocklogic.newCurrentBlock(prev)
}
}
sub drawBlock(ubyte x, ubyte y, ubyte character) {
ubyte i
2020-03-11 19:47:42 +00:00
for i in 15 downto 0 {
ubyte c=blocklogic.currentBlock[i]
if c
c64scr.setcc((i&3)+x, (i/4)+y, character, c)
}
}
sub check_eval_stack() {
if X!=255 {
c64scr.print("stack x=")
c64scr.print_ub(X)
c64scr.print(" error!\n")
}
}
}
2019-07-29 21:11:13 +00:00
blocklogic {
ubyte currentBlockNum
ubyte[16] currentBlock
ubyte[16] rotated
2019-03-06 21:11:16 +00:00
; the 7 tetrominos
ubyte[] blockI = [0,0,0,0, ; cyan ; note: special rotation (around matrix center)
3,3,3,3,
0,0,0,0,
0,0,0,0]
ubyte[] blockJ = [6,0,0,0, ; blue
6,6,6,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockL = [0,0,8,0, ; orange
8,8,8,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockO = [0,7,7,0, ; yellow ; note: no rotation (square)
0,7,7,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockS = [0,5,5,0, ; green
5,5,0,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockT = [0,4,0,0, ; purple
4,4,4,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockZ = [2,2,0,0, ; red
0,2,2,0,
0,0,0,0,
0,0,0,0]
uword[] blocks = [&blockI, &blockJ, &blockL, &blockO, &blockS, &blockT, &blockZ]
sub newCurrentBlock(ubyte block) {
currentBlockNum = block
memcopy(blocks[block], currentBlock, len(currentBlock))
}
2019-02-14 01:23:59 +00:00
sub rotateCW() {
; rotates the current block clockwise.
if currentBlockNum==0 {
; the 'I' block rotates a 4x4 matrix around the center
rotated[0] = currentBlock[12]
rotated[1] = currentBlock[8]
rotated[2] = currentBlock[4]
rotated[3] = currentBlock[0]
rotated[4] = currentBlock[13]
rotated[5] = currentBlock[9]
rotated[6] = currentBlock[5]
rotated[7] = currentBlock[1]
rotated[8] = currentBlock[14]
rotated[9] = currentBlock[10]
rotated[10] = currentBlock[6]
rotated[11] = currentBlock[2]
rotated[12] = currentBlock[15]
rotated[13] = currentBlock[11]
rotated[14] = currentBlock[7]
rotated[15] = currentBlock[3]
2019-03-10 18:24:11 +00:00
memcopy(rotated, currentBlock, len(currentBlock))
}
2019-02-21 00:31:33 +00:00
else if currentBlockNum!=3 {
; rotate all blocks (except 3, the square) around their center square in a 3x3 matrix
memset(rotated, len(rotated), 0)
2019-02-21 00:31:33 +00:00
rotated[0] = currentBlock[8]
rotated[1] = currentBlock[4]
rotated[2] = currentBlock[0]
rotated[4] = currentBlock[9]
rotated[5] = currentBlock[5]
2019-02-21 00:31:33 +00:00
rotated[6] = currentBlock[1]
rotated[8] = currentBlock[10]
rotated[9] = currentBlock[6]
rotated[10] = currentBlock[2]
2019-03-10 18:24:11 +00:00
memcopy(rotated, currentBlock, len(currentBlock))
2019-02-14 01:23:59 +00:00
}
}
sub rotateCCW() {
; rotates the current block counterclockwise.
if currentBlockNum==0 {
; the 'I' block rotates a 4x4 matrix around the center
rotated[0] = currentBlock[3]
rotated[1] = currentBlock[7]
rotated[2] = currentBlock[11]
rotated[3] = currentBlock[15]
rotated[4] = currentBlock[2]
rotated[5] = currentBlock[6]
rotated[6] = currentBlock[10]
rotated[7] = currentBlock[14]
rotated[8] = currentBlock[1]
rotated[9] = currentBlock[5]
rotated[10] = currentBlock[9]
rotated[11] = currentBlock[13]
rotated[12] = currentBlock[0]
rotated[13] = currentBlock[4]
rotated[14] = currentBlock[8]
rotated[15] = currentBlock[12]
2019-03-10 18:24:11 +00:00
memcopy(rotated, currentBlock, len(currentBlock))
}
2019-02-21 00:31:33 +00:00
else if currentBlockNum!=3 {
; rotate all blocks (except 3, the square) around their center square in a 3x3 matrix
memset(rotated, len(rotated), 0)
2019-02-21 00:31:33 +00:00
rotated[0] = currentBlock[2]
rotated[1] = currentBlock[6]
rotated[2] = currentBlock[10]
rotated[4] = currentBlock[1]
rotated[5] = currentBlock[5]
2019-02-21 00:31:33 +00:00
rotated[6] = currentBlock[9]
rotated[8] = currentBlock[0]
rotated[9] = currentBlock[4]
rotated[10] = currentBlock[8]
2019-03-10 18:24:11 +00:00
memcopy(rotated, currentBlock, len(currentBlock))
2019-02-14 01:23:59 +00:00
}
}
2019-03-07 01:28:01 +00:00
; For movement checking it is not needed to clamp the x/y coordinates,
; because we have to check for brick collisions anyway.
; The full play area is bordered by (in)visible characters that will collide.
; Collision is determined by reading the screen data directly.
sub canRotateCW(ubyte xpos, ubyte ypos) -> ubyte {
2019-02-21 00:31:33 +00:00
rotateCW()
2019-03-09 11:52:02 +00:00
ubyte nocollision = noCollision(xpos, ypos)
2019-02-21 00:31:33 +00:00
rotateCCW()
2019-03-09 11:52:02 +00:00
return nocollision
2019-02-14 01:23:59 +00:00
}
2019-03-07 01:28:01 +00:00
sub canRotateCCW(ubyte xpos, ubyte ypos) -> ubyte {
2019-02-21 00:31:33 +00:00
rotateCCW()
2019-03-09 11:52:02 +00:00
ubyte nocollision = noCollision(xpos, ypos)
2019-02-21 00:31:33 +00:00
rotateCW()
2019-03-09 11:52:02 +00:00
return nocollision
2019-02-14 01:23:59 +00:00
}
2019-03-09 11:52:02 +00:00
sub noCollision(ubyte xpos, ubyte ypos) -> ubyte {
ubyte i
2020-03-11 19:47:42 +00:00
for i in 15 downto 0 {
2019-03-09 11:52:02 +00:00
if currentBlock[i] and c64scr.getchr(xpos + (i&3), ypos+i/4)!=32
return false
}
return true
2019-02-14 01:23:59 +00:00
}
2019-03-09 11:52:02 +00:00
sub isGameOver(ubyte xpos, ubyte ypos) -> ubyte {
main.drawBlock(xpos, ypos, 32)
ubyte result = ypos==main.startYpos and not noCollision(xpos, ypos+1)
2019-03-07 01:28:01 +00:00
main.drawBlock(xpos, ypos, 160)
2019-03-09 11:52:02 +00:00
return result
2019-03-07 01:28:01 +00:00
}
2019-03-09 11:52:02 +00:00
sub isLineFull(ubyte ypos) -> ubyte {
ubyte x
for x in main.boardOffsetX to main.boardOffsetX+main.boardWidth-1 {
2019-03-09 11:52:02 +00:00
if c64scr.getchr(x, ypos)==32
return false
}
return true
2019-02-14 01:23:59 +00:00
}
2019-03-09 11:52:02 +00:00
sub collapse(ubyte ypos) {
2020-03-14 16:11:10 +00:00
while ypos>main.startYpos+1 {
ubyte x
2020-03-11 19:47:42 +00:00
for x in main.boardOffsetX+main.boardWidth-1 downto main.boardOffsetX {
2019-03-09 11:52:02 +00:00
ubyte char = c64scr.getchr(x, ypos-1)
ubyte color = c64scr.getclr(x, ypos-1)
c64scr.setcc(x, ypos, char, color)
}
ypos--
}
2019-02-14 01:23:59 +00:00
}
}
2019-07-29 21:11:13 +00:00
sound {
sub init() {
2019-03-10 03:22:02 +00:00
c64.MVOL = 15
}
2019-03-10 03:22:02 +00:00
sub blockrotate() {
; soft click
c64.MVOL = 5
c64.AD1 = %00100010
c64.SR1 = %00000000
c64.FREQ1 = 15600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
2019-03-10 03:22:02 +00:00
sub blockdrop() {
; swish
c64.MVOL = 5
c64.AD1 = %01010111
c64.SR1 = %00000000
c64.FREQ1 = 4600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
2019-03-10 19:17:58 +00:00
sub swapping() {
; beep
c64.MVOL = 8
c64.AD1 = %01010111
c64.SR1 = %00000000
c64.FREQ1 = 5500
c64.CR1 = %00010000
c64.CR1 = %00010001
}
sub lineclear() {
2019-03-10 03:22:02 +00:00
; explosion
c64.MVOL = 15
c64.AD1 = %01100110
c64.SR1 = %00000000
c64.FREQ1 = 1600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
2019-03-10 18:24:11 +00:00
sub lineclear_big() {
; big explosion
c64.MVOL = 15
c64.AD1 = %01101010
c64.SR1 = %00000000
c64.FREQ1 = 2600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
sub gameover() {
2019-03-10 03:22:02 +00:00
; buzz
c64.MVOL = 15
c64.FREQ2 = 600
c64.AD2 = %00111010
c64.SR2 = %00000000
c64.CR2 = %00110000
c64.CR2 = %00110001
}
}