updating stuff

Dependencies:   PWMOut Pokitto_

Fork of Pokittris by Pokitto Community Team

tetris.cpp

Committer:
spinal
Date:
2018-04-08
Revision:
5:abd49397ce0d
Parent:
4:e861ad5ad42d

File content as of revision 5:abd49397ce0d:

// music - 8bit archade4 from www.dl-sounds.com

#include "Pokitto.h"
#include "tetris_gfx.h"
#include "easing.h"

#define REPSPEED 12

Pokitto::Core game;

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;

int sX,sY,sX1,sY1;


/**************************************************************************/
#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];

DigitalIn _aPin(P1_9);
DigitalIn _bPin(P1_4);
DigitalIn _cPin(P1_10);
DigitalIn _upPin(P1_13);
DigitalIn _downPin(P1_3);
DigitalIn _leftPin(P1_25);
DigitalIn _rightPin(P1_7);

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 (_cPin) var |= (1<<1);
   if (_bPin) var |= (1<<2);
   if (_aPin) var |= (1<<3); // P1_9 = A
   if (_downPin) var |= (1<<4);
   if (_leftPin) var |= (1<<5);
   if (_rightPin) var |= (1<<6);
   if (_upPin) var |= (1<<7);

   return var;
}



// some globals...
long int frameNumber = 0;
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, bool bg=0) {
  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 || bg==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() {

    if(frameNumber==1){
        drawBackground();
    }


  for (char y = 2; y < 19; y++) {
    for (char x = 8; x < 18; x++) {
      byte mt = bg_map[x + 28 * y + (616*bgNum)];
      game.display.drawBitmap(x*8, y*8, bg_gfx[mt]);
    }
  }

  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++) {
    for (char x = 3; x < 13; x++) {
      topLine += playfield[x + 16 * y] != 0 ? 1 : 0;
    }
  }


    // mess with the palette
    // remove because it's incompatible with the new draw routines.
/*
      int percent = 100;
      int diff = topLine;

      palNum = 0;//level & 31;
      unsigned short *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);
            }
        }
    }
}



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]);
    }
  }

    float y=48;
    if(frameNumber<=32){
                        // time, start, distance, duration
        y = easeOutElastic(frameNumber, -48, 48+48, 32); 
    }
    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
    frameNumber=0;
    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]);
    }
  }

    float y=48;
    if(frameNumber<=32){
                        // time, start, distance, duration
        y = easeOutElastic(frameNumber, -48, 48+48, 32); 
    }
    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 6
    #define DROPCOUNT 20
    #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;
              drawShape(19, 14, nextTile, 0,1);
            }
        }
        if (_Up[NEW] && splodeOK==1) {
                splodeOK=0;
                animSplode=1;
        }

        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;
        }

        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;
        }

        animCount=0;
        sX=(px + 4)*8;
        sY=py*8;
        sX1=((px+4)*8)+48;
        sY1=(py*8)+48;
        if(sY1>176)sY1=176;
    }

        if(linesToRemove!=0){
            sX=0; sY=0; sX1=220; sY1=176;
            // 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){
                sX=0;
                sY=0;
                sX1=220;
                sY1=176;
                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;
                sX=0;
                sY=0;
                sX1=220;
                sY1=176;
            }
        }

    // 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;

    game.sound.playMusicStream(musicName);

    frameNumber=0;
    animCount=0;
    splodeOK=0;
    animSplode=0;

    sX=0; sY=0;
    sX1=220; sY1=176;

   while (game.isRunning()) {

        // if it is time to update the screen
//        if (game.update(1)){
            frameNumber++;
            game.sound.updateStream();
            myPad = updateButtons(myPad);
            UpdatePad(myPad);

            switch (gameMode) {
            case 0:
              titleScreen();
                break;
            case 1:
                if (paused) {
            //        pauseMenu();
                } else {
                    playGame();
                }
                break;
            case 3:
              gameOver();
              break;
            }
            if(frameNumber==1){
                sX=0; sY=0;
                sX1=220; sY1=176;
            }

            game.display.updateRegion(sX,sY,sX1,sY1);
            game.display.updateRegion(152,112,184,144); // next tile
  //      }
    }
    return 0;
}