"Lost treasure of mBedungu" 100 level puzzle game for RETRO
Dependencies: LCD_ST7735 RetroPlatform mbed
Game/GameScreen.cpp
- Committer:
- Architect
- Date:
- 2015-03-01
- Revision:
- 1:dcea5500a32d
- Parent:
- 0:f5f961973d01
File content as of revision 1:dcea5500a32d:
/* * (C) Copyright 2015 Valentin Ivanov. All rights reserved. * * This file is part of the "Lost treasure of mBedungu" game application for Retro * * The "Lost treasure of mBedungu" application is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * */ #include "GameScreen.h" #include "Retro.h" #include "Sprites.h" #include "Levels.h" #include "Utils.h" extern Retro retro; const int soundfx[][8] = { {0,24,1,1,1,4,4,9}, // gameover {0,27,53,1,1,1,4,5}, // pickup {0,23,60,1,1,1,4,5} // drop }; void sfx(int fxno, int channel) { sfx(soundfx[fxno], channel); }; void sfx( const int * effect, int channel) { retro.sound.command(0, effect[6], 0, channel); // set volume retro.sound.command(1, effect[0], 0, channel); // set waveform retro.sound.command(2, effect[5], -effect[4], channel); // set volume slide retro.sound.command(3, effect[3], effect[2] - 58, channel); // set pitch slide retro.sound.playNote(effect[1], effect[7], channel); // play note } Image sprites[] = { {false, false, NULL}, {false, false, wall}, {false, false, barrel}, {false, false, ladder}, {false, false, key}, {false, false, door}, {false, false, left}, {true, false, left}, {false, false, crate}, {false, false, totem}, {false, true, rick}, {false, false, rick_top}, {false, false, rick_happy} }; GameScreen::GameScreen() { _level = 0; _state = 0; _pocket[0] = 0; _pocket[1] = 0; _rickDirection = 0; _gameOver = false; //for some reason writing to eeprom sometime hangs the program // _gameData[0] = 0; // _gameData[1] = 0; // _gameData[2] = 0; // _gameData[3] = 0; // _gameData[4] = 0; // _gameData[5] = 0; // // read_eeprom((char *)64, _gameData, 8); // if( _gameData[0]=='R' && _gameData[1]=='I' && _gameData[2]=='C' && _gameData[3]=='K' ) // { // _level = _gameData[4]; // _gameComplete = _gameData[5]; // } // // _gameData[0]='R'; // _gameData[1]='I'; // _gameData[2]='C'; // _gameData[3]='K'; } 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; sprites[CELL_RICK].Mirrored = true;//(_rickDirection == 1); drawSprite(_rickX,_rickY, CELL_RICK); } if( _rickX == 0 ) return; uint8_t cell = _maze[(_rickY<<3)+_rickX-1]; if( cell == CELL_KEY || cell == CELL_BARREL ) { if( putInPocket(cell) ) { sfx(1,0); _maze[(_rickY<<3)+_rickX-1] = CELL_EMPTY; drawSprite((_rickX-1),_rickY, CELL_EMPTY); drawPocket(); //Fall any crates on top of that key or barrel int y = _rickY; while( y >= 0 ) { fall(_rickX-1,y--); } } return; } if( (cell == CELL_CRATE) && ((_rickX-1)>0) ) { if( moveto(_rickX-1,_rickY, _rickX-2,_rickY) ) { fall(_rickX-2,_rickY); int y = _rickY; while( y >= 0 ) { fall(_rickX-1,y--); } } return; } if( moveto(_rickX,_rickY,_rickX-1,_rickY) ) fall(_rickX,_rickY); } void GameScreen::moveright() { if( _rickDirection == 1 ) { _rickDirection = 0; sprites[CELL_RICK].Mirrored = false; drawSprite(_rickX,_rickY, CELL_RICK); } if( _rickX == 7 ) return; uint8_t cell = _maze[(_rickY<<3)+_rickX+1]; if( cell == CELL_KEY || cell == CELL_BARREL ) { if( putInPocket(cell) ) { sfx(1,0); _maze[(_rickY<<3)+_rickX+1] = CELL_EMPTY; drawSprite((_rickX+1),_rickY, CELL_EMPTY); drawPocket(); //Fall any crates on top of that key or barrel int y = _rickY; while( y >= 0 ) { fall(_rickX+1,y--); } } return; } if( (cell == CELL_CRATE) && ((_rickX+1)<7) ) { if( moveto(_rickX+1,_rickY, _rickX+2,_rickY) ) { fall(_rickX+2,_rickY); int y = _rickY; while( y >= 0 ) { fall(_rickX+1,y--); } } 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() ) { sfx(2,0); _maze[(y<<3)+x] = CELL_BARREL; drawSprite(x,y,CELL_BARREL); } else if( getKeyFromPocket() ) { sfx(2,0); _maze[(y<<3)+x] = CELL_KEY; drawSprite(x,y,CELL_KEY); } drawPocket(); } } } void GameScreen::movedown() { if( _rickY == 7 ) return; if( moveto(_rickX,_rickY,_rickX,_rickY+1) ) { fall(_rickX,_rickY); } } 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 ) { drawSprite(fromX,fromY, fromCell); _rickX = toX; _rickY = toY; drawSprite(_rickX,_rickY, CELL_RICK); return true; } if( toCell == CELL_TOTEM ) { sfx(0,0); _gameOver = true; drawSprite(fromX,fromY, fromCell); _rickX = toX; _rickY = toY; drawSprite(_rickX,_rickY, CELL_RICK); 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); drawPocket(); return true; } } if( (toCell == CELL_RIGHT && fromX < toX) || (toCell == CELL_LEFT && fromX > toX)) { drawSprite(fromX,fromY, fromCell); _rickX = toX; _rickY = toY; drawSprite(_rickX,_rickY, CELL_RICK); 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; } } _state = 0; _pocket[0] = 0; _pocket[1] = 0; _rickDirection = 0; _gameOver = false; sprites[CELL_RICK].Mirrored = false; frame = 0; } void GameScreen::resetLevel() { unpackLevel(_level); } 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]].Sprite, palette); if( _pocket[1] == 0 ) retro.display.fillRect(136,96,151,111,0); else retro.display.drawBitmapIndexed(136,96, 16,16,sprites[_pocket[1]].Sprite, 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); //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); drawLevelNumber(136,32,_level); drawPocket(); } Screen GameScreen::Update() { frame++; if( _state == 0 ) { drawLevel(); _state = 1; } if( _gameOver ) { if( (frame % 3) == 0 ) { sprites[12].Mirrored = !sprites[12].Mirrored; drawSprite(_rickX,_rickY,12); } } if(retro.pressed(BTN_LEFT)) { //sfx(0,0); if( !_gameOver ) moveleft(); } if(retro.pressed(BTN_RIGHT)) { //sfx(1,0); if( !_gameOver ) moveright(); } if(retro.pressed(BTN_UP)) { //sfx(2,0); if( !_gameOver ) moveup(); } if(retro.pressed(BTN_DOWN)) { //sfx(3,0); if( !_gameOver ) movedown(); } if(retro.pressed(BTN_ROBOT)) { _state = 0; return Menu; } if(retro.pressed(BTN_SHIP)) { if( _gameOver ) { if( _level < 99 ) { _level++; resetLevel(); //for some reason writing to eeprom sometime hangs the program // _gameData[4]= _level; // _gameData[5] = _gameComplete; // // write_eeprom(_gameData, (char *)64, 8 ); } } } return Game; } void drawSprite(int x, int y, int sprite) { 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].Sprite, palette, sprites[sprite].Mirrored); } } void drawLevelNumber(int x, int y, int level) { char buf[3]; if( (level/10) > 0 ) sprintf(buf,"%d",level); else sprintf(buf,"@%d",level); drawString(x,y,buf, palette_orange); }