Christian Kroll
15 years ago
29 changed files with 2739 additions and 2179 deletions
@ -1,254 +0,0 @@ |
|||
#include <inttypes.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include "../../random/prng.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "bast.h" |
|||
|
|||
|
|||
/***************************
|
|||
* non-interface functions * |
|||
***************************/ |
|||
|
|||
/* Function: tetris_bastet_clearColHeights;
|
|||
* Description: resets the array for the column heights |
|||
* Argument pBastet: bastet instance whose array should be reset |
|||
* Argument nStart: start index |
|||
* Argument nStop: stop index |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet_clearColHeights(tetris_bastet_t *pBastet, |
|||
int8_t nStart, |
|||
int8_t nStop) |
|||
{ |
|||
for (int i = nStart; i <= nStop; ++i) |
|||
{ |
|||
pBastet->pColHeights[i] = 0; |
|||
} |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet_qsortCompare
|
|||
* Description: compare function for quick sorting the pieces by score |
|||
* Argument pa: the first value to compare |
|||
* Argument pb: the second value to compare |
|||
* Return value: void |
|||
*/ |
|||
int tetris_bastet_qsortCompare(const void *pa, const void *pb) |
|||
{ |
|||
tetris_bastet_scorepair_t *pScorePairA = (tetris_bastet_scorepair_t *)pa; |
|||
tetris_bastet_scorepair_t *pScorePairB = (tetris_bastet_scorepair_t *)pb; |
|||
if (pScorePairA->nScore == pScorePairB->nScore) |
|||
{ |
|||
return 0; |
|||
} |
|||
else if (pScorePairA->nScore < pScorePairB->nScore) |
|||
{ |
|||
return -1; |
|||
} |
|||
else |
|||
{ |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_bastet_construct
|
|||
* Description: constructs a bastet instance for a given playfield |
|||
* Argument pPlayfield: the playfield to be observed |
|||
* Return value: pointer to a newly created bastet instance |
|||
*/ |
|||
tetris_bastet_t* tetris_bastet_construct(tetris_playfield_t *pPl) |
|||
{ |
|||
tetris_bastet_t *pBastet = |
|||
(tetris_bastet_t *) malloc(sizeof(tetris_bastet_t)); |
|||
|
|||
pBastet->pPlayfield = pPl; |
|||
|
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); |
|||
tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1); |
|||
|
|||
return pBastet; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet_destruct
|
|||
* Description: destructs the given bastet instance |
|||
* Argument pBastet: the bastet instance to be destroyed |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet_destruct(tetris_bastet_t *pBastet) |
|||
{ |
|||
if (pBastet->pColHeights != NULL) |
|||
{ |
|||
free(pBastet->pColHeights); |
|||
} |
|||
|
|||
free(pBastet); |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* bastet related functions * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_bastet_construct
|
|||
* Description: calculates a score for a piece at a given column |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Argument pPiece: the piece to be tested |
|||
* Argument pnColum: the column where the piece should be dropped |
|||
* Return value: score for the given move |
|||
*/ |
|||
int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet, |
|||
tetris_piece_t *pPiece, |
|||
int8_t nColumn) |
|||
{ |
|||
// the row where the given piece collides
|
|||
int8_t nDeepestRow = tetris_playfield_predictDeepestRow(pBastet->pPlayfield, |
|||
pPiece, nColumn); |
|||
|
|||
// initial score of the given piece
|
|||
int16_t nScore = -32000; |
|||
|
|||
// modify score based on complete lines
|
|||
int8_t nLines = tetris_playfield_predictCompleteLines(pBastet->pPlayfield, |
|||
pPiece, nDeepestRow, nColumn); |
|||
nScore += 5000 * nLines; |
|||
|
|||
// determine sane start and stop columns whose heights we want to calculate
|
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
int8_t nStartCol = ((nColumn - 1) < 0) ? 0 : nColumn - 1; |
|||
int8_t nStopCol; |
|||
// Do we start at the left most position?
|
|||
// If we do we MUST calculate the heights of ALL columns (initial step)
|
|||
if (nColumn <= -3) |
|||
{ |
|||
nStopCol = nWidth - 1; |
|||
// reset all column heights to zero
|
|||
tetris_bastet_clearColHeights(pBastet, 0 , nWidth); |
|||
} |
|||
// If not, only calculate columns which are affected by the moved piece.
|
|||
else |
|||
{ |
|||
nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1; |
|||
// clear affected column heights to prevent miscalculations
|
|||
tetris_bastet_clearColHeights(pBastet, nStartCol, nStopCol); |
|||
} |
|||
|
|||
// go through every row and calculate column heights
|
|||
tetris_playfield_iterator_t iterator; |
|||
int8_t nHeight = 1; |
|||
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator, |
|||
pBastet->pPlayfield, pPiece, nDeepestRow, nColumn); |
|||
if (pDump == NULL) |
|||
{ |
|||
// an immediately returned NULL is caused by a full dump -> low score
|
|||
return -32766; |
|||
} |
|||
while (pDump != NULL) |
|||
{ |
|||
uint16_t nColMask = 0x0001 << nStartCol; |
|||
for (int x = nStartCol; x <= nStopCol; ++x) |
|||
{ |
|||
if ((*pDump & nColMask) != 0) |
|||
{ |
|||
pBastet->pColHeights[x] = nHeight; |
|||
} |
|||
nColMask <<= 1; |
|||
} |
|||
pDump = tetris_playfield_predictNextRow(&iterator); |
|||
++nHeight; |
|||
} |
|||
// modify score based on predicted column heights
|
|||
for (int x = 0; x < nWidth; ++x) |
|||
{ |
|||
nScore -= 5 * pBastet->pColHeights[x]; |
|||
} |
|||
|
|||
return nScore; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet_minimax
|
|||
* Description: calculates the best possible score for every piece |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet_minimax(tetris_bastet_t *pBastet) |
|||
{ |
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE, |
|||
TETRIS_PC_ANGLE_0); |
|||
for (int8_t nBlock = TETRIS_PC_LINE; nBlock <= TETRIS_PC_Z; ++nBlock) |
|||
{ |
|||
int16_t nMaxScore = -32768; |
|||
tetris_piece_changeShape(pPiece, nBlock); |
|||
int8_t nAngleCount = tetris_piece_angleCount(pPiece); |
|||
for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) |
|||
{ |
|||
tetris_piece_changeAngle(pPiece, nAngle); |
|||
for (int8_t nCol = -3; nCol < nWidth; ++nCol) |
|||
{ |
|||
int16_t nScore = tetris_bastet_evalPos(pBastet, pPiece, nCol); |
|||
nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; |
|||
} |
|||
} |
|||
pBastet->nPieceScores[nBlock].shape = nBlock; |
|||
pBastet->nPieceScores[nBlock].nScore = nMaxScore; |
|||
} |
|||
tetris_piece_destruct(pPiece); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet_choosePiece
|
|||
* Description: calculates the worst possible piece |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Return value: the worst possible piece |
|||
*/ |
|||
tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet) |
|||
{ |
|||
const uint8_t nPercent[7] = {75, 92, 98, 100, 100, 100, 100}; |
|||
tetris_bastet_minimax(pBastet); |
|||
|
|||
// perturb score (-2 to +2) to avoid stupid tie handling
|
|||
for (uint8_t i = 0; i < 7; ++i) |
|||
{ |
|||
pBastet->nPieceScores[i].nScore += random8() % 5 - 2; |
|||
} |
|||
|
|||
qsort(pBastet->nPieceScores, 7, sizeof(tetris_bastet_scorepair_t), |
|||
&tetris_bastet_qsortCompare); |
|||
|
|||
uint8_t nRnd = rand() % 100; |
|||
for (uint8_t i = 0; i < 7; i++) |
|||
{ |
|||
if (nRnd < nPercent[i]) |
|||
{ |
|||
return tetris_piece_construct(pBastet->nPieceScores[i].shape, |
|||
TETRIS_PC_ANGLE_0); |
|||
} |
|||
} |
|||
|
|||
//should not arrive here
|
|||
return tetris_piece_construct(pBastet->nPieceScores[0].shape, |
|||
TETRIS_PC_ANGLE_0); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet_choosePreviewPiece
|
|||
* Description: returns the best possible piece |
|||
* (run tetris_bastet_choosePiece first!) |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Return value: the worst possible piece |
|||
*/ |
|||
tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet) |
|||
{ |
|||
return tetris_piece_construct(pBastet->nPieceScores[6].shape, |
|||
TETRIS_PC_ANGLE_0); |
|||
} |
@ -1,77 +0,0 @@ |
|||
#ifndef BAST_H_ |
|||
#define BAST_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "playfield.h" |
|||
#include "piece.h" |
|||
|
|||
/*********
|
|||
* types * |
|||
*********/ |
|||
|
|||
typedef struct tetris_bastet_scorepair_t |
|||
{ |
|||
tetris_piece_shape_t shape; |
|||
int16_t nScore; |
|||
} |
|||
tetris_bastet_scorepair_t; |
|||
|
|||
|
|||
typedef struct tetris_bastet_t |
|||
{ |
|||
tetris_playfield_t *pPlayfield; // the playfield to be examined
|
|||
int8_t *pColHeights; // array of calculated heights
|
|||
tetris_bastet_scorepair_t nPieceScores[7]; // score for every piece
|
|||
} |
|||
tetris_bastet_t; |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_bastet_construct
|
|||
* Description: constructs a bastet instance for a given playfield |
|||
* Argument pPlayfield: the playfield to be observed |
|||
* Return value: pointer to a newly created bastet instance |
|||
*/ |
|||
tetris_bastet_t* tetris_bastet_construct(tetris_playfield_t *pPl); |
|||
|
|||
|
|||
/* Function: tetris_bastet_destruct
|
|||
* Description: destructs the given bastet instance |
|||
* Argument pBastet: the bastet instance to be destroyed |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet_destruct(tetris_bastet_t *pBastet); |
|||
|
|||
|
|||
/****************************
|
|||
* bastet related functions * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_bastet_construct
|
|||
* Description: calculates a score for a piece at a given column |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Argument pPiece: the piece to be tested |
|||
* Argument pnColum: the column where the piece should be dropped |
|||
* Return value: score for the given move |
|||
*/ |
|||
int16_t tetris_bastet_evalPos(tetris_bastet_t *pBastet, |
|||
tetris_piece_t *pPiece, |
|||
int8_t nColumn); |
|||
|
|||
|
|||
/* Function: tetris_bastet_minimax
|
|||
* Description: calculates the best possible score for every piece |
|||
* Argument pBastet: the bastet instance of interest |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet_minimax(); |
|||
|
|||
|
|||
tetris_piece_t* tetris_bastet_choosePiece(tetris_bastet_t *pBastet); |
|||
|
|||
tetris_piece_t* tetris_bastet_choosePreviewPiece(tetris_bastet_t *pBastet); |
|||
|
|||
#endif /* BAST_H_ */ |
@ -1,10 +1,57 @@ |
|||
#ifndef TETRIS_HIGHSCORE_H_ |
|||
#define TETRIS_HIGHSCORE_H_ |
|||
|
|||
/* Function: tetris_highscore_inputName
|
|||
* Description: let user input a three character name |
|||
* Return value: name packed into a uint16_t |
|||
/**
|
|||
* indexes for different tetris variants |
|||
*/ |
|||
typedef enum tetris_highscore_index_t |
|||
{ |
|||
TETRIS_HISCORE_TETRIS, /**< highscore index for the standard variant */ |
|||
TETRIS_HISCORE_BASTET, /**< highscore index for the bastet variant */ |
|||
TETRIS_HISCORE_FP, /**< highscore index for the first person variant */ |
|||
TETRIS_HISCORE_PAD, /**< don't use (padding for an even array boundary)*/ |
|||
TETRIS_HISCORE_END /**< boundary for the highscore array */ |
|||
} tetris_highscore_index_t; |
|||
|
|||
|
|||
/**
|
|||
* let user input a three character name |
|||
* @return name packed into a uint16_t |
|||
*/ |
|||
uint16_t tetris_highscore_inputName(void); |
|||
|
|||
|
|||
/**
|
|||
* retrieves the highscore from storage |
|||
* @param nIndex the variant dependent index of the highscore |
|||
* @return the highscore |
|||
*/ |
|||
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex); |
|||
|
|||
|
|||
/**
|
|||
* saves the highscore into the storage |
|||
* @param nIndex the variant dependent index of the highscore |
|||
* @param nHighscoreName the highscore |
|||
*/ |
|||
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex, |
|||
uint16_t nHighscore); |
|||
|
|||
|
|||
/**
|
|||
* retrieves the initials of the champion from storage |
|||
* @param nIdx the variant dependent index of the highscore |
|||
* @return the initials of the champion packed into a uint16_t |
|||
*/ |
|||
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx); |
|||
|
|||
|
|||
/**
|
|||
* saves the initials of the champion |
|||
* @param nIndex the variant dependent index of the highscore |
|||
* @param nHighscoreName the initials of the champion packed into a uint16_t |
|||
*/ |
|||
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex, |
|||
uint16_t nHighscoreName); |
|||
|
|||
#endif /*TETRIS_HIGHSCORE_H_*/ |
|||
|
@ -1,721 +0,0 @@ |
|||
/* Borgtris
|
|||
* by: Christian Kroll |
|||
* date: Tuesday, 2007/09/16 |
|||
*/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
#include "../../autoconf.h" |
|||
#include "../../compat/eeprom.h" |
|||
#include "../../compat/pgmspace.h" |
|||
#include "../../menu/menu.h" |
|||
#include "../../random/prng.h" |
|||
#include "../../pixel.h" |
|||
|
|||
#include "logic.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "view.h" |
|||
#include "input.h" |
|||
#include "highscore.h" |
|||
|
|||
#define NUMHIGHSCORES 3 |
|||
|
|||
#ifdef GAME_BASTET |
|||
#include "bast.h" |
|||
#endif |
|||
|
|||
#ifdef GAME_TETRIS_FP |
|||
#include "tetrisfp.h" |
|||
#endif |
|||
|
|||
#ifdef EEMEM |
|||
/***********************
|
|||
* Highscore in EEPROM * |
|||
***********************/ |
|||
|
|||
uint16_t tetris_logic_nHighscore[NUMHIGHSCORES] EEMEM; |
|||
uint16_t tetris_logic_nHighscoreName[NUMHIGHSCORES] EEMEM; |
|||
#endif |
|||
|
|||
// Tetris icon, MSB is leftmost pixel
|
|||
void tetris(); |
|||
|
|||
#ifdef MENU_SUPPORT |
|||
static uint8_t tetris_icon[8] PROGMEM = |
|||
{ 0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0 }; |
|||
game_descriptor_t tetris_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris, |
|||
tetris_icon, |
|||
}; |
|||
|
|||
|
|||
#ifdef GAME_TETRIS_FP |
|||
// Bastet icon, MSB is leftmost pixel
|
|||
static uint8_t tetrisfp_icon[8] PROGMEM = |
|||
{ 0xee, 0x89, 0xee, 0x88, 0x88, 0x20, 0x2c, 0x6c }; |
|||
game_descriptor_t tetrisfp_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris_fp, |
|||
tetrisfp_icon, |
|||
}; |
|||
#endif |
|||
|
|||
#ifdef GAME_BASTET |
|||
// Bastet icon, MSB is leftmost pixel
|
|||
static uint8_t bastet_icon[8] PROGMEM = |
|||
{ 0x81, 0xc3, 0xff, 0x99, 0xff, 0xff, 0x66, 0x3c }; |
|||
game_descriptor_t bastet_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris_bastet, |
|||
bastet_icon, |
|||
}; |
|||
#endif |
|||
|
|||
|
|||
#endif /*MENU_SUPPORT*/ |
|||
|
|||
/***************************
|
|||
* non-interface functions * |
|||
***************************/ |
|||
|
|||
/* Function: tetris_logic_calculateLines
|
|||
* Description: calculates number of lines for the given row mask |
|||
* Argument nRowMask: row mask from which the no. of lines will be calculated |
|||
* Return value: number of lines of the row mask |
|||
*/ |
|||
uint8_t tetris_logic_calculateLines(uint8_t nRowMask) |
|||
{ |
|||
uint8_t nMask = 0x0001; |
|||
uint8_t nLines = 0; |
|||
for (uint8_t i = 0; i < 4; ++i) |
|||
{ |
|||
if ((nMask & nRowMask) != 0) |
|||
{ |
|||
++nLines; |
|||
} |
|||
nMask <<= 1; |
|||
} |
|||
|
|||
return nLines; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_retrieveHighscore
|
|||
* Description: retrieves the highscore from storate |
|||
* Argument nHighscoreIndex: highscore index (for different game variants) |
|||
* Return value: the highscore |
|||
*/ |
|||
uint16_t tetris_logic_retrieveHighscore(uint8_t nHighscoreIndex) |
|||
{ |
|||
#ifdef EEMEM |
|||
uint16_t nHighscore = 0; |
|||
nHighscore = eeprom_read_word(&tetris_logic_nHighscore[nHighscoreIndex]); |
|||
|
|||
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
|||
if (nHighscore == 65535) |
|||
{ |
|||
nHighscore = 0; |
|||
} |
|||
|
|||
return nHighscore; |
|||
#else |
|||
return 0; |
|||
#endif |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_saveHighscore
|
|||
* Description: saves the highscore into the storage |
|||
* Argument nHighscoreIndex: highscore index (for different game variants) |
|||
* Argument nHighscoreName: the highscore |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_saveHighscore(uint8_t nHighscoreIndex, uint16_t nHighscore) |
|||
{ |
|||
#ifdef EEMEM |
|||
if (nHighscore > tetris_logic_retrieveHighscore(nHighscoreIndex)) |
|||
{ |
|||
eeprom_write_word(&tetris_logic_nHighscore[nHighscoreIndex], |
|||
nHighscore); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_retrieveHighscoreName
|
|||
* Description: retrieves the initials of the champion from storage |
|||
* Argument nHighscoreIndex: highscore index (for different game variants) |
|||
* Return value: the initials of the champion packed into a uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_retrieveHighscoreName(uint8_t nHighscoreIndex) |
|||
{ |
|||
#ifdef EEMEM |
|||
uint16_t nHighscoreName = 0; |
|||
nHighscoreName = |
|||
eeprom_read_word(&tetris_logic_nHighscoreName[nHighscoreIndex]); |
|||
|
|||
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
|||
if (nHighscoreName == 65535) |
|||
{ |
|||
nHighscoreName = 0; |
|||
} |
|||
|
|||
return nHighscoreName; |
|||
#else |
|||
return 0; |
|||
#endif |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_saveHighscoreName
|
|||
* Description: saves the initials of the champion |
|||
* Argument nHighscoreIndex: highscore index (for different game variants) |
|||
* Argument nHighscoreName: the initials of the champion packed into a uint16_t |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_saveHighscoreName(uint8_t nHighscoreIndex, |
|||
uint16_t nHighscoreName) |
|||
{ |
|||
#ifdef EEMEM |
|||
eeprom_write_word(&tetris_logic_nHighscoreName[nHighscoreIndex], |
|||
nHighscoreName); |
|||
#endif |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_logic_construct
|
|||
* Description: constructs a logic object |
|||
* Argument nBastet: 0 for normal tetris, 1 for bastet |
|||
* Return value: pointer to a newly created logic object |
|||
*/ |
|||
tetris_logic_t *tetris_logic_construct(uint8_t nBastet) |
|||
{ |
|||
tetris_logic_t *pLogic = (tetris_logic_t *) malloc(sizeof(tetris_logic_t)); |
|||
assert(pLogic != NULL); |
|||
memset(pLogic, 0, sizeof(tetris_logic_t)); |
|||
pLogic->nBastet = nBastet; |
|||
return pLogic; |
|||
} |
|||
|
|||
/* Function: tetris_logic_destruct
|
|||
* Description: destructs a logic object |
|||
* Argument pIn: pointer to the logic object to be destructed |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_destruct(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != 0); |
|||
free(pLogic); |
|||
} |
|||
|
|||
|
|||
/***************************
|
|||
* logic related functions * |
|||
***************************/ |
|||
|
|||
/* Function: tetris
|
|||
* Description: runs the tetris game |
|||
* Return value: void |
|||
*/ |
|||
void tetris() |
|||
{ |
|||
tetris_main(0); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_bastet
|
|||
* Description: runs the bastet game |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet() |
|||
{ |
|||
tetris_main(1); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_fp
|
|||
* Description: runs the tetris first person game |
|||
* Return value: void |
|||
*/ |
|||
void tetris_fp() |
|||
{ |
|||
tetris_main(2); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_main
|
|||
* Description: runs the tetris game |
|||
* Argument nMode: 0 for normal Tetris, 1 for Bastet |
|||
* 2 for first person tetris |
|||
* Return value: void |
|||
*/ |
|||
void tetris_main(int8_t nMode) |
|||
{ |
|||
// get view dependent dimensions of the playfield
|
|||
int8_t nWidth; |
|||
int8_t nHeight; |
|||
tetris_view_getDimensions(&nWidth, &nHeight); |
|||
|
|||
// holds the current user command which should be processed
|
|||
tetris_input_command_t inCmd; |
|||
|
|||
#ifdef GAME_TETRIS_FP |
|||
tetris_screendir = 0; |
|||
#endif |
|||
|
|||
// prepare data structures that drive the game...
|
|||
tetris_logic_t *pLogic = tetris_logic_construct((nMode==1)); |
|||
tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight); |
|||
tetris_input_t *pIn = tetris_input_construct(); |
|||
tetris_view_t *pView = tetris_view_construct(pLogic, pPl, (nMode==2)); |
|||
#ifdef GAME_BASTET |
|||
tetris_bastet_t *pBastet; |
|||
#endif |
|||
|
|||
// runtime variable
|
|||
int8_t nPieceRow; |
|||
|
|||
// retrieve highscore
|
|||
static uint16_t nHighscore = 0; |
|||
static uint16_t nHighscoreName = 0; |
|||
#ifndef GAME_BASTET |
|||
if (nHighscore == 0) |
|||
{ |
|||
#endif |
|||
nHighscore = tetris_logic_retrieveHighscore(nMode); |
|||
nHighscoreName = tetris_logic_retrieveHighscoreName(nMode); |
|||
#ifndef GAME_BASTET |
|||
} |
|||
#endif |
|||
|
|||
// initialize current and next piece
|
|||
tetris_piece_t *pPiece; |
|||
tetris_piece_t *pNextPiece; |
|||
#ifdef GAME_BASTET |
|||
if (nMode == 1) |
|||
{ |
|||
pBastet = tetris_bastet_construct(pPl); |
|||
pNextPiece = pPiece = NULL; |
|||
} |
|||
else |
|||
{ |
|||
#endif |
|||
pNextPiece = pPiece = |
|||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); |
|||
tetris_logic_setPreviewPiece(pLogic, pNextPiece); |
|||
#ifdef GAME_BASTET |
|||
} |
|||
#endif |
|||
|
|||
// the view only monitors the logic and the playfield object for the game
|
|||
// status so we must put information like the next piece or the current
|
|||
// highscore to a place where the view can find it
|
|||
tetris_logic_setHighscore(pLogic, nHighscore); |
|||
tetris_logic_setHighscoreName(pLogic, nHighscoreName); |
|||
|
|||
// pace flag
|
|||
tetris_input_pace_t inPace; |
|||
|
|||
// game loop, runs as long as the game is not over
|
|||
while (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
// what we do strongly depends on the status of the playfield
|
|||
switch (tetris_playfield_getStatus(pPl)) |
|||
{ |
|||
// the playfield awaits a new piece
|
|||
case TETRIS_PFS_READY: |
|||
#ifdef GAME_BASTET |
|||
if (nMode == 1) |
|||
{ |
|||
if (pPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pPiece); |
|||
} |
|||
if (pNextPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pNextPiece); |
|||
} |
|||
pPiece = tetris_bastet_choosePiece(pBastet); |
|||
pNextPiece = tetris_bastet_choosePreviewPiece(pBastet); |
|||
tetris_piece_t *pOldPiece; |
|||
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); |
|||
tetris_logic_setPreviewPiece(pLogic, pNextPiece); |
|||
} |
|||
else |
|||
{ |
|||
#endif |
|||
// make preview piece the current piece and create a new
|
|||
// preview piece
|
|||
pPiece = pNextPiece; |
|||
pNextPiece = tetris_piece_construct(random8() % 7, |
|||
TETRIS_PC_ANGLE_0); |
|||
tetris_logic_setPreviewPiece(pLogic, pNextPiece); |
|||
|
|||
// insert new piece into playfield
|
|||
tetris_piece_t *pOldPiece; |
|||
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); |
|||
|
|||
// destruct old piece (if it exists) since we don't need it
|
|||
// anymore
|
|||
if (pOldPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pOldPiece); |
|||
pOldPiece = NULL; |
|||
} |
|||
#ifdef GAME_BASTET |
|||
} |
|||
#endif |
|||
break; |
|||
|
|||
// a piece is hovering and can be controlled by the player
|
|||
case TETRIS_PFS_HOVERING: |
|||
case TETRIS_PFS_GLIDING: |
|||
// if the piece is gliding the input module has to grant us
|
|||
// a minimum amount of time to move it
|
|||
if (tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) |
|||
{ |
|||
inPace = TETRIS_INPACE_GLIDING; |
|||
} |
|||
else |
|||
{ |
|||
inPace = TETRIS_INPACE_HOVERING; |
|||
} |
|||
|
|||
// ensure correct view mode if the game isn't paused
|
|||
if ((inCmd = tetris_input_getCommand(pIn, inPace, (nMode==2))) |
|||
!= TETRIS_INCMD_PAUSE) |
|||
{ |
|||
tetris_view_setViewMode(pView, TETRIS_VIMO_RUNNING); |
|||
} |
|||
|
|||
// what we do depends on what the input module tells us
|
|||
switch (inCmd) |
|||
{ |
|||
// game paused?
|
|||
case TETRIS_INCMD_PAUSE: |
|||
// tell the view it should display the pause screen
|
|||
tetris_view_setViewMode(pView, TETRIS_VIMO_PAUSED); |
|||
break; |
|||
|
|||
// the piece was pulled down by the almighty gravity
|
|||
case TETRIS_INCMD_GRAVITY: |
|||
tetris_playfield_advancePiece(pPl); |
|||
break; |
|||
|
|||
// the player has pulled down the piece herself/himself
|
|||
case TETRIS_INCMD_DOWN: |
|||
tetris_playfield_advancePiece(pPl); |
|||
// if the game still runs, reward the player with extra points
|
|||
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
tetris_logic_singleDrop(pLogic, 1); |
|||
} |
|||
break; |
|||
|
|||
// player shifted the piece to the left
|
|||
case TETRIS_INCMD_LEFT: |
|||
tetris_playfield_movePiece(pPl, TETRIS_PFD_LEFT); |
|||
break; |
|||
|
|||
// player shifted the piece to the right
|
|||
case TETRIS_INCMD_RIGHT: |
|||
tetris_playfield_movePiece(pPl, TETRIS_PFD_RIGHT); |
|||
break; |
|||
|
|||
// player rotated the piece clockwise
|
|||
case TETRIS_INCMD_ROT_CW: |
|||
#ifdef GAME_TETRIS_FP |
|||
if (nMode == 2) { |
|||
tetris_view_rotate(); |
|||
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CCW); |
|||
} else |
|||
{ |
|||
#endif |
|||
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CW); |
|||
#ifdef GAME_TETRIS_FP |
|||
} |
|||
#endif |
|||
break; |
|||
|
|||
// player rotated the piece counter clockwise
|
|||
case TETRIS_INCMD_ROT_CCW: |
|||
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CCW); |
|||
break; |
|||
|
|||
// the player decided to make an immediate drop
|
|||
case TETRIS_INCMD_DROP: |
|||
nPieceRow = tetris_playfield_getRow(pPl); |
|||
// emulate immediate drop
|
|||
while((tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) || |
|||
(tetris_playfield_getStatus(pPl) == TETRIS_PFS_HOVERING)) |
|||
{ |
|||
tetris_playfield_advancePiece(pPl); |
|||
} |
|||
// if the game still runs, reward the player with extra points
|
|||
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
tetris_logic_completeDrop(pLogic, |
|||
tetris_playfield_getRow(pPl) - nPieceRow); |
|||
} |
|||
break; |
|||
|
|||
// avoid compiler warnings
|
|||
default: |
|||
break; |
|||
} |
|||
break; |
|||
|
|||
// the piece has irrevocably hit the ground
|
|||
case TETRIS_PFS_DOCKED: |
|||
// avoid accidentally issued "down" commands
|
|||
tetris_input_resetDownKeyRepeat(pIn); |
|||
|
|||
// remove complete lines (if any)
|
|||
tetris_playfield_removeCompleteLines(pPl); |
|||
|
|||
// let the logic object decide how many points the player gets
|
|||
// and whether the level gets changed
|
|||
tetris_logic_removedLines(pLogic, tetris_playfield_getRowMask(pPl)); |
|||
tetris_input_setLevel(pIn, tetris_logic_getLevel(pLogic)); |
|||
break; |
|||
|
|||
// avoid compiler warnings
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
// the view updates it state every loop cycle to make changes visible
|
|||
tetris_view_update(pView); |
|||
} |
|||
|
|||
// game is over and we provide the player with her/his results
|
|||
tetris_view_showResults(pView); |
|||
|
|||
// update highscore if it has been beaten
|
|||
uint16_t nScore = tetris_logic_getScore(pLogic); |
|||
if (nScore > nHighscore) |
|||
{ |
|||
nHighscore = nScore; |
|||
nHighscoreName = tetris_highscore_inputName(); |
|||
tetris_logic_saveHighscore(nMode, nHighscore); |
|||
tetris_logic_saveHighscoreName(nMode, nHighscoreName); |
|||
} |
|||
|
|||
// clean up
|
|||
#ifdef GAME_BASTET |
|||
if (nMode == 1) |
|||
{ |
|||
tetris_bastet_destruct(pBastet); |
|||
} |
|||
#endif |
|||
tetris_view_destruct(pView); |
|||
tetris_input_destruct(pIn); |
|||
tetris_playfield_destruct(pPl); |
|||
tetris_logic_destruct(pLogic); |
|||
tetris_piece_destruct(pPiece); |
|||
tetris_piece_destruct(pNextPiece); |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_singleDrop
|
|||
* Description: add points which result from single step dropping |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nLines: the number of rows involved |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_singleDrop(tetris_logic_t *pLogic, |
|||
uint8_t nLines) |
|||
{ |
|||
assert(pLogic != 0); |
|||
#ifdef GAME_BASTET |
|||
if (pLogic->nBastet) return; |
|||
#endif |
|||
pLogic->nScore += nLines; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_completeDrop
|
|||
* Description: add points which result from a complete drop |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nLines: the number of rows involved |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_completeDrop(tetris_logic_t *pLogic, |
|||
uint8_t nLines) |
|||
{ |
|||
assert(pLogic != 0); |
|||
#ifdef GAME_BASTET |
|||
if (pLogic->nBastet) return; |
|||
#endif |
|||
pLogic->nScore += nLines * 2; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_removedLines
|
|||
* Description: add points which result from removed rows |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nRowMask: see tetris_playfield_completeLines |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_removedLines(tetris_logic_t *pLogic, |
|||
uint8_t nRowMask) |
|||
{ |
|||
assert(pLogic != 0); |
|||
uint8_t nLines = tetris_logic_calculateLines(nRowMask); |
|||
pLogic->nLines += nLines; |
|||
pLogic->nLevel = ((pLogic->nLines / 10) < TETRIS_INPUT_LEVELS) ? |
|||
(pLogic->nLines / 10) : (TETRIS_INPUT_LEVELS - 1); |
|||
|
|||
#ifdef GAME_BASTET |
|||
if (pLogic->nBastet) |
|||
{ |
|||
pLogic->nScore += nLines; |
|||
return; |
|||
} |
|||
#endif |
|||
switch (nLines) |
|||
{ |
|||
case 1: |
|||
pLogic->nScore += 50; |
|||
break; |
|||
case 2: |
|||
pLogic->nScore += 150; |
|||
break; |
|||
case 3: |
|||
pLogic->nScore += 250; |
|||
break; |
|||
case 4: |
|||
pLogic->nScore += 400; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
/*****************
|
|||
* get functions * |
|||
*****************/ |
|||
|
|||
/* Function: tetris_logic_getScore
|
|||
* Description: returns the current score |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the score as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getScore(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->nScore; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_getHighscore
|
|||
* Description: returns the current highscore |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the highscore as uint16_t |
|||
*/ |
|||
|
|||
uint16_t tetris_logic_getHighscore(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->nHighscore; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_setHighscore
|
|||
* Description: set highscore |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argmument nHighscore: highscore |
|||
*/ |
|||
void tetris_logic_setHighscore(tetris_logic_t *pLogic, |
|||
uint16_t nHighscore) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
pLogic->nHighscore = nHighscore; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_getHighscoreName
|
|||
* Description: returns the current highscore name |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the highscore name packed as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getHighscoreName(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->nHighscoreName; |
|||
} |
|||
|
|||
|
|||
|
|||
/* Function: tetris_logic_setHighscoreName
|
|||
* Description: set highscore name |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argmument nHighscoreName: highscore name |
|||
*/ |
|||
void tetris_logic_setHighscoreName(tetris_logic_t *pLogic, |
|||
uint16_t nHighscoreName) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
pLogic->nHighscoreName = nHighscoreName; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_getLevel
|
|||
* Description: returns the current level |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the level as uint8_t |
|||
*/ |
|||
uint8_t tetris_logic_getLevel(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->nLevel; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_getLines
|
|||
* Description: returns the number of completed lines |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: number of completed lines as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getLines(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->nLines; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_setPreviewPiece
|
|||
* Description: help for the view to determine the preview piece |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument pPiece: pointer to piece intended to be the next one (may be NULL) |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_setPreviewPiece(tetris_logic_t *pLogic, |
|||
tetris_piece_t *pPiece) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
pLogic->pPreviewPiece = pPiece; |
|||
} |
|||
|
|||
|
|||
/* Function: tetris_logic_getPreviewPiece
|
|||
* Description: returns piece which was set via tetris_logic_setPreviewPiece |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the piece intended to be the next one (may be NULL) |
|||
*/ |
|||
tetris_piece_t* tetris_logic_getPreviewPiece(tetris_logic_t *pLogic) |
|||
{ |
|||
assert(pLogic != NULL); |
|||
return pLogic->pPreviewPiece; |
|||
} |
@ -1,190 +0,0 @@ |
|||
#ifndef TETRIS_LOGIC_H_ |
|||
#define TETRIS_LOGIC_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "piece.h" |
|||
|
|||
/*********
|
|||
* types * |
|||
*********/ |
|||
|
|||
typedef struct tetris_logic_t |
|||
{ |
|||
uint8_t nBastet; // is gametype bastet?
|
|||
uint16_t nScore; // score of the player
|
|||
uint16_t nHighscore; // highscore
|
|||
uint16_t nHighscoreName; // name of the person who achieved highscore
|
|||
uint8_t nLevel; // current level
|
|||
uint16_t nLines; // number of completed lines
|
|||
tetris_piece_t *pPreviewPiece; // the piece intended to be the next one
|
|||
} |
|||
tetris_logic_t; |
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/* Function: tetris_logic_construct
|
|||
* Description: constructs a logic object |
|||
* Argument nBastet: 0 for normal tetris, 1 for bastet |
|||
* Return value: pointer to a newly created logic object |
|||
*/ |
|||
tetris_logic_t *tetris_logic_construct(uint8_t nBastet); |
|||
|
|||
/* Function: tetris_logic_destruct
|
|||
* Description: destructs a logic object |
|||
* Argument pIn: pointer to the logic object to be destructed |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_destruct(tetris_logic_t *pLogic); |
|||
|
|||
/***************************
|
|||
* logic related functions * |
|||
***************************/ |
|||
|
|||
/* Function: tetris
|
|||
* Description: runs the tetris game |
|||
* Return value: void |
|||
*/ |
|||
void tetris(); |
|||
|
|||
|
|||
/* Function: tetris_bastet
|
|||
* Description: runs the bastet game |
|||
* Return value: void |
|||
*/ |
|||
void tetris_bastet(); |
|||
|
|||
/* Function: tetris_fp
|
|||
* Description: runs the tetris first person game |
|||
* Return value: void |
|||
*/ |
|||
void tetris_fp(); |
|||
|
|||
|
|||
/* Function: tetris_main
|
|||
* Description: runs the tetris game |
|||
* Argument nMode: 0 for normal Tetris, 1 for Bastet, |
|||
* 2 for first person tetris |
|||
* Return value: void |
|||
*/ |
|||
void tetris_main(int8_t nMode); |
|||
|
|||
/* Function: tetris_logic_singleDrop
|
|||
* Description: add points which result from single step dropping |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nLines: the number of rows involved |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_singleDrop(tetris_logic_t *pLogic, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/* Function: tetris_logic_completeDrop
|
|||
* Description: add points which result from a complete drop |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nLines: the number of rows involved |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_completeDrop(tetris_logic_t *pLogic, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/* Function: tetris_logic_removedLines
|
|||
* Description: add points which result from removed rows |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument nRowMask: see tetris_playfield_completeLines |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_removedLines(tetris_logic_t *pLogic, |
|||
uint8_t nRowMask); |
|||
|
|||
|
|||
/*********************
|
|||
* get/set functions * |
|||
*********************/ |
|||
|
|||
/* Function: tetris_logic_getScore
|
|||
* Description: returns the current score |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the score as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getScore(tetris_logic_t *pLogic); |
|||
|
|||
|
|||
/* Function: tetris_logic_getHighscore
|
|||
* Description: returns the current highscore |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the highscore as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getHighscore(tetris_logic_t *pLogic); |
|||
|
|||
|
|||
/* Function: tetris_logic_setHighscore
|
|||
* Description: set highscore |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argmument nHighscore: highscore |
|||
*/ |
|||
void tetris_logic_setHighscore(tetris_logic_t *pLogic, |
|||
uint16_t nHighscore); |
|||
|
|||
|
|||
/* Function: tetris_logic_getHighscoreName
|
|||
* Description: returns the current highscore name |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the highscore name packed as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getHighscoreName(tetris_logic_t *pLogic); |
|||
|
|||
|
|||
/* Function: tetris_logic_setHighscoreName
|
|||
* Description: set highscore name |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argmument nHighscoreName: highscore name |
|||
*/ |
|||
void tetris_logic_setHighscoreName(tetris_logic_t *pLogic, |
|||
uint16_t nHighscoreName); |
|||
|
|||
|
|||
/* Function: tetris_logic_getLevel
|
|||
* Description: returns the current level |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the level as uint8_t |
|||
*/ |
|||
uint8_t tetris_logic_getLevel(tetris_logic_t *pLogic); |
|||
|
|||
|
|||
/* Function: tetris_logic_getLines
|
|||
* Description: returns the number of completed lines |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: number of completed lines as uint16_t |
|||
*/ |
|||
uint16_t tetris_logic_getLines(tetris_logic_t *pLogic); |
|||
|
|||
|
|||
/* Function: tetris_logic_setPreviewPiece
|
|||
* Description: help for the view to determine the preview piece |
|||
* Argument pLogic: the logic object we want to modify |
|||
* Argument pPiece: pointer to piece intended to be the next one |
|||
* Return value: void |
|||
*/ |
|||
void tetris_logic_setPreviewPiece(tetris_logic_t *pLogic, |
|||
tetris_piece_t *pPiece); |
|||
|
|||
|
|||
/* Function: tetris_logic_getPreviewPiece
|
|||
* Description: returns piece which was set via tetris_logic_setPreviewPiece |
|||
* Argument pLogic: the logic object we want information from |
|||
* Return value: the piece intended to be the next one |
|||
*/ |
|||
tetris_piece_t* tetris_logic_getPreviewPiece(tetris_logic_t *pLogic); |
|||
|
|||
#ifdef GAME_TETRIS_FP |
|||
/* Function: tetris_view_rotate
|
|||
* Description: rotate view for first person mode |
|||
* Return value: void |
|||
*/ |
|||
void tetris_view_rotate(void); |
|||
#endif |
|||
|
|||
#endif /*TETRIS_LOGIC_H_*/ |
@ -0,0 +1,13 @@ |
|||
#ifndef ORIENTATION_H_ |
|||
#define ORIENTATION_H_ |
|||
|
|||
typedef enum tetris_orientation_t |
|||
{ |
|||
TETRIS_ORIENTATION_0, |
|||
TETRIS_ORIENTATION_90, |
|||
TETRIS_ORIENTATION_180, |
|||
TETRIS_ORIENTATION_270 |
|||
} |
|||
tetris_orientation_t; |
|||
|
|||
#endif /* ORIENTATION_H_ */ |
@ -0,0 +1,205 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
#include "tetris_main.h" |
|||
#include "variants.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "view.h" |
|||
#include "input.h" |
|||
#include "highscore.h" |
|||
|
|||
|
|||
void tetris_main(const tetris_variant_t *const pVariantMethods) |
|||
{ |
|||
// get view dependent dimensions of the playfield
|
|||
int8_t nWidth; |
|||
int8_t nHeight; |
|||
tetris_view_getDimensions(&nWidth, &nHeight); |
|||
|
|||
// holds the current user command which should be processed
|
|||
tetris_input_command_t inCmd; |
|||
|
|||
// prepare data structures that drive the game...
|
|||
tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight); |
|||
void *pVariantData = pVariantMethods->construct(pPl); |
|||
tetris_input_t *pIn = tetris_input_construct(); |
|||
tetris_view_t *pView = tetris_view_construct(pVariantMethods, |
|||
pVariantData, pPl); |
|||
|
|||
// retrieve highscore
|
|||
tetris_highscore_index_t nHighscoreIndex = |
|||
pVariantMethods->getHighscoreIndex(pVariantData); |
|||
uint16_t nHighscore = |
|||
tetris_highscore_retrieveHighscore(nHighscoreIndex); |
|||
uint16_t nHighscoreName = |
|||
tetris_highscore_retrieveHighscoreName(nHighscoreIndex); |
|||
|
|||
// the view only monitors the variant data and the playfield object for the
|
|||
// game status so we must put information like the next piece or the current
|
|||
// highscore to a place where the view can find it
|
|||
pVariantMethods->setHighscore(pVariantData, nHighscore); |
|||
pVariantMethods->setHighscoreName(pVariantData, nHighscoreName); |
|||
|
|||
int8_t nPieceRow; // for determining skipped lines after a piece drop
|
|||
tetris_piece_t *pPiece = NULL; // initialize piece
|
|||
tetris_input_pace_t inPace; // pace flag
|
|||
|
|||
// game loop, runs as long as the game is not over
|
|||
while (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
// what we do strongly depends on the status of the playfield
|
|||
switch (tetris_playfield_getStatus(pPl)) |
|||
{ |
|||
// the playfield awaits a new piece
|
|||
case TETRIS_PFS_READY: |
|||
pPiece = pVariantMethods->choosePiece(pVariantData); |
|||
tetris_piece_t *pOldPiece; |
|||
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); |
|||
// destruct old piece (if it exists) since we don't need it anymore
|
|||
if (pOldPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pOldPiece); |
|||
pOldPiece = NULL; |
|||
} |
|||
break; |
|||
|
|||
// a piece is hovering and can be controlled by the player
|
|||
case TETRIS_PFS_HOVERING: |
|||
case TETRIS_PFS_GLIDING: |
|||
// if the piece is gliding the input module has to grant us
|
|||
// a minimum amount of time to move it
|
|||
if (tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) |
|||
{ |
|||
inPace = TETRIS_INPACE_GLIDING; |
|||
} |
|||
else |
|||
{ |
|||
inPace = TETRIS_INPACE_HOVERING; |
|||
} |
|||
|
|||
// ensure correct view mode if the game isn't paused
|
|||
if ((inCmd = tetris_input_getCommand(pIn, inPace)) |
|||
!= TETRIS_INCMD_PAUSE) |
|||
{ |
|||
tetris_view_setViewMode(pView, TETRIS_VIMO_RUNNING); |
|||
} |
|||
|
|||
// what we do depends on what the input module tells us
|
|||
switch (inCmd) |
|||
{ |
|||
// game paused?
|
|||
case TETRIS_INCMD_PAUSE: |
|||
// tell the view it should display the pause screen
|
|||
tetris_view_setViewMode(pView, TETRIS_VIMO_PAUSED); |
|||
break; |
|||
|
|||
// the piece was pulled down by the almighty gravity
|
|||
case TETRIS_INCMD_GRAVITY: |
|||
tetris_playfield_advancePiece(pPl); |
|||
break; |
|||
|
|||
// the player has pulled down the piece herself/himself
|
|||
case TETRIS_INCMD_DOWN: |
|||
tetris_playfield_advancePiece(pPl); |
|||
// if the game still runs, reward the player with extra points
|
|||
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
pVariantMethods->singleDrop(pVariantData, 1); |
|||
} |
|||
break; |
|||
|
|||
// player shifted the piece to the left
|
|||
case TETRIS_INCMD_LEFT: |
|||
tetris_playfield_movePiece(pPl, TETRIS_PFD_LEFT); |
|||
break; |
|||
|
|||
// player shifted the piece to the right
|
|||
case TETRIS_INCMD_RIGHT: |
|||
tetris_playfield_movePiece(pPl, TETRIS_PFD_RIGHT); |
|||
break; |
|||
|
|||
// player rotated the piece clockwise
|
|||
case TETRIS_INCMD_ROT_CW: |
|||
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CW); |
|||
break; |
|||
|
|||
// player rotated the piece counter clockwise
|
|||
case TETRIS_INCMD_ROT_CCW: |
|||
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CCW); |
|||
break; |
|||
|
|||
// the player decided to make an immediate drop
|
|||
case TETRIS_INCMD_DROP: |
|||
nPieceRow = tetris_playfield_getRow(pPl); |
|||
// emulate immediate drop
|
|||
while((tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) || |
|||
(tetris_playfield_getStatus(pPl) == TETRIS_PFS_HOVERING)) |
|||
{ |
|||
tetris_playfield_advancePiece(pPl); |
|||
} |
|||
// if the game still runs, reward the player with extra points
|
|||
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) |
|||
{ |
|||
pVariantMethods->completeDrop(pVariantData, |
|||
tetris_playfield_getRow(pPl) - nPieceRow); |
|||
} |
|||
break; |
|||
|
|||
// avoid compiler warnings
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
pVariantMethods->setLastInput(pVariantData, inCmd); |
|||
tetris_input_setOrientation(pIn, |
|||
pVariantMethods->getOrientation(pVariantData)); |
|||
|
|||
break; |
|||
|
|||
// the piece has irrevocably hit the ground
|
|||
case TETRIS_PFS_DOCKED: |
|||
// avoid accidentally issued "down" commands
|
|||
tetris_input_resetDownKeyRepeat(pIn); |
|||
|
|||
// remove complete lines (if any)
|
|||
tetris_playfield_removeCompleteLines(pPl); |
|||
|
|||
// let the variant object decide how many points the player gets and
|
|||
// whether the level gets changed
|
|||
pVariantMethods->removedLines(pVariantData, |
|||
tetris_playfield_getRowMask(pPl)); |
|||
tetris_input_setLevel(pIn, pVariantMethods->getLevel(pVariantData)); |
|||
break; |
|||
|
|||
// avoid compiler warnings
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
// the view updates its state every loop cycle to make changes visible
|
|||
tetris_view_update(pView); |
|||
} |
|||
|
|||
// game is over and we provide the player with her/his results
|
|||
tetris_view_showResults(pView); |
|||
|
|||
// update highscore if it has been beaten
|
|||
uint16_t nScore = pVariantMethods->getScore(pVariantData); |
|||
if (nScore > nHighscore) |
|||
{ |
|||
nHighscore = nScore; |
|||
nHighscoreName = tetris_highscore_inputName(); |
|||
tetris_highscore_saveHighscore(nHighscoreIndex, nHighscore); |
|||
tetris_highscore_saveHighscoreName(nHighscoreIndex, nHighscoreName); |
|||
} |
|||
|
|||
// cleanup
|
|||
tetris_view_destruct(pView); |
|||
tetris_input_destruct(pIn); |
|||
pVariantMethods->destruct(pVariantData); |
|||
tetris_playfield_destruct(pPl); |
|||
tetris_piece_destruct(pPiece); |
|||
} |
@ -0,0 +1,14 @@ |
|||
#ifndef TETRIS_MAIN_H_ |
|||
#define TETRIS_MAIN_H_ |
|||
|
|||
#include "variants.h" |
|||
|
|||
|
|||
/**
|
|||
* runs the tetris game |
|||
* @param pVariantMethods struct of function pointers for a game variant |
|||
*/ |
|||
void tetris_main(const tetris_variant_t *const pVariantMethods); |
|||
|
|||
|
|||
#endif /* TETRIS_MAIN_H_ */ |
@ -1,6 +0,0 @@ |
|||
#ifndef TETRISFP_H_ |
|||
#define TETRISFP_H_ |
|||
|
|||
extern uint8_t tetris_screendir; |
|||
|
|||
#endif /* BAST_H_ */ |
@ -0,0 +1,416 @@ |
|||
#include <inttypes.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
|
|||
#include "../../random/prng.h" |
|||
#include "../../compat/pgmspace.h" |
|||
#include "../../menu/menu.h" |
|||
#include "variant_bastet.h" |
|||
#include "variants.h" |
|||
#include "tetris_main.h" |
|||
#include "input.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
|
|||
/***************************
|
|||
* non-interface functions * |
|||
***************************/ |
|||
|
|||
/**
|
|||
* resets the array for the column heights |
|||
* @param pBastet bastet instance whose array should be reset |
|||
* @param nStart start index |
|||
* @param nStop stop index |
|||
*/ |
|||
void tetris_bastet_clearColHeights(tetris_bastet_variant_t *pBastet, |
|||
int8_t nStart, |
|||
int8_t nStop) |
|||
{ |
|||
for (int i = nStart; i <= nStop; ++i) |
|||
{ |
|||
pBastet->pColHeights[i] = 0; |
|||
} |
|||
} |
|||
|
|||
|
|||
/**
|
|||
* compare function for quick sorting the pieces by score |
|||
* @param pa the first value to compare |
|||
* @param pb the second value to compare |
|||
*/ |
|||
int tetris_bastet_qsortCompare(const void *pa, const void *pb) |
|||
{ |
|||
tetris_bastet_scorepair_t *pScorePairA = (tetris_bastet_scorepair_t *)pa; |
|||
tetris_bastet_scorepair_t *pScorePairB = (tetris_bastet_scorepair_t *)pb; |
|||
if (pScorePairA->nScore == pScorePairB->nScore) |
|||
{ |
|||
return 0; |
|||
} |
|||
else if (pScorePairA->nScore < pScorePairB->nScore) |
|||
{ |
|||
return -1; |
|||
} |
|||
else |
|||
{ |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
#ifdef MENU_SUPPORT |
|||
// Bastet icon, MSB is leftmost pixel
|
|||
static uint8_t bastet_icon[8] PROGMEM = |
|||
{ 0x81, 0xc3, 0xff, 0x99, 0xff, 0xff, 0x66, 0x3c }; |
|||
game_descriptor_t bastet_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris_bastet, |
|||
bastet_icon, |
|||
}; |
|||
#endif |
|||
|
|||
|
|||
void tetris_bastet(void) |
|||
{ |
|||
tetris_main(&tetrisBastetVariant); |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
const tetris_variant_t tetrisBastetVariant = |
|||
{ |
|||
&tetris_bastet_construct, |
|||
&tetris_bastet_destruct, |
|||
&tetris_bastet_choosePiece, |
|||
&tetris_bastet_singleDrop, |
|||
&tetris_bastet_completeDrop, |
|||
&tetris_bastet_removedLines, |
|||
&tetris_bastet_getScore, |
|||
&tetris_bastet_getHighscore, |
|||
&tetris_bastet_setHighscore, |
|||
&tetris_bastet_getHighscoreName, |
|||
&tetris_bastet_setHighscoreName, |
|||
&tetris_bastet_getLevel, |
|||
&tetris_bastet_getLines, |
|||
&tetris_bastet_getPreviewPiece, |
|||
&tetris_bastet_getHighscoreIndex, |
|||
&tetris_bastet_setLastInput, |
|||
&tetris_bastet_getOrientation |
|||
}; |
|||
|
|||
|
|||
void *tetris_bastet_construct(tetris_playfield_t *pPl) |
|||
{ |
|||
tetris_bastet_variant_t *pBastet = |
|||
(tetris_bastet_variant_t *) malloc(sizeof(tetris_bastet_variant_t)); |
|||
memset(pBastet, 0, sizeof(tetris_bastet_variant_t)); |
|||
|
|||
pBastet->pPlayfield = pPl; |
|||
|
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t)); |
|||
tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1); |
|||
|
|||
return pBastet; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_destruct(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
if (pBastetVariant->pColHeights != NULL) |
|||
{ |
|||
free(pBastetVariant->pColHeights); |
|||
} |
|||
if (pBastetVariant->pPreviewPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pBastetVariant->pPreviewPiece); |
|||
} |
|||
|
|||
free(pBastetVariant); |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* bastet related functions * |
|||
****************************/ |
|||
|
|||
int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, |
|||
tetris_piece_t *pPiece, |
|||
int8_t nColumn) |
|||
{ |
|||
// the row where the given piece collides
|
|||
int8_t nDeepestRow = tetris_playfield_predictDeepestRow(pBastet->pPlayfield, |
|||
pPiece, nColumn); |
|||
|
|||
// initial score of the given piece
|
|||
int16_t nScore = -32000; |
|||
|
|||
// modify score based on complete lines
|
|||
int8_t nLines = tetris_playfield_predictCompleteLines(pBastet->pPlayfield, |
|||
pPiece, nDeepestRow, nColumn); |
|||
nScore += 5000 * nLines; |
|||
|
|||
// determine sane start and stop columns whose heights we want to calculate
|
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
int8_t nStartCol = ((nColumn - 1) < 0) ? 0 : nColumn - 1; |
|||
int8_t nStopCol; |
|||
// Do we start at the left most position?
|
|||
// If we do we MUST calculate the heights of ALL columns (initial step)
|
|||
if (nColumn <= -3) |
|||
{ |
|||
nStopCol = nWidth - 1; |
|||
// reset all column heights to zero
|
|||
tetris_bastet_clearColHeights(pBastet, 0 , nWidth); |
|||
} |
|||
// If not, only calculate columns which are affected by the moved piece.
|
|||
else |
|||
{ |
|||
nStopCol = (nColumn + 3) < nWidth ? nColumn + 3 : nWidth - 1; |
|||
// clear affected column heights to prevent miscalculations
|
|||
tetris_bastet_clearColHeights(pBastet, nStartCol, nStopCol); |
|||
} |
|||
|
|||
// go through every row and calculate column heights
|
|||
tetris_playfield_iterator_t iterator; |
|||
int8_t nHeight = 1; |
|||
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator, |
|||
pBastet->pPlayfield, pPiece, nDeepestRow, nColumn); |
|||
if (pDump == NULL) |
|||
{ |
|||
// an immediately returned NULL is caused by a full dump -> low score
|
|||
return -32766; |
|||
} |
|||
while (pDump != NULL) |
|||
{ |
|||
uint16_t nColMask = 0x0001 << nStartCol; |
|||
for (int x = nStartCol; x <= nStopCol; ++x) |
|||
{ |
|||
if ((*pDump & nColMask) != 0) |
|||
{ |
|||
pBastet->pColHeights[x] = nHeight; |
|||
} |
|||
nColMask <<= 1; |
|||
} |
|||
pDump = tetris_playfield_predictNextRow(&iterator); |
|||
++nHeight; |
|||
} |
|||
// modify score based on predicted column heights
|
|||
for (int x = 0; x < nWidth; ++x) |
|||
{ |
|||
nScore -= 5 * pBastet->pColHeights[x]; |
|||
} |
|||
|
|||
return nScore; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet) |
|||
{ |
|||
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield); |
|||
tetris_piece_t *pPiece = tetris_piece_construct(TETRIS_PC_LINE, |
|||
TETRIS_PC_ANGLE_0); |
|||
for (int8_t nBlock = TETRIS_PC_LINE; nBlock <= TETRIS_PC_Z; ++nBlock) |
|||
{ |
|||
int16_t nMaxScore = -32768; |
|||
tetris_piece_setShape(pPiece, nBlock); |
|||
int8_t nAngleCount = tetris_piece_getAngleCount(pPiece); |
|||
for (int8_t nAngle = TETRIS_PC_ANGLE_0; nAngle < nAngleCount; ++nAngle) |
|||
{ |
|||
tetris_piece_setAngle(pPiece, nAngle); |
|||
for (int8_t nCol = -3; nCol < nWidth; ++nCol) |
|||
{ |
|||
int16_t nScore = tetris_bastet_evaluateMove(pBastet, |
|||
pPiece, nCol); |
|||
nMaxScore = nMaxScore > nScore ? nMaxScore : nScore; |
|||
} |
|||
} |
|||
pBastet->nPieceScores[nBlock].shape = nBlock; |
|||
pBastet->nPieceScores[nBlock].nScore = nMaxScore; |
|||
} |
|||
tetris_piece_destruct(pPiece); |
|||
} |
|||
|
|||
|
|||
tetris_piece_t* tetris_bastet_choosePiece(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastet = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
|
|||
// determine the best score for every piece
|
|||
tetris_bastet_evaluatePieces(pBastet); |
|||
// perturb score (-2 to +2) to avoid stupid tie handling
|
|||
for (uint8_t i = 0; i < 7; ++i) |
|||
{ |
|||
pBastet->nPieceScores[i].nScore += random8() % 5 - 2; |
|||
} |
|||
|
|||
// sort pieces by their score in ascending order
|
|||
qsort(pBastet->nPieceScores, 7, sizeof(tetris_bastet_scorepair_t), |
|||
&tetris_bastet_qsortCompare); |
|||
|
|||
// new "preview" piece (AKA "won't give you this one")
|
|||
if (pBastet->pPreviewPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pBastet->pPreviewPiece); |
|||
} |
|||
pBastet->pPreviewPiece = |
|||
tetris_piece_construct(pBastet->nPieceScores[6].shape, |
|||
TETRIS_PC_ANGLE_0); |
|||
|
|||
tetris_piece_t *pPiece; |
|||
const uint8_t nPercent[4] = {75, 92, 98, 100}; |
|||
uint8_t nRnd = rand() % 100; |
|||
for (uint8_t i = 0; i < 4; ++i) |
|||
{ |
|||
if (nRnd < nPercent[i]) |
|||
{ |
|||
pPiece = tetris_piece_construct(pBastet->nPieceScores[i].shape, |
|||
TETRIS_PC_ANGLE_0); |
|||
break; |
|||
} |
|||
} |
|||
return pPiece; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_singleDrop(void *pVariantData, |
|||
uint8_t nLines) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_completeDrop(void *pVariantData, |
|||
uint8_t nLines) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_removedLines(void *pVariantData, |
|||
uint8_t nRowMask) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastet = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
uint8_t nLines = tetris_playfield_calculateLines(nRowMask); |
|||
|
|||
pBastet->nLines += nLines; |
|||
pBastet->nLevel = ((pBastet->nLines / 10) < TETRIS_INPUT_LEVELS) ? |
|||
(pBastet->nLines / 10) : (TETRIS_INPUT_LEVELS - 1); |
|||
|
|||
pBastet->nScore += nLines; |
|||
return; |
|||
} |
|||
|
|||
|
|||
/*****************
|
|||
* get functions * |
|||
*****************/ |
|||
|
|||
uint16_t tetris_bastet_getScore(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastetVariant->nScore; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_bastet_getHighscore(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastetVariant->nHighscore; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_setHighscore(void *pVariantData, |
|||
uint16_t nHighscore) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
pBastetVariant->nHighscore = nHighscore; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_bastet_getHighscoreName(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastetVariant->nHighscoreName; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_setHighscoreName(void *pVariantData, |
|||
uint16_t nHighscoreName) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
pBastetVariant->nHighscoreName = nHighscoreName; |
|||
} |
|||
|
|||
|
|||
uint8_t tetris_bastet_getLevel(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastet = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastet->nLevel; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_bastet_getLines(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastet = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastet->nLines; |
|||
} |
|||
|
|||
|
|||
tetris_piece_t* tetris_bastet_getPreviewPiece(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_bastet_variant_t *pBastetVariant = |
|||
(tetris_bastet_variant_t *)pVariantData; |
|||
return pBastetVariant->pPreviewPiece; |
|||
} |
|||
|
|||
|
|||
tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData) |
|||
{ |
|||
return TETRIS_HISCORE_BASTET; |
|||
} |
|||
|
|||
|
|||
void tetris_bastet_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
|
|||
tetris_orientation_t tetris_bastet_getOrientation(void *pVariantData) |
|||
{ |
|||
return TETRIS_ORIENTATION_0; |
|||
} |
@ -0,0 +1,218 @@ |
|||
#ifndef BAST_H_ |
|||
#define BAST_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "variants.h" |
|||
#include "playfield.h" |
|||
#include "piece.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
/**
|
|||
* runs the Bastet game |
|||
*/ |
|||
void tetris_bastet(void); |
|||
|
|||
|
|||
/*********
|
|||
* types * |
|||
*********/ |
|||
|
|||
typedef struct tetris_bastet_scorepair_t |
|||
{ |
|||
tetris_piece_shape_t shape; |
|||
int16_t nScore; |
|||
} |
|||
tetris_bastet_scorepair_t; |
|||
|
|||
|
|||
typedef struct tetris_bastet_variant_t |
|||
{ |
|||
uint16_t nScore; /** score of the player */ |
|||
uint16_t nHighscore; /** highscore */ |
|||
uint16_t nHighscoreName; /** champion's initials */ |
|||
uint8_t nLevel; /** current level */ |
|||
uint16_t nLines; /** number of completed lines */ |
|||
tetris_piece_t *pPreviewPiece; /** the piece for the preview */ |
|||
tetris_playfield_t *pPlayfield; /** playfield to be examined */ |
|||
int8_t *pColHeights; /** calculated heights */ |
|||
tetris_bastet_scorepair_t nPieceScores[7]; /** score for every piece */ |
|||
} |
|||
tetris_bastet_variant_t; |
|||
|
|||
const tetris_variant_t tetrisBastetVariant; |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/**
|
|||
* constructs a bastet instance for a given playfield |
|||
* @param pPlayfield the playfield to be observed |
|||
* @return pointer to a newly created bastet instance |
|||
*/ |
|||
void* tetris_bastet_construct(tetris_playfield_t *pPl); |
|||
|
|||
|
|||
/**
|
|||
* destructs the given bastet instance |
|||
* @param pVariantData the bastet instance to be destroyed |
|||
*/ |
|||
void tetris_bastet_destruct(void *pVariantData); |
|||
|
|||
|
|||
/****************************
|
|||
* bastet related functions * |
|||
****************************/ |
|||
|
|||
/**
|
|||
* calculates a score for a piece at a given column |
|||
* @param pBastet the bastet instance of interest |
|||
* @param pPiece the piece to be tested |
|||
* @param pnColum the column where the piece should be dropped |
|||
* @return score for the given move |
|||
*/ |
|||
int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet, |
|||
tetris_piece_t *pPiece, |
|||
int8_t nColumn); |
|||
|
|||
|
|||
/**
|
|||
* calculates the best possible score for every piece |
|||
* @param pBastet the bastet instance of interest |
|||
*/ |
|||
void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet); |
|||
|
|||
|
|||
/**
|
|||
* chooses a new worst possible piece |
|||
* @param pVariantData the variant instance of interest |
|||
* @return a tetris piece |
|||
*/ |
|||
tetris_piece_t* tetris_bastet_choosePiece(void *pBastet); |
|||
|
|||
|
|||
/**
|
|||
* chooses a new (best possible) piece for the preview |
|||
* @param pVariantData the variant instance of interest |
|||
* @return a tetris piece |
|||
*/ |
|||
tetris_piece_t* tetris_bastet_choosePreviewPiece(void *pBastet); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from single step dropping |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void tetris_bastet_singleDrop(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from a complete drop |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void tetris_bastet_completeDrop(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from removed rows |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nRowMask bit mask of removed lines |
|||
*/ |
|||
void tetris_bastet_removedLines(void *pVariantData, |
|||
uint8_t nRowMask); |
|||
|
|||
|
|||
/*********************
|
|||
* get/set functions * |
|||
*********************/ |
|||
|
|||
/**
|
|||
* returns the current score |
|||
* @param pVariantData variant data object we want information from |
|||
* @return score |
|||
*/ |
|||
uint16_t tetris_bastet_getScore(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore |
|||
* @param pVariantData variant data object we want information from |
|||
* @return highscore |
|||
*/ |
|||
uint16_t tetris_bastet_getHighscore(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore |
|||
* @param pVariantData variant data object we want to modify |
|||
* @param nHighscore highscore |
|||
*/ |
|||
void tetris_bastet_setHighscore(void *pVariantData, |
|||
uint16_t nHighscore); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore name |
|||
* @param pVariantData variant data object we want information from |
|||
* @return champion's name packed as uint16_t |
|||
*/ |
|||
uint16_t tetris_bastet_getHighscoreName(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore name |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nHighscoreName champion's name packed as uint16_t |
|||
*/ |
|||
void tetris_bastet_setHighscoreName(void *pVariantData, |
|||
uint16_t nHighscoreName); |
|||
|
|||
|
|||
/**
|
|||
* returns the current level |
|||
* @param pVariantData variant data object we want information from |
|||
* @return the level as uint8_t |
|||
*/ |
|||
uint8_t tetris_bastet_getLevel(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the number of completed lines |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return number of completed lines |
|||
*/ |
|||
uint16_t tetris_bastet_getLines(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns piece which was set via tetris_std_setPreviewPiece |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return the piece intended to be the next one |
|||
*/ |
|||
tetris_piece_t* tetris_bastet_getPreviewPiece(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* retrieves the variant's highscore index |
|||
* @param pVariantData the variant data object we want information from |
|||
*/ |
|||
tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData); |
|||
|
|||
|
|||
void tetris_bastet_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd); |
|||
|
|||
|
|||
tetris_orientation_t tetris_bastet_getOrientation(void *pVariantData); |
|||
|
|||
#endif /* BAST_H_ */ |
@ -0,0 +1,94 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
#include "../../random/prng.h" |
|||
#include "../../compat/pgmspace.h" |
|||
#include "../../menu/menu.h" |
|||
#include "variant_fp.h" |
|||
#include "variant_std.h" |
|||
#include "variants.h" |
|||
#include "tetris_main.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "highscore.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
#ifdef MENU_SUPPORT |
|||
// First Person Tetris icon, MSB is leftmost pixel
|
|||
static uint8_t tetrisfp_icon[8] PROGMEM = |
|||
{ 0xee, 0x89, 0xee, 0x88, 0x88, 0x20, 0x2c, 0x6c }; |
|||
game_descriptor_t tetrisfp_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris_fp, |
|||
tetrisfp_icon, |
|||
}; |
|||
#endif |
|||
|
|||
|
|||
void tetris_fp(void) |
|||
{ |
|||
tetris_main(&tetrisFpVariant); |
|||
} |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
const tetris_variant_t tetrisFpVariant = |
|||
{ |
|||
&tetris_std_construct, |
|||
&tetris_std_destruct, |
|||
&tetris_std_choosePiece, |
|||
&tetris_std_singleDrop, |
|||
&tetris_std_completeDrop, |
|||
&tetris_std_removedLines, |
|||
&tetris_std_getScore, |
|||
&tetris_std_getHighscore, |
|||
&tetris_std_setHighscore, |
|||
&tetris_std_getHighscoreName, |
|||
&tetris_std_setHighscoreName, |
|||
&tetris_std_getLevel, |
|||
&tetris_std_getLines, |
|||
&tetris_std_getPreviewPiece, |
|||
&tetris_fp_getHighscoreIndex, |
|||
&tetris_fp_setLastInput, |
|||
&tetris_std_getOrientation |
|||
}; |
|||
|
|||
|
|||
/*****************
|
|||
* get functions * |
|||
*****************/ |
|||
|
|||
tetris_highscore_index_t tetris_fp_getHighscoreIndex(void *pVariantData) |
|||
{ |
|||
return TETRIS_HISCORE_FP; |
|||
} |
|||
|
|||
|
|||
void tetris_fp_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd) |
|||
{ |
|||
assert (pVariantData != NULL); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
|
|||
if (inCmd == TETRIS_INCMD_ROT_CW) |
|||
{ |
|||
pStdVariant->nOrient = (pStdVariant->nOrient + 1) % 4; |
|||
} |
|||
else if (inCmd == TETRIS_INCMD_ROT_CCW) |
|||
{ |
|||
pStdVariant->nOrient = (pStdVariant->nOrient + 3) % 4; |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
#ifndef VARIANT_FP_H_ |
|||
#define VARIANT_FP_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "variant_std.h" |
|||
#include "variants.h" |
|||
#include "highscore.h" |
|||
#include "piece.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
/**
|
|||
* runs the First Person Tetris game |
|||
*/ |
|||
void tetris_fp(void); |
|||
|
|||
|
|||
const tetris_variant_t tetrisFpVariant; |
|||
|
|||
|
|||
/*********************
|
|||
* get/set functions * |
|||
*********************/ |
|||
|
|||
|
|||
/**
|
|||
* retrieves the variant's highscore index |
|||
* @param pVariantData the variant data object we want information from |
|||
*/ |
|||
tetris_highscore_index_t tetris_fp_getHighscoreIndex(void *pVariantData); |
|||
|
|||
|
|||
void tetris_fp_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd); |
|||
|
|||
#endif /*VARIANT_FP_H_*/ |
@ -0,0 +1,273 @@ |
|||
/* Borgtris
|
|||
* by: Christian Kroll |
|||
* date: Tuesday, 2007/09/16 |
|||
*/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
#include "../../autoconf.h" |
|||
#include "../../random/prng.h" |
|||
#include "../../compat/pgmspace.h" |
|||
#include "../../menu/menu.h" |
|||
#include "variant_std.h" |
|||
#include "variants.h" |
|||
#include "tetris_main.h" |
|||
#include "piece.h" |
|||
#include "playfield.h" |
|||
#include "highscore.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
#ifdef GAME_TETRIS |
|||
#ifdef MENU_SUPPORT |
|||
// Tetris icon, MSB is leftmost pixel
|
|||
static uint8_t tetris_icon[8] PROGMEM = |
|||
{ 0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0 }; |
|||
game_descriptor_t tetris_game_descriptor |
|||
__attribute__((section(".game_descriptors"))) = |
|||
{ |
|||
&tetris, |
|||
tetris_icon, |
|||
}; |
|||
#endif |
|||
|
|||
|
|||
void tetris(void) |
|||
{ |
|||
tetris_main(&tetrisStdVariant); |
|||
} |
|||
#endif |
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
#ifdef GAME_TETRIS |
|||
const tetris_variant_t tetrisStdVariant = |
|||
{ |
|||
&tetris_std_construct, |
|||
&tetris_std_destruct, |
|||
&tetris_std_choosePiece, |
|||
&tetris_std_singleDrop, |
|||
&tetris_std_completeDrop, |
|||
&tetris_std_removedLines, |
|||
&tetris_std_getScore, |
|||
&tetris_std_getHighscore, |
|||
&tetris_std_setHighscore, |
|||
&tetris_std_getHighscoreName, |
|||
&tetris_std_setHighscoreName, |
|||
&tetris_std_getLevel, |
|||
&tetris_std_getLines, |
|||
&tetris_std_getPreviewPiece, |
|||
&tetris_std_getHighscoreIndex, |
|||
&tetris_std_setLastInput, |
|||
&tetris_std_getOrientation |
|||
}; |
|||
#endif |
|||
|
|||
|
|||
void *tetris_std_construct(tetris_playfield_t *pPl) |
|||
{ |
|||
tetris_standard_variant_t *pStdVariant = (tetris_standard_variant_t *) |
|||
malloc(sizeof(tetris_standard_variant_t)); |
|||
assert(pStdVariant != NULL); |
|||
memset(pStdVariant, 0, sizeof(tetris_standard_variant_t)); |
|||
|
|||
return pStdVariant; |
|||
} |
|||
|
|||
|
|||
void tetris_std_destruct(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
if (pStdVariant->pPreviewPiece != NULL) |
|||
{ |
|||
tetris_piece_destruct(pStdVariant->pPreviewPiece); |
|||
} |
|||
free(pStdVariant); |
|||
} |
|||
|
|||
|
|||
/*****************************
|
|||
* variant related functions * |
|||
*****************************/ |
|||
|
|||
|
|||
tetris_piece_t* tetris_std_choosePiece(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
if (pStdVariant->pPreviewPiece == NULL) |
|||
{ |
|||
pStdVariant->pPreviewPiece = |
|||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); |
|||
return tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); |
|||
} |
|||
else |
|||
{ |
|||
tetris_piece_t *pPiece = pStdVariant->pPreviewPiece; |
|||
pStdVariant->pPreviewPiece = |
|||
tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); |
|||
return pPiece; |
|||
} |
|||
} |
|||
|
|||
|
|||
void tetris_std_singleDrop(void *pVariantData, |
|||
uint8_t nLines) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
pStdVariant->nScore += nLines; |
|||
} |
|||
|
|||
|
|||
void tetris_std_completeDrop(void *pVariantData, |
|||
uint8_t nLines) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
pStdVariant->nScore += nLines * 2; |
|||
} |
|||
|
|||
|
|||
void tetris_std_removedLines(void *pVariantData, |
|||
uint8_t nRowMask) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
uint8_t nLines = tetris_playfield_calculateLines(nRowMask); |
|||
pStdVariant->nLines += nLines; |
|||
pStdVariant->nLevel = ((pStdVariant->nLines / 10) < TETRIS_INPUT_LEVELS) ? |
|||
(pStdVariant->nLines / 10) : (TETRIS_INPUT_LEVELS - 1); |
|||
|
|||
switch (nLines) |
|||
{ |
|||
case 1: |
|||
pStdVariant->nScore += 50; |
|||
break; |
|||
case 2: |
|||
pStdVariant->nScore += 150; |
|||
break; |
|||
case 3: |
|||
pStdVariant->nScore += 250; |
|||
break; |
|||
case 4: |
|||
pStdVariant->nScore += 400; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
/*****************
|
|||
* get functions * |
|||
*****************/ |
|||
|
|||
uint16_t tetris_std_getScore(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->nScore; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_std_getHighscore(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->nHighscore; |
|||
} |
|||
|
|||
|
|||
void tetris_std_setHighscore(void *pVariantData, |
|||
uint16_t nHighscore) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
pStdVariant->nHighscore = nHighscore; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_std_getHighscoreName(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->nHighscoreName; |
|||
} |
|||
|
|||
|
|||
void tetris_std_setHighscoreName(void *pVariantData, |
|||
uint16_t nHighscoreName) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
pStdVariant->nHighscoreName = nHighscoreName; |
|||
} |
|||
|
|||
|
|||
uint8_t tetris_std_getLevel(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->nLevel; |
|||
} |
|||
|
|||
|
|||
uint16_t tetris_std_getLines(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->nLines; |
|||
} |
|||
|
|||
|
|||
tetris_piece_t* tetris_std_getPreviewPiece(void *pVariantData) |
|||
{ |
|||
assert(pVariantData != 0); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
return pStdVariant->pPreviewPiece; |
|||
} |
|||
|
|||
|
|||
tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData) |
|||
{ |
|||
return TETRIS_HISCORE_TETRIS; |
|||
} |
|||
|
|||
|
|||
void tetris_std_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd) |
|||
{ |
|||
} |
|||
|
|||
|
|||
tetris_orientation_t tetris_std_getOrientation(void *pVariantData) |
|||
{ |
|||
assert (pVariantData != NULL); |
|||
tetris_standard_variant_t *pStdVariant = |
|||
(tetris_standard_variant_t *)pVariantData; |
|||
|
|||
return pStdVariant->nOrient; |
|||
} |
@ -0,0 +1,186 @@ |
|||
#ifndef VARIANT_STD_H_ |
|||
#define VARIANT_STD_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "../../autoconf.h" |
|||
#include "variants.h" |
|||
#include "piece.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
|
|||
/***************
|
|||
* entry point * |
|||
***************/ |
|||
|
|||
#ifdef GAME_TETRIS |
|||
/**
|
|||
* runs the tetris game |
|||
*/ |
|||
void tetris(void); |
|||
|
|||
#endif |
|||
|
|||
|
|||
/*********
|
|||
* types * |
|||
*********/ |
|||
|
|||
typedef struct tetris_standard_variant_t |
|||
{ |
|||
uint16_t nScore; /** score of the player */ |
|||
uint16_t nHighscore; /** highscore */ |
|||
uint16_t nHighscoreName; /** champion's initials */ |
|||
uint8_t nLevel; /** current level */ |
|||
uint16_t nLines; /** number of completed lines */ |
|||
tetris_piece_t *pPreviewPiece; /** the piece intended to be the next one */ |
|||
tetris_orientation_t nOrient; /** desired orientation of the playfield */ |
|||
} |
|||
tetris_standard_variant_t; |
|||
|
|||
|
|||
const tetris_variant_t tetrisStdVariant; |
|||
|
|||
|
|||
/****************************
|
|||
* construction/destruction * |
|||
****************************/ |
|||
|
|||
/**
|
|||
* constructs a variant data object |
|||
* @param pPl related playfield object |
|||
* @return pointer to a newly created variant data object |
|||
*/ |
|||
void *tetris_std_construct(tetris_playfield_t *pPl); |
|||
|
|||
|
|||
/**
|
|||
* destructs a variant data object |
|||
* @param pVariantData pointer to a variant data object to be destructed |
|||
*/ |
|||
void tetris_std_destruct(void *pVariantData); |
|||
|
|||
|
|||
/*****************************
|
|||
* variant related functions * |
|||
*****************************/ |
|||
|
|||
/**
|
|||
* chooses a new piece |
|||
* @param pVariantData the variant instance of interest |
|||
* @return a tetris piece |
|||
*/ |
|||
tetris_piece_t* tetris_std_choosePiece(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from single step dropping |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void tetris_std_singleDrop(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from a complete drop |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void tetris_std_completeDrop(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from removed rows |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nRowMask bit mask of removed lines |
|||
*/ |
|||
void tetris_std_removedLines(void *pVariantData, |
|||
uint8_t nRowMask); |
|||
|
|||
|
|||
/*********************
|
|||
* get/set functions * |
|||
*********************/ |
|||
|
|||
/**
|
|||
* returns the current score |
|||
* @param pVariantData variant data object we want information from |
|||
* @return score |
|||
*/ |
|||
uint16_t tetris_std_getScore(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore |
|||
* @param pVariantData variant data object we want information from |
|||
* @return highscore |
|||
*/ |
|||
uint16_t tetris_std_getHighscore(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore |
|||
* @param pVariantData variant data object we want to modify |
|||
* @param nHighscore highscore |
|||
*/ |
|||
void tetris_std_setHighscore(void *pVariantData, |
|||
uint16_t nHighscore); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore name |
|||
* @param pVariantData variant data object we want information from |
|||
* @return champion's name packed as uint16_t |
|||
*/ |
|||
uint16_t tetris_std_getHighscoreName(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore name |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nHighscoreName champion's name packed as uint16_t |
|||
*/ |
|||
void tetris_std_setHighscoreName(void *pVariantData, |
|||
uint16_t nHighscoreName); |
|||
|
|||
|
|||
/**
|
|||
* returns the current level |
|||
* @param pVariantData variant data object we want information from |
|||
* @return the level as uint8_t |
|||
*/ |
|||
uint8_t tetris_std_getLevel(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the number of completed lines |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return number of completed lines |
|||
*/ |
|||
uint16_t tetris_std_getLines(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns piece which was set via tetris_std_setPreviewPiece |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return the piece intended to be the next one |
|||
*/ |
|||
tetris_piece_t* tetris_std_getPreviewPiece(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* retrieves the variant's highscore index |
|||
* @param pVariantData the variant data object we want information from |
|||
*/ |
|||
tetris_highscore_index_t tetris_std_getHighscoreIndex(void *pVariantData); |
|||
|
|||
|
|||
void tetris_std_setLastInput(void *pVariantData, |
|||
tetris_input_command_t inCmd); |
|||
|
|||
|
|||
tetris_orientation_t tetris_std_getOrientation(void *pVariantData); |
|||
|
|||
#endif /*VARIANT_STD_H_*/ |
@ -0,0 +1,142 @@ |
|||
#ifndef VARIANTS_H_ |
|||
#define VARIANTS_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "playfield.h" |
|||
#include "piece.h" |
|||
#include "highscore.h" |
|||
#include "orientation.h" |
|||
#include "input.h" |
|||
|
|||
typedef struct tetris_variant_t |
|||
{ |
|||
/**
|
|||
* constructs a variant data object |
|||
* @param pPl related playfield object |
|||
* @return pointer to a newly created variant data object |
|||
*/ |
|||
void* (*construct)(tetris_playfield_t *pPl); |
|||
|
|||
|
|||
/**
|
|||
* destructs a variant data object |
|||
* @param pVariantData pointer to a logic object to be destructed |
|||
*/ |
|||
void (*destruct)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* chooses a new piece |
|||
* @param pVariantData the variant instance of interest |
|||
* @return a tetris piece |
|||
*/ |
|||
tetris_piece_t* (*choosePiece)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from single step dropping |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void (*singleDrop)(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from a complete drop |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nLines the number of rows involved |
|||
*/ |
|||
void (*completeDrop)(void *pVariantData, |
|||
uint8_t nLines); |
|||
|
|||
|
|||
/**
|
|||
* add points which result from removed rows |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nRowMask bit mask of removed lines |
|||
*/ |
|||
void (*removedLines)(void *pVariantData, |
|||
uint8_t nRowMask); |
|||
|
|||
|
|||
/**
|
|||
* returns the current score |
|||
* @param pVariantData variant data object we want information from |
|||
* @return score |
|||
*/ |
|||
uint16_t (*getScore)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore |
|||
* @param pVariantData variant data object we want information from |
|||
* @return highscore |
|||
*/ |
|||
uint16_t (*getHighscore)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore |
|||
* @param pVariantData variant data object we want to modify |
|||
* @param nHighscore highscore |
|||
*/ |
|||
void (*setHighscore)(void *pVariantData, |
|||
uint16_t nHighscore); |
|||
|
|||
|
|||
/**
|
|||
* returns the current highscore name |
|||
* @param pVariantData variant data object we want information from |
|||
* @return champion's name packed as uint16_t |
|||
*/ |
|||
uint16_t (*getHighscoreName)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* set highscore name |
|||
* @param pVariantData the variant data object we want to modify |
|||
* @param nHighscoreName champion's name packed as uint16_t |
|||
*/ |
|||
void (*setHighscoreName)(void *pVariantData, |
|||
uint16_t nHighscoreName); |
|||
|
|||
|
|||
/**
|
|||
* returns the current level |
|||
* @param pVariantData variant data object we want information from |
|||
* @return the level as uint8_t |
|||
*/ |
|||
uint8_t (*getLevel)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns the number of completed lines |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return number of completed lines |
|||
*/ |
|||
uint16_t (*getLines)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* returns piece which was set via tetris_std_setPreviewPiece |
|||
* @param pVariantData the variant data object we want information from |
|||
* @return the piece intended to be the next one |
|||
*/ |
|||
tetris_piece_t* (*getPreviewPiece)(void *pVariantData); |
|||
|
|||
|
|||
/**
|
|||
* retrieves the variant's highscore index |
|||
* @param pVariantData the variant data object we want information from |
|||
*/ |
|||
tetris_highscore_index_t (*getHighscoreIndex)(void *pVariantData); |
|||
|
|||
void (*setLastInput)(void *pVariantData, |
|||
tetris_input_command_t inCmd); |
|||
|
|||
tetris_orientation_t (*getOrientation)(void *pVariantData); |
|||
} |
|||
tetris_variant_t; |
|||
|
|||
#endif /* VARIANTS_H_ */ |
Loading…
Reference in new issue