A great PuzzleAction game originally by Aphrodite and Ported to Pokitto by Catsfolly

Dependencies:   PokittoLib

Squiddy.cpp

Committer:
Pokitto
Date:
2018-01-05
Revision:
3:998abe0a1900
Parent:
0:411a75fba946

File content as of revision 3:998abe0a1900:

#include "Pokitto.h"
Pokitto::Core game;
int width=110;
int height=88;

// squiddy based on Aphrodite's Pico 8 game
// Pokitto port copyright 2017 Dave Akers

extern int16_t lil_map[];   // table of all the level maps
extern int16_t tile_table[];    // table of colors for the map screen
extern uint8_t *bitmap_table[];  // table of pointers to the bitmaps for the game screen
extern uint8_t squiddy[];        // bitmap for squddy, the main character
extern uint8_t grid[];              //bimap for the grid )(used on the title screen)
extern uint8_t ball[];          // bitmap for the ball
extern uint8_t heart[];         // bitmap for the heart, used in a level description
extern uint8_t face[];          // bitmap for the face, used in a level descriiption
extern uint8_t cw[];            // bitmap for the copyright symbol
extern const char *msg_table[64];   // table of text messages for each level
#define TWOPI (3.14159265359 * 2)      // 2 times pi
#define TILESIZE (10)                   // height and width of a tile
#define MINSX (30)                      // ddefine the screnn coordinate limits for squiddy
#define MAXSX (80)                      // the screen scrolls to keep squiddy in these limits
#define MAXSY (60)
#define MINSY (20)
// game states
#define S_TITLE ( 0)
#define S_MAP   ( 1)
#define S_TRANSITION (2)
#define S_PLAY (3)
#define S_WON (4)
#define S_LOST (5)

#define WORDSPERLEVEL (72)

const int NUM_LEVELS = 32;
struct ldata{
    double startx;          // squiddys starting x position, in number of tiles
    double starty;          // squiddys starting x position, in number of tiles
    double startangle;      // xgzfg znbld, in rotations
    double dist;            // distance in tiles between squiddy and the ball
    double speed;           // rotation speed, in rotatio9ns per second
    float attract;          // force of the magnetic attraction, in pixels per second
};
static ldata leveldata[NUM_LEVELS] = {
{ 7.5, 7.5, 0.5,2. , 0.5 , 30 },    // 0
{ 3  , 7. , 0.5,2. , 0.75, 30 },    // 1
{ 3  ,12  , 0.5,1.5,-0.50, 10 },    // 2
{ 3  ,12  , 0.5,2  , 0.75,  1 },    // 3
{ 2  , 2  , 0.0,1.5, 0.60,  1 },    // 4

{ 2  , 6  , 0.25,2. , 0.6 , 10 },    // 5
{ 2  ,13. , 0.5 ,2. ,-0.5 , 20 },    // 6
{ 3  , 3  , 0.75,2  , 0.5 , 15 },    // 7
{ 4  ,11  , 0.25,1.5, 0.5 , 40 },    // 8
{ 2  ,13  , 0.75,2  , 0.50,  1 },    // 9

{ 1.5,13  , 0.75,2.  , 0.5 ,  1 },    // 10
{ 4  , 2. , 0   ,1.5 , 0.5 ,  1 },    // 11
{ 2  , 6  , 0.25,2   , 0.60, 10 },    // 12
{ 8  , 6.5, 0.0 ,3   ,-0.30,  1 },    // 13  sb 9.5, 7.5
{ 2  , 2  , 0.0 ,2   , 0.30, 10 },    // 14

{ 2  , 2. , 0   ,2.  , 0.3 ,  5 },    // 15
{ 4  , 5. , 0   ,2.  , 0.3 ,  1 },    // 16
{11.5, 3.5, 0   ,1.5 , 0.60, 20 },    // 17
{ 5.5, 2.5, 0.0 ,1.5 , 0.60, 20 },    // 18
{ 1.5, 1.5, 0.0 ,1.5 ,-0.40, 20 },    // 19

{ 4  , 2  , 0.  ,1.5 ,-0.5 ,  5 },    // 20
{ 2  , 6. , 0   ,1.5 ,-0.5 ,-10 },    // 21
{ 3  , 4  , 0.0 ,1.5 ,-0.50, 10 },    // 22
{ 7.5, 7.5, 0.0 ,2.5 ,-0.50, 20 },    // 23
{ 1  , 6.5, 0.5 ,1.5 , 0.50, 10 },    // 24  y was 7.5

{ 7.5, 2.5, 0   ,1.4 ,-1.5 , 20 },    // 25
{ 3  , 5. , 0   ,1.5 ,-0.5 , 12 },    // 26
{ 3  , 5. , 0   ,3.  ,-0.50, 10 },    // 27
{ 7.5,11. , 0.0 ,1.5 ,-0.50, 10 },    // 28
{ 1.5,13.5, 0.0 ,1.5 ,-0.50, 10 },    // 29

{ 1  , 1  , 0   ,1.5 ,-0.33, 0  },        // 30
{ 7.5, 4.5, 0.25,2.  , 0.6 , 10 },        // 31


};
/////////////////////////////////////////////////////////////////////////////
//
// Read man - return index for a given map position
//
//////////////////////////////////////////////////////////////////////////////

