"Lost treasure of mBedungu" 100 level puzzle game for RETRO

Dependencies:   LCD_ST7735 RetroPlatform mbed

Into Level 0 Menu Level 99

Game/GameScreen.cpp

Committer:
Architect
Date:
2015-02-21
Revision:
0:f5f961973d01
Child:
1:dcea5500a32d

File content as of revision 0:f5f961973d01:

#include "GameScreen.h"
#include "Retro.h"
#include "Sprites.h"
#include "Levels.h"

extern Retro retro;

#ifdef FULL_COLOR
const uint16_t * sprites[] = {
#else
const uint8_t * sprites[] = {
#endif
    NULL,
    wall,
    barrel,
    ladder,
    key,
    door,
    left,
    right,
    crate,
    totem,
    rick
};

GameScreen::GameScreen()
{
    _level = 0;
    _state = 0;
    _pocket[0] = 0;
    _pocket[1] = 0;
    _rickDirection = 0;
}

bool GameScreen::isPocketFull()
{
    return (_pocket[0] != 0 && _pocket[1] != 0);
}

bool GameScreen::isPocketEmpty()
{
    return (_pocket[0] == 0 && _pocket[1] == 0);
}

bool GameScreen::putInPocket( int item )
{
    if( item != CELL_BARREL && item != CELL_KEY )
        return false;

    bool bRet = true;

    if( _pocket[0] == 0 )
        _pocket[0] = item;
    else if( _pocket[1] == 0 )
        _pocket[1] = item;
    else
        bRet = false;

    return bRet;
}

bool GameScreen::getKeyFromPocket()
{
    bool bRet = true;

    if( _pocket[0] == CELL_KEY )
        _pocket[0] = 0;
    else if( _pocket[1] == CELL_KEY )
        _pocket[1] = 0;
    else
        bRet = false;

    return bRet;
}

bool GameScreen::getBarrelFromPocket()
{
    bool bRet = true;

    if( _pocket[0] == CELL_BARREL )
        _pocket[0] = 0;
    else if( _pocket[1] == CELL_BARREL )
        _pocket[1] = 0;
    else
        bRet = false;

    return bRet;
}

void GameScreen::moveleft()
{
    if( _rickDirection == 0 )
    {
        _rickDirection = 1;
        drawSprite(_rickX,_rickY, CELL_RICK, _rickDirection == 1);
    }
    
    if( _rickX == 0 )
        return;

    uint8_t cell = _maze[(_rickY<<3)+_rickX-1];


    if( cell == CELL_KEY || cell == CELL_BARREL ) {
        if( putInPocket(cell) ) {
            _maze[(_rickY<<3)+_rickX-1] = CELL_EMPTY;
            drawSprite((_rickX-1),_rickY, CELL_EMPTY);
            drawPocket();
        }
        return;
    }

    if( cell == CELL_CRATE && (_rickX-1)>0 )
    {
        if( moveto(_rickX-1,_rickY, _rickX-2,_rickY) )
            fall(_rickX-2,_rickY);
        return;
    }


    if( moveto(_rickX,_rickY,_rickX-1,_rickY) )
        fall(_rickX,_rickY);

}

void GameScreen::moveright()
{
    if( _rickDirection == 1 )
    {
        _rickDirection = 0;
        drawSprite(_rickX,_rickY, CELL_RICK, _rickDirection == 1);
    }
    
    if( _rickX == 7 )
        return;

    uint8_t cell = _maze[(_rickY<<3)+_rickX+1];

    if( cell == CELL_KEY || cell == CELL_BARREL ) {
        if( putInPocket(cell) ) {
            _maze[(_rickY<<3)+_rickX+1] = CELL_EMPTY;
            drawSprite((_rickX+1),_rickY, CELL_EMPTY);
            drawPocket();
        }
        return;
    }
    
    if( cell == CELL_CRATE && (_rickX+1)<7 )
    {
        if( moveto(_rickX+1,_rickY, _rickX+2,_rickY) )
            fall(_rickX+2,_rickY);
        return;
    }

    if( moveto(_rickX,_rickY,_rickX+1,_rickY) )
        fall(_rickX,_rickY);

}

void GameScreen::moveup()
{
    if( _rickY == 0 )
        return;

    uint8_t currentCell = _maze[((_rickY)<<3)+_rickX];
    uint8_t aboveCell = _maze[((_rickY-1)<<3)+_rickX];

    //if already on ladder
    if( currentCell == CELL_LADDER )
        moveto(_rickX,_rickY,_rickX,_rickY-1);
    else if( currentCell == CELL_EMPTY && !isPocketEmpty()) {
        uint8_t x = _rickX;
        uint8_t y = _rickY;
        if( moveto(_rickX,_rickY,_rickX,_rickY-1) ) {
            if( getBarrelFromPocket() ) {
                _maze[(y<<3)+x] = CELL_BARREL;
                drawSprite(x,y,CELL_BARREL);
            } else if( getKeyFromPocket() ) {
                _maze[(y<<3)+x] = CELL_KEY;
                drawSprite(x,y,CELL_KEY);
            }

            drawPocket();
        }
    }
}

void GameScreen::movedown()
{
    if( _rickY == 0 )
        return;

//    uint8_t currentCell = _maze[((_rickY)<<3)+_rickX];
//    uint8_t belowCell = _maze[((_rickY+1)<<3)+_rickX];

        
    if( moveto(_rickX,_rickY,_rickX,_rickY+1) )
    {
         fall(_rickX,_rickY);
    }
//    if( _rickY > 0 ) {
//        uint8_t cellAbove = _maze[((_rickY-1)<<3)+_rickX];
//        if(cellAbove == CELL_EMPTY && !isPocketEmpty()) {
//            if( getKeyFromPocket() ) {
//                _maze[(_rickY<<3)+_rickX] = CELL_KEY;
//            } else if( getBarrelFromPocket() )
//                _maze[(_rickY<<3)+_rickX] = CELL_BARREL;
//
//            _rickY--;
//            drawSprite(_rickX,_rickY+1, _maze[((_rickY+1)<<3)+_rickX]);
//            drawSprite(_rickX,_rickY, CELL_RICK, _rickDirection == 1);
//            drawPocket();
//        }
//    }
}


bool GameScreen::moveto(uint8_t fromX, uint8_t fromY, uint8_t toX, uint8_t toY)
{
    
    bool isRick = false;

    if( fromX == _rickX && fromY == _rickY )
        isRick = true;

    uint8_t fromCell = _maze[((fromY)<<3)+fromX];
    uint8_t toCell = _maze[((toY)<<3)+toX];

    if( isRick ) {
        if( toCell == CELL_EMPTY || toCell == CELL_LADDER || toCell == CELL_TOTEM ) {
            drawSprite(fromX,fromY, fromCell);
            _rickX = toX;
            _rickY = toY;
            drawSprite(_rickX,_rickY, CELL_RICK, _rickDirection == 1);
            return true;
        }
        if( toCell == CELL_DOOR ) {
            if( getKeyFromPocket() ) {
                drawSprite(fromX,fromY, fromCell);
                _maze[((toY)<<3)+toX] = CELL_EMPTY;
                _rickX = toX;
                _rickY = toY;
                drawSprite(_rickX,_rickY, CELL_RICK, _rickDirection == 1);
                drawPocket();
                return true;
            }
        }
    }else if( fromCell == CELL_CRATE && toCell == CELL_EMPTY )
    {
        _maze[((toY)<<3)+toX] = CELL_CRATE;
        _maze[((fromY)<<3)+fromX] = CELL_EMPTY;
        
        drawSprite(fromX,fromY, toCell);
        drawSprite(toX,toY, fromCell);
        return true;
    }

    return false;
}

bool GameScreen::fall(uint8_t fromX, uint8_t fromY)
{
    if( fromY == 7 )
        return false;

    uint8_t curCell = _maze[(fromY<<3)+fromX];

    if( curCell == CELL_LADDER )
        return false;

    uint8_t cell = _maze[((fromY+1)<<3)+fromX];



    while( cell == CELL_EMPTY || cell == CELL_TOTEM ) {
        if( moveto(fromX,fromY,fromX,fromY+1) ) {
            fromY++;

            if( fromY == 7 )
                break;

            cell = _maze[((fromY+1)<<3)+fromX];
        } else {
            break;
        }
    }

    return true;
}




void GameScreen::unpackLevel( int level )
{
    if( level < 0 || level > 99 )
        level = 0;

    _level = level;

    const uint32_t * pLevel = &levels[level*8];

    for( int y = 0; y < 8; y++ )
        for( int x = 0; x < 8; x++ ) {
            _maze[(y<<3) + x] = (pLevel[y]>>(28-(x<<2))) & 0x0F;

            switch( _maze[(y<<3) + x] ) {
                case CELL_RICK:
                    //The level data has specialy marked cell for Rick
                    //During the game Rick position is tracked separately
                    //This allows us to put Rick on none EMPTY cells
                    _maze[(y<<3) + x] = CELL_EMPTY;
                    _rickX = x;
                    _rickY = y;
                    break;
                case CELL_TOTEM:
                    _totemX = x;
                    _totemY = y;
                    break;
                default:
                    break;
            }
        }
}

void GameScreen::resetLevel()
{
    unpackLevel(_level);
    
    _state = 0;
    _pocket[0] = 0;
    _pocket[1] = 0;
    _rickDirection = 0;    
}

void GameScreen::drawSprite(int x, int y, int sprite, bool mirrored)
{
    int screenx = x<<4;
    int screeny = y<<4;
    if( sprite == 0 )
        retro.display.fillRect(screenx,screeny, screenx+15,screeny+15,0);
    else
    {
        retro.display.drawBitmapIndexed(screenx,screeny, 16,16,sprites[sprite],palette, mirrored);
    }
}

void GameScreen::drawPocket()
{
    if( _pocket[0] == 0 )
        retro.display.fillRect(136,80,151,95,0);
    else
        retro.display.drawBitmapIndexed(136,80, 16,16,sprites[_pocket[0]], palette);

    if( _pocket[1] == 0 )
        retro.display.fillRect(136,96,151,111,0);
    else
        retro.display.drawBitmapIndexed(136,96, 16,16,sprites[_pocket[1]], palette);
}


void GameScreen::drawLevel()
{
    //Draw the maze
    for( int y = 0; y < 8; y++ )
        for( int x = 0; x < 8; x++ ) {
            drawSprite(x, y, _maze[(y<<3)+x]);
        }

    //Put Rick on the map
    drawSprite(_rickX, _rickY, CELL_RICK, _rickDirection == 1);

    //Draw the statistics and "pocket" area
    for( int y = 0; y < 8; y++ ) {
        retro.display.drawBitmapIndexed(128,y<<4, 16,16,wall, palette);
        retro.display.drawBitmapIndexed(144,y<<4, 16,16, wall, palette);
    }
    retro.display.drawBitmapIndexed(136,16, 16,16,totem,palette);
    retro.display.fillRect(132,32,155,39,0);

    char buff[4];
    sprintf(buff,"%d",_level);

    drawString(132,32,buff);

    drawPocket();
}


Screen GameScreen::Update()
{
    if( _state == 0 ) {
        drawLevel();
        _state = 1;
    }

    if(retro.buttons.pressed(BTN_LEFT)) {
        moveleft();
    }
    if(retro.buttons.pressed(BTN_RIGHT)) {
        moveright();
    }
    if(retro.buttons.pressed(BTN_UP)) {
        moveup();
    }
    if(retro.buttons.pressed(BTN_DOWN)) {
        movedown();
    }
    if(retro.buttons.pressed(BTN_ROBOT)) {
        _state = 0;
        return Menu;
    }

    return Game;
}