Fork of "Pokittris" for the Pokitto

Dependencies:   PWMOut Pokitto

Fork of Pokittris by Nicolas Mougin

Revision:
0:f759a823d3ae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tetris.cpp	Tue Oct 10 07:17:45 2017 +0000
@@ -0,0 +1,576 @@
+// music - 8bit archade4 from www.dl-sounds.com
+
+#include "Pokitto.h"
+#include "tetris_gfx.h"
+#include "easing.h"
+
+#define REPSPEED 12
+
+Pokitto::Core game;
+
+#define HELD 0
+#define NEW 1
+#define RELEASE 2
+byte CompletePad, ExPad, TempPad, myPad;
+bool _A[3], _B[3], _C[3], _Up[3], _Down[3], _Left[3], _Right[3];
+bool bgNum = 1;
+char musicName[] = "pokittris.raw";
+byte palNum = 0;
+
+int topLine;
+byte unlockedPal=0;
+bool removeLine[19];
+byte linesToRemove=0;
+byte animCount;
+bool splodeOK=0;
+byte animSplode=0;
+
+void UPDATEPAD(int pad, int var) {
+  _C[pad] = (var >> 1)&1;
+  _B[pad] = (var >> 2)&1;
+  _A[pad] = (var >> 3)&1;
+  _Down[pad] = (var >> 4)&1;
+  _Left[pad] = (var >> 5)&1;
+  _Right[pad] = (var >> 6)&1;
+  _Up[pad] = (var >> 7)&1;
+}
+
+void UpdatePad(int joy_code){
+  ExPad = CompletePad;
+  CompletePad = joy_code;
+  UPDATEPAD(HELD, CompletePad); // held
+  UPDATEPAD(RELEASE, (ExPad & (~CompletePad))); // released
+  UPDATEPAD(NEW, (CompletePad & (~ExPad))); // newpress
+}
+
+byte updateButtons(byte var){
+   var = 0;
+   if (game.buttons.cBtn()) var |= (1<<1);
+   if (game.buttons.bBtn()) var |= (1<<2);
+   if (game.buttons.aBtn()) var |= (1<<3);
+   if (game.buttons.downBtn()) var |= (1<<4);
+   if (game.buttons.leftBtn()) var |= (1<<5);
+   if (game.buttons.rightBtn()) var |= (1<<6);
+   if (game.buttons.upBtn()) var |= (1<<7);
+
+   return var;
+}
+
+
+
+// some globals...
+long int frameNumber = 0;
+long int myDelay;
+long int tempTime;
+int dropTime = 0;
+int slideTime = 0;
+byte gameMode = 0;
+bool paused = 0;
+byte menuItem;
+bool bgmusic = 1;
+
+byte px, py, ps, pr; // player x,y,shape,rotation
+byte nextTile;
+byte lineCount, level;
+int score, lines;
+bool okToContinue = 0;
+byte slideSpeed = 10;
+
+
+void loadPal(char num){
+    unsigned short curPal[4];
+    curPal[0] = pallet[(num*4)];
+    curPal[1] = pallet[(num*4)+1];
+    curPal[2] = pallet[(num*4)+2];
+    curPal[3] = pallet[(num*4)+3];
+    game.display.load565Palette(curPal);
+}
+
+void drawShape(byte x1, signed char y1, byte shape, byte frame) {
+  for (char y = 0; y < 4; y++) {
+    if (y1 + y > 1) {
+      for (char x = 0; x < 4; x++) {
+        byte mt = pgm_read_byte(shapeMap + (x + 4 * y) + shape * 64 + (frame * 16));
+        if (mt > 1) {
+          game.display.drawBitmap((x1 + x)*8, (y1 + y)*8, tile_gfx[(mt-1)+shape*6]);
+        }
+      }
+    }
+  }
+}
+
+bool check(signed char x1, signed char y1, char rot) {
+    byte ret=0;
+  for (char y = 0; y < 4; y++) {
+    if (y1 + y >= 0) {
+      for (char x = 0; x < 4; x++) {
+        byte mt = pgm_read_byte(shapeMap + (x + 4 * y) + ps * 64 + (rot * 16));
+        if (mt > 1) {
+          if ( playfield[(x1 + x) + 16 * (y1 + y)] != 0) {
+            ret= 1;
+          }
+        }
+      }
+    }
+  }
+  return ret;
+}
+
+void stamp(signed char x1, signed char y1, byte shape, byte rot) {
+  for (char y = 0; y < 4; y++) {
+    if (y1 + y >= 0) {
+      for (char x = 0; x < 4; x++) {
+        byte mt = pgm_read_byte(shapeMap + (x + 4 * y) + shape * 64 + (rot * 16));
+        if (mt > 1) {
+          playfield[(x1 + x) + 16 * (y1 + y)] = (mt-1)+shape*6;
+        }
+      }
+    }
+  }
+}
+
+
+void clearPlayfield() {
+  for (char y = 0; y < 19; y++) {
+    for (char x = 3; x < 13; x++) {
+      playfield[x + 16 * y] = 0;
+    }
+  }
+}
+
+void drawBackground(){
+  for (char y = 0; y < 22; y++) {
+    for (char x = 0; x < 28; x++) {
+      byte mt = bg_map[x + 28 * y + (616*bgNum)];
+      game.display.drawBitmap(x*8, y*8, bg_gfx[mt]);
+    }
+  }
+}
+
+void drawPlayfield() {
+    drawBackground();
+
+  for (char y = 1; y < 19; y++) {
+    for (char x = 3; x < 13; x++) {
+      byte mt = playfield[x + 16 * y];
+      game.display.drawBitmap((x + 5)*8, (y+1 )*8, tile_gfx[mt]);
+    }
+  }
+
+    if(animSplode==0){
+        // current shape
+        drawShape(px+5, py+1, ps, pr);
+    }
+    // next shape?
+    drawShape(19, 14, nextTile, 0);
+
+    char text[] = "        ";
+    sprintf(text, "%05d", score);
+    game.display.setCursor(152,56);
+    game.display.color=3;
+    game.display.print(text);
+    sprintf(text, "%5d", level);
+    game.display.setCursor(16,96);
+    game.display.print(text);
+    sprintf(text, "%5d", lines);
+    game.display.setCursor(16,48);
+    game.display.print(text);
+
+}
+
+
+
+void checkLine() {
+
+    for(char t=0; t<19; t++){
+        removeLine[t]=0;
+    }
+
+  if (py <= 0) {
+    loadPal(1); // default green palette
+    gameMode = 3;  // gameOver if off top of screen
+    frameNumber=0;
+    return;
+  }
+
+  score++; // increase score here as it's called whenever a tile drops
+  topLine = 0;
+
+  for (char y = 0; y < 19; y++) {
+    char line = 0;
+    for (char x = 3; x < 13; x++) {
+      line += playfield[x + 16 * y] != 0 ? 1 : 0;
+    }
+    if (line == 10) { // remove line
+        removeLine[y]=1;
+        linesToRemove++;
+        if(linesToRemove==4){splodeOK=1;}
+        lineCount++;
+        if (lineCount == 10) {
+            lineCount = 0;
+            level++;
+        }
+        lines++;
+        score += 10;
+        }
+    }
+
+  for (char y = 0; y < 10; y++) {
+    char line = 0;
+    for (char x = 3; x < 13; x++) {
+      topLine += playfield[x + 16 * y] != 0 ? 1 : 0;
+    }
+  }
+
+
+    // mess with the palette
+
+      int percent = 100;
+      int diff = topLine;
+
+      unsigned short *p;
+      palNum = 0;//level & 31;
+      p=pallet+(palNum*4);
+      unsigned short curPal[4];
+
+      curPal[0] = pallet[(palNum*4)];
+      curPal[1] = pallet[(palNum*4)+1];
+      curPal[2] = pallet[(palNum*4)+2];
+      curPal[3] = pallet[(palNum*4)+3];
+
+     int greyPal[] = {0xF800,0xF8000,0xF800,0xF800}; // it's actually RED for danger!
+
+    unsigned short red[4], green[4], blue[4], red1[4], green1[4], blue1[4], red2[4], green2[4], blue2[4];
+
+    for(char t=0; t<4; t++){
+        red1[t] = (curPal[t]>>11) & 31;
+        red2[t] = (greyPal[t]>> 11) & 31;
+        green1[t] = (curPal[t]>> 5) & 63;
+        green2[t] = (greyPal[t]>> 5) & 63;
+        blue1[t] = curPal[t] & 31;
+        blue2[t] = greyPal[t] & 31;
+
+        red[t] = red1[t]+((red2[t]-red1[t])*diff/percent);
+        green[t] = green1[t]+((green2[t]-green1[t])*diff/percent);
+        blue[t] = blue1[t]+((blue2[t]-blue1[t])*diff/percent);
+
+        curPal[t] = (red[t]<<11)+(green[t]<<5)+blue[t];
+
+    }
+
+    game.display.load565Palette(curPal);
+
+}
+
+
+// transparent 2bit bitmap with mask
+void drawMyBitmap(int16_t x, int16_t y, const uint8_t* bitmap, const uint8_t* mask)
+{
+    int16_t w = *bitmap;
+    int16_t h = *(bitmap + 1);
+    bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
+    /** visibility check */
+    if (y<-h || y>game.display.height) return; //invisible
+    if (x<-w || x>game.display.width) return;  //invisible
+
+    /** 2 bpp mode */
+    int16_t i, j, byteNum, bitNum, byteWidth = w >> 2;
+    for (i = 0; i < w; i++) {
+        byteNum = i / 4;
+        bitNum = (i % 4)<<1;
+        for (j = 0; j < h; j++) {
+            uint8_t source = *(bitmap + j * byteWidth + byteNum);
+            uint8_t source2 = *(mask + j * byteWidth + byteNum+2);
+            uint8_t output = (source & (0xC0 >> bitNum));
+            output >>= (6-bitNum);
+
+            uint8_t output2 = (source2 & (0xC0 >> bitNum));
+            output2 >>= (6-bitNum);
+
+            if (output2 != 0) {
+                game.display.setColor(output);
+                game.display.drawPixel(x + i, y + j);
+            }
+        }
+
+    //return;
+    }
+}
+
+
+
+void titleScreen(){
+
+  // background
+  for (char y = 0; y < 22; y++) {
+    for (char x = 0; x < 28; x++) {
+      byte mt = bg_map[x + 28 * y];
+      game.display.drawBitmap(x*8, y*8, bg_gfx[mt]);
+    }
+  }
+
+int y=48;
+    if(frameNumber<=64){
+                        // time, start, distance, duration
+        #ifdef POK_SIM
+        y = easeOutBounce(frameNumber, -48, 48+48, 64);
+        #else
+        y = easeOutBounce(frameNumber*4, -48, 48+48, 64);
+        if (y>48) y=48;
+        #endif
+    }
+    drawMyBitmap(16, y, title_bitmap, title_mask);
+
+
+    char text[] = " Press A to Start ";
+    game.display.setCursor(40,120);
+    game.display.color=3;
+    game.display.print(text);
+
+  if(_A[NEW]){
+    // make sure the playfield is clear!
+      for (char y = 18; y > 0; y--) {
+        for (char x = 3; x < 13; x++) {
+          playfield[x + 16 * y] = 0;
+        }
+      }
+
+    loadPal(0); // default green palette
+    gameMode = 1;
+  }
+
+}
+
+void gameOver(){
+  // background
+  for (char y = 0; y < 22; y++) {
+    for (char x = 0; x < 28; x++) {
+      byte mt = bg_map[x + 28 * y];
+      game.display.drawBitmap(x*8, y*8, bg_gfx[mt]);
+    }
+  }
+
+    int y=48;
+    if(frameNumber<=64){
+                        // time, start, distance, duration
+        y = easeOutBounce(frameNumber, -48, 48+48, 64);
+    }
+    drawMyBitmap(1, y, gameover_bitmap, gameover_mask);
+
+    char text[] = " Press A ";
+    game.display.setCursor(62,120);
+    game.display.color=3;
+    game.display.print(text);
+
+  if(_A[NEW]){
+    gameMode = 0;
+    frameNumber = 0;
+    score=0;
+    lines=0;
+    level=0;
+    splodeOK=0;
+    animSplode=0;
+  }
+
+}
+
+void playGame(){
+    #ifdef POK_SIM
+    #define SLIDECOUNT 6
+    #define DROPCOUNT 20
+    #else
+    #define SLIDECOUNT 1
+    #define DROPCOUNT 2
+    #endif
+
+    if(linesToRemove==0 && animSplode==0){
+
+        if (_Left[NEW]) {
+          if (check(px - 1, py, pr) == 0) {
+            px--;
+            slideTime = 0;
+          }
+        }
+        if (_Right[NEW]) {
+          if (check(px + 1, py, pr) == 0) {
+            px++;
+            slideTime = 0;
+          }
+        }
+        if (_Left[HELD] && slideTime++ > SLIDECOUNT) {
+          if (check(px - 1, py, pr) == 0) {
+            px--;
+            slideTime = 12;
+          }
+        }
+        if (_Right[HELD] && slideTime++ > SLIDECOUNT) {
+          if (check(px + 1, py, pr) == 0) {
+            px++;
+            slideTime = 12;
+          }
+        }
+
+        if ((_Down[HELD]) || (dropTime++ > DROPCOUNT - (level * 2))) {
+          dropTime = 0;
+          if (check(px, py+1, pr) == 0) {
+            py++;
+          } else {
+            // place shape and create new one
+            stamp(px, py, ps, pr);
+            checkLine();
+            py = 0; px = 6; ps = nextTile; nextTile = random(6); pr = 0;
+          }
+        }
+        if (_Up[NEW] && splodeOK==1) {
+                splodeOK=0;
+                animSplode=1;
+        }
+
+        if (_A[NEW]) {
+          if (check(px, py, (pr - 1) & 3) == 0) {
+            pr--;
+          } else if (check(px - 1, py, (pr - 1) & 3) == 0) {
+            pr--; px--;
+          } else if (check(px + 1, py, (pr - 1) & 3) == 0) {
+            pr--; px++;
+          } else if (check(px - 2, py, (pr - 1) & 3) == 0) {
+            pr--; px -= 2;
+          } else if (check(px + 2, py, (pr - 1) & 3) == 0) {
+            pr--; px += 2;
+          }
+          pr &= 3;
+        }
+
+        if (_B[NEW]) {
+          if (check(px, py, (pr + 1) & 3) == 0) {
+            pr++;
+          } else if (check(px - 1, py, (pr + 1) & 3) == 0) {
+            pr++; px--;
+          } else if (check(px + 1, py, (pr + 1) & 3) == 0) {
+            pr++; px++;
+          } else if (check(px - 2, py, (pr + 1) & 3) == 0) {
+            pr++; px -= 2;
+          } else if (check(px + 2, py, (pr + 1) & 3) == 0) {
+            pr++; px += 2;
+          }
+          pr &= 3;
+        }
+
+        animCount=0;
+    }
+
+        if(linesToRemove!=0){
+            // remove some lines
+            for(byte t=0; t<19; t++){
+                if(removeLine[t]==1){
+                    if(animCount<5){
+                        for (char x = 3; x < 13; x++) {
+                            playfield[x + 16 * t] = 5+animCount*6;
+                        } // x
+                    }else{
+                        removeLine[t]=0;
+                        linesToRemove--;
+                        for (char y1 = t; y1 > 0; y1--) {
+                            for (char x = 3; x < 13; x++) {
+                                playfield[x + 16 * y1] = playfield[x + 16 * (y1 - 1)];
+                            }
+                        }
+                    }
+                }
+            }
+            animCount++;
+        }
+
+        if(animSplode!=0){
+
+            if(animSplode<6){
+                for (char y = 0; y < 4; y++) {
+                    if (py + y >= 0) {
+                        for (char x = 0; x < 4; x++) {
+                            byte mt = pgm_read_byte(shapeMap + (x + 4 * y) + ps * 64 + (pr * 16));
+                            if (mt > 1) {
+                                playfield[(px + x) + 16 * (py + y)] = 5+animSplode*6;
+                            }
+                        }
+                    }
+                }
+                animSplode++;
+            }else{
+
+                for (char y = 0; y < 4; y++) {
+                    if (py + y >= 0) {
+                        for (char x = 0; x < 4; x++) {
+                            byte mt = pgm_read_byte(shapeMap + (x + 4 * y) + ps * 64 + (pr * 16));
+                            if (mt > 1) {
+                                playfield[(px + x) + 16 * (py + y)] = 0;
+                            }
+                        }
+                    }
+                }
+                py = 0; px = 6; ps = nextTile;
+                nextTile = random(6); pr = 0;
+                animSplode=0;
+            }
+        }
+
+    // render screen
+    drawPlayfield();
+}
+
+
+
+
+int main(){
+
+    game.begin();
+    game.display.width = 220; // full size
+    game.display.height = 176;
+    game.display.setFont(fontC64);
+    //game.display.charSpacingAdjust = 0; //needed for the non-proportional C64 font (normal value=1)
+    game.display.fixedWidthFont = true;
+
+    loadPal(1); // default green palette
+
+    px=6;
+    gameMode=0;
+    char oldMode = 50;
+    myDelay=40;
+
+    game.sound.playMusicStream(musicName);
+
+    frameNumber=0;
+    animCount=0;
+    splodeOK=0;
+    animSplode=0;
+
+   while (game.isRunning()) {
+
+        // if it is time to update the screen
+        if (game.update()){
+
+            frameNumber++;
+            game.sound.updateStream();
+            game.buttons.update();
+            myPad = updateButtons(myPad);
+            UpdatePad(myPad);
+
+            switch (gameMode) {
+            case 0:
+              titleScreen();
+                break;
+            case 1:
+                if (paused) {
+            //        pauseMenu();
+                } else {
+                    playGame();
+                }
+                break;
+            case 3:
+              gameOver();
+              break;
+            }
+
+        }
+    }
+    return 0;
+}