int8_t shiftval[] = {
    12, 8, 4, 0,
    12, 8, 4, 0,
    12, 8, 4, 0,
    12, 8, 4, 0,
    12, 8, 4, 0 };


int16_t read_map(int x, int y, int level)
{
    int index;
    int col;
    uint16_t data;
    if ((x < 0) || (y < 0)) return (0);
    index = ((level -1) * WORDSPERLEVEL) + ((y/TILESIZE) * 4);
    col = x/TILESIZE;
    index += col/4;         // 4 words oer row
    data = lil_map[index];
    //  one word has 4 nibbles of data col0col1col2ol3
    data = data >> shiftval[col];
    return (data & 0x0f);
}
////////////////////////////////////////////////////////////////////
////
//// draw_world draw the workd using bitmaps
////
////////////////////////////////////////////////////////////////////

void draw_world(int xstart, int ystart, int step, int index,int aframe){
int i,x,y,j;
uint16_t temp;
int color;
int rowstart;
int xfirst;

    xfirst = xstart;
    rowstart = 0;
    while( xfirst < (1 - step))
    {
        xfirst += step;
        rowstart++;
    }

    y= ystart;
    j = 0;
    while ( y < (1-step))
    {
        y = y + step;
        j++;
    }
    index += j << 2;
    for (; (y < height) && (j < 18); y+= step, j++, index += 4)
    {
        x = xfirst;
        for (i = rowstart; (i < 16) && (x < width) ; i++, x += step)
        {
            temp = lil_map[index + (i >> 2)];
            color = (temp >> shiftval[i]) & 0x0f;
            if (color > 0)
            {
                if (color > 3)
                    game.display.drawBitmap(x,y,bitmap_table[color] + aframe);
                else
                    game.display.drawBitmap(x,y,bitmap_table[color]);
            }
        }
    }

}

//////////////////////////////////////////////////////////////////
////
//// draw_map - draw the world using solid colors
////
//////////////////////////////////////////////////////
void draw_map(int xstart, int ystart, int step, int index){
int i,x,y,j;
uint16_t temp;
int color_index;
int rowstart;
int xfirst;

    xfirst = xstart;
    rowstart = 0;
    while( xfirst < (1 - step))
    {
        xfirst += step;
        rowstart++;
    }

    y= ystart;
    j = 0;
    while ( y < (1-step))
    {
        y = y + step;
        j++;
    }
    index += j << 2;
    for (; (y < height) && (j < 18); y+= step, j++, index += 4)
    {
        x = xfirst;
        for (i = rowstart; (i < 16) && (x < width) ; i++, x += step)
        {
            temp = lil_map[index + (i >> 2)];
            color_index = (temp >> shiftval[i]) & 0x0f;
            if (color_index > 0)
            {
                game.display.color = tile_table[color_index];
                game.display.fillRectangle(x,y,step,step);

            }
        }
    }

}

