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_ |
#ifndef TETRIS_HIGHSCORE_H_ |
||||
#define TETRIS_HIGHSCORE_H_ |
#define TETRIS_HIGHSCORE_H_ |
||||
|
|
||||
/* Function: tetris_highscore_inputName
|
/**
|
||||
* Description: let user input a three character name |
* indexes for different tetris variants |
||||
* Return value: name packed into a uint16_t |
*/ |
||||
|
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); |
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_*/ |
#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