vastly improved modularization and the view is resizable now
This commit is contained in:
parent
e733427e3b
commit
3f2d878b7d
|
@ -71,7 +71,7 @@ comment "Animations"
|
||||||
dep_bool "Feuer" ANIMATION_FEUER $RANDOM_SUPPORT
|
dep_bool "Feuer" ANIMATION_FEUER $RANDOM_SUPPORT
|
||||||
dep_bool "Matrix" ANIMATION_MATRIX $RANDOM_SUPPORT
|
dep_bool "Matrix" ANIMATION_MATRIX $RANDOM_SUPPORT
|
||||||
dep_bool "Random Bright" ANIMATION_RANDOM_BRIGHT $RANDOM_SUPPORT
|
dep_bool "Random Bright" ANIMATION_RANDOM_BRIGHT $RANDOM_SUPPORT
|
||||||
dep_bool "Stonefly" ANIMATION_STONEFLY $RANDOM_SUPPORT $GAME_TETRIS
|
dep_bool "Stonefly" ANIMATION_STONEFLY $RANDOM_SUPPORT $GAME_TETRIS_CORE
|
||||||
dep_bool "Flying Dots" ANIMATION_FLYINGDOTS $RANDOM_SUPPORT
|
dep_bool "Flying Dots" ANIMATION_FLYINGDOTS $RANDOM_SUPPORT
|
||||||
dep_bool "Game of Life" ANIMATION_GAMEOFLIFE $RANDOM_SUPPORT
|
dep_bool "Game of Life" ANIMATION_GAMEOFLIFE $RANDOM_SUPPORT
|
||||||
bool "M Herweg" ANIMATION_MHERWEG
|
bool "M Herweg" ANIMATION_MHERWEG
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
mainmenu_option next_comment
|
mainmenu_option next_comment
|
||||||
comment "Games"
|
comment "Games"
|
||||||
|
|
||||||
dep_bool "tetris" GAME_TETRIS $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
dep_bool_menu "Tetris Core" GAME_TETRIS_CORE $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
||||||
dep_bool "bastet" GAME_BASTET $GAME_TETRIS
|
dep_bool "Standard Tetris" GAME_TETRIS $GAME_TETRIS_CORE
|
||||||
dep_bool "first person tetris" GAME_TETRIS_FP $GAME_TETRIS
|
dep_bool "Bastard Tetris" GAME_BASTET $GAME_TETRIS_CORE
|
||||||
|
dep_bool "First Person Tetris" GAME_TETRIS_FP $GAME_TETRIS_CORE
|
||||||
|
endmenu
|
||||||
|
|
||||||
dep_bool "space invaders" GAME_SPACE_INVADERS $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
dep_bool "space invaders" GAME_SPACE_INVADERS $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
||||||
dep_bool "snake" GAME_SNAKE $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
dep_bool "snake" GAME_SNAKE $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
||||||
dep_bool "breakout" GAME_BREAKOUT $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
dep_bool "breakout" GAME_BREAKOUT $JOYSTICK_SUPPORT $RANDOM_SUPPORT
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
ifeq ($(GAME_TETRIS),y)
|
ifeq ($(GAME_TETRIS_CORE),y)
|
||||||
SUBDIRS += games/tetris
|
SUBDIRS += games/tetris
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,21 @@ TOPDIR = ../..
|
||||||
|
|
||||||
include $(TOPDIR)/defaults.mk
|
include $(TOPDIR)/defaults.mk
|
||||||
|
|
||||||
|
SRC = tetris_main.c piece.c playfield.c view.c input.c highscore.c
|
||||||
|
|
||||||
|
ifeq ($(GAME_TETRIS),y)
|
||||||
|
SRC += variant_std.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(GAME_BASTET),y)
|
ifeq ($(GAME_BASTET),y)
|
||||||
SRC = piece.c playfield.c view.c logic.c input.c highscore.c bast.c
|
SRC += variant_bastet.c
|
||||||
else
|
endif
|
||||||
SRC = piece.c playfield.c view.c logic.c input.c highscore.c
|
|
||||||
|
ifeq ($(GAME_TETRIS_FP),y)
|
||||||
|
ifneq ($(GAME_TETRIS),y)
|
||||||
|
SRC += variant_std.c
|
||||||
|
endif
|
||||||
|
SRC += variant_fp.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
|
@ -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_ */
|
|
|
@ -2,16 +2,19 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "highscore.h"
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#include "../../scrolltext/scrolltext.h"
|
#include "../../scrolltext/scrolltext.h"
|
||||||
#include "../../joystick/joystick.h"
|
#include "../../joystick/joystick.h"
|
||||||
#include "highscore.h"
|
#include "../../compat/eeprom.h"
|
||||||
|
|
||||||
|
// global array for the highscores
|
||||||
|
uint16_t tetris_highscore[TETRIS_HISCORE_END] EEMEM;
|
||||||
|
|
||||||
|
// global array for the champions' initials
|
||||||
|
uint16_t tetris_highscore_name[TETRIS_HISCORE_END] EEMEM;
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_highscore_inputName
|
|
||||||
* Description: let user input a three character name
|
|
||||||
* Return value: name packed into a uint16_t
|
|
||||||
*/
|
|
||||||
uint16_t tetris_highscore_inputName(void)
|
uint16_t tetris_highscore_inputName(void)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLTEXT_SUPPORT
|
#ifdef SCROLLTEXT_SUPPORT
|
||||||
|
@ -111,3 +114,50 @@ uint16_t tetris_highscore_inputName(void)
|
||||||
return (0);
|
return (0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex)
|
||||||
|
{
|
||||||
|
uint16_t nHighscore = 0;
|
||||||
|
nHighscore = eeprom_read_word(&tetris_highscore[nIndex]);
|
||||||
|
|
||||||
|
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||||
|
if (nHighscore == 65535)
|
||||||
|
{
|
||||||
|
nHighscore = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nHighscore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
|
||||||
|
uint16_t nHighscore)
|
||||||
|
{
|
||||||
|
if (nHighscore > tetris_highscore_retrieveHighscore(nIndex))
|
||||||
|
{
|
||||||
|
eeprom_write_word(&tetris_highscore[nIndex], nHighscore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx)
|
||||||
|
{
|
||||||
|
uint16_t nHighscoreName = 0;
|
||||||
|
nHighscoreName = eeprom_read_word(&tetris_highscore_name[nIdx]);
|
||||||
|
|
||||||
|
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||||
|
if (nHighscoreName == 65535)
|
||||||
|
{
|
||||||
|
nHighscoreName = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nHighscoreName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex,
|
||||||
|
uint16_t nHighscoreName)
|
||||||
|
{
|
||||||
|
eeprom_write_word(&tetris_highscore_name[nIndex], nHighscoreName);
|
||||||
|
}
|
||||||
|
|
|
@ -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_*/
|
||||||
|
|
|
@ -6,63 +6,79 @@
|
||||||
#include "../../joystick/joystick.h"
|
#include "../../joystick/joystick.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "orientation.h"
|
||||||
#ifdef GAME_TETRIS_FP
|
|
||||||
#include "tetrisfp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../../compat/pgmspace.h"
|
#include "../../compat/pgmspace.h"
|
||||||
#define WAIT(ms) wait(ms)
|
#define WAIT(ms) wait(ms)
|
||||||
#define PM(value) pgm_read_word(&value)
|
#define PM(value) pgm_read_word(&value)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInputDefinesPrivate Input: Internal constants
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/***********
|
/***********
|
||||||
* defines *
|
* defines *
|
||||||
***********/
|
***********/
|
||||||
|
|
||||||
// amount of milliseconds that each loop cycle waits
|
/** amount of milliseconds that each loop cycle waits */
|
||||||
#define TETRIS_INPUT_TICKS 5
|
#define TETRIS_INPUT_TICKS 5
|
||||||
|
|
||||||
// amount of milliseconds the input is ignored after the pause combo has been
|
/**
|
||||||
// pressed, since it is difficult to release all buttons simultaneously
|
* amount of milliseconds the input is ignored after the pause combo has been
|
||||||
|
* pressed, since it is difficult to release all buttons simultaneously
|
||||||
|
*/
|
||||||
#define TETRIS_INPUT_PAUSE_TICKS 100
|
#define TETRIS_INPUT_PAUSE_TICKS 100
|
||||||
|
|
||||||
// amount of allowed loop cycles while in pause mode so that the game
|
/**
|
||||||
// automatically continues after five minutes
|
* amount of allowed loop cycles while in pause mode so that the game
|
||||||
|
* automatically continues after five minutes
|
||||||
|
*/
|
||||||
#define TETRIS_INPUT_PAUSE_CYCLES 60000
|
#define TETRIS_INPUT_PAUSE_CYCLES 60000
|
||||||
|
|
||||||
// minimum of cycles in gliding mode
|
/** minimum of cycles in gliding mode */
|
||||||
#define TETRIS_INPUT_GLIDE_CYCLES 75
|
#define TETRIS_INPUT_GLIDE_CYCLES 75
|
||||||
|
|
||||||
// here you can adjust the delays (in loop cycles) for key repeat
|
/** initial delay (in loop cycles) for key repeat */
|
||||||
#define TETRIS_INPUT_REPEAT_INITIALDELAY 35
|
#define TETRIS_INPUT_REPEAT_INITIALDELAY 35
|
||||||
|
/** delay (in loop cycles) for key repeat */
|
||||||
#define TETRIS_INPUT_REPEAT_DELAY 5
|
#define TETRIS_INPUT_REPEAT_DELAY 5
|
||||||
|
|
||||||
// Here you can adjust the amount of loop cycles a command is ignored after
|
/** amount of loop cyles the left button is ignored */
|
||||||
// its button has been released (to reduce joystick chatter)
|
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_ROT_CW 24
|
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_ROT_CCW 24
|
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_LEFT 12
|
#define TETRIS_INPUT_CHATTER_TICKS_LEFT 12
|
||||||
|
/** amount of loop cyles the right button is ignored */
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_RIGHT 12
|
#define TETRIS_INPUT_CHATTER_TICKS_RIGHT 12
|
||||||
|
/** amount of loop cyles the down button is ignored */
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_DOWN 12
|
#define TETRIS_INPUT_CHATTER_TICKS_DOWN 12
|
||||||
|
/** amount of loop cyles the clockwise rotation button is ignored */
|
||||||
|
#define TETRIS_INPUT_CHATTER_TICKS_ROT_CW 24
|
||||||
|
/** amount of loop cyles the counter clockwise rotation button is ignored */
|
||||||
|
#define TETRIS_INPUT_CHATTER_TICKS_ROT_CCW 24
|
||||||
|
/** amount of loop cyles the drop button is ignored */
|
||||||
#define TETRIS_INPUT_CHATTER_TICKS_DROP 20
|
#define TETRIS_INPUT_CHATTER_TICKS_DROP 20
|
||||||
|
|
||||||
// wait cycles per level (array of uint8_t)
|
/** wait cycles per level (array of uint8_t) */
|
||||||
#define TETRIS_INPUT_LVL_CYCLES 200, 133, 100, 80, 66, 57, 50, 44, 40, 36, 33, \
|
#define TETRIS_INPUT_LVL_CYCLES 200, 133, 100, 80, 66, 57, 50, 44, 40, 36, 33, \
|
||||||
30, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9
|
30, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInputNoInterface Input: Internal non-interface functions
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
* non-interface functions *
|
* non-interface functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_input_chatterProtect;
|
/**
|
||||||
* Description: sets an ignore counter to a command specific value if it is 0
|
* sets an ignore counter to a command specific value if it is 0
|
||||||
* Argument pIn: pointer to an input object
|
* @param pIn pointer to an input object
|
||||||
* Argument cmd: the command whose counter should be set
|
* @param cmd the command whose counter should be set
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_input_chatterProtect (tetris_input_t *pIn,
|
void tetris_input_chatterProtect(tetris_input_t *pIn,
|
||||||
tetris_input_command_t cmd)
|
tetris_input_command_t cmd)
|
||||||
{
|
{
|
||||||
// never exceed the index
|
// never exceed the index
|
||||||
assert(cmd < TETRIS_INCMD_NONE);
|
assert(cmd < TETRIS_INCMD_NONE);
|
||||||
|
@ -71,11 +87,11 @@ void tetris_input_chatterProtect (tetris_input_t *pIn,
|
||||||
// released (every command has its own counter)
|
// released (every command has its own counter)
|
||||||
static const uint8_t nInitialIgnoreValue[TETRIS_INCMD_NONE] PROGMEM =
|
static const uint8_t nInitialIgnoreValue[TETRIS_INCMD_NONE] PROGMEM =
|
||||||
{
|
{
|
||||||
TETRIS_INPUT_CHATTER_TICKS_ROT_CW,
|
|
||||||
TETRIS_INPUT_CHATTER_TICKS_ROT_CCW,
|
|
||||||
TETRIS_INPUT_CHATTER_TICKS_LEFT,
|
TETRIS_INPUT_CHATTER_TICKS_LEFT,
|
||||||
TETRIS_INPUT_CHATTER_TICKS_RIGHT,
|
TETRIS_INPUT_CHATTER_TICKS_RIGHT,
|
||||||
TETRIS_INPUT_CHATTER_TICKS_DOWN,
|
TETRIS_INPUT_CHATTER_TICKS_DOWN,
|
||||||
|
TETRIS_INPUT_CHATTER_TICKS_ROT_CW,
|
||||||
|
TETRIS_INPUT_CHATTER_TICKS_ROT_CCW,
|
||||||
TETRIS_INPUT_CHATTER_TICKS_DROP,
|
TETRIS_INPUT_CHATTER_TICKS_DROP,
|
||||||
0, // TETRIS_INCMD_GRAVITY (irrelevant because it doesn't have a button)
|
0, // TETRIS_INCMD_GRAVITY (irrelevant because it doesn't have a button)
|
||||||
0 // TETRIS_INCMD_PAUSE (is a combination of ROT_CW and DOWN)
|
0 // TETRIS_INCMD_PAUSE (is a combination of ROT_CW and DOWN)
|
||||||
|
@ -116,101 +132,118 @@ void tetris_input_chatterProtect (tetris_input_t *pIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_queryJoystick
|
/**
|
||||||
* Description: translates joystick movements into tetris_input_command_t
|
* remaps tetris commands according to current orientation
|
||||||
* Argument pIn: pointer to an input object
|
* @param pIn pointer to an input object
|
||||||
* Return value: see definition of tetris_input_command_t
|
* @param nCmd command which has to be mapped
|
||||||
|
* @return mapped tetris command
|
||||||
|
* @see tetris_input_command_t
|
||||||
*/
|
*/
|
||||||
tetris_input_command_t tetris_input_queryJoystick(uint8_t nFirstPerson)
|
tetris_input_command_t tetris_input_mapCommand(tetris_orientation_t nOrient,
|
||||||
|
tetris_input_command_t nCmd)
|
||||||
{
|
{
|
||||||
tetris_input_command_t cmdReturn;
|
const tetris_input_command_t nMapping[] =
|
||||||
|
{
|
||||||
|
TETRIS_INCMD_DOWN, TETRIS_INCMD_ROT_CW, TETRIS_INCMD_RIGHT,
|
||||||
|
TETRIS_INCMD_LEFT,
|
||||||
|
|
||||||
|
TETRIS_INCMD_RIGHT, TETRIS_INCMD_LEFT, TETRIS_INCMD_ROT_CW,
|
||||||
|
TETRIS_INCMD_DOWN,
|
||||||
|
|
||||||
|
TETRIS_INCMD_ROT_CW, TETRIS_INCMD_DOWN, TETRIS_INCMD_LEFT,
|
||||||
|
TETRIS_INCMD_RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
return (nOrient == TETRIS_ORIENTATION_0) || (nCmd >= TETRIS_INCMD_ROT_CCW) ?
|
||||||
|
nCmd : (nMapping[(nOrient - 1) * 4 + nCmd]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translates joystick movements into tetris commands
|
||||||
|
* @return interpreted joystick command
|
||||||
|
* @see tetris_input_command_t
|
||||||
|
*/
|
||||||
|
tetris_input_command_t tetris_input_queryJoystick(tetris_input_t *pIn)
|
||||||
|
{
|
||||||
|
// map port input to a tetris command
|
||||||
|
tetris_input_command_t cmdJoystick;
|
||||||
if (JOYISFIRE)
|
if (JOYISFIRE)
|
||||||
{
|
{
|
||||||
cmdReturn = TETRIS_INCMD_DROP;
|
cmdJoystick = TETRIS_INCMD_DROP;
|
||||||
}
|
}
|
||||||
else if (JOYISLEFT)
|
else if (JOYISLEFT)
|
||||||
{
|
{
|
||||||
#ifdef GAME_TETRIS_FP
|
cmdJoystick = TETRIS_INCMD_LEFT;
|
||||||
switch (tetris_screendir) {
|
|
||||||
case 0: cmdReturn = TETRIS_INCMD_LEFT; break;
|
|
||||||
case 1: cmdReturn = TETRIS_INCMD_DOWN; break;
|
|
||||||
case 2: cmdReturn = TETRIS_INCMD_RIGHT; break;
|
|
||||||
case 3: cmdReturn = TETRIS_INCMD_ROT_CW; break;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cmdReturn = TETRIS_INCMD_LEFT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (JOYISRIGHT)
|
else if (JOYISRIGHT)
|
||||||
{
|
{
|
||||||
#ifdef GAME_TETRIS_FP
|
cmdJoystick = TETRIS_INCMD_RIGHT;
|
||||||
switch (tetris_screendir) {
|
|
||||||
case 0: cmdReturn = TETRIS_INCMD_RIGHT; break;
|
|
||||||
case 1: cmdReturn = TETRIS_INCMD_ROT_CW; break;
|
|
||||||
case 2: cmdReturn = TETRIS_INCMD_LEFT; break;
|
|
||||||
case 3: cmdReturn = TETRIS_INCMD_DOWN; break;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cmdReturn = TETRIS_INCMD_RIGHT;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (JOYISUP && JOYISDOWN)
|
else if (JOYISUP && JOYISDOWN)
|
||||||
{
|
{
|
||||||
cmdReturn = TETRIS_INCMD_PAUSE;
|
cmdJoystick = TETRIS_INCMD_PAUSE;
|
||||||
WAIT(TETRIS_INPUT_PAUSE_TICKS);
|
WAIT(TETRIS_INPUT_PAUSE_TICKS);
|
||||||
}
|
}
|
||||||
else if (JOYISDOWN)
|
else if (JOYISDOWN)
|
||||||
{
|
{
|
||||||
#ifdef GAME_TETRIS_FP
|
cmdJoystick = TETRIS_INCMD_DOWN;
|
||||||
switch (tetris_screendir) {
|
|
||||||
case 0: cmdReturn = TETRIS_INCMD_DOWN; break;
|
|
||||||
case 1: cmdReturn = TETRIS_INCMD_RIGHT; break;
|
|
||||||
case 2: cmdReturn = TETRIS_INCMD_ROT_CW; break;
|
|
||||||
case 3: cmdReturn = TETRIS_INCMD_LEFT; break;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cmdReturn = TETRIS_INCMD_DOWN;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (JOYISUP)
|
else if (JOYISUP)
|
||||||
{
|
{
|
||||||
#ifdef GAME_TETRIS_FP
|
cmdJoystick = TETRIS_INCMD_ROT_CW;
|
||||||
switch (tetris_screendir) {
|
|
||||||
case 0: cmdReturn = TETRIS_INCMD_ROT_CW; break;
|
|
||||||
case 1: cmdReturn = TETRIS_INCMD_LEFT; break;
|
|
||||||
case 2: cmdReturn = TETRIS_INCMD_DOWN; break;
|
|
||||||
case 3: cmdReturn = TETRIS_INCMD_RIGHT; break;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cmdReturn = TETRIS_INCMD_ROT_CW;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmdReturn = TETRIS_INCMD_NONE;
|
cmdJoystick = TETRIS_INCMD_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decrement all ignore counters
|
||||||
|
for (int nIgnIndex = 0; nIgnIndex < TETRIS_INCMD_NONE; ++nIgnIndex)
|
||||||
|
{
|
||||||
|
if (pIn->nIgnoreCmdCounter[nIgnIndex] != 0)
|
||||||
|
{
|
||||||
|
--pIn->nIgnoreCmdCounter[nIgnIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// chatter protection
|
||||||
|
if (cmdJoystick < TETRIS_INCMD_NONE)
|
||||||
|
{
|
||||||
|
if (pIn->nIgnoreCmdCounter[cmdJoystick] == 0)
|
||||||
|
{
|
||||||
|
tetris_input_chatterProtect(pIn, cmdJoystick);
|
||||||
|
}
|
||||||
|
else if (cmdJoystick != pIn->cmdRawLast)
|
||||||
|
{
|
||||||
|
cmdJoystick = TETRIS_INCMD_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// memorize current command (for detecting prolonged key presses)
|
||||||
|
pIn->cmdRawLast = cmdJoystick;
|
||||||
|
|
||||||
|
tetris_input_command_t cmdReturn =
|
||||||
|
tetris_input_mapCommand(pIn->nOrientation, cmdJoystick);
|
||||||
|
// remap command according to current orientation
|
||||||
return cmdReturn;
|
return cmdReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
/*****************************
|
|
||||||
* construction/destruction *
|
|
||||||
*****************************/
|
|
||||||
|
|
||||||
/* Function: tetris_input_construct
|
/****************************
|
||||||
* Description: constructs an input object for André's borg
|
* construction/destruction *
|
||||||
* Return value: pointer to a newly created input object
|
****************************/
|
||||||
*/
|
|
||||||
tetris_input_t *tetris_input_construct()
|
tetris_input_t *tetris_input_construct(void)
|
||||||
{
|
{
|
||||||
tetris_input_t *pIn = (tetris_input_t *)malloc(sizeof(tetris_input_t));
|
tetris_input_t *pIn = (tetris_input_t *)malloc(sizeof(tetris_input_t));
|
||||||
assert(pIn != NULL);
|
assert(pIn != NULL);
|
||||||
|
|
||||||
pIn->cmdLast = TETRIS_INCMD_NONE;
|
pIn->cmdRawLast = pIn->cmdLast = TETRIS_INCMD_NONE;
|
||||||
pIn->nLevel = 0xFF;
|
pIn->nOrientation = TETRIS_ORIENTATION_0;
|
||||||
|
// pIn->nLevel = 0xFF;
|
||||||
tetris_input_setLevel(pIn, 0);
|
tetris_input_setLevel(pIn, 0);
|
||||||
pIn->nLoopCycles = 0;
|
pIn->nLoopCycles = 0;
|
||||||
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
||||||
|
@ -221,11 +254,6 @@ tetris_input_t *tetris_input_construct()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_destruct
|
|
||||||
* Description: destructs an input structure
|
|
||||||
* Argument pIn: pointer to the input object which should to be destructed
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_input_destruct(tetris_input_t *pIn)
|
void tetris_input_destruct(tetris_input_t *pIn)
|
||||||
{
|
{
|
||||||
assert(pIn != NULL);
|
assert(pIn != NULL);
|
||||||
|
@ -237,15 +265,8 @@ void tetris_input_destruct(tetris_input_t *pIn)
|
||||||
* input related functions *
|
* input related functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_input_getCommand
|
|
||||||
* Description: retrieves commands from joystick or loop interval
|
|
||||||
* Argument pIn: pointer to an input object
|
|
||||||
* Argument nPace: falling pace (see definition of tetris_input_pace_t)
|
|
||||||
* Return value: see definition of tetris_input_command_t
|
|
||||||
*/
|
|
||||||
tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
||||||
tetris_input_pace_t nPace,
|
tetris_input_pace_t nPace)
|
||||||
uint8_t nFirstPerson)
|
|
||||||
{
|
{
|
||||||
assert (pIn != NULL);
|
assert (pIn != NULL);
|
||||||
|
|
||||||
|
@ -272,122 +293,96 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
||||||
|
|
||||||
while (pIn->nLoopCycles < nMaxCycles)
|
while (pIn->nLoopCycles < nMaxCycles)
|
||||||
{
|
{
|
||||||
cmdJoystick = tetris_input_queryJoystick(nFirstPerson);
|
cmdJoystick = tetris_input_queryJoystick(pIn);
|
||||||
|
|
||||||
// only obey current command if it is not considered as chattering
|
switch (cmdJoystick)
|
||||||
if (((cmdJoystick < TETRIS_INCMD_NONE) ?
|
|
||||||
pIn->nIgnoreCmdCounter[cmdJoystick] : 0) == 0)
|
|
||||||
{
|
{
|
||||||
switch (cmdJoystick)
|
case TETRIS_INCMD_LEFT:
|
||||||
|
case TETRIS_INCMD_RIGHT:
|
||||||
|
case TETRIS_INCMD_DOWN:
|
||||||
|
// only react if either the current command differs from the
|
||||||
|
// last one or enough loop cycles have been run on the same
|
||||||
|
// command (for key repeat)
|
||||||
|
if ((pIn->cmdLast != cmdJoystick) || ((pIn->cmdLast == cmdJoystick)
|
||||||
|
&& (pIn->nRepeatCount >= TETRIS_INPUT_REPEAT_DELAY)))
|
||||||
{
|
{
|
||||||
case TETRIS_INCMD_LEFT:
|
// reset repeat counter
|
||||||
case TETRIS_INCMD_RIGHT:
|
|
||||||
case TETRIS_INCMD_DOWN:
|
|
||||||
// only react if either the current command differs from the
|
|
||||||
// last one or enough loop cycles have been run on the same
|
|
||||||
// command (for key repeat)
|
|
||||||
if ((pIn->cmdLast != cmdJoystick)
|
|
||||||
|| ((pIn->cmdLast == cmdJoystick)
|
|
||||||
&& (pIn->nRepeatCount >= TETRIS_INPUT_REPEAT_DELAY)))
|
|
||||||
{
|
|
||||||
// reset repeat counter
|
|
||||||
if (pIn->cmdLast != cmdJoystick)
|
|
||||||
{
|
|
||||||
// different command: we set an extra initial delay
|
|
||||||
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// same command: there's no extra initial delay
|
|
||||||
pIn->nRepeatCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update cmdLast and return value
|
|
||||||
pIn->cmdLast = cmdReturn = cmdJoystick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if not enough loop cycles have been run we increment the
|
|
||||||
// repeat counter, ensure that we continue the loop and
|
|
||||||
// keep the key repeat functioning
|
|
||||||
++pIn->nRepeatCount;
|
|
||||||
cmdReturn = TETRIS_INCMD_NONE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TETRIS_INCMD_DROP:
|
|
||||||
case TETRIS_INCMD_ROT_CW:
|
|
||||||
case TETRIS_INCMD_ROT_CCW:
|
|
||||||
// no key repeat here
|
|
||||||
if (pIn->cmdLast != cmdJoystick)
|
if (pIn->cmdLast != cmdJoystick)
|
||||||
{
|
{
|
||||||
pIn->cmdLast = cmdReturn = cmdJoystick;
|
// different command: we set an extra initial delay
|
||||||
|
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if we reach here the command is ignored
|
// same command: there's no extra initial delay
|
||||||
cmdReturn = TETRIS_INCMD_NONE;
|
pIn->nRepeatCount = 0;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TETRIS_INCMD_PAUSE:
|
|
||||||
// if this is an initial pause command, make sure that the logic
|
|
||||||
// module is informed about it
|
|
||||||
if (pIn->cmdLast != TETRIS_INCMD_PAUSE)
|
|
||||||
{
|
|
||||||
pIn->cmdLast = cmdReturn = cmdJoystick;
|
|
||||||
pIn->nPauseCount = 0;
|
|
||||||
}
|
|
||||||
// consecutive pause commands should not cause the loop to leave
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cmdReturn = TETRIS_INCMD_NONE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TETRIS_INCMD_NONE:
|
|
||||||
// chatter protection
|
|
||||||
if (pIn->cmdLast != TETRIS_INCMD_NONE)
|
|
||||||
{
|
|
||||||
tetris_input_chatterProtect(pIn, pIn->cmdLast);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the game is paused (last command was TETRIS_INCMD_PAUSE)
|
// update cmdLast and return value
|
||||||
// we ensure that the variable which holds that last command
|
pIn->cmdLast = cmdReturn = cmdJoystick;
|
||||||
// isn't touched. We use this as a flag so that the loop cycle
|
|
||||||
// counter doesn't get incremented.
|
|
||||||
// We count the number of pause cycles, though. If enough cycles
|
|
||||||
// have been run, we enforce the continuation of the game.
|
|
||||||
if ((pIn->cmdLast != TETRIS_INCMD_PAUSE) ||
|
|
||||||
(++pIn->nPauseCount > TETRIS_INPUT_PAUSE_CYCLES))
|
|
||||||
{
|
|
||||||
pIn->cmdLast = TETRIS_INCMD_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset repeat counter
|
|
||||||
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
|
||||||
|
|
||||||
// using cmdReturn as a flag for not leaving the loop
|
|
||||||
cmdReturn = TETRIS_INCMD_NONE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
// current command is considered as chattering
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pIn->cmdLast = cmdReturn = TETRIS_INCMD_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrement all ignore counters
|
|
||||||
for (int nIgnIndex = 0; nIgnIndex < TETRIS_INCMD_NONE; ++nIgnIndex)
|
|
||||||
{
|
|
||||||
if (pIn->nIgnoreCmdCounter[nIgnIndex] != 0)
|
|
||||||
{
|
{
|
||||||
--pIn->nIgnoreCmdCounter[nIgnIndex];
|
// if not enough loop cycles have been run we increment the
|
||||||
|
// repeat counter, ensure that we continue the loop and
|
||||||
|
// keep the key repeat functioning
|
||||||
|
++pIn->nRepeatCount;
|
||||||
|
cmdReturn = TETRIS_INCMD_NONE;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TETRIS_INCMD_DROP:
|
||||||
|
case TETRIS_INCMD_ROT_CW:
|
||||||
|
case TETRIS_INCMD_ROT_CCW:
|
||||||
|
// no key repeat here
|
||||||
|
if (pIn->cmdLast != cmdJoystick)
|
||||||
|
{
|
||||||
|
pIn->cmdLast = cmdReturn = cmdJoystick;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we reach here the command is ignored
|
||||||
|
cmdReturn = TETRIS_INCMD_NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TETRIS_INCMD_PAUSE:
|
||||||
|
// if this is an initial pause command, make sure that the logic
|
||||||
|
// module is informed about it
|
||||||
|
if (pIn->cmdLast != TETRIS_INCMD_PAUSE)
|
||||||
|
{
|
||||||
|
pIn->cmdLast = cmdReturn = cmdJoystick;
|
||||||
|
pIn->nPauseCount = 0;
|
||||||
|
}
|
||||||
|
// consecutive pause commands should not cause the loop to leave
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmdReturn = TETRIS_INCMD_NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TETRIS_INCMD_NONE:
|
||||||
|
// If the game is paused (last command was TETRIS_INCMD_PAUSE)
|
||||||
|
// we ensure that the variable which holds that last command
|
||||||
|
// isn't touched. We use this as a flag so that the loop cycle
|
||||||
|
// counter doesn't get incremented.
|
||||||
|
// We count the number of pause cycles, though. If enough cycles
|
||||||
|
// have been run, we enforce the continuation of the game.
|
||||||
|
if ((pIn->cmdLast != TETRIS_INCMD_PAUSE) ||
|
||||||
|
(++pIn->nPauseCount > TETRIS_INPUT_PAUSE_CYCLES))
|
||||||
|
{
|
||||||
|
pIn->cmdLast = TETRIS_INCMD_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset repeat counter
|
||||||
|
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
||||||
|
|
||||||
|
// using cmdReturn as a flag for not leaving the loop
|
||||||
|
cmdReturn = TETRIS_INCMD_NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset automatic falling if the player has dropped a piece
|
// reset automatic falling if the player has dropped a piece
|
||||||
|
@ -418,12 +413,6 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_setLevel
|
|
||||||
* Description: modifies time interval of input events
|
|
||||||
* Argument pIn: pointer to an input object
|
|
||||||
* Argument nLvl: desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1)
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_input_setLevel(tetris_input_t *pIn,
|
void tetris_input_setLevel(tetris_input_t *pIn,
|
||||||
uint8_t nLvl)
|
uint8_t nLvl)
|
||||||
{
|
{
|
||||||
|
@ -439,11 +428,7 @@ void tetris_input_setLevel(tetris_input_t *pIn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function: tetris_input_resetDownKeyRepeat
|
|
||||||
* Description: resets the key repeat count for the down key
|
|
||||||
* Argument pIn: pointer to an input object
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn)
|
void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn)
|
||||||
{
|
{
|
||||||
assert(pIn != NULL);
|
assert(pIn != NULL);
|
||||||
|
@ -452,3 +437,19 @@ void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn)
|
||||||
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tetris_input_setOrientation(tetris_input_t *pIn,
|
||||||
|
tetris_orientation_t nOrient)
|
||||||
|
{
|
||||||
|
if (pIn->nOrientation != nOrient)
|
||||||
|
{
|
||||||
|
pIn->nOrientation = nOrient;
|
||||||
|
|
||||||
|
// avoid weird key repeating effects because the currently pressed
|
||||||
|
// button changes its meaning as soon as the orientation changes
|
||||||
|
pIn->cmdLast = tetris_input_mapCommand(pIn->nOrientation,
|
||||||
|
pIn->cmdRawLast);
|
||||||
|
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,101 +2,155 @@
|
||||||
#define INPUT_H_
|
#define INPUT_H_
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "orientation.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInputDefinesPublic Input: Public constants
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/***********
|
/***********
|
||||||
* defines *
|
* defines *
|
||||||
***********/
|
***********/
|
||||||
|
|
||||||
// number of levels
|
/** number of levels */
|
||||||
#define TETRIS_INPUT_LEVELS 30
|
#define TETRIS_INPUT_LEVELS 30
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInputTypes Input: Data types
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
* types *
|
* types *
|
||||||
*********/
|
*********/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allowed input values
|
||||||
|
*/
|
||||||
typedef enum tetris_input_command_t
|
typedef enum tetris_input_command_t
|
||||||
{
|
{
|
||||||
TETRIS_INCMD_ROT_CW, // rotate clockwise
|
TETRIS_INCMD_LEFT, /**< move piece left */
|
||||||
TETRIS_INCMD_ROT_CCW, // rotate counter clockwise
|
TETRIS_INCMD_RIGHT, /**< move piece right */
|
||||||
TETRIS_INCMD_LEFT, // move piece left
|
TETRIS_INCMD_DOWN, /**< lower piece by one row */
|
||||||
TETRIS_INCMD_RIGHT, // move piece right
|
TETRIS_INCMD_ROT_CW, /**< rotate clockwise */
|
||||||
TETRIS_INCMD_DOWN, // lower piece by one row
|
TETRIS_INCMD_ROT_CCW, /**< rotate counter clockwise */
|
||||||
TETRIS_INCMD_DROP, // move piece to the ground immediately
|
TETRIS_INCMD_DROP, /**< move piece to the ground immediately */
|
||||||
TETRIS_INCMD_GRAVITY, // piece gets pulled by gravity
|
TETRIS_INCMD_GRAVITY, /**< piece gets pulled by gravity */
|
||||||
TETRIS_INCMD_PAUSE, // pause the game
|
TETRIS_INCMD_PAUSE, /**< pause the game */
|
||||||
TETRIS_INCMD_NONE // idle (must alway be the last one)
|
TETRIS_INCMD_NONE /**< idle (must alway be the last one) */
|
||||||
}
|
}
|
||||||
tetris_input_command_t;
|
tetris_input_command_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* values which influence the gravity time limit for a piece
|
||||||
|
*/
|
||||||
typedef enum tetris_input_pace_t
|
typedef enum tetris_input_pace_t
|
||||||
{
|
{
|
||||||
TETRIS_INPACE_HOVERING, // normal falling pace
|
TETRIS_INPACE_HOVERING, /**< normal falling pace */
|
||||||
TETRIS_INPACE_GLIDING /* guarantees a minimum docking time to avoid
|
TETRIS_INPACE_GLIDING /**< guarantees a minimum docking time to avoid
|
||||||
accidentally docked pieces in higher levels */
|
accidentally docked pieces in higher levels */
|
||||||
}
|
}
|
||||||
tetris_input_pace_t;
|
tetris_input_pace_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* data structure for the input module
|
||||||
|
*/
|
||||||
typedef struct tetris_input_t
|
typedef struct tetris_input_t
|
||||||
{
|
{
|
||||||
// current level (determines falling speed)
|
/**
|
||||||
|
* current level (determines falling speed)
|
||||||
|
*/
|
||||||
uint8_t nLevel;
|
uint8_t nLevel;
|
||||||
|
|
||||||
// Amount of loop cycles between forced piece movements. This value gets
|
/**
|
||||||
// set via the tetris_input_setLevel() function.
|
* Amount of loop cycles between forced piece movements. This value gets
|
||||||
|
* set via the tetris_input_setLevel() function.
|
||||||
|
*/
|
||||||
uint8_t nMaxCycles;
|
uint8_t nMaxCycles;
|
||||||
|
|
||||||
// This counter keeps track of the number of loop cycles which have been
|
/**
|
||||||
// done since the last forced piece movement. It gets reset if it either
|
* This counter keeps track of the number of loop cycles which have been
|
||||||
// reaches a well defined value (causing a gravity command to be issued)
|
* done since the last forced piece movement. It gets reset if it either
|
||||||
// or the player has moved down the piece herself/himself.
|
* reaches a well defined value (causing a gravity command to be issued)
|
||||||
|
* or the player has moved down the piece herself/himself.
|
||||||
|
*/
|
||||||
uint8_t nLoopCycles;
|
uint8_t nLoopCycles;
|
||||||
|
|
||||||
// Amount of loop cycles in which the same command has been issued
|
/**
|
||||||
// consecutively. It gets reset if either the current command differs from
|
* Amount of loop cycles in which the same command has been issued
|
||||||
// the last one or a well-defined value has been reached (thereby
|
* consecutively. It gets reset if either the current command differs from
|
||||||
// regulating the pace of the key repeat as commands are only processed
|
* the last one or a well-defined value has been reached (thereby
|
||||||
// if that value is reached).
|
* regulating the pace of the key repeat as commands are only processed
|
||||||
|
* if that value is reached).
|
||||||
|
*/
|
||||||
int8_t nRepeatCount;
|
int8_t nRepeatCount;
|
||||||
|
|
||||||
// Keeps track of the number of loop cycles which have been run while in
|
/**
|
||||||
// pause mode. As soon as a well defined value is reached, the game
|
* Keeps track of the number of loop cycles which have been run while in
|
||||||
// continues (in case someone paused the game and forgot to resume it).
|
* pause mode. As soon as a well defined value is reached, the game
|
||||||
|
* continues (in case someone paused the game and forgot to resume it).
|
||||||
|
*/
|
||||||
uint16_t nPauseCount;
|
uint16_t nPauseCount;
|
||||||
|
|
||||||
|
|
||||||
// last command (important for key repeat)
|
/**
|
||||||
|
* last real command (important for key repeat and chatter protection)
|
||||||
|
*/
|
||||||
|
tetris_input_command_t cmdRawLast;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* last mapped command (important for key repeat)
|
||||||
|
*/
|
||||||
tetris_input_command_t cmdLast;
|
tetris_input_command_t cmdLast;
|
||||||
|
|
||||||
// Every command has its own counter. A command is ignored as long as its
|
|
||||||
// counter is unequal to 0. A counter gets set to a specific value (or 0)
|
/**
|
||||||
// if the button of the corresponding command has been released by the
|
* Every command has its own counter. A command is ignored as long as its
|
||||||
// player. All counters get decremented by one every loop cycle until they
|
* counter is unequal to 0. A counter gets set to a specific value (or 0)
|
||||||
// are zero. This is used to work against joystick chatter. Look at the
|
* if the button of the corresponding command has been released by the
|
||||||
// TETRIS_INPUT_CHATTER_TICKS_... constants in input.c for the initial
|
* player. All counters get decremented by one every loop cycle until they
|
||||||
// values of these counters.
|
* are zero. This is used to work against joystick chatter. Look at the
|
||||||
|
* TETRIS_INPUT_CHATTER_TICKS_... constants in input.c for the initial
|
||||||
|
* values of these counters.
|
||||||
|
*/
|
||||||
uint8_t nIgnoreCmdCounter[TETRIS_INCMD_NONE];
|
uint8_t nIgnoreCmdCounter[TETRIS_INCMD_NONE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* orientation of the direction mapping
|
||||||
|
*/
|
||||||
|
tetris_orientation_t nOrientation;
|
||||||
}
|
}
|
||||||
tetris_input_t;
|
tetris_input_t;
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInputRelated Input: Interface functions
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/****************************
|
/****************************
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
/* Function: tetris_input_construct
|
/**
|
||||||
* Description: constructs an input object for André's borg
|
* constructs an input object for André's borg
|
||||||
* Return value: pointer to a newly created input object
|
* @return pointer to a newly created input object
|
||||||
*/
|
*/
|
||||||
tetris_input_t *tetris_input_construct();
|
tetris_input_t *tetris_input_construct(void);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_destruct
|
/**
|
||||||
* Description: destructs an input object
|
* destructs an input object
|
||||||
* Argument pIn: pointer to the input object which should be destructed
|
* @param pIn pointer to the input object which should be destructed
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_input_destruct(tetris_input_t *pIn);
|
void tetris_input_destruct(tetris_input_t *pIn);
|
||||||
|
|
||||||
|
@ -105,32 +159,41 @@ void tetris_input_destruct(tetris_input_t *pIn);
|
||||||
* input related functions *
|
* input related functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: retris_input_getCommand
|
/**
|
||||||
* Description: retrieves commands from joystick or loop interval
|
* retrieves commands from joystick or loop interval
|
||||||
* Argument pIn: pointer to an input object
|
* @param pIn pointer to an input object
|
||||||
* Argument nPace: falling pace (see definition of tetris_input_pace_t)
|
* @param nPace falling pace
|
||||||
* Return value: see definition of tetris_input_command_t
|
* @return see definition of tetris_input_command_t
|
||||||
|
* @see definition of tetris_input_pace_t
|
||||||
*/
|
*/
|
||||||
tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
|
||||||
tetris_input_pace_t nPace,
|
tetris_input_pace_t nPace);
|
||||||
uint8_t nFirstPerson);
|
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_setLevel
|
/**
|
||||||
* Description: modifies time interval of input events
|
* modifies time interval of input events
|
||||||
* Argument pIn: pointer to an input object
|
* @param pIn pointer to an input object
|
||||||
* Argument nLvl: desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1)
|
* @param nLvl desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1)
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_input_setLevel(tetris_input_t *pIn,
|
void tetris_input_setLevel(tetris_input_t *pIn,
|
||||||
uint8_t nLvl);
|
uint8_t nLvl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_input_resetDownKeyRepeat
|
/**
|
||||||
* Description: resets the key repeat count for the down key
|
* resets the key repeat count for the down key
|
||||||
* Argument pIn: pointer to an input object
|
* @param pIn pointer to an input object
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn);
|
void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the orientation of the direction control mapping
|
||||||
|
* @param pIn pointer to an input object
|
||||||
|
* @param nOrient desired orientation
|
||||||
|
*/
|
||||||
|
void tetris_input_setOrientation(tetris_input_t *pIn,
|
||||||
|
tetris_orientation_t nOrient);
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
#endif /*INPUT_H_*/
|
#endif /*INPUT_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_ */
|
|
@ -14,12 +14,6 @@
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
/* Function: tetris_piece_construct
|
|
||||||
* Description: constructs a piece with the given attributes
|
|
||||||
* Argument s: shape of the piece (see tetris_piece_shape_t)
|
|
||||||
* Argument a: its angle (see tetris_piece_angel_t)
|
|
||||||
* Return value: pointer to a newly created piece
|
|
||||||
*/
|
|
||||||
tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s,
|
tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s,
|
||||||
tetris_piece_angle_t a)
|
tetris_piece_angle_t a)
|
||||||
{
|
{
|
||||||
|
@ -32,11 +26,6 @@ tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s,
|
||||||
return p_piece;
|
return p_piece;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function: tetris_piece_destruct
|
|
||||||
* Description: destructs a piece
|
|
||||||
* Argument pPc: pointer to the piece to be destructed
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_piece_destruct(tetris_piece_t *pPc)
|
void tetris_piece_destruct(tetris_piece_t *pPc)
|
||||||
{
|
{
|
||||||
assert(pPc != NULL);
|
assert(pPc != NULL);
|
||||||
|
@ -48,13 +37,6 @@ void tetris_piece_destruct(tetris_piece_t *pPc)
|
||||||
* piece related functions *
|
* piece related functions *
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
/* Function: tetris_piece_getBitmap
|
|
||||||
* Description: returns bitfield representation of the piece
|
|
||||||
* Argument pPc: piece from which the bitfield shuld be retrieved
|
|
||||||
* Return value: bitfield representation of the piece
|
|
||||||
* - nth nibble is nth row of the piece (from upper left)
|
|
||||||
* - the LSB of a nibble represents the left side of a row
|
|
||||||
*/
|
|
||||||
uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc)
|
uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc)
|
||||||
{
|
{
|
||||||
assert(pPc != NULL);
|
assert(pPc != NULL);
|
||||||
|
@ -79,12 +61,6 @@ uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_rotate
|
|
||||||
* Description: rotates a piece
|
|
||||||
* Argument pPc: piece to rotate
|
|
||||||
* Argument r: type of rotation (see tetris_piece_rotation_t)
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_piece_rotate(tetris_piece_t *pPc,
|
void tetris_piece_rotate(tetris_piece_t *pPc,
|
||||||
tetris_piece_rotation_t r)
|
tetris_piece_rotation_t r)
|
||||||
{
|
{
|
||||||
|
@ -117,14 +93,9 @@ void tetris_piece_rotate(tetris_piece_t *pPc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function: tetris_piece_changeShape
|
|
||||||
* Description: changes the shape of a piece
|
void tetris_piece_setShape(tetris_piece_t *pPc,
|
||||||
* Argument pPc: piece to change
|
tetris_piece_shape_t shape)
|
||||||
* Argument shape: the shape of interest
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_piece_changeShape(tetris_piece_t *pPc,
|
|
||||||
tetris_piece_shape_t shape)
|
|
||||||
{
|
{
|
||||||
assert(pPc != NULL);
|
assert(pPc != NULL);
|
||||||
assert((shape >= 0) && (shape <= TETRIS_PC_Z));
|
assert((shape >= 0) && (shape <= TETRIS_PC_Z));
|
||||||
|
@ -133,14 +104,8 @@ void tetris_piece_changeShape(tetris_piece_t *pPc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_changeAngle
|
void tetris_piece_setAngle(tetris_piece_t *pPc,
|
||||||
* Description: changes the angle of a piece
|
tetris_piece_angle_t angle)
|
||||||
* Argument pPc: piece to change
|
|
||||||
* Argument angle: the angle of interest
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_piece_changeAngle(tetris_piece_t *pPc,
|
|
||||||
tetris_piece_angle_t angle)
|
|
||||||
{
|
{
|
||||||
assert(pPc != NULL);
|
assert(pPc != NULL);
|
||||||
assert((angle >= TETRIS_PC_ANGLE_0) && (angle <= TETRIS_PC_ANGLE_270));
|
assert((angle >= TETRIS_PC_ANGLE_0) && (angle <= TETRIS_PC_ANGLE_270));
|
||||||
|
@ -149,12 +114,7 @@ void tetris_piece_changeAngle(tetris_piece_t *pPc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_angleCount
|
int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc)
|
||||||
* Description: returns the number of different angles
|
|
||||||
* Argument pPc: piece whose angle count is of interest
|
|
||||||
* Return value: number of different angles
|
|
||||||
*/
|
|
||||||
int8_t tetris_piece_angleCount(tetris_piece_t *pPc)
|
|
||||||
{
|
{
|
||||||
assert(pPc != NULL);
|
assert(pPc != NULL);
|
||||||
|
|
||||||
|
|
|
@ -3,122 +3,135 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisPieceTypes Piece: Data types
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
* types *
|
* types *
|
||||||
*********/
|
*********/
|
||||||
|
|
||||||
|
/** shape attributes for a piece */
|
||||||
typedef enum tetris_piece_shape_t
|
typedef enum tetris_piece_shape_t
|
||||||
{
|
{
|
||||||
TETRIS_PC_LINE,
|
TETRIS_PC_LINE, /**< the I shaped brick */
|
||||||
TETRIS_PC_T,
|
TETRIS_PC_T, /**< the T shaped brick */
|
||||||
TETRIS_PC_SQUARE,
|
TETRIS_PC_SQUARE, /**< the sqare shaped brick */
|
||||||
TETRIS_PC_L,
|
TETRIS_PC_L, /**< the L shaped brick */
|
||||||
TETRIS_PC_LBACK,
|
TETRIS_PC_LBACK, /**< the reverse L shaped brick */
|
||||||
TETRIS_PC_S,
|
TETRIS_PC_S, /**< the S shaped brick */
|
||||||
TETRIS_PC_Z
|
TETRIS_PC_Z /**< the Z shaped brick */
|
||||||
}
|
}
|
||||||
tetris_piece_shape_t;
|
tetris_piece_shape_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** possible angles for a brick */
|
||||||
typedef enum tetris_piece_angle_t
|
typedef enum tetris_piece_angle_t
|
||||||
{
|
{
|
||||||
TETRIS_PC_ANGLE_0,
|
TETRIS_PC_ANGLE_0, /**< standard angle */
|
||||||
TETRIS_PC_ANGLE_90,
|
TETRIS_PC_ANGLE_90, /**< rotated by 90 degrees */
|
||||||
TETRIS_PC_ANGLE_180,
|
TETRIS_PC_ANGLE_180, /**< rotated by 180 degrees */
|
||||||
TETRIS_PC_ANGLE_270
|
TETRIS_PC_ANGLE_270 /**< rotated by 270 degrees */
|
||||||
}
|
}
|
||||||
tetris_piece_angle_t;
|
tetris_piece_angle_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** rotation attributes */
|
||||||
typedef enum tetris_piece_rotation_t
|
typedef enum tetris_piece_rotation_t
|
||||||
{
|
{
|
||||||
TETRIS_PC_ROT_CW, // clockwise rotation
|
TETRIS_PC_ROT_CW, /**< clockwise rotation */
|
||||||
TETRIS_PC_ROT_CCW // counter clockwise rotation
|
TETRIS_PC_ROT_CCW /**< counter clockwise rotation */
|
||||||
}
|
}
|
||||||
tetris_piece_rotation_t;
|
tetris_piece_rotation_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* describes the attributes of a piece
|
||||||
|
* @see tetris_piece_shape_t
|
||||||
|
* @see tetris_piece_angle_t
|
||||||
|
*/
|
||||||
typedef struct tetris_piece_t
|
typedef struct tetris_piece_t
|
||||||
{
|
{
|
||||||
tetris_piece_shape_t shape; // specifies the shape of the piece
|
tetris_piece_shape_t shape; /**< specifies the shape of the piece */
|
||||||
tetris_piece_angle_t angle; // specifies one of 4 angels
|
tetris_piece_angle_t angle; /**< specifies one of 4 angels */
|
||||||
}
|
}
|
||||||
tetris_piece_t;
|
tetris_piece_t;
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisPieceRelated Piece: Interface functions
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
/* Function: tetris_piece_construct
|
/**
|
||||||
* Description: constructs a piece with the given attributes
|
* constructs a piece with the given attributes
|
||||||
* Argument s: shape of the piece (see tetris_piece_shape_t)
|
* @param s shape of the piece (see tetris_piece_shape_t)
|
||||||
* Argument a: its angle (see tetris_piece_angel_t)
|
* @param a its angle (see tetris_piece_angel_t)
|
||||||
* Return value: pointer to a newly created piece
|
* @return pointer to a newly created piece
|
||||||
*/
|
*/
|
||||||
tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s,
|
tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s,
|
||||||
tetris_piece_angle_t a);
|
tetris_piece_angle_t a);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_destruct
|
/**
|
||||||
* Description: destructs a piece
|
* destructs a piece
|
||||||
* Argument pPc: pointer to the piece to be destructed
|
* @param pPc pointer to the piece to be destructed
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_piece_destruct(tetris_piece_t *pPc);
|
void tetris_piece_destruct(tetris_piece_t *pPc);
|
||||||
|
|
||||||
|
|
||||||
/****************************
|
/***************************
|
||||||
* piece related functions *
|
* piece related functions *
|
||||||
****************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_piece_getBitmap
|
/**
|
||||||
* Description: returns bitfield representation of the piece
|
* returns bitfield representation of the piece
|
||||||
* Argument pPc: piece from which the bitfield shuld be retrieved
|
* @param pPc piece from which the bitfield shuld be retrieved
|
||||||
* Return value: bitfield representation of the piece
|
* @return bitfield representation of the piece
|
||||||
* - nth nibble is nth row of the piece (from upper left)
|
|
||||||
* - the LSB of a nibble represents the left side of a row
|
|
||||||
*/
|
*/
|
||||||
uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc);
|
uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_rotate
|
/**
|
||||||
* Description: rotates a piece
|
* rotates a piece
|
||||||
* Argument pPc: piece to rotate
|
* @param pPc piece to rotate
|
||||||
* Argument r: type of rotation (see tetris_piece_rotation_t)
|
* @param r type of rotation (see tetris_piece_rotation_t)
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_piece_rotate(tetris_piece_t *pPc,
|
void tetris_piece_rotate(tetris_piece_t *pPc,
|
||||||
tetris_piece_rotation_t r);
|
tetris_piece_rotation_t r);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_changeShape
|
/**
|
||||||
* Description: changes the shape of a piece
|
* changes the shape of a piece
|
||||||
* Argument pPc: piece to change
|
* @param pPc piece to change
|
||||||
* Argument shape: the shape of interest
|
* @param shape the shape of interest
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_piece_changeShape(tetris_piece_t *pPc,
|
void tetris_piece_setShape(tetris_piece_t *pPc,
|
||||||
tetris_piece_shape_t shape);
|
tetris_piece_shape_t shape);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_changeAngle
|
/**
|
||||||
* Description: changes the angle of a piece
|
* changes the angle of a piece
|
||||||
* Argument pPc: piece to change
|
* @param pPc piece to change
|
||||||
* Argument angle: the angle of interest
|
* @param angle the angle of interest
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_piece_changeAngle(tetris_piece_t *pPc,
|
void tetris_piece_setAngle(tetris_piece_t *pPc,
|
||||||
tetris_piece_angle_t angle);
|
tetris_piece_angle_t angle);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_piece_angleCount
|
/**
|
||||||
* Description: returns the number of different angles
|
* returns the number of different angles
|
||||||
* Argument pPc: piece whose angle count is of interest
|
* @param pPc piece whose angle count we want to know
|
||||||
* Return value: number of different angles
|
* @return number of different angles
|
||||||
*/
|
*/
|
||||||
int8_t tetris_piece_angleCount(tetris_piece_t *pPc);
|
int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc);
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
#endif /*TETRIS_PIECE_H_*/
|
#endif /*TETRIS_PIECE_H_*/
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
* non-interface functions *
|
* non-interface functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_hoverStatus;
|
/**
|
||||||
* Description: determines if piece is either hovering or gliding
|
* determines if piece is either hovering or gliding
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: TETRIS_PFS_HOVERING or TETRIS_PFS_GLIDING
|
* @eturn TETRIS_PFS_HOVERING or TETRIS_PFS_GLIDING
|
||||||
*/
|
*/
|
||||||
tetris_playfield_status_t tetris_playfield_hoverStatus(tetris_playfield_t* pPl)
|
tetris_playfield_status_t tetris_playfield_hoverStatus(tetris_playfield_t* pPl)
|
||||||
{
|
{
|
||||||
|
@ -35,12 +35,6 @@ tetris_playfield_status_t tetris_playfield_hoverStatus(tetris_playfield_t* pPl)
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_construct
|
|
||||||
* Description: constructs a playfield with the given dimensions
|
|
||||||
* Argument nWidth: width of playfield (4 <= n <= 16)
|
|
||||||
* Argument nHeight: height of playfield (4 <= n <= 124)
|
|
||||||
* Return value: pointer to a newly created playfield
|
|
||||||
*/
|
|
||||||
tetris_playfield_t *tetris_playfield_construct(int8_t nWidth,
|
tetris_playfield_t *tetris_playfield_construct(int8_t nWidth,
|
||||||
int8_t nHeight)
|
int8_t nHeight)
|
||||||
{
|
{
|
||||||
|
@ -75,11 +69,6 @@ tetris_playfield_t *tetris_playfield_construct(int8_t nWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_destruct
|
|
||||||
* Description: destructs a playfield
|
|
||||||
* Argument pPl: pointer to the playfield to be destructed
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_playfield_destruct(tetris_playfield_t *pPl)
|
void tetris_playfield_destruct(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -97,11 +86,23 @@ void tetris_playfield_destruct(tetris_playfield_t *pPl)
|
||||||
* playfield related functions *
|
* playfield related functions *
|
||||||
*******************************/
|
*******************************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_reset
|
uint8_t tetris_playfield_calculateLines(uint8_t nRowMask)
|
||||||
* Description: resets playfield to begin a new game
|
{
|
||||||
* Argument pPl: playfield to perform action on
|
uint8_t nMask = 0x0001;
|
||||||
* Return value: void
|
uint8_t nLines = 0;
|
||||||
*/
|
for (uint8_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if ((nMask & nRowMask) != 0)
|
||||||
|
{
|
||||||
|
++nLines;
|
||||||
|
}
|
||||||
|
nMask <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void tetris_playfield_reset(tetris_playfield_t *pPl)
|
void tetris_playfield_reset(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -141,13 +142,6 @@ int8_t tetris_playfield_getPieceStartPos(tetris_piece_t *pPiece)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_insertPiece
|
|
||||||
* Description: inserts a new piece
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Argument pPiece: piece to be inserted
|
|
||||||
* Argument ppOldPiece: [out] indirect pointer to former piece for deallocation
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_playfield_insertPiece(tetris_playfield_t *pPl,
|
void tetris_playfield_insertPiece(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
tetris_piece_t** ppOldPiece)
|
tetris_piece_t** ppOldPiece)
|
||||||
|
@ -184,13 +178,6 @@ void tetris_playfield_insertPiece(tetris_playfield_t *pPl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_collision
|
|
||||||
* Description: detects if piece collides with s.th. at a given position
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Argument nColumn: column where the piece should be moved
|
|
||||||
* Argument nRow: row where the piece should be moved
|
|
||||||
* Return value: 1 for collision, 0 otherwise
|
|
||||||
*/
|
|
||||||
uint8_t tetris_playfield_collision(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_collision(tetris_playfield_t *pPl,
|
||||||
int8_t nColumn,
|
int8_t nColumn,
|
||||||
int8_t nRow)
|
int8_t nRow)
|
||||||
|
@ -290,11 +277,6 @@ uint8_t tetris_playfield_collision(tetris_playfield_t *pPl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_advancePiece
|
|
||||||
* Description: lowers piece by one row or finally docks it
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_playfield_advancePiece(tetris_playfield_t *pPl)
|
void tetris_playfield_advancePiece(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -367,12 +349,6 @@ void tetris_playfield_advancePiece(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_movePiece
|
|
||||||
* Description: moves piece to the given direction
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Argument direction: direction (see tetris_playfield_direction_t)
|
|
||||||
* Return value: 1 if piece could be moved, 0 otherwise
|
|
||||||
*/
|
|
||||||
uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl,
|
||||||
tetris_playfield_direction_t direction)
|
tetris_playfield_direction_t direction)
|
||||||
{
|
{
|
||||||
|
@ -396,12 +372,6 @@ uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_rotatePiece
|
|
||||||
* Description: rotates piece to the given direction
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Argument r: type of rotation (see tetris_piece_rotation_t)
|
|
||||||
* Return value: 1 if piece could be rotated, 0 otherwise
|
|
||||||
*/
|
|
||||||
uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl,
|
||||||
tetris_piece_rotation_t rotation)
|
tetris_piece_rotation_t rotation)
|
||||||
{
|
{
|
||||||
|
@ -436,11 +406,6 @@ uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_removeCompletedLines
|
|
||||||
* Description: removes completed lines (if any) and lowers the dump
|
|
||||||
* Argument pPl: playfield to perform action on
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl)
|
void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -524,11 +489,6 @@ void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl)
|
||||||
* get functions *
|
* get functions *
|
||||||
*****************/
|
*****************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_getWidth
|
|
||||||
* Description: returns the width of the playfield
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: width of the playfield
|
|
||||||
*/
|
|
||||||
int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl)
|
int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -547,11 +507,6 @@ int8_t tetris_playfield_getHeight(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getPiece
|
|
||||||
* Description: returns the currently falling piece
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: pointer to the currently falling piece
|
|
||||||
*/
|
|
||||||
tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl)
|
tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -559,11 +514,6 @@ tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getColumn
|
|
||||||
* Description: returns the column of the currently falling piece
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: column of the currently falling piece
|
|
||||||
*/
|
|
||||||
int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl)
|
int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -571,11 +521,6 @@ int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getRow
|
|
||||||
* Description: returns the row of the currently falling piece
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: row of the currently falling piece
|
|
||||||
*/
|
|
||||||
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl)
|
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -583,13 +528,6 @@ int8_t tetris_playfield_getRow(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getRowMask
|
|
||||||
* Description: returns the row mask relative to nRow
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: the first 4 bits indicate which lines (relative to nRow)
|
|
||||||
* have been removed if we are in status TETRIS_PFS_READY
|
|
||||||
* LSB is the highest line
|
|
||||||
*/
|
|
||||||
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl)
|
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -597,11 +535,6 @@ uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getStatus
|
|
||||||
* Description: returns the status of the playfield
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Return value: status of the playfield (see tetris_playfield_status_t)
|
|
||||||
*/
|
|
||||||
tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl)
|
tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl)
|
||||||
{
|
{
|
||||||
assert(pPl != NULL);
|
assert(pPl != NULL);
|
||||||
|
@ -609,12 +542,6 @@ tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getDumpRow
|
|
||||||
* Description: returns the given row of the dump (as bitmap)
|
|
||||||
* Argument pPl: the playfield we want information from
|
|
||||||
* Argument nRow: the number of the row (0 <= nRow < height of playfield)
|
|
||||||
* Return value: bitmap of the requested row (LSB is leftmost column)
|
|
||||||
*/
|
|
||||||
uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
||||||
int8_t nRow)
|
int8_t nRow)
|
||||||
{
|
{
|
||||||
|
@ -626,13 +553,6 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
||||||
|
|
||||||
#ifdef GAME_BASTET
|
#ifdef GAME_BASTET
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictDeepestRow
|
|
||||||
* Description: returns the deepest possible row of a given piece
|
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
|
||||||
* Argument pPiece: the piece which should be tested
|
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
|
||||||
* Return value: the row of the piece (playfield compliant coordinates)
|
|
||||||
*/
|
|
||||||
int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
|
int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
int8_t nColumn)
|
int8_t nColumn)
|
||||||
|
@ -665,15 +585,7 @@ int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
|
||||||
return nRow;
|
return nRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictCompleteLines
|
|
||||||
* Description: predicts the number of complete lines for a piece at
|
|
||||||
* a given column
|
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
|
||||||
* Argument pPiece: the piece which should be tested
|
|
||||||
* Argument nRow: the row where the given piece collides
|
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
|
||||||
* Return value: amount of complete lines
|
|
||||||
*/
|
|
||||||
int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
int8_t nRow,
|
int8_t nRow,
|
||||||
|
@ -724,17 +636,6 @@ int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictBottomRow
|
|
||||||
* Description: predicts the appearance of the bottom row of the
|
|
||||||
* playfield (for a piece at a given column) and
|
|
||||||
* initializes an iterator structure
|
|
||||||
* Argument pIt: [out] a pointer to an iterator which should be initialized
|
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
|
||||||
* Argument pPiece: the piece which should be tested
|
|
||||||
* Argument nRow: the row where the given piece collides
|
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
|
||||||
* Return value: appearance of the predicted dump row at the bottom
|
|
||||||
*/
|
|
||||||
uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
||||||
tetris_playfield_t *pPl,
|
tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
|
@ -761,12 +662,6 @@ uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictNextRow
|
|
||||||
* Description: predicts the appearance of the next row of the playfield
|
|
||||||
* (for a given iterator)
|
|
||||||
* Argument pIt: a pointer to a dump iterator
|
|
||||||
* Return value: appearance of next predicted row (or NULL -> no next line)
|
|
||||||
*/
|
|
||||||
uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt)
|
uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt)
|
||||||
{
|
{
|
||||||
uint16_t nPieceMap = 0;
|
uint16_t nPieceMap = 0;
|
||||||
|
|
|
@ -22,11 +22,11 @@ tetris_playfield_direction_t;
|
||||||
// status of the playfield
|
// status of the playfield
|
||||||
typedef enum tetris_playfield_status_t
|
typedef enum tetris_playfield_status_t
|
||||||
{
|
{
|
||||||
TETRIS_PFS_READY, // ready to get next piece
|
TETRIS_PFS_READY, /** ready to get next piece */
|
||||||
TETRIS_PFS_HOVERING, // piece is still hovering
|
TETRIS_PFS_HOVERING, /** piece is still hovering */
|
||||||
TETRIS_PFS_GLIDING, // piece is gliding on the dump
|
TETRIS_PFS_GLIDING, /** piece is gliding on the dump */
|
||||||
TETRIS_PFS_DOCKED, // piece has been docked
|
TETRIS_PFS_DOCKED, /** piece has been docked */
|
||||||
TETRIS_PFS_GAMEOVER // playfield is filled up
|
TETRIS_PFS_GAMEOVER /** playfield is filled up */
|
||||||
}
|
}
|
||||||
tetris_playfield_status_t;
|
tetris_playfield_status_t;
|
||||||
|
|
||||||
|
@ -34,15 +34,15 @@ tetris_playfield_status_t;
|
||||||
// tetris_playfield_t
|
// tetris_playfield_t
|
||||||
typedef struct tetris_playfield_t
|
typedef struct tetris_playfield_t
|
||||||
{
|
{
|
||||||
int8_t nWidth; // width of playfield
|
int8_t nWidth; /** width of playfield */
|
||||||
int8_t nHeight; // height of playfield
|
int8_t nHeight; /** height of playfield */
|
||||||
tetris_piece_t *pPiece; // currently falling piece
|
tetris_piece_t *pPiece; /** currently falling piece */
|
||||||
int8_t nColumn; // horz. piece pos. (0 is left)
|
int8_t nColumn; /** horz. piece pos. (0 is left) */
|
||||||
int8_t nRow; // vert. piece pos. (0 is top)
|
int8_t nRow; /** vert. piece pos. (0 is top) */
|
||||||
uint8_t nRowMask; // removed lines relative to nRow (bitmap)
|
uint8_t nRowMask; /** removed lines relative to nRow */
|
||||||
tetris_playfield_status_t status; // status
|
tetris_playfield_status_t status; /** status */
|
||||||
int8_t nFirstMatterRow; // first row (from top) which contains matter
|
int8_t nFirstMatterRow; /** first row from top which has matter */
|
||||||
uint16_t *dump; // playfield itself
|
uint16_t *dump; /** playfield itself */
|
||||||
}
|
}
|
||||||
tetris_playfield_t;
|
tetris_playfield_t;
|
||||||
|
|
||||||
|
@ -50,15 +50,15 @@ tetris_playfield_t;
|
||||||
// iterator for predicted dump rows
|
// iterator for predicted dump rows
|
||||||
typedef struct tetris_playfield_iterator_t
|
typedef struct tetris_playfield_iterator_t
|
||||||
{
|
{
|
||||||
tetris_playfield_t *pPlayfield; // playfield to be examined
|
tetris_playfield_t *pPlayfield; /** playfield to be examined */
|
||||||
tetris_piece_t *pPiece; // piece which should be tested
|
tetris_piece_t *pPiece; /** piece which should be tested */
|
||||||
int8_t nColumn; // the column where the piece should be dropped
|
int8_t nColumn; /** column where piece should be dropped */
|
||||||
uint16_t nFullRow; // value of a full row
|
uint16_t nFullRow; /** value of a full row */
|
||||||
int8_t nCurrentRow; // the actual row in the playfield
|
int8_t nCurrentRow; /** the actual row in the playfield */
|
||||||
int8_t nPieceHighestRow; // the highest row index of the piece
|
int8_t nPieceHighestRow; /** the highest row index of the piece */
|
||||||
int8_t nPieceLowestRow; // the lowest row index of the piece
|
int8_t nPieceLowestRow; /** the lowest row index of the piece */
|
||||||
int8_t nStopRow; // the last row to be examined
|
int8_t nStopRow; /** the last row to be examined */
|
||||||
uint16_t nRowBuffer; // internal buffer for returned row values
|
uint16_t nRowBuffer; /** internal buffer for returned rows */
|
||||||
}
|
}
|
||||||
tetris_playfield_iterator_t;
|
tetris_playfield_iterator_t;
|
||||||
|
|
||||||
|
@ -67,19 +67,18 @@ tetris_playfield_iterator_t;
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_construct
|
/**
|
||||||
* Description: constructs a playfield with the given diemensions
|
* constructs a playfield with the given diemensions
|
||||||
* Argument nWidth: width of playfield (4 <= n <= 16)
|
* @param nWidth width of playfield (4 <= n <= 16)
|
||||||
* Argument nHeight: height of playfield (4 <= n <= 124)
|
* @param nHeight height of playfield (4 <= n <= 124)
|
||||||
* Return value: pointer to a newly created playfield
|
* @return pointer to a newly created playfield
|
||||||
*/
|
*/
|
||||||
tetris_playfield_t *tetris_playfield_construct(int8_t nWidth, int8_t nHeight);
|
tetris_playfield_t *tetris_playfield_construct(int8_t nWidth, int8_t nHeight);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_destruct
|
/**
|
||||||
* Description: destructs a playfield
|
* destructs a playfield
|
||||||
* Argument pPl: pointer to the playfield to be destructed
|
* @param pPl pointer to the playfield to be destructed
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_playfield_destruct(tetris_playfield_t *pPl);
|
void tetris_playfield_destruct(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
@ -88,70 +87,74 @@ void tetris_playfield_destruct(tetris_playfield_t *pPl);
|
||||||
* playfield related functions *
|
* playfield related functions *
|
||||||
*******************************/
|
*******************************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_reset
|
/**
|
||||||
* Description: resets playfield to begin a new game
|
* calculates number of lines for the given row mask
|
||||||
* Argument pPl: playfield to perform action on
|
* @param nRowMask row mask from which the no. of lines will be calculated
|
||||||
* Return value: void
|
* @return number of lines of the row mask
|
||||||
|
*/
|
||||||
|
uint8_t tetris_playfield_calculateLines(uint8_t nRowMask);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resets playfield to begin a new game
|
||||||
|
* @param pPl playfield to perform action on
|
||||||
*/
|
*/
|
||||||
void tetris_playfield_reset(tetris_playfield_t *pPl);
|
void tetris_playfield_reset(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_insertPiece
|
/**
|
||||||
* Description: inserts a new piece
|
* inserts a new piece
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Argument pPiece: piece to be inserted
|
* @param pPiece piece to be inserted
|
||||||
* Argument ppOldPiece: [out] indirect pointer to former piece for deallocation
|
* @param ppOldPiece [out] indirect pointer to former piece for deallocation
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_playfield_insertPiece(tetris_playfield_t *pPl,
|
void tetris_playfield_insertPiece(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
tetris_piece_t** ppOldPiece);
|
tetris_piece_t** ppOldPiece);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_collision
|
/**
|
||||||
* Description: detects if piece collides with s.th. at a given position
|
* detects if piece collides with s.th. at a given position
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Argument nColumn: column where the piece should be moved
|
* @param nColumn column where the piece should be moved
|
||||||
* Argument nRow: row where the piece should be moved
|
* @param nRow row where the piece should be moved
|
||||||
* Return value: 1 for collision, 0 otherwise
|
* @return 1 for collision, 0 otherwise
|
||||||
*/
|
*/
|
||||||
uint8_t tetris_playfield_collision(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_collision(tetris_playfield_t *pPl,
|
||||||
int8_t nColumn,
|
int8_t nColumn,
|
||||||
int8_t nRow);
|
int8_t nRow);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_advancePiece
|
/**
|
||||||
* Description: lowers piece by one row or finally docks it
|
* lowers piece by one row or finally docks it
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_playfield_advancePiece(tetris_playfield_t *pPl);
|
void tetris_playfield_advancePiece(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_movePiece
|
/**
|
||||||
* Description: moves piece to the given direction
|
* moves piece to the given direction
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Argument direction: direction (see tetris_playfield_direction_t)
|
* @param direction direction (see tetris_playfield_direction_t)
|
||||||
* Return value: 1 if piece could be moved, 0 otherwise
|
* @return 1 if piece could be moved, 0 otherwise
|
||||||
*/
|
*/
|
||||||
uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl,
|
||||||
tetris_playfield_direction_t direction);
|
tetris_playfield_direction_t direction);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_rotatePiece
|
/**
|
||||||
* Description: rotates piece to the given direction
|
* rotates piece to the given direction
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Argument r: type of rotation (see tetris_piece_rotation_t)
|
* @param r type of rotation (see tetris_piece_rotation_t)
|
||||||
* Return value: 1 if piece could be rotated, 0 otherwise
|
* @return 1 if piece could be rotated, 0 otherwise
|
||||||
*/
|
*/
|
||||||
uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl,
|
uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl,
|
||||||
tetris_piece_rotation_t rotation);
|
tetris_piece_rotation_t rotation);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_removeCompletedLines
|
/**
|
||||||
* Description: removes completed lines (if any) and lowers the dump
|
* removes completed lines (if any) and lowers the dump
|
||||||
* Argument pPl: playfield to perform action on
|
* @param pPl playfield to perform action on
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl);
|
void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
@ -160,68 +163,67 @@ void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl);
|
||||||
* get functions *
|
* get functions *
|
||||||
*****************/
|
*****************/
|
||||||
|
|
||||||
/* Function: tetris_playfield_getWidth
|
/**
|
||||||
* Description: returns the width of the playfield
|
* returns the width of the playfield
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: width of the playfield
|
* @return width of the playfield
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl);
|
int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getHeight
|
/**
|
||||||
* Description: returns the height of the playfield
|
* returns the height of the playfield
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: height of the playfield
|
* @return height of the playfield
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_getHeight(tetris_playfield_t *pPl);
|
int8_t tetris_playfield_getHeight(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getPiece
|
/**
|
||||||
* Description: returns the currently falling piece
|
* returns the currently falling piece
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: pointer to the currently falling piece
|
* @return pointer to the currently falling piece
|
||||||
*/
|
*/
|
||||||
tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl);
|
tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getColumn
|
/**
|
||||||
* Description: returns the column of the currently falling piece
|
* returns the column of the currently falling piece
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: column of the currently falling piece
|
* @return column of the currently falling piece
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl);
|
int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getRow
|
/**
|
||||||
* Description: returns the row of the currently falling piece
|
* returns the row of the currently falling piece
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: row of the currently falling piece
|
* @return row of the currently falling piece
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl);
|
int8_t tetris_playfield_getRow(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getRowMask
|
/**
|
||||||
* Description: returns the row mask relative to nRow
|
* returns the row mask relative to nRow
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: the first 4 bits indicate which lines (relative to nRow)
|
* @return bit mask of removed lines (relative to current position)
|
||||||
* have been removed if we are in status TETRIS_PFS_READY
|
|
||||||
*/
|
*/
|
||||||
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl);
|
uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getStatus
|
/**
|
||||||
* Description: returns the status of the playfield
|
* returns the status of the playfield
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Return value: status of the playfield (see tetris_playfield_status_t)
|
* @return status of the playfield (see tetris_playfield_status_t)
|
||||||
*/
|
*/
|
||||||
tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl);
|
tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_getDumpRow
|
/**
|
||||||
* Description: returns the given row of the dump (as bitmap)
|
* returns the given row of the dump (as bitmap)
|
||||||
* Argument pPl: the playfield we want information from
|
* @param pPl the playfield we want information from
|
||||||
* Argument nRow: the number of the row (0 <= nRow <= 124)
|
* @param nRow the number of the row (0 <= nRow <= 124)
|
||||||
* Return value: bitmap of the requested row (LSB is leftmost column)
|
* @return bitmap of the requested row (LSB is leftmost column)
|
||||||
*/
|
*/
|
||||||
uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
||||||
int8_t nRow);
|
int8_t nRow);
|
||||||
|
@ -229,26 +231,25 @@ uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl,
|
||||||
|
|
||||||
#ifdef GAME_BASTET
|
#ifdef GAME_BASTET
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictDeepestRow
|
/**
|
||||||
* Description: returns the deepest possible row of a given piece
|
* returns the deepest possible row for a given piece
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
* @param pPl the playfield on which we want to test a piece
|
||||||
* Argument pPiece: the piece which should be tested
|
* @param pPiece the piece which should be tested
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
* @param nColumn the column where the piece should be dropped
|
||||||
* Return value: the row of the piece (playfield compliant coordinates)
|
* @return the row of the piece (playfield compliant coordinates)
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
|
int8_t tetris_playfield_predictDeepestRow(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
int8_t nColumn);
|
int8_t nColumn);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictCompleteLines
|
/**
|
||||||
* Description: predicts the number of complete lines for a piece at
|
* predicts the number of complete lines for a piece at a given column
|
||||||
* a given column
|
* @param pPl the playfield on which we want to test a piece
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
* @param pPiece the piece which should be tested
|
||||||
* Argument pPiece: the piece which should be tested
|
* @param nRow the row where the given piece collides
|
||||||
* Argument nRow: the row where the given piece collides
|
* @param nColumn the column where the piece should be dropped
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
* @return amount of complete lines
|
||||||
* Return value: amount of complete lines
|
|
||||||
*/
|
*/
|
||||||
int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
||||||
tetris_piece_t *pPiece,
|
tetris_piece_t *pPiece,
|
||||||
|
@ -256,16 +257,14 @@ int8_t tetris_playfield_predictCompleteLines(tetris_playfield_t *pPl,
|
||||||
int8_t nColumn);
|
int8_t nColumn);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictBottomRow
|
/**
|
||||||
* Description: predicts the appearance of the bottom row of the
|
* predicts appearance of the bottom row and initializes an iterator structure
|
||||||
* playfield (for a piece at a given column) and
|
* @param pIt a pointer to an iterator which should be initialized
|
||||||
* initializes an iterator structure
|
* @param pPl the playfield on which we want to test a piece
|
||||||
* Argument pIt: a pointer to an iterator which should be initialized
|
* @param pPiece the piece which should be tested
|
||||||
* Argument pPl: the playfield on which we want to test a piece
|
* @param nRow the row where the given piece collides
|
||||||
* Argument pPiece: the piece which should be tested
|
* @param nColumn the column where the piece should be dropped
|
||||||
* Argument nRow: the row where the given piece collides
|
* @return appearance of the predicted dump row at the bottom as bit mask
|
||||||
* Argument nColumn: the column where the piece should be dropped
|
|
||||||
* Return value: appearance of the predicted dump row at the bottom
|
|
||||||
*/
|
*/
|
||||||
uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
||||||
tetris_playfield_t *pPl,
|
tetris_playfield_t *pPl,
|
||||||
|
@ -274,11 +273,10 @@ uint16_t* tetris_playfield_predictBottomRow(tetris_playfield_iterator_t *pIt,
|
||||||
int8_t nColumn);
|
int8_t nColumn);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_playfield_predictNextRow
|
/**
|
||||||
* Description: predicts the appearance of the next row of the playfield
|
* predicts appearance of the next row of the playfield (for a given iterator)
|
||||||
* (for a given iterator)
|
* @param pIt a pointer to a dump iterator
|
||||||
* Argument pIt: a pointer to a dump iterator
|
* @return appearance of next predicted row (or NULL -> no next line)
|
||||||
* Return value: appearance of next predicted row (or NULL -> no next line)
|
|
||||||
*/
|
*/
|
||||||
uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt);
|
uint16_t* tetris_playfield_predictNextRow(tetris_playfield_iterator_t *pIt);
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
|
@ -3,60 +3,202 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "../../config.h"
|
#include "../../autoconf.h"
|
||||||
#include "../../pixel.h"
|
#include "../../pixel.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
#include "../../scrolltext/scrolltext.h"
|
#include "../../scrolltext/scrolltext.h"
|
||||||
#include "logic.h"
|
#include "variants.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "playfield.h"
|
#include "playfield.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
|
|
||||||
#define WAIT(ms) wait(ms)
|
#define WAIT(ms) wait(ms)
|
||||||
|
|
||||||
#ifdef GAME_TETRIS_FP
|
/**
|
||||||
uint8_t tetris_screendir;
|
* \defgroup TetrisViewDefinesPrivate View: Internal constants
|
||||||
#endif
|
*/
|
||||||
|
/*@{*/
|
||||||
void (*setpixel_wrapper)(pixel p, unsigned char value);
|
|
||||||
|
|
||||||
|
|
||||||
/***********
|
/***********
|
||||||
* defines *
|
* defines *
|
||||||
***********/
|
***********/
|
||||||
|
|
||||||
// how often should the border blink (to indicate level up)
|
/** how often should the border blink (to indicate level up) */
|
||||||
#define TETRIS_VIEW_BORDER_BLINK_COUNT 2
|
#define TETRIS_VIEW_BORDER_BLINK_COUNT 2
|
||||||
// amount of time (in ms) between border color changes
|
/** amount of time (in ms) between border color changes */
|
||||||
#define TETRIS_VIEW_BORDER_BLINK_DELAY 100
|
#define TETRIS_VIEW_BORDER_BLINK_DELAY 100
|
||||||
|
|
||||||
// how often should the lines blink when they get removed
|
/** how often should the lines blink when they get removed */
|
||||||
#define TETRIS_VIEW_LINE_BLINK_COUNT 3
|
#define TETRIS_VIEW_LINE_BLINK_COUNT 3
|
||||||
// amount of time (in ms) between line color changes
|
/** amount of time (in ms) between line color changes */
|
||||||
#define TETRIS_VIEW_LINE_BLINK_DELAY 75
|
#define TETRIS_VIEW_LINE_BLINK_DELAY 75
|
||||||
|
|
||||||
// colors of game elements
|
/** color of space */
|
||||||
#define TETRIS_VIEW_COLORSPACE 0
|
#define TETRIS_VIEW_COLORSPACE 0
|
||||||
|
/** color of border */
|
||||||
#define TETRIS_VIEW_COLORBORDER 1
|
#define TETRIS_VIEW_COLORBORDER 1
|
||||||
|
/** color of fading lines */
|
||||||
#define TETRIS_VIEW_COLORFADE 2
|
#define TETRIS_VIEW_COLORFADE 2
|
||||||
|
/** color of a piece */
|
||||||
#define TETRIS_VIEW_COLORPIECE 3
|
#define TETRIS_VIEW_COLORPIECE 3
|
||||||
|
/** color of pause mode */
|
||||||
#define TETRIS_VIEW_COLORPAUSE 1
|
#define TETRIS_VIEW_COLORPAUSE 1
|
||||||
|
/** color of line counter */
|
||||||
#define TETRIS_VIEW_COLORCOUNTER 2
|
#define TETRIS_VIEW_COLORCOUNTER 2
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GAME_TETRIS_FP
|
||||||
|
#if NUM_ROWS < NUM_COLS
|
||||||
|
#define VIEWCOLS NUM_ROWS
|
||||||
|
#define VIEWROWS NUM_ROWS
|
||||||
|
#elif NUM_ROWS > NUM_COLS
|
||||||
|
#define VIEWCOLS NUM_COLS
|
||||||
|
#define VIEWROWS NUM_COLS
|
||||||
|
#else
|
||||||
|
#define VIEWCOLS NUM_COLS
|
||||||
|
#define VIEWROWS NUM_ROWS
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define VIEWCOLS NUM_COLS
|
||||||
|
#define VIEWROWS NUM_ROWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if VIEWROWS >= 20
|
||||||
|
#define TETRIS_VIEW_YOFFSET_DUMP ((VIEWROWS - 20) / 2)
|
||||||
|
#define TETRIS_VIEW_HEIGHT_DUMP 20
|
||||||
|
#else
|
||||||
|
#define TETRIS_VIEW_YOFFSET_DUMP 0
|
||||||
|
#define TETRIS_VIEW_HEIGHT_DUMP VIEWROWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if VIEWCOLS >= 16
|
||||||
|
#define TETRIS_VIEW_XOFFSET_DUMP (((VIEWCOLS - 16) / 2) + 1)
|
||||||
|
#define TETRIS_VIEW_WIDTH_DUMP 10
|
||||||
|
|
||||||
|
#if VIEWROWS >= 16
|
||||||
|
#define TETRIS_VIEW_XOFFSET_COUNTER \
|
||||||
|
(TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP + 1)
|
||||||
|
#define TETRIS_VIEW_YOFFSET_COUNT100 ((VIEWCOLS - 14) / 2)
|
||||||
|
#define TETRIS_VIEW_YOFFSET_COUNT10 (TETRIS_VIEW_YOFFSET_COUNT100 + 2)
|
||||||
|
#define TETRIS_VIEW_YOFFSET_COUNT1 (TETRIS_VIEW_YOFFSET_COUNT10 + 4)
|
||||||
|
|
||||||
|
#define TETRIS_VIEW_XOFFSET_PREVIEW \
|
||||||
|
(TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP + 1)
|
||||||
|
#define TETRIS_VIEW_YOFFSET_PREVIEW (TETRIS_VIEW_YOFFSET_COUNT1 + 4)
|
||||||
|
#elif VIEWROWS < 16 && VIEWROWS >= 4
|
||||||
|
#define TETRIS_VIEW_XOFFSET_PREVIEW \
|
||||||
|
(TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP + 1)
|
||||||
|
#define TETRIS_VIEW_YOFFSET_PREVIEW ((VIEWROWS - 4) / 2)
|
||||||
|
#endif
|
||||||
|
#elif (VIEWCOLS < 16) && (VIEWCOLS >= 12)
|
||||||
|
#define TETRIS_VIEW_XOFFSET_DUMP ((VIEWCOLS - 10) / 2)
|
||||||
|
#define TETRIS_VIEW_WIDTH_DUMP 10
|
||||||
|
#elif VIEWCOLS == 11
|
||||||
|
#define TETRIS_VIEW_XOFFSET_DUMP 1
|
||||||
|
#define TETRIS_VIEW_WIDTH_DUMP 10
|
||||||
|
#else
|
||||||
|
#define TETRIS_VIEW_XOFFSET_DUMP 0
|
||||||
|
#define TETRIS_VIEW_WIDTH_DUMP VIEWCOLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisViewNoInterface View: Internal non-interface functions
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
* non-interface functions *
|
* non-interface functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_view_getPieceColor
|
/**
|
||||||
* Description: helper function to dim the piece color if game is paused
|
* setpixel replacement which may transform the pixel coordinates
|
||||||
* Argument pV: pointer to the view whose pause status is of interest
|
* @param pV pointer to the view we want to draw on
|
||||||
* Return value: void
|
* @param x x-coordinate of the pixel
|
||||||
|
* @param y y-coordinate of the pixel
|
||||||
|
* @param nColor Color of the pixel
|
||||||
*/
|
*/
|
||||||
uint8_t tetris_view_getPieceColor (tetris_view_t *pV)
|
void tetris_view_setpixel(tetris_orientation_t nOrientation,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t nColor)
|
||||||
|
{
|
||||||
|
x = VIEWCOLS - 1 - x;
|
||||||
|
|
||||||
|
switch (nOrientation)
|
||||||
|
{
|
||||||
|
case TETRIS_ORIENTATION_0:
|
||||||
|
setpixel((pixel){x, y}, nColor);
|
||||||
|
break;
|
||||||
|
case TETRIS_ORIENTATION_90:
|
||||||
|
setpixel((pixel){y, VIEWCOLS - 1 - x}, nColor);
|
||||||
|
break;
|
||||||
|
case TETRIS_ORIENTATION_180:
|
||||||
|
setpixel((pixel){VIEWCOLS - 1 - x, VIEWROWS - 1 - y}, nColor);
|
||||||
|
break;
|
||||||
|
case TETRIS_ORIENTATION_270:
|
||||||
|
setpixel((pixel){VIEWROWS - 1 - y, x}, nColor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draws a horizontal line
|
||||||
|
* @param nOrient orientation of the view
|
||||||
|
* @param x1 first x-coordinate of the line
|
||||||
|
* @param x2 second x-coordinate of the line
|
||||||
|
* @param y y-coordinate of the line
|
||||||
|
* @param nColor Color of the line
|
||||||
|
*/
|
||||||
|
void tetris_view_drawHLine(tetris_orientation_t nOrient,
|
||||||
|
uint8_t x1,
|
||||||
|
uint8_t x2,
|
||||||
|
uint8_t y,
|
||||||
|
uint8_t nColor)
|
||||||
|
{
|
||||||
|
assert(x1 <= x2);
|
||||||
|
|
||||||
|
for (uint8_t x = x1; x <= x2; ++x)
|
||||||
|
{
|
||||||
|
tetris_view_setpixel(nOrient, x, y, nColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draws a vertical line
|
||||||
|
* @param nOrient orientation of the view
|
||||||
|
* @param x x-coordinate of the line
|
||||||
|
* @param y1 first y-coordinate of the line
|
||||||
|
* @param y2 second y-coordinate of the line
|
||||||
|
* @param nColor Color of the line
|
||||||
|
*/
|
||||||
|
void tetris_view_drawVLine(tetris_orientation_t nOrient,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y1,
|
||||||
|
uint8_t y2,
|
||||||
|
uint8_t nColor)
|
||||||
|
{
|
||||||
|
assert(y1 <= y2);
|
||||||
|
|
||||||
|
for (uint8_t y = y1; y <= y2; ++y)
|
||||||
|
{
|
||||||
|
tetris_view_setpixel(nOrient, x, y, nColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper function to dim the piece color if game is paused
|
||||||
|
* @param pV pointer to the view whose pause status is of interest
|
||||||
|
*/
|
||||||
|
uint8_t tetris_view_getPieceColor(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
if (pV->modeCurrent == TETRIS_VIMO_RUNNING)
|
if (pV->modeCurrent == TETRIS_VIMO_RUNNING)
|
||||||
{
|
{
|
||||||
|
@ -69,10 +211,9 @@ uint8_t tetris_view_getPieceColor (tetris_view_t *pV)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_drawDump
|
/**
|
||||||
* Description: redraws the dump and the falling piece (if necessary)
|
* redraws the dump and the falling piece (if necessary)
|
||||||
* Argument pV: pointer to the view on which the dump should be drawn
|
* @param pV pointer to the view on which the dump should be drawn
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_drawDump(tetris_view_t *pV)
|
void tetris_view_drawDump(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
|
@ -82,24 +223,15 @@ void tetris_view_drawDump(tetris_view_t *pV)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tetris_orientation_t nOrient =
|
||||||
|
pV->pVariantMethods->getOrientation(pV->pVariant);
|
||||||
|
|
||||||
int8_t nPieceRow = tetris_playfield_getRow(pV->pPl);
|
int8_t nPieceRow = tetris_playfield_getRow(pV->pPl);
|
||||||
|
|
||||||
// only redraw dump completely if the view mode has been changed
|
|
||||||
int8_t nStartRow;
|
|
||||||
if (pV->modeCurrent == pV->modeOld)
|
|
||||||
{
|
|
||||||
nStartRow = ((nPieceRow + 3) < 16) ? (nPieceRow + 3) : 15;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nStartRow = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t nRowMap;
|
uint16_t nRowMap;
|
||||||
uint16_t nElementMask;
|
uint16_t nElementMask;
|
||||||
|
|
||||||
tetris_playfield_status_t status = tetris_playfield_getStatus(pV->pPl);
|
tetris_playfield_status_t status = tetris_playfield_getStatus(pV->pPl);
|
||||||
for (int8_t nRow = nStartRow; nRow >= 0; --nRow)
|
for (int8_t nRow = TETRIS_VIEW_HEIGHT_DUMP - 1; nRow >= 0; --nRow)
|
||||||
{
|
{
|
||||||
nRowMap = tetris_playfield_getDumpRow(pV->pPl, nRow);
|
nRowMap = tetris_playfield_getDumpRow(pV->pPl, nRow);
|
||||||
|
|
||||||
|
@ -126,7 +258,7 @@ void tetris_view_drawDump(tetris_view_t *pV)
|
||||||
nPieceMap >>= -nColumn;
|
nPieceMap >>= -nColumn;
|
||||||
}
|
}
|
||||||
// cut off unwanted stuff
|
// cut off unwanted stuff
|
||||||
nPieceMap &= 0x03ff;
|
// nPieceMap &= 0x03ff;
|
||||||
// finally embed piece into the view
|
// finally embed piece into the view
|
||||||
nRowMap |= nPieceMap;
|
nRowMap |= nPieceMap;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +266,7 @@ void tetris_view_drawDump(tetris_view_t *pV)
|
||||||
|
|
||||||
nElementMask = 0x0001;
|
nElementMask = 0x0001;
|
||||||
|
|
||||||
for (int8_t x = 0; x < 10; ++x)
|
for (int8_t x = 0; x < TETRIS_VIEW_WIDTH_DUMP; ++x)
|
||||||
{
|
{
|
||||||
unsigned char nColor;
|
unsigned char nColor;
|
||||||
if ((nRowMap & nElementMask) != 0)
|
if ((nRowMap & nElementMask) != 0)
|
||||||
|
@ -145,21 +277,24 @@ void tetris_view_drawDump(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
nColor = TETRIS_VIEW_COLORSPACE;
|
nColor = TETRIS_VIEW_COLORSPACE;
|
||||||
}
|
}
|
||||||
setpixel_wrapper((pixel){14-x,nRow}, nColor);
|
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_DUMP + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + nRow, nColor);
|
||||||
nElementMask <<= 1;
|
nElementMask <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TETRIS_VIEW_XOFFSET_PREVIEW
|
||||||
/* Function: tetris_view_drawPreviewPiece
|
/**
|
||||||
* Description: redraws the preview window
|
* redraws the preview window
|
||||||
* Argument pV: pointer to the view on which the piece should be drawn
|
* @param pV pointer to the view on which the piece should be drawn
|
||||||
* Argmument pPc: pointer to the piece for the preview window (may be NULL)
|
* @param pPc pointer to the piece for the preview window (may be NULL)
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
|
void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
|
||||||
{
|
{
|
||||||
|
tetris_orientation_t nOrient =
|
||||||
|
pV->pVariantMethods->getOrientation(pV->pVariant);
|
||||||
|
|
||||||
if (pPc != NULL)
|
if (pPc != NULL)
|
||||||
{
|
{
|
||||||
uint8_t nColor;
|
uint8_t nColor;
|
||||||
|
@ -171,6 +306,7 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// an iconized "P"
|
||||||
nPieceMap = 0x26a6;
|
nPieceMap = 0x26a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +322,10 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
|
||||||
{
|
{
|
||||||
nColor = TETRIS_VIEW_COLORSPACE;
|
nColor = TETRIS_VIEW_COLORSPACE;
|
||||||
}
|
}
|
||||||
setpixel_wrapper((pixel) {3 - x, y + 6}, nColor);
|
tetris_view_setpixel(nOrient,
|
||||||
|
TETRIS_VIEW_XOFFSET_PREVIEW + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_PREVIEW + y,
|
||||||
|
nColor);
|
||||||
nElementMask <<= 1;
|
nElementMask <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,74 +336,153 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
|
||||||
{
|
{
|
||||||
for (uint8_t x = 0; x < 4; ++x)
|
for (uint8_t x = 0; x < 4; ++x)
|
||||||
{
|
{
|
||||||
setpixel_wrapper((pixel) {3 - x, y + 6}, TETRIS_VIEW_COLORSPACE);
|
tetris_view_setpixel(nOrient,
|
||||||
|
TETRIS_VIEW_XOFFSET_PREVIEW + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_PREVIEW + y,
|
||||||
|
TETRIS_VIEW_COLORSPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
/* Function: tetris_view_drawBorders
|
* draws borders in the given color
|
||||||
* Description: draws borders in the given color
|
* @param pV pointer to the view on which the borders should be drawn
|
||||||
* Argument nColor: the color for the border
|
* @param nColor the color for the border
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_drawBorders(uint8_t nColor)
|
void tetris_view_drawBorders(tetris_view_t *pV,
|
||||||
|
uint8_t nColor)
|
||||||
{
|
{
|
||||||
// drawing playfield
|
tetris_orientation_t nOrient =
|
||||||
uint8_t x, y;
|
pV->pVariantMethods->getOrientation(pV->pVariant);
|
||||||
for (y = 0; y < 16; ++y)
|
|
||||||
|
#if TETRIS_VIEW_YOFFSET_DUMP != 0
|
||||||
|
// fill upper space if required
|
||||||
|
for (uint8_t y = 0; y < TETRIS_VIEW_YOFFSET_DUMP; ++y)
|
||||||
{
|
{
|
||||||
setpixel_wrapper((pixel){4, y}, nColor);
|
tetris_view_drawHLine(nOrient, 0, VIEWCOLS - 1, y, nColor);
|
||||||
setpixel_wrapper((pixel){15, y}, nColor);
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if VIEWROWS > TETRIS_VIEW_HEIGHT_DUMP
|
||||||
|
// fill lower space if required
|
||||||
|
uint8_t y = TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP;
|
||||||
|
for (; y < VIEWROWS; ++y)
|
||||||
|
{
|
||||||
|
tetris_view_drawHLine(nOrient, 0, VIEWCOLS - 1, y, nColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TETRIS_VIEW_XOFFSET_DUMP != 0
|
||||||
|
// fill left space if required
|
||||||
|
for (uint8_t x = 0; x < TETRIS_VIEW_XOFFSET_DUMP; ++x)
|
||||||
|
{
|
||||||
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if VIEWCOLS > 16
|
||||||
|
// fill right space if required
|
||||||
|
uint8_t x = TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP + 5;
|
||||||
|
for (; x < VIEWCOLS; ++x)
|
||||||
|
{
|
||||||
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TETRIS_VIEW_XOFFSET_COUNTER
|
||||||
|
tetris_view_drawVLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER - 1,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
|
||||||
|
for (uint8_t x = TETRIS_VIEW_XOFFSET_COUNTER;
|
||||||
|
x < TETRIS_VIEW_XOFFSET_COUNTER + 3; ++x)
|
||||||
|
{
|
||||||
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_COUNT100 - 1, nColor);
|
||||||
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0; y < 5; ++y)
|
tetris_view_drawVLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + 3,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP, TETRIS_VIEW_YOFFSET_COUNT1 + 3, nColor);
|
||||||
|
|
||||||
|
tetris_view_drawVLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + 3,
|
||||||
|
TETRIS_VIEW_YOFFSET_PREVIEW + 4,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
|
||||||
|
tetris_view_drawHLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER,
|
||||||
|
TETRIS_VIEW_XOFFSET_COUNTER + 3, TETRIS_VIEW_YOFFSET_COUNT100 + 1,
|
||||||
|
nColor);
|
||||||
|
|
||||||
|
tetris_view_drawHLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER,
|
||||||
|
TETRIS_VIEW_XOFFSET_COUNTER + 3, TETRIS_VIEW_YOFFSET_COUNT10 + 3,
|
||||||
|
nColor);
|
||||||
|
|
||||||
|
tetris_view_drawHLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER,
|
||||||
|
TETRIS_VIEW_XOFFSET_COUNTER + 3, TETRIS_VIEW_YOFFSET_COUNT1 + 3,
|
||||||
|
nColor);
|
||||||
|
#elif defined TETRIS_VIEW_XOFFSET_PREVIEW
|
||||||
|
tetris_view_drawVLine(nOrient, TETRIS_VIEW_XOFFSET_PREVIEW - 1,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
|
||||||
|
for (uint8_t x = TETRIS_VIEW_XOFFSET_PREVIEW;
|
||||||
|
x < TETRIS_VIEW_XOFFSET_PREVIEW + 4; ++x)
|
||||||
{
|
{
|
||||||
for (x = 0; x <= 3; ++x)
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
{
|
TETRIS_VIEW_YOFFSET_PREVIEW - 1, nColor);
|
||||||
if ((y < 1 || y > 3) || (x < 1 || y > 3))
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
|
||||||
{
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
setpixel_wrapper((pixel){x, y}, nColor);
|
|
||||||
setpixel_wrapper((pixel){x, y + 11}, nColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#elif TETRIS_VIEW_WIDTH_DUMP < VIEWCOLS
|
||||||
|
for (uint8_t x = TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP;
|
||||||
|
x < VIEWCOLS; ++x)
|
||||||
|
{
|
||||||
|
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_blinkBorders
|
/**
|
||||||
* Description: lets the borders blink to notify player of a level change
|
* lets the borders blink to notify player of a level change
|
||||||
* Return value: void
|
* @param pV pointer to the view whose borders should blink
|
||||||
*/
|
*/
|
||||||
void tetris_view_blinkBorders()
|
void tetris_view_blinkBorders(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < TETRIS_VIEW_BORDER_BLINK_COUNT; ++i)
|
for (uint8_t i = 0; i < TETRIS_VIEW_BORDER_BLINK_COUNT; ++i)
|
||||||
{
|
{
|
||||||
tetris_view_drawBorders(TETRIS_VIEW_COLORPIECE);
|
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORPIECE);
|
||||||
WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
||||||
tetris_view_drawBorders(TETRIS_VIEW_COLORBORDER);
|
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORBORDER);
|
||||||
WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_blinkLines
|
/**
|
||||||
* Description: lets complete lines blink to emphasize their removal
|
* lets complete lines blink to emphasize their removal
|
||||||
* Argmument pPl: pointer to the playfield whose complete lines should blink
|
* @param pPl pointer to the view whose complete lines should blink
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
|
void tetris_view_blinkLines(tetris_view_t *pV)
|
||||||
|
|
||||||
void tetris_view_blinkLines(tetris_playfield_t *pPl)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// reduce necessity of pointer arithmetic
|
// reduce necessity of pointer arithmetic
|
||||||
int8_t nRow = tetris_playfield_getRow(pPl);
|
int8_t nRow = tetris_playfield_getRow(pV->pPl);
|
||||||
uint8_t nRowMask = tetris_playfield_getRowMask(pPl);
|
uint8_t nRowMask = tetris_playfield_getRowMask(pV->pPl);
|
||||||
|
|
||||||
|
tetris_orientation_t nOrient =
|
||||||
|
pV->pVariantMethods->getOrientation(pV->pVariant);
|
||||||
|
|
||||||
// don't try to draw below the border
|
// don't try to draw below the border
|
||||||
int8_t nDeepestRowOffset = ((nRow + 3) < tetris_playfield_getHeight(pPl) ?
|
int8_t nDeepestRowOffset = ((nRow + 3) < TETRIS_VIEW_HEIGHT_DUMP ?
|
||||||
3 : tetris_playfield_getHeight(pPl) - (nRow + 1));
|
3 : TETRIS_VIEW_HEIGHT_DUMP - (nRow + 1));
|
||||||
|
|
||||||
// this loop controls how often the lines should blink
|
// this loop controls how often the lines should blink
|
||||||
for (uint8_t i = 0; i < TETRIS_VIEW_LINE_BLINK_COUNT; ++i)
|
for (uint8_t i = 0; i < TETRIS_VIEW_LINE_BLINK_COUNT; ++i)
|
||||||
|
@ -285,7 +503,11 @@ void tetris_view_blinkLines(tetris_playfield_t *pPl)
|
||||||
|
|
||||||
uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE
|
uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE
|
||||||
: TETRIS_VIEW_COLORPIECE);
|
: TETRIS_VIEW_COLORPIECE);
|
||||||
setpixel_wrapper((pixel){14 - x, y}, nColor);
|
// setpixel((pixel){14 - x, y}, nColor);
|
||||||
|
tetris_view_setpixel(nOrient,
|
||||||
|
TETRIS_VIEW_XOFFSET_DUMP + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_DUMP + y,
|
||||||
|
nColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,92 +518,122 @@ void tetris_view_blinkLines(tetris_playfield_t *pPl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_showLineNumbers
|
#ifdef TETRIS_VIEW_XOFFSET_COUNTER
|
||||||
* Description: displays completed Lines (0-99)
|
/**
|
||||||
* Argmument pV: pointer to the view
|
* displays completed Lines (0-99)
|
||||||
* Return value: void
|
* @param pV pointer to the view
|
||||||
*/
|
*/
|
||||||
void tetris_view_showLineNumbers(tetris_view_t *pV)
|
void tetris_view_showLineNumbers(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
tetris_orientation_t nOrient =
|
||||||
|
pV->pVariantMethods->getOrientation(pV->pVariant);
|
||||||
|
|
||||||
// get number of completed lines
|
// get number of completed lines
|
||||||
uint16_t nLines = tetris_logic_getLines(pV->pLogic);
|
uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);
|
||||||
|
|
||||||
// get decimal places
|
// get decimal places
|
||||||
int8_t nOnes = nLines % 10;
|
int8_t nOnes = nLines % 10;
|
||||||
int8_t nTens = (nLines / 10) % 10;
|
int8_t nTens = (nLines / 10) % 10;
|
||||||
|
int8_t nHundreds = (nLines / 100) % 10;
|
||||||
|
|
||||||
// draws the decimal places as 3x3 squares with 9 pixels
|
// draws the decimal places as 3x3 squares with 9 pixels
|
||||||
for (int i = 0, x = 1, y = 1; i < 9; ++i)
|
for (int i = 0, x = 0, y = 0; i < 9; ++i)
|
||||||
{
|
{
|
||||||
// pick drawing color
|
// pick drawing color for the ones
|
||||||
uint8_t nOnesPen = nOnes > i ?
|
uint8_t nOnesPen = nOnes > i ?
|
||||||
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
||||||
|
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_COUNT1 + y, nOnesPen);
|
||||||
|
|
||||||
|
// pick drawing color for the tens
|
||||||
uint8_t nTensPen = nTens > i ?
|
uint8_t nTensPen = nTens > i ?
|
||||||
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
||||||
// wrap lines if required
|
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
|
||||||
if ((x % 4) == 0)
|
TETRIS_VIEW_YOFFSET_COUNT10 + y, nTensPen);
|
||||||
|
|
||||||
|
// a maximum of 399 lines can be displayed
|
||||||
|
if (i < 3)
|
||||||
{
|
{
|
||||||
y++;
|
// pick drawing color for the hundreds
|
||||||
x = 1;
|
uint8_t nHundredsPen = nHundreds > i ?
|
||||||
|
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
|
||||||
|
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
|
||||||
|
TETRIS_VIEW_YOFFSET_COUNT100 + y, nHundredsPen);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap lines if required
|
||||||
|
if ((++x % 3) == 0)
|
||||||
|
{
|
||||||
|
++y;
|
||||||
|
x = 0;
|
||||||
}
|
}
|
||||||
// ones
|
|
||||||
setpixel_wrapper((pixel){x, y}, nOnesPen);
|
|
||||||
// tens (increment x, add vertical offset for lower part of the border)
|
|
||||||
setpixel_wrapper((pixel){x++, y + 11}, nTensPen);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unpacks the champion's initials from the uint16_t packed form
|
||||||
|
* @param nHighscoreName the champion's initials packed into a uint16_t
|
||||||
|
* @param pszName pointer to an array of char for the unpacked initials
|
||||||
|
*/
|
||||||
|
void tetris_view_formatHighscoreName(uint16_t nHighscoreName,
|
||||||
|
char *pszName)
|
||||||
|
{
|
||||||
|
pszName[0] = ((nHighscoreName >> 10) & 0x1F) + 65;
|
||||||
|
if (pszName[0] == '_')
|
||||||
|
{
|
||||||
|
pszName[0] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
pszName[1] = ((nHighscoreName >> 5) & 0x1F) + 65;
|
||||||
|
if (pszName[1] == '_')
|
||||||
|
{
|
||||||
|
pszName[1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
pszName[2] = (nHighscoreName & 0x1F) + 65;
|
||||||
|
if (pszName[2] == '_')
|
||||||
|
{
|
||||||
|
pszName[2] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
pszName[3] = '\0';
|
||||||
|
}
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
/****************************
|
/****************************
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
****************************/
|
****************************/
|
||||||
|
|
||||||
/* Function: tetris_view_construct
|
tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods,
|
||||||
* Description: constructs a view for André's borg
|
void *pVariantData,
|
||||||
* Argument pPl: pointer to logic object which should be observed
|
tetris_playfield_t *pPl)
|
||||||
* Argument pPl: pointer to playfield which should be observed
|
|
||||||
* Return value: pointer to a newly created view
|
|
||||||
*/
|
|
||||||
tetris_view_t *tetris_view_construct(tetris_logic_t *pLogic,
|
|
||||||
tetris_playfield_t *pPl,
|
|
||||||
uint8_t nFirstPerson)
|
|
||||||
{
|
{
|
||||||
// memory allocation
|
// memory allocation
|
||||||
assert((pLogic != NULL) && (pPl != NULL));
|
assert((pVariantData != NULL) && (pPl != NULL));
|
||||||
tetris_view_t *pView =
|
tetris_view_t *pView =
|
||||||
(tetris_view_t *) malloc(sizeof(tetris_view_t));
|
(tetris_view_t *) malloc(sizeof(tetris_view_t));
|
||||||
assert(pView != NULL);
|
assert(pView != NULL);
|
||||||
|
|
||||||
// init
|
// init
|
||||||
memset(pView, 0, sizeof(tetris_view_t));
|
memset(pView, 0, sizeof(tetris_view_t));
|
||||||
pView->pLogic = pLogic;
|
pView->pVariantMethods = pVarMethods;
|
||||||
|
pView->pVariant = pVariantData;
|
||||||
pView->pPl = pPl;
|
pView->pPl = pPl;
|
||||||
pView->modeCurrent = TETRIS_VIMO_RUNNING;
|
pView->modeCurrent = pView->modeOld = TETRIS_VIMO_RUNNING;
|
||||||
pView->modeOld = TETRIS_VIMO_RUNNING;
|
|
||||||
|
|
||||||
#ifdef GAME_TETRIS_FP
|
|
||||||
// set setpixel wrapper
|
|
||||||
if (nFirstPerson)
|
|
||||||
setpixel_wrapper = tetris_view_setpixel_fp;
|
|
||||||
else
|
|
||||||
setpixel_wrapper = setpixel;
|
|
||||||
#else
|
|
||||||
setpixel_wrapper = setpixel;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// drawing some first stuff
|
// drawing some first stuff
|
||||||
clear_screen(0);
|
clear_screen(0);
|
||||||
tetris_view_drawBorders(TETRIS_VIEW_COLORBORDER);
|
tetris_view_drawBorders(pView, TETRIS_VIEW_COLORBORDER);
|
||||||
|
|
||||||
return pView;
|
return pView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_destruct
|
|
||||||
* Description: destructs a view
|
|
||||||
* Argument pView: pointer to the view which should be destructed
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_destruct(tetris_view_t *pView)
|
void tetris_view_destruct(tetris_view_t *pView)
|
||||||
{
|
{
|
||||||
assert(pView != NULL);
|
assert(pView != NULL);
|
||||||
|
@ -393,27 +645,15 @@ void tetris_view_destruct(tetris_view_t *pView)
|
||||||
* view related functions *
|
* view related functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_view_getDimensions
|
|
||||||
* Description: destructs a view
|
|
||||||
* Argument w: [out] pointer to an int8_t to store the playfield width
|
|
||||||
* Argument h: [out] pointer to an int8_t to store the playfield height
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_getDimensions(int8_t *w,
|
void tetris_view_getDimensions(int8_t *w,
|
||||||
int8_t *h)
|
int8_t *h)
|
||||||
{
|
{
|
||||||
assert((w != NULL) && (h != NULL));
|
assert((w != NULL) && (h != NULL));
|
||||||
*w = 10;
|
*w = TETRIS_VIEW_WIDTH_DUMP;
|
||||||
*h = 16;
|
*h = TETRIS_VIEW_HEIGHT_DUMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_setViewMode
|
|
||||||
* Description: sets the view mode (pause or running)
|
|
||||||
* Argument pV: pointer to the view whose mode should be set
|
|
||||||
* Argument vm: see definition of tetris_view_mode_t
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm)
|
void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm)
|
||||||
{
|
{
|
||||||
pV->modeOld = pV->modeCurrent;
|
pV->modeOld = pV->modeCurrent;
|
||||||
|
@ -421,75 +661,52 @@ void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_update
|
|
||||||
* Description: informs a view about changes in the game
|
|
||||||
* Argument pV: pointer to the view which should be updated
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_update(tetris_view_t *pV)
|
void tetris_view_update(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
assert(pV != NULL);
|
assert(pV != NULL);
|
||||||
|
|
||||||
|
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORBORDER);
|
||||||
|
|
||||||
|
#ifdef TETRIS_VIEW_XOFFSET_PREVIEW
|
||||||
|
// draw preview piece
|
||||||
|
tetris_view_drawPreviewPiece(pV,
|
||||||
|
pV->pVariantMethods->getPreviewPiece(pV->pVariant));
|
||||||
|
#endif
|
||||||
|
|
||||||
// let complete lines blink (if there are any)
|
// let complete lines blink (if there are any)
|
||||||
if (tetris_playfield_getRowMask(pV->pPl) != 0)
|
if (tetris_playfield_getRowMask(pV->pPl) != 0)
|
||||||
{
|
{
|
||||||
tetris_view_blinkLines(pV->pPl);
|
tetris_view_blinkLines(pV);
|
||||||
tetris_view_showLineNumbers(pV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw preview piece
|
#ifdef TETRIS_VIEW_XOFFSET_COUNTER
|
||||||
tetris_view_drawPreviewPiece(pV, tetris_logic_getPreviewPiece(pV->pLogic));
|
// update line counter
|
||||||
|
tetris_view_showLineNumbers(pV);
|
||||||
|
#endif
|
||||||
|
|
||||||
// draw dump
|
// draw dump
|
||||||
tetris_view_drawDump(pV);
|
tetris_view_drawDump(pV);
|
||||||
|
|
||||||
// visual feedback to inform about a level change
|
// visual feedback to inform about a level change
|
||||||
uint8_t nLevel = tetris_logic_getLevel(pV->pLogic);
|
uint8_t nLevel = pV->pVariantMethods->getLevel(pV->pVariant);
|
||||||
if (nLevel != pV->nOldLevel)
|
if (nLevel != pV->nOldLevel)
|
||||||
{
|
{
|
||||||
tetris_view_blinkBorders();
|
tetris_view_blinkBorders(pV);
|
||||||
pV->nOldLevel = nLevel;
|
pV->nOldLevel = nLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_formatHighscoreName
|
|
||||||
* Description: convert uint16_t into ascii Highscore
|
|
||||||
* (only used internally in view.c)
|
|
||||||
* Argument nHighscoreName: packed integer with highscoreName
|
|
||||||
* Argument pszName: pointer to a char array where result is stored
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_formatHighscoreName(uint16_t nHighscoreName, char *pszName)
|
|
||||||
{
|
|
||||||
pszName[0] = ((nHighscoreName>>10)&0x1F) + 65;
|
|
||||||
if (pszName[0] == '_') pszName[0] = ' ';
|
|
||||||
|
|
||||||
pszName[1] = ((nHighscoreName>> 5)&0x1F) + 65;
|
|
||||||
if (pszName[1] == '_') pszName[1] = ' ';
|
|
||||||
|
|
||||||
pszName[2] = ( nHighscoreName &0x1F) + 65;
|
|
||||||
if (pszName[2] == '_') pszName[2] = ' ';
|
|
||||||
|
|
||||||
pszName[3] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_showResults
|
|
||||||
* Description: shows results after game
|
|
||||||
* Argument pV: pointer to the view which should show the reults
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_showResults(tetris_view_t *pV)
|
void tetris_view_showResults(tetris_view_t *pV)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLTEXT_SUPPORT
|
#ifdef SCROLLTEXT_SUPPORT
|
||||||
char pszResults[54], pszHighscoreName[4];
|
char pszResults[54], pszHighscoreName[4];
|
||||||
uint16_t nScore = tetris_logic_getScore(pV->pLogic);
|
uint16_t nScore = pV->pVariantMethods->getScore(pV->pVariant);
|
||||||
uint16_t nHighscore = tetris_logic_getHighscore(pV->pLogic);
|
uint16_t nHighscore = pV->pVariantMethods->getHighscore(pV->pVariant);
|
||||||
uint16_t nLines = tetris_logic_getLines(pV->pLogic);
|
uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);
|
||||||
|
uint16_t nHighscoreName =
|
||||||
uint16_t nHighscoreName = tetris_logic_getHighscoreName(pV->pLogic);
|
pV->pVariantMethods->getHighscoreName(pV->pVariant);
|
||||||
tetris_view_formatHighscoreName(nHighscoreName, pszHighscoreName);
|
tetris_view_formatHighscoreName(nHighscoreName, pszHighscoreName);
|
||||||
|
|
||||||
if (nScore <= nHighscore)
|
if (nScore <= nHighscore)
|
||||||
|
@ -506,60 +723,3 @@ void tetris_view_showResults(tetris_view_t *pV)
|
||||||
scrolltext(pszResults);
|
scrolltext(pszResults);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef GAME_TETRIS_FP
|
|
||||||
/* Function: tetris_view_setpixel_fp
|
|
||||||
* Description: own setpixel wrapper for first person mode
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_setpixel_fp(pixel p, unsigned char value) {
|
|
||||||
switch (tetris_screendir) {
|
|
||||||
case 0: setpixel(p,value); break;
|
|
||||||
case 1: setpixel((pixel){p.y,15-p.x}, value); break;
|
|
||||||
case 2: setpixel((pixel){15-p.x,15-p.y}, value); break;
|
|
||||||
case 3: setpixel((pixel){15-p.y,p.x}, value); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function: tetris_view_rotate
|
|
||||||
* Description: rotate view for first person mode
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_rotate(void) {
|
|
||||||
unsigned char plane, row, byte, shift, off, sbyte, hrow;
|
|
||||||
unsigned char new_pixmap[NUMPLANE][NUM_ROWS][LINEBYTES];
|
|
||||||
|
|
||||||
tetris_screendir = (tetris_screendir+1)%4;
|
|
||||||
|
|
||||||
// if ( NUM_ROWS != 16 || LINEBYTES != 2 ) return;
|
|
||||||
|
|
||||||
memset(&new_pixmap, 0, sizeof(new_pixmap));
|
|
||||||
for(plane=0; plane<NUMPLANE; plane++){
|
|
||||||
for(row=0;row<NUM_ROWS; row++){
|
|
||||||
for(byte=0;byte<LINEBYTES;byte++){
|
|
||||||
hrow = row%8;
|
|
||||||
shift = 7-hrow;
|
|
||||||
off = ((byte==0)?15:7);
|
|
||||||
sbyte = (row<8) ? 1 : 0;
|
|
||||||
|
|
||||||
new_pixmap[plane][row][1-byte] =
|
|
||||||
(
|
|
||||||
( ((pixmap[plane][off ][sbyte] >> shift)&1) << 7 ) |
|
|
||||||
( ((pixmap[plane][off-1][sbyte] >> shift)&1) << 6 ) |
|
|
||||||
( ((pixmap[plane][off-2][sbyte] >> shift)&1) << 5 ) |
|
|
||||||
( ((pixmap[plane][off-3][sbyte] >> shift)&1) << 4 ) |
|
|
||||||
( ((pixmap[plane][off-4][sbyte] >> shift)&1) << 3 ) |
|
|
||||||
( ((pixmap[plane][off-5][sbyte] >> shift)&1) << 2 ) |
|
|
||||||
( ((pixmap[plane][off-6][sbyte] >> shift)&1) << 1 ) |
|
|
||||||
( ((pixmap[plane][off-7][sbyte] >> shift)&1) << 0 )
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&pixmap, &new_pixmap, sizeof(pixmap));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,16 +2,21 @@
|
||||||
#define TETRIS_VIEW_H_
|
#define TETRIS_VIEW_H_
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "logic.h"
|
#include "variants.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "playfield.h"
|
#include "playfield.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisViewTypes View: Data types
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
* types *
|
* types *
|
||||||
*********/
|
*********/
|
||||||
|
|
||||||
// presentation modes
|
/** presentation modes */
|
||||||
typedef enum tetris_view_mode_t
|
typedef enum tetris_view_mode_t
|
||||||
{
|
{
|
||||||
TETRIS_VIMO_PAUSED,
|
TETRIS_VIMO_PAUSED,
|
||||||
|
@ -19,37 +24,47 @@ typedef enum tetris_view_mode_t
|
||||||
}
|
}
|
||||||
tetris_view_mode_t;
|
tetris_view_mode_t;
|
||||||
|
|
||||||
|
|
||||||
|
/** data structure that drives the view module */
|
||||||
typedef struct tetris_view_t
|
typedef struct tetris_view_t
|
||||||
{
|
{
|
||||||
tetris_logic_t *pLogic; // associated logic object
|
const tetris_variant_t *pVariantMethods; /** variant function pointers */
|
||||||
tetris_playfield_t *pPl; // associated playfield
|
void *pVariant; /** associated variant object */
|
||||||
tetris_view_mode_t modeCurrent; // current presentation mode
|
tetris_playfield_t *pPl; /** associated playfield */
|
||||||
tetris_view_mode_t modeOld; // old presentation mode
|
tetris_view_mode_t modeCurrent; /** current presentation mode */
|
||||||
uint8_t nOldLevel; // helper variable to recognize level changes
|
tetris_view_mode_t modeOld; /** old presentation mode */
|
||||||
|
uint8_t nOldLevel; /** for detecting level changes */
|
||||||
|
tetris_orientation_t nOrient; /** orientation for the playfield */
|
||||||
}
|
}
|
||||||
tetris_view_t;
|
tetris_view_t;
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup TetrisInterface View: Interface functions
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
* construction/destruction *
|
* construction/destruction *
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
/* Function: tetris_view_construct
|
/**
|
||||||
* Description: constructs a view for André's borg
|
* constructs a view for André's borg
|
||||||
* Argument pPl: pointer to logic object which should be observed
|
* @param pVarMethods associated variant method pointers
|
||||||
* Argument pPl: pointer to playfield which should be observed
|
* @param pVariantData pointer to variant data object which should be observed
|
||||||
* Return value: pointer to a newly created view
|
* @param pPl pointer to playfield which should be observed
|
||||||
|
* @return pointer to a newly created view
|
||||||
*/
|
*/
|
||||||
tetris_view_t *tetris_view_construct(tetris_logic_t *pLogic,
|
tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods,
|
||||||
tetris_playfield_t *pPl,
|
void *pVariantData,
|
||||||
uint8_t nFirstPerson);
|
tetris_playfield_t *pPl);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_destruct
|
/**
|
||||||
* Description: destructs a view
|
* destructs a view
|
||||||
* Argument pView: pointer to the view to be destructed
|
* @param pView: pointer to the view to be destructed
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_destruct(tetris_view_t *pView);
|
void tetris_view_destruct(tetris_view_t *pView);
|
||||||
|
|
||||||
|
@ -58,47 +73,37 @@ void tetris_view_destruct(tetris_view_t *pView);
|
||||||
* view related functions *
|
* view related functions *
|
||||||
***************************/
|
***************************/
|
||||||
|
|
||||||
/* Function: tetris_view_getDimensions
|
/**
|
||||||
* Description: destructs a view
|
* destructs a view
|
||||||
* Argument w: [out] pointer to an int8_t to store the playfield width
|
* @param w pointer to an int8_t to store the playfield width
|
||||||
* Argument h: [out] pointer to an int8_t to store the playfield height
|
* @param h pointer to an int8_t to store the playfield height
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_getDimensions(int8_t *w,
|
void tetris_view_getDimensions(int8_t *w,
|
||||||
int8_t *h);
|
int8_t *h);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_setViewMode
|
/**
|
||||||
* Description: sets the view mode (pause or running)
|
* sets the view mode (pause or running)
|
||||||
* Argument pV: pointer to the view whose mode should be set
|
* @param pV pointer to the view whose mode should be set
|
||||||
* Argument vm: see definition of tetris_view_mode_t
|
* @param vm see definition of tetris_view_mode_t
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm);
|
void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_update
|
/**
|
||||||
* Description: informs a view about changes in the game
|
* informs a view about changes in the game
|
||||||
* Argument pV: pointer to the view which should be updated
|
* @param pV pointer to the view which should be updated
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_update(tetris_view_t *pV);
|
void tetris_view_update(tetris_view_t *pV);
|
||||||
|
|
||||||
|
|
||||||
/* Function: tetris_view_showResults
|
/**
|
||||||
* Description: shows results after game
|
* shows results after game
|
||||||
* Argument pV: pointer to the view which should show the reults
|
* @param pV pointer to the view which should show the results
|
||||||
* Return value: void
|
|
||||||
*/
|
*/
|
||||||
void tetris_view_showResults(tetris_view_t *pV);
|
void tetris_view_showResults(tetris_view_t *pV);
|
||||||
|
|
||||||
#ifdef GAME_TETRIS_FP
|
|
||||||
/* Function: tetris_view_setpixel_fp
|
|
||||||
* Description: own setpixel wrapper for first person mode
|
|
||||||
* Return value: void
|
|
||||||
*/
|
|
||||||
void tetris_view_setpixel_fp(pixel p, unsigned char value);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /*TETRIS_VIEW_H_*/
|
#endif /*TETRIS_VIEW_H_*/
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
Loading…
Reference in New Issue