////////////////////////////////////////////////////////////////////////////
////
////  draw_textbox draw a box to write text into
////
////////////////////////////////////////////////////////////////////////////////

void draw_textbox(int x, int y,int boxlen, int boxheight, int bcolor, int frameColor)
{

            game.display.color = bcolor;
            game.display.fillRectangle(x-2,y-3,boxlen,boxheight);
            game.display.color = frameColor;
            game.display.drawRectangle(x-3,y -4,boxlen+1,boxheight+2);

}


int main(){

int xworld, yworld;     // screen coordinates for drawing the world
float ballwx, ballwy;   // world coordinates of the ball
int ballsx, ballsy;     // screen coordinates of the ball
float squidwx,squidwy;  // world coordinates for squiddy
int squidsx,squidsy;    // screen coordinates for squiddy
int release_count;      // number of frames that no buttons were pushed
int level;              // game level
int state, state_count; // game state
ldata *lptr;            // pointer to current level map data
int dist;               // distance between squiddy and the ball
int sx,sy;
int test;
int mag_flags;
int animframe;          // anim frame for arrows
float attract;          // current magnetic attraction
int zoomsize;           // transition size
boolean ball_spins = true;
double angle, angleinc;
game.begin();
game.display.width = width; // full size
game.display.height = height;
game.setFrameRate(20);
game.display.load565Palette(def565palette);
game.display.setFont(font5x7);
xworld = 0;
yworld = 0;
angle = 0.0;
angleinc = 0.1 ;
squidwx = 50;
squidwy = 40;
animframe = 0;

level = 1;
state = S_TITLE;
state_count = 0;


while (game.isRunning()) {
    if (game.update()) {

#if 0
            // test code to scroll the screen
            if (game.buttons.repeat(BTN_UP,0)){
    			yworld++;
            }
            if (game.buttons.repeat(BTN_DOWN,0)){
    			yworld--;
            }
            if (game.buttons.repeat(BTN_LEFT,0)){
    			xworld++;
            }
             if (game.buttons.repeat(BTN_RIGHT,0)){
    			xworld--;
            }
#endif
        switch(state)
        {


        //game.display.drawPixel(x,y,pixel/16);

    case S_TITLE:
        {
            int i,j;
            // fill the background with the grid
            for (i = 0 ; i < 120 ; i = i + 10)
            {
                for(j = 0; j < 90 ; j= j + 10)
                {
                    game.display.drawBitmap(i,j,grid);
                }
            }
            draw_textbox(10,10,12 * 6, 12, 0, C_DARKGREEN);
            game.display.color = C_GREEN;
            game.display.setCursor(10,10);
            game.display.print("Aphrodite's");

            draw_textbox(30,30,8 * 6, 12, 0, C_DARKGREEN);
            game.display.color = C_GREEN;
            game.display.setCursor(30,30);

            game.display.print("SQUIDDY");


             draw_textbox(20,77,11 * 6, 12, 0, C_WHITE);
            game.display.setCursor(20,77);
             game.display.color = C_WHITE;
             game.display.print("   2017 DSA");
            game.display.drawBitmap(20,77,cw);

            state_count++;
            // blink the "press a" message
            if ((state_count & 0x0f) > 3)
            {
                draw_textbox(30,55,7 * 6, 12, 0, 3);
                game.display.setCursor(30,55);
                game.display.color = C_GREEN;
                game.display.print("PRESS A");

            }
            if (game.buttons.repeat(BTN_A,0))
                state = S_MAP;
                release_count = 0;

        break;
        }
    case S_MAP:
        {
            game.display.color = C_WHITE;
            game.display.setCursor(3,3);
            // show the text message for this level
#if 1
            if (msg_table[level *2] != 0)
                game.display.print(msg_table[level * 2]);
            game.display.setCursor(3,12);
            if (msg_table[(level *2) + 1] != 0)
                game.display.print(msg_table[(level * 2) + 1]);
#endif
            if (level == 9)
            {
                game.display.drawBitmap(16, 3,heart);
                game.display.drawBitmap(16,12,heart);
            }
               if (level == 18)
            {
                game.display.drawBitmap(22, 3,face);

            }
            draw_map(30,20,3,(level-1) * 72);
            lptr = &leveldata[level];
            // draw an x for the players starting position
             sx = (int) (lptr->startx * 3 ) + 30;
             sy = (int) (lptr->starty * 3) + (3 * 3) + 20;
            game.display.color = C_RED;
            game.display.drawLine(sx - 3,sy -3,sx + 3,sy + 3);
            game.display.drawLine(sx - 3,sy +3,sx + 3,sy - 3);

               if (game.buttons.repeat(BTN_A,0) ||
                   game.buttons.repeat(BTN_LEFT,0) ||
                   game.buttons.repeat(BTN_RIGHT,0))
            {
                if (release_count > 1)
                {
                    if (game.buttons.repeat(BTN_A,0))
                    {
                        if (level > 30) level = 1;
                        lptr = &leveldata[level];
                       //  squidwx =  (lptr->startx * TILESIZE);
                       //  squidwy =  (lptr->starty * TILESIZE) + (3 * TILESIZE);
                       //  xworld = (width/2)  - squidwx;
                        // yworld = (height/2) - squidwy - 15;

                           zoomsize = 3;
                           squidwx =  (lptr->startx * zoomsize);
                          squidwy =  (lptr->starty * zoomsize) + (3 * zoomsize);
                          xworld = (width/2)  - squidwx;
                          yworld = (height/2) - squidwy - 15;
                          state_count = 0;
                        angle = lptr->startangle * TWOPI;
                        angleinc = lptr->speed * (TWOPI/20);
                        dist = (int) (lptr->dist * TILESIZE);
                        ball_spins = true;
                        state = S_TRANSITION ; // should be transition
                         attract = lptr->attract / 20.0;
                    }
                    else if (game.buttons.repeat(BTN_LEFT,0))
                    {
                        if (level > 1) level = level -1;
                    }
                    else if (game.buttons.repeat(BTN_RIGHT,0))
                    {
                        if (level < 30) level = level +1;
                    }
                    release_count = 0;

                }
            }
            else
            {
                if (release_count < 5) release_count++ ;
            }
        }
        break;
    case S_TRANSITION:
    {
          zoomsize = 3 + (state_count);
          squidwx =  (lptr->startx * zoomsize);
          squidwy =  (lptr->starty * zoomsize) + (3 * zoomsize);
          xworld = (width/2)  - squidwx;
          yworld = (height/2) - squidwy - 15;
          draw_map(xworld,yworld,zoomsize,(level-1) * 72);

        state_count++;
        if (state_count > (7))
        {
            squidwx =  (lptr->startx * TILESIZE);
            squidwy =  (lptr->starty * TILESIZE) + (3 * TILESIZE);
            xworld = (width/2)  - squidwx;
            yworld = (height/2) - squidwy - 15;
            state = S_PLAY;
        }


    }
    break;
    case S_WON:
    case S_LOST:
    {
        int boxlen,cury;
        ballsx = ballwx + xworld;
            ballsy = ballwy + yworld;

            animframe++;
            if (animframe > 9) animframe = 0;

            game.display.invisiblecolor = 17 ;
            draw_world(xworld,yworld,10,(level -1) * 72,animframe * 52);

            game.display.invisiblecolor = 15 ;

            game.display.color = 0;
            game.display.drawLine(squidsx + 5,squidsy + 5,ballsx+5,ballsy+5);

            game.display.drawBitmap(squidsx,squidsy,squiddy);

            game.display.drawBitmap(ballsx,ballsy,ball);
                  game.display.color = 0;
            if (state == S_WON) boxlen = 6 * 8; else boxlen = 6 * 9;
            if (squidsy > 50) cury = 20; else cury = 70;

            game.display.setCursor(30,cury);
            draw_textbox(30,cury,boxlen,12,C_BLACK,C_DARKGREEN);
            //game.display.color = 0;
            //game.display.fillRectangle(28,cury-3,boxlen,12);
            //game.display.color = C_DARKGREEN;
            //game.display.drawRectangle(27,cury -4,boxlen+1,14);

            game.display.color = C_GREEN;
            if (state == S_WON)
            {
                game.display.print("YOU WON!");
            }
            else
            {
                game.display.print("YOU LOST!");
            }
             if (game.buttons.repeat(BTN_A,0)) //if button a is pressed
            {
                if (release_count > 4)
                {
                    if (state == S_WON) level = level +1;
                    release_count = 0;
                    state = S_MAP;
                }
            }
            else
            {
                if (release_count < 5) release_count++ ;
            }
    }
    break;
    case S_PLAY :
        {
            if (ball_spins == true)
            {
                angle += angleinc;
                ballwx =  (sin(angle) * dist) + squidwx ;
                ballwy =  (cos(angle) * dist) + squidwy ;
            }
            else
            {
                angle -= angleinc;
                squidwx = (sin(angle) * dist) + ballwx ;
                squidwy = (cos(angle) * dist) + ballwy ;
            }

            if (angle >  TWOPI) angle -= TWOPI;
            if (angle < -TWOPI) angle += TWOPI;

            squidsx = (int) squidwx + xworld;
            squidsy = (int) squidwy + yworld;

            // keep player near the center of the screen
            if (squidsx < MINSX)
            {
                xworld += MINSX - squidsx;
                squidsx = MINSX;
            }

            if (squidsx > MAXSX)
            {
                xworld += MAXSX - squidsx;
                squidsx = MAXSX;
            }
            if (squidsy < MINSY)
            {
                yworld += MINSY - squidsy;
                squidsy = MINSY;
            }
            if (squidsy > MAXSY)
            {
                yworld += MAXSY - squidsy;
                squidsy = MAXSY;
            }

            ballsx = ballwx + xworld;
            ballsy = ballwy + yworld;

            // maybe the bitmap draws are faster if the invisible color is > 15?
            game.display.invisiblecolor = 17 ;
            animframe++;
            if (animframe > 9) animframe = 0;

            draw_world(xworld,yworld,10,(level -1) * 72,(animframe) * 52);

            game.display.invisiblecolor = 15 ;

            game.display.color = 0;
            game.display.drawLine(squidsx + 5,squidsy + 5,ballsx+5,ballsy+5);

            game.display.drawBitmap(squidsx,squidsy,squiddy);

            game.display.drawBitmap(ballsx,ballsy,ball);

            // hangle magnets
            mag_flags = 0;
            test = read_map(ballwx, ballwy,level);
            mag_flags |= 1 << test;
            // if the ball isn't centered on a grid square, check more points
            if ((((int)ballwx) % 10) >= 1)
            {
                test = read_map(ballwx+9, ballwy,level);
                mag_flags |= 1 << test;
            }
           if ((((int)ballwy) % 10) >= 1)
            {
                test = read_map(ballwx, ballwy+9,level);
                mag_flags |= 1 << test;
                if ((((int)ballwx) % 10) >= 1)
                {
                    test = read_map(ballwx+9, ballwy+9,level);
                    mag_flags |= 1 << test;
                }

            }
            if (mag_flags & (1 << 4)) {ballwx += attract; squidwx  += attract;}
            if (mag_flags & (1 << 5)) {ballwy += attract; squidwy  += attract;}
            if (mag_flags & (1 << 6)) {ballwx -= attract; squidwx  -= attract;}
            if (mag_flags & (1 << 7)) {ballwy -= attract; squidwy  -= attract;}




            // see if squiddy has won or lost

            test = read_map(squidwx+ 5, squidwy+8,level);


#if 1
            if (test == 0)
            {
                state = S_LOST;
                release_count = 0;
            }
            if (test == 2)
            {
                state = S_WON;
                release_count = 0;
            }
#endif
            if (game.buttons.repeat(BTN_A,0)) //if button a is pressed
            {
                if (release_count > 1)
                {
                    ball_spins = !ball_spins;
                    angle = angle + 3.14159265359;
                    release_count = 0;
                }
            }
            else
            {
                if (release_count < 5) release_count++ ;
            }
        }
    }
}
}
return 1;
}