diff --git a/MODE9pp.txt b/MODE9pp.txt new file mode 100644 index 0000000..be044fd --- /dev/null +++ b/MODE9pp.txt @@ -0,0 +1,32 @@ +; MODE 9++ + + org $2000 + + mwa #dli $200 + + mva #$22 $22f + + mwa #dl $230 + + mva #$40 $26f + + mva #$c0 $d40e + + jmp * + + +dli pha + sta $d40a + + lda #13 + sta $d405 + + lda #3 + sta $d405 + + pla + rti + +dl dta $90,$6f,a($f000) ; 2 puste linie, 1 linia trybu + :29 dta a($2f8f) ; $8f,$2f powtorzone 29 razy => 58 linii + dta $41,a(dl) \ No newline at end of file diff --git a/art/CLEAR.docx b/art/CLEAR.docx new file mode 100644 index 0000000..d014289 Binary files /dev/null and b/art/CLEAR.docx differ diff --git a/art/WIZ.xex b/art/WIZ.xex new file mode 100644 index 0000000..2821db4 Binary files /dev/null and b/art/WIZ.xex differ diff --git a/art/WIZs.xex b/art/WIZs.xex new file mode 100644 index 0000000..652f0d8 Binary files /dev/null and b/art/WIZs.xex differ diff --git a/art/clear.PNG b/art/clear.PNG new file mode 100644 index 0000000..1c6b3b0 Binary files /dev/null and b/art/clear.PNG differ diff --git a/art/clear2.PNG b/art/clear2.PNG new file mode 100644 index 0000000..555846d Binary files /dev/null and b/art/clear2.PNG differ diff --git a/art/clear2.bmp b/art/clear2.bmp new file mode 100644 index 0000000..24d3daf Binary files /dev/null and b/art/clear2.bmp differ diff --git a/art/clear3.bmp b/art/clear3.bmp new file mode 100644 index 0000000..7349c5f Binary files /dev/null and b/art/clear3.bmp differ diff --git a/art/levels.xlsx b/art/levels.xlsx new file mode 100644 index 0000000..338268e Binary files /dev/null and b/art/levels.xlsx differ diff --git a/art/wizd.xex b/art/wizd.xex new file mode 100644 index 0000000..6ddbc4e Binary files /dev/null and b/art/wizd.xex differ diff --git a/averybreakout.asm b/averybreakout.asm new file mode 100644 index 0000000..8b3108e --- /dev/null +++ b/averybreakout.asm @@ -0,0 +1,1048 @@ +;Acid Breakout - a break from the daily acid +;build 006, 2010-05-12 +;CLEAR! +;あめでと +;--------------------------------------------------- + + icl '../lib/atari.hea' + icl '../lib/macro.hea' + +display=$a000 +screenWidth = 80 ;in pixels +maxLines = 57 ; number of lines on the screen (must be odd) +spawnProbability = (256*1/5) +margin = 2 ; top and bottom screen safety margin +racquetPosMin = $2 ; min position of the paddle moved by the user +racquetPosMax = screenWidth-8 ; max position of the paddle moved by the user +racquetSize = 10 +maxSpeed = 2; maximum speed of a ball. must be power of 2 ('and #' used) +maxBalls = 100 ; maximum number of moving balls, <$80 (bpl used!) +maxMemory = 7 ; number of saved pixel positions + ;Beware! For easier calc somewhere it uses "modulo maxMemory" + ;calculations and therefore this value must be a power of 2! +maxBrickLines = 14 ; maximum number of lines of bricks to be eradicated + + .zpvar xpos ypos .word = $80 ; position of the ball + .zpvar colour .byte ; colour of the pixel to plot + .zpvar deXpos deYpos .byte ;position for deletion + .zpvar dX dY .word ;main loop shortcuts to the table values + ;.zpvar dx dy .word ;delta + ;xpos, dx - "static point precision" - [dx+1].[dx] (big endian!) + ;this static point precision is emulated with .word calcs, just a result is the high byte + .zpvar currBall collisionCheck racquetPos MyClok eXistenZstackPtr .byte + .zpvar xMemAddr yMemAddr .word ; address where to store memories of the current ball + .zpvar temp .word + .zpvar clearCount clearBallNr .byte + .zpvar DLI_A DLI_X dliCount .byte + org $2000 +;--------------------------------------------------- +dl + .by $80+$20 + dta $4f+$20,a(display) ;VSCROLL + :((maxlines-1)/2) dta a($2f8f) + + ;---- + .by $42+$10 ;Hscroll +DLracquetAddr0 + .wo racquetDisp + .by $41 + .wo dl +;--------------------------------------------------- +racquetDisp + :42 .byte $0 + .byte $80, $80, $80, $80, $80 + :36 .byte $0 + +;-------------------------------------------------- +vint + ;------------JOY------------- + ;happy happy joy joy + ;check for joystick now +/* + inc MyClok + lda MyClok + and #$07 + bne jNotRight +*/ + ldy PORTA +/* + tya + and #$01 ;up + bne jNotUp + ldx joystickConversion ;up + lda #1 + sta keyboardGrid,x +jNotUp + tya + and #$02 ;down + bne jNotDown + ldx joystickConversion+1 ;up + lda #1 + sta keyboardGrid,x +jNotDown +*/ + tya + and #$04 ;left + bne jNotLeft + ldx racquetPos + cpx #racquetPosMin+1 + bcc jNotLeft + dex + stx racquetPos + +jNotLeft + tya + and #$08 ;right + bne jNotRight + ldx racquetPos + cpx #racquetPosMax + bcs jNotRight + inx + stx racquetPos +jNotRight +/* + ;fire + lda TRIG0 + bne JNotFire + ... +JNotFire +*/ + + + + lda racquetPos + + sec + lda #screenWidth-1 + sbc racquetPos + lsr + clc + adc #racquetDisp + adc #0 + sta dlracquetAddr0+1 + + lda racquetPos + lsr + and #$01 + ;sta HSCROL + + ;pos print + lda racquetPos + :4 lsr + clc + adc #'0' + sta hexDump + + lda racquetPos + and #$0F + clc + adc #'0' + sta hexDump+1 + + mva #0 dliCount + mva #13 VSCROL + jmp XITVBV + +;-------------------------------------------------- +DLI + sta DLI_A + stx DLI_X + ldx dliCount + sta WSYNC + + lda #13 + sta VSCROL + + lda #3 + sta VSCROL + + txa + asl + asl + ;lda brickColourTab,x + sta COLBAK + + inx + stx dliCount + ldx DLI_X + lda DLI_A + rti +;-------------------------------------------------- +main + jsr initialize + +loop + + mva #maxBalls-1 currBall + jsr cycleColours + +flight + + ldx currBall + lda BalleXistenZ,x + jeq ballDoesNotexist + lda xposTableL,x + sta xpos + lda xposTableH,x + sta xpos+1 + + lda yposTableL,x + sta ypos + lda yposTableH,x + sta ypos+1 + + lda dxTableL,x + sta dX + lda dxTableH,x + sta dX+1 + + lda dyTableL,x + sta dY + lda dYTableH,x + sta dY+1 + + ; now, delete the oldest pixel + ; + lda memCycleTable,x + clc + adc #1 ;next position in the table + cmp #maxMemory + bne notMaxMem + lda #0 +notMaxMem + sta memCycleTable,x ; memCycleTable saved + tax + lda xposMemTableAdrL,x + sta xMemAddr + lda xposMemTableAdrH,x + sta xMemAddr+1 + lda yposMemTableAdrL,x + sta yMemAddr + lda yposMemTableAdrH,x + sta yMemAddr+1 + ;now on zero page I've got the addressess to store the old xPos and yPos + ldy currBall + lda (yMemAddr),y + tax + lda (xMemAddr),y + sta dexpos + + + ; and erase the last point in the "snake" + ;jsr deplot +;-------------------------------------------------- +;deplot +; moved here for the speeeeeed +; deyxpos, deypos (.byte) - pixel position +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + ;lda dexpos + lsr + tay +;--- + ;ldx deypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda dexpos + and #$01 + tax + + lda (temp),y + and debittable,x + sta (temp),y + + ;move the ball!!! + adw xpos dX xpos + + adw ypos dY ypos + + + +;top bounce + ; if yposmaxLines+margin then bounce + lda ypos+1 + cmp #maxLines+margin + bcc noBottom + + ; check if the ball hits the racquette + lda CONSOL + and #%00000100 ; OPTION + bne bounceNormally + jmp bottomBounce ; turns off the ball kill +bounceNormally + + lda ypos+1 + cmp #maxLines+margin*2+maxSpeed*2 ; that makes the ball below the racquet + bcs flyDown2 ;kinda lame optimisation as A carries ypos+1 + + + + lda racquetPos + sec + sbc #racquetPosMin+1 + bpl racquettePlus + lda #0 +racquettePlus + cmp xpos+1 + + jcs flyDown + + clc + adc #racquetSize-1 + cmp xpos+1 + jcs bottomBounce + +flyDown + lda ypos+1 +flyDown2 + cmp #maxLines+margin*6+maxSpeed*2 ;maximum depth + bcc noBottom + + +ballOut + + lda currBall + +eXistenZdEstroy + ;destroys ball number A + ;pushes one free slot to the eXistenZstack + ;ends with !number of balls in X (maxBalls == end of the game) + ;txa + ldy eXistenZstackPtr + iny + sta eXistenZstack,y + sty eXistenZstackPtr + + ;ldx currBall + tax + lda #0 + sta balleXistenZ,x + + jmp flightLoopEnd + +bottomBounce + ; assuming that here a plot can get only from below, + ; so it is enough to switch dy sign + ; sbw #$ffff dy dy ;this does not compile :( + negw dY + mva #maxLines+margin-2 ypos+1 + + +noBottom + +;left bounce + lda xpos+1 + cmp #margin + bcs noLeft + negw dX + mva #margin+1 xpos+1 + +noLeft + + +;right border bounce + lda xpos+1 + cmp #screenWidth-margin + bcc noRight + negw dX + mva #screenWidth-margin-1 xpos+1 +noRight + + ;jsr plot + ; the full plot copied here to get few cycles and collision + ; high byte is the integer position + ; low byte is the "fractional" part + ; let's calculate coordinates from xpos and ypos + lda xpos+1 + lsr + tay +;--- + ldx ypos+1 + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + ldx colour + + lda xpos+1 + and #$01 + bne pRightNibble +pLeftNibble + lda (temp),y + sta collisionCheck + and #$0F + ora LNColtable,x + sta (temp),y + lda collisionCheck + and #$F0 + cmp #%10000000 + jne noCollision + jmp plotEnd ;unconditional branch + +pRightNibble + lda (temp),y + sta collisionCheck + and #$F0 + ora RNColtable,x + sta (temp),y + lda collisionCheck + and #$0F + cmp #%00001000 + jne noCollision + +plotEnd + + lda ypos+1 + cmp #maxLines+margin-2-1 + jcs noCollision ;ball is outside the screen! + + ;switch direction, Charles + ; an idea for assuming which direction to switch - dX or dY? + ; on a diagram below in the middle there is an approached brick +/* + \ / + \-dY / + \ / + -dX [] -dX + / \ + /-dY \ + / \ +*/ + ; it means: + ; if |dX|>|dY| then dX == -dX + ; else dY == -dY + + ; get absolute values + lda dX+1 + bpl dXpositive +;dX is negative here + lda dY+1 + bpl dXneg_dYpos + +;dX and dY are negative here + cmp dX+1 + bcc dX_gr_dY__dX_dYneg + ; |dY| >= |dX| ; hour 5 + negw dY + jmp bounceDone +dX_gr_dY__dX_dYneg + ; hour 4 + negw dX + jmp bounceDone + +dXneg_dYpos + ; dY in A + clc + adc dX+1 + bpl dY_gr_dX__dXneg_dYpos + ; |dX| > |dy|; hour 2 + negw dX + jmp bounceDone +dY_gr_dX__dXneg_dYpos + ; hour 1 + negw dY + jmp bounceDone + +dXpositive + lda dY+1 + bpl dX_dYpositive +;dX positive, dY negative + clc + adc dX+1 + bpl dX_gr_dY__dXpos_dYneg + ; hour 7 + negw dY + jmp bounceDone + +dX_gr_dY__dXpos_dYneg + ; hour 8 + negw dX + jmp bounceDone + +dX_dYpositive + ;(dY+1)* is in A + cmp dX+1 + bcc dX_gr_dY__dX_dYpos + ; dY > dX ; hour 11 + negw dY + jmp bounceDone +dX_gr_dY__dX_dYpos + ; dY < dX ; hour 10 + negw dX + +bounceDone +;spawn the new bally + ; if there is still an empty slot for a new ball somewhere... + ;lda RANDOM + ;cmp #spawnProbability + ;bcs noCollision + lda colour + cmp #1 + bne noCollision + +eXistenZcReate + ;creates a new ball + ;removes one free slot from the eXistenZstack + ;ends with ball number in X + ;ends with zero when there is no free slot for a ball + ldy eXistenZstackPtr + beq noMoreSlots + lda eXistenZstack,Y + dey + sty eXistenZstackPtr + tax + + ;OK, in X there is an empty slot for a ball + + ;spawn it + lda #1 + sta balleXistenZ,x + lda xPos + sta xPosTableL,x + lda xPos+1 + sta xPosTableH,x + lda yPos + sta yPosTableL,x + lda yPos+1 + sta yPosTableH,x + +; random initial speed and direction + lda random + bpl dXplus + + lda #-1 + sta dxTableH,x + bne dXlower + +dXplus + lda #1 + sta dxTableH,x +dXlower + lda random + sta dxTableL,x + + + ;randomize 1 maxSpeed-1 ;dy can not be too small or the game would take forever + lda #1 + sta dyTableH,x + lda random + sta dyTableL,x + + + + ; sound + ;lda random + ;and #%00001000 + ;lda #%00000000 + ;sta consol + + +noCollision +noMoreSlots + + +flightLoopEnd +;end of the cycle for one ball + ;save the changes now + ldx currBall + + ; let's save the position for the future erase + ; old position of ball(currBall) is saved here + ; in table nr memCycleTable(currBall) + ldy currBall + lda xpos+1 ;high byte is the integer position + sta (xMemAddr),y + lda ypos+1 + sta (yMemAddr),y + ; saved + + lda xpos + sta xposTableL,x + lda xpos+1 + sta xposTableH,x + + lda ypos + sta yposTableL,x + lda ypos+1 + sta yposTableH,x + + lda dX + sta dxTableL,x + lda dX+1 + sta dxTableH,x + + lda dY + sta dyTableL,x + lda dY+1 + sta dYTableH,x + + + +endOfBallzLoop + ;pause + + dec currBall + jpl flight + + + pause 0;all balls + + lda eXistenZstackPtr + cmp #maxBalls + jne loop + + ;game over +gameOver + lda RANDOM + and #$07 + sta COLPM0 + jmp gameOver + +;------------------- +ballDoesNotexist + ;a delay loop for a ball that does not really exist (yet) + ldx #70 +delayLoop + dex + bne delayLoop + jmp endOfBallzLoop +;-------------------------------------------------- +fatplot +; xpos, ypos (.byte) - pixel position +; xpos<80 +; pixel colour in "colour" +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + lda xpos + lsr + tay +;--- + ldx ypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + ldx colour + + lda xpos + and #$01 + bne fpRightNibble +fpLeftNibble + lda (temp),y + and #$0F + ora LNColtable,x + sta (temp),y + rts + +fpRightNibble + lda (temp),y + and #$F0 + ora RNColtable,x + sta (temp),y + rts +;-------------------------------------------------- +fatdeplot +; deyxpos, deypos (.byte) - pixel position +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + lda dexpos + lsr + tay +;--- + ldx deypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda dexpos + and #$01 + tax + + lda (temp),y + and debittable,x + sta (temp),y + rts +;-------------------------------------------------- +clearDeadBall +;-------------------------------------------------- +;dead ball in clearBallNr + + ldx #maxMemory-1 + stx clearCount + +clearDeadLoop + ldx clearCount + lda xposMemTableAdrL,x + sta xMemAddr + lda xposMemTableAdrH,x + sta xMemAddr+1 + lda yposMemTableAdrL,x + sta yMemAddr + lda yposMemTableAdrH,x + sta yMemAddr+1 + ;now on zero page I've got the addressess to store the old xPos and yPos + ldy clearBallNr + lda (xMemAddr),y + sta dexpos + lda (yMemAddr),y + sta deypos + + jsr fatdeplot + + dec clearCount + bpl clearDeadLoop + + rts +;-------------------------------------------------- +clearScreen +;-------------------------------------------------- + lda #0 + tax +Loopi1 + :(maxLines*40/256+1) sta display+$100*#,x + inx + bne Loopi1 + rts +;-------------------------------------------------- +cycleColoursReset + ldy #6 +cycleRloop + lda colourCycleTabReset,y + sta colourCycleTab,y + dey + bpl cycleRloop + mva #0 colour +;-------------------------------------------------- +cycleColours +;-------------------------------------------------- + inc colour + lda colour + cmp #8 + bne noColourReset + mva #1 colour +noColourReset + ldy #6 +cycleCloop + lda colourCycleTab,y + ;sta COLPM1,y + sta COLPM1S,y + dey + bpl cycleCloop + +;shift colours +/* + 2 + 2 4 + 2 4 6 + 2 4 6 8 + 2 4 6 8 10 + 2 4 6 8 10 12 +2 4 6 8 10 12 14 +4 6 8 10 12 14 2 +6 8 10 12 14 2 4 +8 10 12 14 2 4 6 +10 12 14 2 4 6 8 +12 14 2 4 6 8 10 +14 2 4 6 8 10 12 +2 4 6 8 10 12 14 +4 6 8 10 12 14 +6 8 10 12 14 +8 10 12 14 +10 12 14 +12 14 +14 +261 262 263 264 265 266 267 +*/ +cct = colourCycleTab + ldx cct+6 + mva cct+5 cct+6 + mva cct+4 cct+5 + mva cct+3 cct+4 + mva cct+2 cct+3 + mva cct+1 cct+2 + mva cct+0 cct+1 + stx cct+0 + + rts +colourCycleTab + + .by 14,2,4,6,8,10,12 + +colourCycleTabReset + .by 14,2,4,6,8,10,12 +brickColourTab + .by 0 +;-------------------------------------------------- +initialize +;-------------------------------------------------- + + mva #$00 COLPM0S ; = $02C0 ;- - rejestr-cień COLPM0 + + jsr cycleColoursReset + + mva #$7C COLBAKS + + mva #0 dliCount + jsr clearscreen + jsr drawBricks + + lda dmactls + and #$fc + ora #$02 ; normal screen width + ;ora #$01 ; narrow screen width + sta dmactls + mwa #dl dlptrs + vdli DLI + + + +; prepare mem address tables (for "snake" routine) + + ;first address initialized + mva #xposMemTable xposMemTableAdrH + mva #yposMemTable yposMemTableAdrH + ;now add maxBalls to the following addresses + ;just take the previous one and add "maxBalls" + ldx #0 +initLoop1 + clc + lda xposMemTableAdrL,x + adc #maxBalls ; maxBalls <$80, so it is == 0 + sta xposMemTableAdrH+1,x + clc + lda yposMemTableAdrL,x + adc #maxBalls ; maxBalls <$80, so it is == 0 + sta yposMemTableAdrH+1,x + inx + cpx #maxMemory-1 + bne initLoop1 + ;snake memory addressess initialized! + + ;clear the balleXistenZ (nothing is bouncing!) + ;and other tables + ldx #0 + txa +eXistenZclearLoop + sta balleXistenZ,x + sta dxTableL,x + sta dxTableH,x + sta dyTableL,x + sta dyTableH,x + sta xposTableL,x + sta xposTableH,x + sta yposTableL,x + sta yposTableH,x + sta memCycleTable,x + + inx + cpx #maxBalls + bne eXistenZclearLoop + sta balleXistenZcatch + + + dex + ; X == maxBalls-1 + txa +eXistenZstackFill + sta eXistenZstack+1,x + dex + txa + bne eXistenZstackFill + + + ldy #maxBalls + sty eXistenZstackPtr + ;sty clearPtr + + + ;OK, one ball starts! + + ;ldy eXistenZstackPtr + lda eXistenZstack,Y + dey + sty eXistenZstackPtr + + tax + + + jsr randomStart ;just one random pixxxel + ;previously the whole band of ballz + + ;VBI + mva #screenWidth/2 racquetPos + vmain vint,7 + lda #$80 ;+GTIACTLBITS + sta GTIACTL + sta GTICTLS + + mva #1 colour + + rts +;-------------------------------------------------- +drawBricks +;-------------------------------------------------- + +; solid maxBrickLines field +; for x=margin to screenWidth-margin: +; for y=margin to maxBrickLines+margin: +; fatplot(x,y) + mva #8 colour + mva #margin*2 ypos +drawBricksLoopY + mva #margin*3 xpos +drawBricksLoop + jsr fatplot + inc xpos + lda xpos + cmp #screenWidth-margin*3 + bne drawBricksLoop + inc ypos + lda ypos + cmp #maxBrickLines+margin*2 + bne drawBricksLoopY + + rts +;-------------------------------------------------- +randomStart +; X - ball number +;-------------------------------------------------- + lda #1 + sta balleXistenZ,x + + ;randomize margin $ff-margin + lda #40 + sta xposTableH,x + ;randomize margin*2+maxBrickLines maxLines-margin*4 + lda #30 + sta yposTableH,x + +; random initial speed and direction + ;randomize 0 maxSpeed-1 + lda #1 ;easy start + sta dxTableH,x + lda random + sta dxTableL,x + + ;randomize 1 maxSpeed-1 ;dy can not be too small or the game would take forever + lda #-1 ;easy start + sta dyTableH,x + lda #1 + sta dyTableL,x + rts +;-------------------------------------------------- + +lineAdrL + :margin .byte marginLine + :maxLines .byte >(display+40*#) + ;:margin .byte >marginLine + :256-maxLines-1*margin .by >marginLine; (display+40*#) ;just to let the plot smear on full .byte ypos + ; $E000 is an address in ROM - the trick to avoid spawning new balls! +bittable + .byte %11110000 + .byte %00001111 +RNColtable ; Right Nibble Colour Table + .byte %00000000 + .byte %00000001 + .byte %00000010 + .byte %00000011 + .byte %00000100 + .byte %00000101 + .byte %00000110 + .byte %00000111 + .byte %00001000 +LNColtable ; Left Nibble Colour Table + .byte %00000000 + .byte %00010000 + .byte %00100000 + .byte %00110000 + .byte %01000000 + .byte %01010000 + .byte %01100000 + .byte %01110000 + .byte %10000000 +debittable + .byte %00001111 + .byte %11110000 + +dxTableL :maxBalls .byte 0 +dxTableH :maxBalls .byte 0 +dyTableL :maxBalls .byte 0 +dyTableH :maxBalls .byte 0 +; xpos and ydaw are "decimal" parts of static point precision .word +xposTableL :maxBalls .byte 0 ; "fractional" part +xposTableH :maxBalls .byte 0 ; "fractional" part +yposTableL :maxBalls .byte 0 ; +yposTableH :maxBalls .byte 0 ; +;ball position memory tables - the ball trace works like a "snake" +; (one set, one erased) +; there are "maxMemory" number of tables, "maxballs" length each +; too bad their addressess are not known in advance, +; so a short subrourine must calculate them and place to XposMemTableAdrL, etc. +balleXistenZ :maxBalls .byte 0 ; 0-dead, 1-alive! +balleXistenZcatch + .byte 0 ; catch last ball byte +eXistenZstack ; goes from index [1..maxBalls]. maxBalls[0] is unused + ; keeps the list of free slots for balls + ; goes from down to top. ptr==0 means stack is empty (all balls playing) + :maxBalls+1 .byte 0 +xposMemTable + :maxBalls*maxMemory .byte 0 +yposMemTable + :maxBalls*maxMemory .byte 0 +;addressess of the tables with +xposMemTableAdrL + :maxMemory .byte 0 +xposMemTableAdrH + :maxMemory .byte 0 +yposMemTableAdrL + :maxMemory .byte 0 +yposMemTableAdrH + :maxMemory .byte 0 +;table for keeping the count on the last position to be deleted from the "snake" +memCycleTable + :maxBalls .byte 0 +statusBar + dta d"rc$" +hexDump + dta d" dx$" +dxDisp + dta d" dy$" +dyDisp + dta d" balls$" +ballDisp + dta d" " +marginLine :40 .byte 0 + + RUN main diff --git a/averybreakout_2012.xex b/averybreakout_2012.xex new file mode 100644 index 0000000..83e16c7 Binary files /dev/null and b/averybreakout_2012.xex differ diff --git a/backup/acidbreakout.asm b/backup/acidbreakout.asm new file mode 100644 index 0000000..4407bf4 --- /dev/null +++ b/backup/acidbreakout.asm @@ -0,0 +1,964 @@ +;Acid Breakout - a break from the daily acid +;build 006, 2010-05-12 +;CLEAR! +;あめでと +;--------------------------------------------------- + + icl '../lib/atari.hea' + icl '../lib/system.hea' + +display=$a000 +screenWidth = 256 ;in pixels +maxLines = 210 ; number of lines on the screen +spawnProbability = (256*1/5) +margin = 8 ; top and bottom screen safety margin +racquetPosMin = $8 ; min position of the paddle moved by the user +racquetPosMax = $e8 ; max position of the paddle moved by the user +racquetSize = 4*8 +maxSpeed = 4; maximum speed of a ball. must be power of 2 ('and #' used) +maxBalls = 64 ; maximum number of moving balls, <$80 (bpl used!) +maxMemory = 8 ; number of saved pixel positions + ;Beware! For easier calc somewhere it uses "modulo maxMemory" + ;calculations and therefore this value must be a power of 2! +maxBrickLines = 80 ; maximum number of lines of bricks to be eradicated + + .zpvar xpos ypos .word = $80 ; position of the ball + .zpvar deXpos deYpos .byte ;position for deletion + .zpvar dX dY .word ;main loop shortcuts to the table values + ;.zpvar dx dy .word ;delta + ;xpos, dx - "static point precision" - [dx+1].[dx] (big endian!) + ;this static point precision is emulated with .word calcs, just a result is the high byte + .zpvar currBall collisionCheck racquetPos MyClok eXistenZstackPtr .byte + .zpvar xMemAddr yMemAddr .word ; address where to store memories of the current ball + .zpvar temp .word + .zpvar clearCount clearBallNr .byte + + org $2000 +;--------------------------------------------------- +dl + .by $70,$30 + ;.by $42 + ;.wo statusBar + ;.wo eXistenZstack+1 + ;.by $02 + ;.by 0 + .by $4f ; 1 line + .wo display + :127 .by $0f ;128 lines here + .by $4f + .wo display+$1000 + .by $0f ; 130 lines here + :maxlines-130 .byte $0f ; maxLines lines total + .by $4f+$10 ;Hscroll +DLracquetAddr0 + .wo racquetDispEven + .by $4f+$10 ;Hscroll +DLracquetAddr1 + .wo racquetDispEven + .by $4f+$10 ;Hscroll +DLracquetAddr2 + .wo racquetDispEven + .by $4f+$10 ;Hscroll +DLracquetAddr3 + .wo racquetDispEven + .by $41 + .wo dl +;--------------------------------------------------- +racquetDispEven + :34 .byte $0 + .byte $ff, $ff, $ff, $ff + :28 .byte $0 + +main + jsr initialize + +loop + + mva #maxBalls-1 currBall + +flight + + ldx currBall + lda BalleXistenZ,x + jeq ballDoesNotexist + lda xposTableL,x + sta xpos + lda xposTableH,x + sta xpos+1 + + lda yposTableL,x + sta ypos + lda yposTableH,x + sta ypos+1 + + lda dxTableL,x + sta dX + lda dxTableH,x + sta dX+1 + + lda dyTableL,x + sta dY + lda dYTableH,x + sta dY+1 + + ; now, delete the oldest pixel + ; + lda memCycleTable,x + clc + adc #1 ;next position in the table + and #maxMemory-1 ; this is the tricky part (mod #maxMemory) + ; due to this AND maxMemory MUST be power of 2!!! + sta memCycleTable,x ; memCycleTable saved + tax + lda xposMemTableAdrL,x + sta xMemAddr + lda xposMemTableAdrH,x + sta xMemAddr+1 + lda yposMemTableAdrL,x + sta yMemAddr + lda yposMemTableAdrH,x + sta yMemAddr+1 + ;now on zero page I've got the addressess to store the old xPos and yPos + ldy currBall + lda (yMemAddr),y + tax + lda (xMemAddr),y + sta dexpos + + + ; and erase the last point in the "snake" + ;jsr deplot +;-------------------------------------------------- +;deplot +; moved here for the speeeeeed +; deyxpos, deypos (.byte) - pixel position +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + ;lda dexpos + lsr + lsr + lsr + tay +;--- + ;ldx deypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda dexpos + and #$07 + tax + + lda (temp),y + and debittable,x + sta (temp),y + + ;move the ball!!! + adw xpos dX xpos + + adw ypos dY ypos + + + +;top bounce + ; if yposmaxLines+margin then bounce + lda ypos+1 + cmp #maxLines+margin + bcc noBottom + + ; check if the ball hits the racquette + ;jmp noBallOut ; turns off the ball kill + + lda ypos+1 + cmp #maxLines+margin+maxSpeed*2 ; that makes the ball below the racquet + bcs flyDown2 ;kinda lame optimisation as A carries ypos+1 + + + + lda racquetPos + sec + sbc #racquetPosMin + cmp xpos+1 + + jcs flyDown + + clc + adc #racquetSize-1 + cmp xpos+1 + jcs bottomBounce + +flyDown + lda ypos+1 +flyDown2 + cmp #255-margin ;maximum depth + bcc noBottom + + + + + +ballOut + + lda currBall + +eXistenZdEstroy + ;destroys ball number A + ;pushes one free slot to the eXistenZstack + ;ends with !number of balls in X (maxBalls == end of the game) + ;txa + ldy eXistenZstackPtr + iny + sta eXistenZstack,y + sty eXistenZstackPtr + + ;ldx currBall + tax + lda #0 + sta balleXistenZ,x + + jmp flightLoopEnd + +bottomBounce + ; assuming that here a plot can get only from below, + ; so it is enough to switch dy sign + ; sbw #$ffff dy dy ;this does not compile :( + negw dY + mva #maxLines+margin-2 ypos+1 + + +noBottom + +;left bounce + lda xpos+1 + cmp #0+maxSpeed+1 + bcs noLeft + negw dX + mva #0+maxSpeed+3 xpos+1 + +noLeft + + +;right border bounce + lda xpos+1 + .if $100-maxSpeed > $ff + .error "maxSpeed too low!!!" + .endif + cmp #$100-maxSpeed-1 + bcc noRight + negw dX + mva #$ff-maxSpeed-3 xpos+1 +noRight + + ;jsr plot + ; the full plot copied here to get few cycles and collision + ; high byte is the integer position + ; low byte is the "fractional" part + ; let's calculate coordinates from xpos and ypos + lda xpos+1 + lsr + lsr + lsr + tay +;--- + ldx ypos+1 + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda xpos+1 + and #$07 + tax + + lda (temp),y + sta collisionCheck + ora bittable,x ;eor + sta (temp),y + cmp collisionCheck + ; when final byte and the original bytes are equal, it means it is a collision (plot in the place of a dot) + jne noCollision + + lda ypos+1 + cmp #maxLines+margin-2-1 + jcs noCollision ;ball is outside the screen! + + ;switch direction, Charles + ; an idea for assuming which direction to switch - dX or dY? + ; on a diagram below in the middle there is an approached brick +/* + \ / + \-dY / + \ / + -dX [] -dX + / \ + /-dY \ + / \ +*/ + ; it means: + ; if |dX|>|dY| then dX == -dX + ; else dY == -dY + + ; get absolute values + lda dX+1 + bpl dXpositive +;dX is negative here + lda dY+1 + bpl dXneg_dYpos + +;dX and dY are negative here + cmp dX+1 + bcc dX_gr_dY__dX_dYneg + ; |dY| >= |dX| ; hour 5 + negw dY + jmp bounceDone +dX_gr_dY__dX_dYneg + ; hour 4 + negw dX + jmp bounceDone + +dXneg_dYpos + ; dY in A + clc + adc dX+1 + bpl dY_gr_dX__dXneg_dYpos + ; |dX| > |dy|; hour 2 + negw dX + jmp bounceDone +dY_gr_dX__dXneg_dYpos + ; hour 1 + negw dY + jmp bounceDone + +dXpositive + lda dY+1 + bpl dX_dYpositive +;dX positive, dY negative + clc + adc dX+1 + bpl dX_gr_dY__dXpos_dYneg + ; hour 7 + negw dY + jmp bounceDone + +dX_gr_dY__dXpos_dYneg + ; hour 8 + negw dX + jmp bounceDone + +dX_dYpositive + ;(dY+1)* is in A + cmp dX+1 + bcc dX_gr_dY__dX_dYpos + ; dY > dX ; hour 11 + negw dY + jmp bounceDone +dX_gr_dY__dX_dYpos + ; dY < dX ; hour 10 + negw dX + +bounceDone +;spawn the new bally + ; if there is still an empty slot for a new ball somewhere... + lda RANDOM + cmp #spawnProbability + bcs noCollision + +eXistenZcReate + ;creates a new ball + ;removes one free slot from the eXistenZstack + ;ends with ball number in X + ;ends with zero when there is no free slot for a ball + ldy eXistenZstackPtr + beq noMoreSlots + lda eXistenZstack,Y + dey + sty eXistenZstackPtr + tax + + ;OK, in X there is an empty slot for a ball + + ;spawn it + lda #1 + sta balleXistenZ,x + lda xPos + sta xPosTableL,x + lda xPos+1 + sta xPosTableH,x + lda yPos + sta yPosTableL,x + lda yPos+1 + sta yPosTableH,x + +; random initial speed and direction + lda random + bpl dXplus + + ;A carries a random number + and #maxSpeed-1 ;a variable speed limiter + clc + adc #$FF-(maxSpeed-1) + sta dxTableH,x + bne dXlower + +dXplus + clc + ;A carries a random number + and #maxSpeed-1 ;a variable speed limiter + adc #1 + sta dxTableH,x +dXlower + lda random + sta dxTableL,x + + + randomize 1 maxSpeed-1 ;dy can not be too small or the game would take forever + sta dyTableH,x + lda random + sta dyTableL,x + + + + ; sound + ;lda random + ;and #%00001000 + lda #%00000000 + sta consol + + +noCollision +noMoreSlots + + +flightLoopEnd +;end of the cycle for one ball + ;save the changes now + ldx currBall + + ; let's save the position for the future erase + ; old position of ball(currBall) is saved here + ; in table nr memCycleTable(currBall) + ldy currBall + lda xpos+1 ;high byte is the integer position + sta (xMemAddr),y + lda ypos+1 + sta (yMemAddr),y + ; saved + + lda xpos + sta xposTableL,x + lda xpos+1 + sta xposTableH,x + + lda ypos + sta yposTableL,x + lda ypos+1 + sta yposTableH,x + + lda dX + sta dxTableL,x + lda dX+1 + sta dxTableH,x + + lda dY + sta dyTableL,x + lda dY+1 + sta dYTableH,x + + + +endOfBallzLoop + + dec currBall + jpl flight + + ;deaD Ball erasing + ; if clearPtr (pointer for lazy crearing) + ; is lower than eXistenZstackPtr + ; then erase 1 memory ball and increase the pointer + ; the pointer gets lowered with eXistenZstackPtr + +/* + ldx clearPtr + dex + cpx eXistenZstackPtr + bcS clearPrt_GREQ_eXistenZstackPtr + + lda eXistenZstack,x + sta clearBallNr + jsr clearDeadBall + inc clearPtr + +clearPrt_GREQ_eXistenZstackPtr +*/ + + + lda eXistenZstackPtr + cmp #maxBalls + bne gameIsNotOver + ;game over +zzz + inc colbak + jmp zzz + +gameIsNotOver + jmp loop +;------------------- +ballDoesNotexist + ;a delay loop for a ball that does not really exist (yet) + ldx #75 +delayLoop + dex + bne delayLoop + jmp endOfBallzLoop +;-------------------------------------------------- +plot +; xpos, ypos (.byte) - pixel position +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + lda xpos + lsr + lsr + lsr + tay +;--- + ldx ypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda xpos + and #$07 + tax + + lda (temp),y + ora bittable,x ;eor + sta (temp),y + rts +;-------------------------------------------------- +deplot +; deyxpos, deypos (.byte) - pixel position +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos + lda dexpos + lsr + lsr + lsr + tay +;--- + ldx deypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + lda dexpos + and #$07 + tax + + lda (temp),y + and debittable,x + sta (temp),y + rts +;-------------------------------------------------- +byteDePlot +; deyxpos, deypos (.byte) - byte-pixel position 32xmaxlines screen +;-------------------------------------------------- + ; let's calculate coordinates from xpos and ypos +;--- + ldx deypos + lda lineAdrL,x + sta temp + lda lineAdrH,x + sta temp+1 + + ldy dexpos + lda #0 + sta (temp),y + rts +;-------------------------------------------------- +clearDeadBall +;-------------------------------------------------- +;dead ball in clearBallNr + + ldx #maxMemory-1 + stx clearCount + +clearDeadLoop + ldx clearCount + lda xposMemTableAdrL,x + sta xMemAddr + lda xposMemTableAdrH,x + sta xMemAddr+1 + lda yposMemTableAdrL,x + sta yMemAddr + lda yposMemTableAdrH,x + sta yMemAddr+1 + ;now on zero page I've got the addressess to store the old xPos and yPos + ldy clearBallNr + lda (xMemAddr),y + sta dexpos + lda (yMemAddr),y + sta deypos + + jsr deplot + + dec clearCount + bpl clearDeadLoop + + rts +;-------------------------------------------------- +clearScreen +;-------------------------------------------------- + lda #0 + tax +Loopi1 + :(maxLines*32/256+1) sta display+$100*#,x + inx + bne Loopi1 + rts +;-------------------------------------------------- +drawBricks +;-------------------------------------------------- + +; solid maxBrickLines field + lda #%11111111 + ldx #0 +loopi2 + :(maxBrickLines+margin)*32/256-1 sta display+screenWidth+$100*#,x + inx + bne loopi2 + +; empty borders + mva #margin deypos +loopi3 + mva #0 dexpos + jsr byteDePlot + mva #1 dexpos + jsr byteDePlot + mva #30 dexpos + jsr byteDePlot + mva #31 dexpos + jsr byteDePlot + inc deypos + lda deypos + cmp #maxBrickLines+margin*2 + bne loopi3 + + rts +;-------------------------------------------------- +randomStart +; X - ball number +;-------------------------------------------------- + lda #1 + sta balleXistenZ,x + + randomize margin $ff-margin + sta xposTableH,x + randomize margin*2+maxBrickLines maxLines-margin*4 + sta yposTableH,x + +; random initial speed and direction + ;randomize 0 maxSpeed-1 + lda #1 ;easy start + sta dxTableH,x + lda random + sta dxTableL,x + + ;randomize 1 maxSpeed-1 ;dy can not be too small or the game would take forever + lda #-2 ;easy start + sta dyTableH,x + lda random + sta dyTableL,x + rts + + +;-------------------------------------------------- +initialize +;-------------------------------------------------- + ;mva 0 COLPF2S + jsr clearscreen + jsr drawBricks + + lda dmactls + and #$fc + ;ora #$02 ; normal screen width + ora #$01 ; narrow screen width + sta dmactls + mwa #dl dlptrs +; prepare mem address tables (for "snake" routine) + + ;first address initialized + mva #xposMemTable xposMemTableAdrH + mva #yposMemTable yposMemTableAdrH + ;now add maxBalls to the following addresses + ;just take the previous one and add "maxBalls" + ldx #0 +initLoop1 + clc + lda xposMemTableAdrL,x + adc #maxBalls ; maxBalls <$80, so it is == 0 + sta xposMemTableAdrH+1,x + clc + lda yposMemTableAdrL,x + adc #maxBalls ; maxBalls <$80, so it is == 0 + sta yposMemTableAdrH+1,x + inx + cpx #maxMemory-1 + bne initLoop1 + ;snake memory addressess initialized! + + ;clear the balleXistenZ (nothing is bouncing!) + ;and other tables + ldx #0 + txa +eXistenZclearLoop + sta balleXistenZ,x + sta dxTableL,x + sta dxTableH,x + sta dyTableL,x + sta dyTableH,x + sta xposTableL,x + sta xposTableH,x + sta yposTableL,x + sta yposTableH,x + sta memCycleTable,x + + inx + cpx #maxBalls + bne eXistenZclearLoop + sta balleXistenZcatch + + + dex + ; X == maxBalls-1 + txa +eXistenZstackFill + sta eXistenZstack+1,x + dex + txa + bne eXistenZstackFill + + + ldy #maxBalls + sty eXistenZstackPtr + ;sty clearPtr + + + ;OK, one ball starts! + + ;ldy eXistenZstackPtr + lda eXistenZstack,Y + dey + sty eXistenZstackPtr + + tax + + + jsr randomStart ;just one random pixxxel + ;previously the whole band of ballz + + ;VBI + mva #$b0 racquetPos + vmain vint,7 + rts +;-------------------------------------------------- +vint + ;------------JOY------------- + ;happy happy joy joy + ;check for joystick now +/* + inc MyClok + lda MyClok + and #$07 + bne jNotRight +*/ + ldy PORTA +/* + tya + and #$01 ;up + bne jNotUp + ldx joystickConversion ;up + lda #1 + sta keyboardGrid,x +jNotUp + tya + and #$02 ;down + bne jNotDown + ldx joystickConversion+1 ;up + lda #1 + sta keyboardGrid,x +jNotDown +*/ + tya + and #$04 ;left + bne jNotLeft + ldx racquetPos + cpx #racquetPosMin+1 + bcc jNotLeft + dex + dex + stx racquetPos + +jNotLeft + tya + and #$08 ;right + bne jNotRight + ldx racquetPos + cpx #racquetPosMax + bcs jNotRight + inx + inx + stx racquetPos +jNotRight +/* + ;fire + lda TRIG0 + bne JNotFire + ... +JNotFire +*/ + + + + lda racquetPos + + sec + lda #screenWidth-1 + sbc racquetPos + :3 lsr + clc + adc #racquetDispEven + adc #0 + sta dlracquetAddr0+1 + + lda dlracquetAddr0 + sta dlracquetAddr1 + sta dlracquetAddr2 + sta dlracquetAddr3 + lda dlracquetAddr0+1 + sta dlracquetAddr1+1 + sta dlracquetAddr2+1 + sta dlracquetAddr3+1 + + lda racquetPos + lsr + and #$03 + sta HSCROL + + lda racquetPos + :4 lsr + tax + lda hexconv,x + sta hexDump + + lda racquetPos + and #$0F + tax + lda hexconv,x + sta hexDump+1 + + + jmp XITVBV + +;-------------------------------------------------- +hexConv + dta d"0123456789abcdef" +marginLine :32 .byte 0 + +lineAdrL + :margin .byte marginLine + :maxLines .byte >(display+32*#) + ;:margin .byte >marginLine + :256-maxLines-1*margin .by >marginLine; (display+32*#) ;just to let the plot smear on full .byte ypos + ; $E000 is an address in ROM - the trick to avoid spawning new balls! +bittable + .byte $80,$40,$20,$10,$08,$04,$02,$01 +debittable + .byte %01111111 + .byte %10111111 + .byte %11011111 + .byte %11101111 + .byte %11110111 + .byte %11111011 + .byte %11111101 + .byte %11111110 + +dxTableL :maxBalls .byte 0 +dxTableH :maxBalls .byte 0 +dyTableL :maxBalls .byte 0 +dyTableH :maxBalls .byte 0 +; xpos and ydaw are "decimal" parts of static point precision .word +xposTableL :maxBalls .byte 0 ; "fractional" part +xposTableH :maxBalls .byte 0 ; "fractional" part +yposTableL :maxBalls .byte 0 ; +yposTableH :maxBalls .byte 0 ; +;ball position memory tables - the ball trace works like a "snake" +; (one set, one erased) +; there are "maxMemory" number of tables, "maxballs" length each +; too bad their addressess are not known in advance, +; so a short subrourine must calculate them and place to XposMemTableAdrL, etc. +balleXistenZ :maxBalls .byte 0 ; 0-dead, 1-alive! +balleXistenZcatch + .byte 0 ; catch last ball byte +eXistenZstack ; goes from index [1..maxBalls]. maxBalls[0] is unused + ; keeps the list of free slots for balls + ; goes from down to top. ptr==0 means stack is empty (all balls playing) + :maxBalls+1 .byte 0 +xposMemTable + :maxBalls*maxMemory .byte 0 +yposMemTable + :maxBalls*maxMemory .byte 0 +;addressess of the tables with +xposMemTableAdrL + :maxMemory .byte 0 +xposMemTableAdrH + :maxMemory .byte 0 +yposMemTableAdrL + :maxMemory .byte 0 +yposMemTableAdrH + :maxMemory .byte 0 +;table for keeping the count on the last position to be deleted from the "snake" +memCycleTable + :maxBalls .byte 0 +statusBar + dta d"rc$" +hexDump + dta d" dx$" +dxDisp + dta d" dy$" +dyDisp + dta d" balls$" +ballDisp + dta d" " + + RUN main + + \ No newline at end of file diff --git a/backup/acidbreakout.obx b/backup/acidbreakout.obx new file mode 100644 index 0000000..a60b70f Binary files /dev/null and b/backup/acidbreakout.obx differ diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..60a15ff --- /dev/null +++ b/changes.txt @@ -0,0 +1,97 @@ + +TODO +T021: balls are ferking stick to the right part of the screen... +T023: find and set few nice starting points and speeds to be rotated (remove not really sexy random start) +T025: do nice game over (when not clear) +T026: do nice "ALL CLEAR" screen + +T028: (idea) spinning the ball - when ball bounces the racquette when it is moving, dX adds or subs + +Changes: + +2012-02-16 +Fork to the colour version. (averybreakout.asm) Graphics mode tests. + + +build 023: 2010-06-26 + + idle ball delay loop shortened to 75 loops for a smoother experience +T027: when ball is down out of the screen and the racquette is over it, it bounces. + Need to add a check for it! (no bounces when out of the screen) + +build 022: 2010-06-24 +T022: when balls disappear, their traces should disappear, too, even when a new ball is NOT created + now the dead pixels disappear only when a new ball is created. + It has been done by expanding the bottom area, so the balls are going down. + Screen had to been cut 10 lines. Not a big deal. +T024: detect the ending + Detected (gameIsNotOver label). + + +build 021: 2010-06-21 ++ apparently the slowest part of the engine is eXistenZcheck - rewrite as a simple stack! + as usual, it was not as simple as thought previously... But works now! + Will be easier to clear traces of the dead balls now. + +build 020: 2010-06-02 ++ when the racquette is max to the right it does not bounce balls! ++ still problems with racquet + solved - pos+size was >$ff ++ very fast balls get through the left-right side borders + solved by a better usage of "maxSpeed" + +build 019: 2010-05-27 ++ alive balls are somewhere in the outer space - check where and fix + where: YposTableH -- 00 -- 08 most 01, XposTableH - FF, FE, 00, 01 + basicaly these are places where a ball should never be! + One fix let other "outer-space" related buggies die, too. + The problem was that bouncing ball got behind the border and started to bounce + there and forth outside the screen. Fix - bring it back on the playfield. ++ balls are created somewhere outside the screen ++ when balls disappear, their traces should disappear, too (now 1 pixel stays on screen) ++ high dX balls were sticking to Vborders. Fixed by increasing the margin + +build 018: 2010-05-26 ++ 1 pixel out of the deleted bunch stays forever (erase/store sequence was invalid) + + +build 017: 2010-05-25 ++ too few high dX balls +x low-priority: rewrite memorytables to use lda (zpage,x) addressing (cool:) + Turned out not to be such a low-priority job as wrong sequence of writes + to memorytables make one pixel staying on the screen. Rewrite to simplify! + Turned out that indirect X addressing is not good for it and this is closed. + +build 016: 2010-05-24 +Forgot about documenting updates... +Basically the game is close to the end, but number of small issues emerged. ++ racquette is too slow (and it was such a work to make it 1-px smooth...) + +build 006: 2010-05-12 +Collision detection +Ough... turned out to be way more difficult than expected, but now collisions are detected and balls are bouncing! + +build 005: 2010-05-10 +Snake like plot memory! Lots and lots of pixels, less balls (64 is the max...) + + +build 004: 2010-05-09 +Multiple ballz + + +build 003: 2010-05-08 +Feeling bouncy +simple boundary bounces work nicely. +Unfrtunately number of draws per frame dropped to circa 70. +I guess 64 will be an achievement for 2 frames. + +build 002: 2010-05-06 +MADS rewrite :-] +;bare plots get circa 320 pixels per frame. I will go for 128 pix max now + + +build 001: 2010-05-04 + +First try: +Strip scorch sources to get clean gr.8 screen. +(and PLOT) +Basic idea: http://wonderfl.net/c/tNGi/fullscreen