vastly improved modularization and the view is resizable now

This commit is contained in:
Christian Kroll 2010-04-01 03:11:59 +00:00
parent e733427e3b
commit 3f2d878b7d
29 changed files with 2743 additions and 2183 deletions

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
ifeq ($(GAME_TETRIS),y) ifeq ($(GAME_TETRIS_CORE),y)
SUBDIRS += games/tetris SUBDIRS += games/tetris
endif endif

View File

@ -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

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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_*/

View File

@ -6,62 +6,78 @@
#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
@ -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 * * construction/destruction *
*****************************/ ****************************/
/* Function: tetris_input_construct tetris_input_t *tetris_input_construct(void)
* Description: constructs an input object for André's borg
* Return value: pointer to a newly created input object
*/
tetris_input_t *tetris_input_construct()
{ {
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,12 +293,8 @@ 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
if (((cmdJoystick < TETRIS_INCMD_NONE) ?
pIn->nIgnoreCmdCounter[cmdJoystick] : 0) == 0)
{
switch (cmdJoystick) switch (cmdJoystick)
{ {
case TETRIS_INCMD_LEFT: case TETRIS_INCMD_LEFT:
@ -286,8 +303,7 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
// only react if either the current command differs from the // only react if either the current command differs from the
// last one or enough loop cycles have been run on the same // last one or enough loop cycles have been run on the same
// command (for key repeat) // command (for key repeat)
if ((pIn->cmdLast != cmdJoystick) if ((pIn->cmdLast != cmdJoystick) || ((pIn->cmdLast == cmdJoystick)
|| ((pIn->cmdLast == cmdJoystick)
&& (pIn->nRepeatCount >= TETRIS_INPUT_REPEAT_DELAY))) && (pIn->nRepeatCount >= TETRIS_INPUT_REPEAT_DELAY)))
{ {
// reset repeat counter // reset repeat counter
@ -346,12 +362,6 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
break; break;
case TETRIS_INCMD_NONE: 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) // If the game is paused (last command was TETRIS_INCMD_PAUSE)
// we ensure that the variable which holds that last command // we ensure that the variable which holds that last command
// isn't touched. We use this as a flag so that the loop cycle // isn't touched. We use this as a flag so that the loop cycle
@ -374,21 +384,6 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
default: default:
break; break;
} }
}
// 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];
}
}
// reset automatic falling if the player has dropped a piece // reset automatic falling if the player has dropped a piece
if ((cmdReturn == TETRIS_INCMD_DOWN) if ((cmdReturn == TETRIS_INCMD_DOWN)
@ -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;
}
}

View File

@ -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_*/

View File

@ -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;
}

View File

@ -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_*/

View File

@ -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_ */

View File

@ -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,13 +93,8 @@ 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
* Argument shape: the shape of interest
* Return value: void
*/
void tetris_piece_changeShape(tetris_piece_t *pPc,
tetris_piece_shape_t shape) tetris_piece_shape_t shape)
{ {
assert(pPc != NULL); assert(pPc != NULL);
@ -133,13 +104,7 @@ 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
* 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) tetris_piece_angle_t angle)
{ {
assert(pPc != NULL); assert(pPc != NULL);
@ -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);

View File

@ -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_*/

View File

@ -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;

View File

@ -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);

205
games/tetris/tetris_main.c Normal file
View File

@ -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);
}

View File

@ -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_ */

View File

@ -1,6 +0,0 @@
#ifndef TETRISFP_H_
#define TETRISFP_H_
extern uint8_t tetris_screendir;
#endif /* BAST_H_ */

View File

@ -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;
}

View File

@ -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_ */

94
games/tetris/variant_fp.c Normal file
View File

@ -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;
}
}

41
games/tetris/variant_fp.h Normal file
View File

@ -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_*/

273
games/tetris/variant_std.c Normal file
View File

@ -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;
}

186
games/tetris/variant_std.h Normal file
View File

@ -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_*/

142
games/tetris/variants.h Normal file
View File

@ -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_ */

View File

@ -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);
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
}
#elif TETRIS_VIEW_WIDTH_DUMP < VIEWCOLS
for (uint8_t x = TETRIS_VIEW_XOFFSET_DUMP + TETRIS_VIEW_WIDTH_DUMP;
x < VIEWCOLS; ++x)
{ {
if ((y < 1 || y > 3) || (x < 1 || y > 3)) tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
{ TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
setpixel_wrapper((pixel){x, y}, nColor);
setpixel_wrapper((pixel){x, y + 11}, 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

View File

@ -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_*/
/*@}*/