Browse Source

renamed some modules

feature/2015
Christian Kroll 15 years ago
parent
commit
59b18f30d0
  1. 2
      games/tetris/Makefile
  2. 13
      games/tetris/bearing.h
  3. 717
      games/tetris/bucket.c
  4. 295
      games/tetris/bucket.h
  5. 325
      games/tetris/highscore.c
  6. 114
      games/tetris/highscore.h
  7. 31
      games/tetris/input.c
  8. 16
      games/tetris/input.h
  9. 72
      games/tetris/tetris_main.c
  10. 45
      games/tetris/variant_bastet.c
  11. 24
      games/tetris/variant_bastet.h
  12. 10
      games/tetris/variant_fp.c
  13. 2
      games/tetris/variant_fp.h
  14. 14
      games/tetris/variant_std.c
  15. 10
      games/tetris/variant_std.h
  16. 19
      games/tetris/variants.h
  17. 128
      games/tetris/view.c
  18. 24
      games/tetris/view.h

2
games/tetris/Makefile

@ -3,7 +3,7 @@ TOPDIR = ../..
include $(TOPDIR)/defaults.mk
SRC = tetris_main.c piece.c playfield.c view.c input.c highscore.c
SRC = tetris_main.c piece.c bucket.c view.c input.c highscore.c
ifeq ($(GAME_TETRIS),y)
SRC += variant_std.c

13
games/tetris/bearing.h

@ -0,0 +1,13 @@
#ifndef BEARING_H_
#define BEARING_H_
typedef enum tetris_bearing_t
{
TETRIS_BEARING_0,
TETRIS_BEARING_90,
TETRIS_BEARING_180,
TETRIS_BEARING_270
}
tetris_bearing_t;
#endif /* BEARING_H_ */

717
games/tetris/bucket.c

@ -0,0 +1,717 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include "../../autoconf.h"
#include "bucket.h"
#include "piece.h"
/***************************
* non-interface functions *
***************************/
/**
* determines if piece is either hovering or gliding
* @param pBucket the bucket we want information from
* @return TETRIS_PFS_HOVERING or TETRIS_PFS_GLIDING
*/
tetris_bucket_status_t tetris_bucket_hoverStatus(tetris_bucket_t* pBucket)
{
// if the piece touches the dump we ensure that the status is "gliding"
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow + 1))
{
return TETRIS_BUS_GLIDING;
}
// otherwise the status must be "hovering"
else
{
return TETRIS_BUS_HOVERING;
}
}
/****************************
* construction/destruction *
****************************/
tetris_bucket_t *tetris_bucket_construct(int8_t nWidth,
int8_t nHeight)
{
assert((nWidth >= 4) && (nWidth <= 16));
assert((nHeight >= 4) && (nHeight <= 124));
tetris_bucket_t *pBucket =
(tetris_bucket_t *)malloc(sizeof(tetris_bucket_t));
if (pBucket != NULL)
{
// allocating memory for dump array
pBucket->dump = (uint16_t*) calloc(nHeight, sizeof(uint16_t));
if (pBucket->dump != NULL)
{
// setting requested attributes
pBucket->nFirstMatterRow = nHeight - 1;
pBucket->nWidth = nWidth;
pBucket->nHeight = nHeight;
tetris_bucket_reset(pBucket);
return pBucket;
}
else
{
free(pBucket);
pBucket = NULL;
}
}
return NULL;
}
void tetris_bucket_destruct(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
// if memory for the dump array has been allocated, free it
if (pBucket->dump != NULL)
{
free(pBucket->dump);
}
free(pBucket);
}
/*******************************
* bucket related functions *
*******************************/
uint8_t tetris_bucket_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;
}
void tetris_bucket_reset(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
pBucket->pPiece = NULL;
pBucket->nColumn = 0;
pBucket->nRow = 0;
pBucket->nRowMask = 0;
// clear dump if it has been allocated in memory
if (pBucket->dump != NULL)
{
memset(pBucket->dump, 0, pBucket->nHeight);
}
pBucket->status = TETRIS_BUS_READY;
}
int8_t tetris_bucket_getPieceStartPos(tetris_piece_t *pPiece)
{
// set vertical start position (first piece row with matter at pos. 1)
uint16_t nPieceMap = tetris_piece_getBitmap(pPiece);
uint16_t nElementMask = 0xF000;
int8_t nRow = -3;
while ((nPieceMap & nElementMask) == 0)
{
++nRow;
nElementMask >>= 4;
}
if (nRow < 0)
{
++nRow;
}
return nRow;
}
void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
tetris_piece_t** ppOldPiece)
{
assert((pBucket != NULL) && (pPiece != NULL) && (ppOldPiece != NULL));
// a piece can only be inserted in state TETRIS_PFS_READY
assert(pBucket->status == TETRIS_BUS_READY);
// row mask is now meaningless
pBucket->nRowMask = 0;
// replace old piece
*ppOldPiece = pBucket->pPiece;
pBucket->pPiece = pPiece;
// set horizontal start position (in the middle of the top line)
pBucket->nColumn = (pBucket->nWidth - 2) / 2;
// set vertical start position (first piece row with matter at pos. 1)
pBucket->nRow = tetris_bucket_getPieceStartPos(pBucket->pPiece);
// did we already collide with something?
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow) == 1)
{
// game over man, game over!!
pBucket->status = TETRIS_BUS_GAMEOVER;
}
else
{
// bring it on!
pBucket->status = tetris_bucket_hoverStatus(pBucket);
}
}
uint8_t tetris_bucket_collision(tetris_bucket_t *pBucket,
int8_t nColumn,
int8_t nRow)
{
assert(pBucket != NULL);
// only allow coordinates which are within sane ranges
assert((nColumn > -4) && (nColumn < pBucket->nWidth));
assert((nRow > -4) && (nRow < pBucket->nHeight));
// The rows of a piece get compared with the background one by one
// until either a collision occures or all rows are compared. Both the
// piece row and the part of the bucket it covers are represented in
// 4 bits which were singled out from their corresponding uint16_t
// values and are aligned to LSB. In case where a piece overlaps with
// either the left or the right border we "enhance" the bucket part
// via bit shifting and set all bits representing the border to 1.
//
// NOTE: LSB represents the left most position.
uint16_t nPieceMap = tetris_piece_getBitmap(pBucket->pPiece);
uint16_t nBucketPart;
uint16_t nPieceRowMap;
// negative nRow values indicate that the piece hasn't fully entered the
// bucket yet which requires special treatment if the piece overlaps
// with either the left or the right border
if (nRow < 0)
{
uint16_t nBorderMask = 0x0000;
// piece overlaps with left border
if (nColumn < 0)
{
nBorderMask = 0x1111 << (-nColumn - 1);
}
// piece overlaps with right border
else if ((nColumn + 3) >= pBucket->nWidth)
{
nBorderMask = 0x8888 >> ((nColumn + 3) - pBucket->nWidth);
}
// return if piece collides with border
if ((nPieceMap & nBorderMask) != 0)
{
return 1;
}
}
// here we check the part which has already entered the bucket
for (int8_t y = (nRow < 0) ? -nRow : 0; y < 4; ++y)
{
// current piece row overlaps with lower border
if ((y + nRow) >= pBucket->nHeight)
{
// all 4 bits represent the lower border
nBucketPart = 0x000F;
}
// piece overlaps with left border
else if (nColumn < 0)
{
// clear all bits we are not interested in
nBucketPart = (pBucket->dump[y + nRow] & (0x000F >> -nColumn));
// add zeros to the left (the bits "behind" the left border)
nBucketPart <<= -nColumn;
// set bits beyond left border to 1
nBucketPart |= 0x000F >> (4 + nColumn);
}
// piece overlaps with right border
else if ((nColumn + 3) >= pBucket->nWidth)
{
// align the bits we are interested in to LSB
// (thereby clearing the rest)
nBucketPart = pBucket->dump[y + nRow] >> nColumn;
// set bits beyond right border to 1
nBucketPart |= 0xFFF8 >> (nColumn + 3 - pBucket->nWidth);
}
// current row neither overlaps with left, right nor lower border
else
{
// clear all bits we are not interested in and align the
// remaing row to LSB
nBucketPart =
(pBucket->dump[y + nRow] & (0x000F << nColumn)) >> nColumn;
}
// clear all bits of the piece we are not interested in and
// align the remaing row to LSB
nPieceRowMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2);
// finally check for a collision
if ((nBucketPart & nPieceRowMap) != 0)
{
return 1;
}
}
// if we reach here, no collision was detected
return 0;
}
void tetris_bucket_advancePiece(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
// a piece can only be lowered if it is hovering or gliding
assert ((pBucket->status == TETRIS_BUS_HOVERING) ||
(pBucket->status == TETRIS_BUS_GLIDING));
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow + 1))
{
uint16_t nPiece = tetris_piece_getBitmap(pBucket->pPiece);
// Is the bucket filled up?
if ((pBucket->nRow < 0) && (nPiece & (0x0FFF >> ((3 + pBucket->nRow) << 2))) != 0)
{
pBucket->status = TETRIS_BUS_GAMEOVER;
}
else
{
// determine valid start point for dump index
int8_t nStartRow = ((pBucket->nRow + 3) < pBucket->nHeight) ?
(pBucket->nRow + 3) : pBucket->nHeight - 1;
for (int8_t i = nStartRow; i >= pBucket->nRow; --i)
{
int8_t y = i - pBucket->nRow;
// clear all bits of the piece we are not interested in and
// align the rest to LSB
uint16_t nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2);
// shift the remaining content to the current column
if (pBucket->nColumn >= 0)
{
nPieceMap <<= pBucket->nColumn;
}
else
{
nPieceMap >>= -pBucket->nColumn;
}
// embed piece in bucket
pBucket->dump[i] |= nPieceMap;
}
// update value for the highest row with matter
int8_t nPieceRow = pBucket->nRow;
uint16_t nMask = 0x000F;
for (int i = 0; i < 4; ++i, nMask <<= 4)
{
if ((nMask & nPiece) != 0)
{
nPieceRow += i;
break;
}
}
pBucket->nFirstMatterRow = (pBucket->nFirstMatterRow > nPieceRow) ?
nPieceRow : pBucket->nFirstMatterRow;
// the piece has finally been docked
pBucket->status = TETRIS_BUS_DOCKED;
}
}
else
{
// since there is no collision the piece may continue its travel
// to the ground...
pBucket->nRow++;
// are we gliding?
pBucket->status = tetris_bucket_hoverStatus(pBucket);
}
}
uint8_t tetris_bucket_movePiece(tetris_bucket_t *pBucket,
tetris_bucket_direction_t direction)
{
assert(pBucket != NULL);
// a piece can only be moved if it is still hovering or gliding
assert((pBucket->status == TETRIS_BUS_HOVERING) ||
(pBucket->status == TETRIS_BUS_GLIDING));
int8_t nOffset = (direction == TETRIS_BUD_LEFT) ? -1 : 1;
if (tetris_bucket_collision(pBucket, pBucket->nColumn + nOffset,
pBucket->nRow) == 0)
{
pBucket->nColumn += nOffset;
// are we gliding?
pBucket->status = tetris_bucket_hoverStatus(pBucket);
return 1;
}
return 0;
}
uint8_t tetris_bucket_rotatePiece(tetris_bucket_t *pBucket,
tetris_piece_rotation_t rotation)
{
assert(pBucket != NULL);
// a piece can only be rotation if it is still hovering or gliding
assert((pBucket->status == TETRIS_BUS_HOVERING) ||
(pBucket->status == TETRIS_BUS_GLIDING));
tetris_piece_rotate(pBucket->pPiece, rotation);
// does the rotated piece cause a collision?
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow) != 0)
{
// in that case we revert the rotation
if (rotation == TETRIS_PC_ROT_CW)
{
tetris_piece_rotate(pBucket->pPiece, TETRIS_PC_ROT_CCW);
}
else
{
tetris_piece_rotate(pBucket->pPiece, TETRIS_PC_ROT_CW);
}
return 0;
}
// are we gliding?
pBucket->status = tetris_bucket_hoverStatus(pBucket);
return 1;
}
void tetris_bucket_removeCompleteLines(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
// rows can only be removed if we are in state TETRIS_PFS_DOCKED
assert(pBucket->status == TETRIS_BUS_DOCKED);
// bit mask of a full row
uint16_t nFullRow = 0xFFFF >> (16 - pBucket->nWidth);
// bit mask (only 4 bits) that tells us if the n-th row after the
// current nRow is complete (n-th bit set to 1, LSB represents nRow itself)
uint8_t nRowMask = 0;
// determine sane start and stop values for the dump' index
int8_t nStartRow = ((pBucket->nRow + 3) >= pBucket->nHeight) ?
pBucket->nHeight - 1 : pBucket->nRow + 3;
int8_t nStopRow = (pBucket->nRow < 0) ? 0 : pBucket->nRow;
// dump index variables
// for incomplete rows, both variables will be decremented
// for complete rows, only i gets decremented
int8_t nLowestRow = nStartRow;
// save old value for the first dump index with matter
int8_t nFormerFirstMatterRow = pBucket->nFirstMatterRow;
// this loop only considers rows which are affected by the piece
for (int8_t i = nStartRow; i >= nStopRow; --i)
{
// is current row a full row?
if ((nFullRow & pBucket->dump[i]) == nFullRow)
{
// adjust value for the highest row with matter
pBucket->nFirstMatterRow++;
// set corresponding bit for the row mask
// nRowMask |= 0x08 >> (nStartRow - i);
nRowMask |= 0x01 << (i - pBucket->nRow);
}
else
{
// if nLowestRow and i differ, the dump has to be shifted
if (i < nLowestRow)
{
pBucket->dump[nLowestRow] = pBucket->dump[i];
}
--nLowestRow;
}
}
// if rows have been removed, this loop shifts the rest of the dump
uint8_t nComplete = nLowestRow - nStopRow + 1;
if (nComplete > 0)
{
for (int8_t i = nStopRow - 1; nLowestRow >= nFormerFirstMatterRow; --i)
{
// is the row we are copying from below the upper border?
if (i >= nFormerFirstMatterRow)
{
// just copy from that row
pBucket->dump[nLowestRow] = pBucket->dump[i];
}
else
{
// rows above the upper border are always empty
pBucket->dump[nLowestRow] = 0;
}
--nLowestRow;
}
}
// ready to get the next piece
pBucket->status = TETRIS_BUS_READY;
pBucket->nRowMask = nRowMask;
}
/*****************
* get functions *
*****************/
int8_t tetris_bucket_getWidth(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nWidth;
}
int8_t tetris_bucket_getHeight(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nHeight;
}
tetris_piece_t *tetris_bucket_getPiece(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->pPiece;
}
int8_t tetris_bucket_getColumn(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nColumn;
}
int8_t tetris_bucket_getRow(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nRow;
}
int8_t tetris_bucket_getFirstMatterRow(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nFirstMatterRow;
}
uint8_t tetris_bucket_getRowMask(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->nRowMask;
}
tetris_bucket_status_t tetris_bucket_getStatus(tetris_bucket_t *pBucket)
{
assert(pBucket != NULL);
return pBucket->status;
}
uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,
int8_t nRow)
{
assert(pBucket != NULL);
assert((0 <= nRow) && (nRow < pBucket->nHeight));
return pBucket->dump[nRow];
}
#ifdef GAME_BASTET
int8_t tetris_bucket_predictDeepestRow(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nColumn)
{
int8_t nRow = tetris_bucket_getPieceStartPos(pPiece);
tetris_piece_t *pActualPiece = pBucket->pPiece;
pBucket->pPiece = pPiece;
// is it actually possible to use this piece?
if (tetris_bucket_collision(pBucket, (pBucket->nWidth - 2) / 2, nRow) ||
(tetris_bucket_collision(pBucket, nColumn, nRow)))
{
// restore real piece
pBucket->pPiece = pActualPiece;
return -4;
}
// determine deepest row
nRow = (nRow < pBucket->nFirstMatterRow - 4) ?
pBucket->nFirstMatterRow - 4 : nRow;
while ((nRow < pBucket->nHeight) &&
(!tetris_bucket_collision(pBucket, nColumn, nRow + 1)))
{
++nRow;
}
// restore real piece
pBucket->pPiece = pActualPiece;
return nRow;
}
int8_t tetris_bucket_predictCompleteLines(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nRow,
int8_t nColumn)
{
int8_t nCompleteRows = 0;
// bit mask of a full row
uint16_t nFullRow = 0xFFFF >> (16 - pBucket->nWidth);
if (nRow > -4)
{
// determine sane start and stop values for the dump's index
int8_t nStartRow =
((nRow + 3) >= pBucket->nHeight) ? pBucket->nHeight - 1 : nRow + 3;
int8_t nStopRow = (nRow < 0) ? 0 : nRow;
uint16_t nPiece = tetris_piece_getBitmap(pPiece);
for (int8_t i = nStartRow; i >= nStopRow; --i)
{
int8_t y = i - nRow;
// clear all bits of the piece we are not interested in and
// align the rest to LSB
uint16_t nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2);
// shift the remaining content to the current column
if (nColumn >= 0)
{
nPieceMap <<= nColumn;
}
else
{
nPieceMap >>= -nColumn;
}
// embed piece in dump map
uint16_t nDumpMap = pBucket->dump[i] | nPieceMap;
// is current row a full row?
if ((nFullRow & nDumpMap) == nFullRow)
{
++nCompleteRows;
}
}
}
return nCompleteRows;
}
uint16_t* tetris_bucket_predictBottomRow(tetris_bucket_iterator_t *pIt,
tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nRow,
int8_t nColumn)
{
pIt->pBucket = pBucket;
pIt->pPiece = pPiece;
pIt->nColumn = nColumn;
pIt->nFullRow = 0xFFFF >> (16 - pBucket->nWidth);
pIt->nCurrentRow = pBucket->nHeight - 1;
pIt->nRowBuffer = 0;
// determine sane start and stop values for the piece's row indices
pIt->nPieceHighestRow = nRow;
pIt->nPieceLowestRow = ((pIt->nPieceHighestRow + 3) < pBucket->nHeight) ?
(pIt->nPieceHighestRow + 3) : pBucket->nHeight - 1;
// don't return any trailing rows which are empty, so we look for a stop row
pIt->nStopRow = pBucket->nFirstMatterRow < nRow ?
pBucket->nFirstMatterRow : nRow;
pIt->nStopRow = pIt->nStopRow < 0 ? 0 : pIt->nStopRow;
return tetris_bucket_predictNextRow(pIt);
}
uint16_t* tetris_bucket_predictNextRow(tetris_bucket_iterator_t *pIt)
{
uint16_t nPieceMap = 0;
if ((pIt->nPieceHighestRow > -4) && (pIt->nCurrentRow >= pIt->nStopRow))
{
uint16_t nPiece = tetris_piece_getBitmap(pIt->pPiece);
if ((pIt->nCurrentRow <= pIt->nPieceLowestRow) &&
(pIt->nCurrentRow >= pIt->nPieceHighestRow))
{
int8_t y = pIt->nCurrentRow - pIt->nPieceHighestRow;
// clear all bits of the piece we are not interested in and
// align the rest to LSB
nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2);
// shift the remaining content to the current column
if (pIt->nColumn >= 0)
{
nPieceMap <<= pIt->nColumn;
}
else
{
nPieceMap >>= -pIt->nColumn;
}
}
pIt->nRowBuffer = pIt->pBucket->dump[pIt->nCurrentRow--] | nPieceMap;
// don't return full (and therefore removed) rows
if (pIt->nRowBuffer == pIt->nFullRow)
{
// recursively determine next (?) row instead
return tetris_bucket_predictNextRow(pIt);
}
// row isn't full
else
{
return &pIt->nRowBuffer;
}
}
else
{
return NULL;
}
}
#endif /* GAME_BASTET */

295
games/tetris/bucket.h

@ -0,0 +1,295 @@
#ifndef BUCKET_H_
#define BUCKET_H_
#include <inttypes.h>
#include "../../autoconf.h"
#include "piece.h"
/*********
* types *
*********/
// directions to which a piece can be moved
typedef enum tetris_bucket_direction_t
{
TETRIS_BUD_LEFT,
TETRIS_BUD_RIGHT
}
tetris_bucket_direction_t;
// status of the bucket
typedef enum tetris_bucket_status_t
{
TETRIS_BUS_READY, /** ready to get next piece */
TETRIS_BUS_HOVERING, /** piece is still hovering */
TETRIS_BUS_GLIDING, /** piece is gliding on the dump */
TETRIS_BUS_DOCKED, /** piece has been docked */
TETRIS_BUS_GAMEOVER /** bucket is filled up */
}
tetris_bucket_status_t;
// tetris_bucket_t
typedef struct tetris_bucket_t
{
int8_t nWidth; /** width of bucket */
int8_t nHeight; /** height of bucket */
tetris_piece_t *pPiece; /** currently falling piece */
int8_t nColumn; /** horz. piece pos. (0 is left) */
int8_t nRow; /** vert. piece pos. (0 is top) */
uint8_t nRowMask; /** removed lines relative to nRow */
tetris_bucket_status_t status; /** status of the bucket */
int8_t nFirstMatterRow; /** top most row which has matter */
uint16_t *dump; /** bucket itself */
}
tetris_bucket_t;
// iterator for predicted dump rows
typedef struct tetris_bucket_iterator_t
{
tetris_bucket_t *pBucket; /** bucket to be examined */
tetris_piece_t *pPiece; /** piece which should be tested */
int8_t nColumn; /** column where piece should be dropped */
uint16_t nFullRow; /** value of a full row */
int8_t nCurrentRow; /** the actual row in the bucket */
int8_t nPieceHighestRow; /** the highest row index of the piece */
int8_t nPieceLowestRow; /** the lowest row index of the piece */
int8_t nStopRow; /** the last row to be examined */
uint16_t nRowBuffer; /** internal buffer for returned rows */
}
tetris_bucket_iterator_t;
/****************************
* construction/destruction *
****************************/
/**
* constructs a bucket with the given dimensions
* @param nWidth width of bucket (4 <= n <= 16)
* @param nHeight height of bucket (4 <= n <= 124)
* @return pointer to a newly created bucket
*/
tetris_bucket_t *tetris_bucket_construct(int8_t nWidth,
int8_t nHeight);
/**
* destructs a bucket
* @param pBucket pointer to the bucket to be destructed
*/
void tetris_bucket_destruct(tetris_bucket_t *pBucket);
/*******************************
* bucket related functions *
*******************************/
/**
* calculates number of lines for the given row mask
* @param nRowMask row mask from which the no. of lines will be calculated
* @return number of lines of the row mask
*/
uint8_t tetris_bucket_calculateLines(uint8_t nRowMask);
/**
* resets bucket to begin a new game
* @param pBucket bucket to perform action on
*/
void tetris_bucket_reset(tetris_bucket_t *pBucket);
/**
* inserts a new piece
* @param pBucket bucket to perform action on
* @param pPiece piece to be inserted
* @param ppOldPiece [out] indirect pointer to former piece for deallocation
*/
void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
tetris_piece_t** ppOldPiece);
/**
* detects if piece collides with s.th. at a given position
* @param pBucket bucket to perform action on
* @param nColumn column where the piece should be moved
* @param nRow row where the piece should be moved
* @return 1 for collision, 0 otherwise
*/
uint8_t tetris_bucket_collision(tetris_bucket_t *pBucket,
int8_t nColumn,
int8_t nRow);
/**
* lowers piece by one row or finally docks it
* @param pBucket bucket to perform action on
*/
void tetris_bucket_advancePiece(tetris_bucket_t *pBucket);
/**
* moves piece to the given direction
* @param pBucket bucket to perform action on
* @param direction direction (see tetris_bucket_direction_t)
* @return 1 if piece could be moved, 0 otherwise
*/
uint8_t
tetris_bucket_movePiece(tetris_bucket_t *pBucket,
tetris_bucket_direction_t direction);
/**
* rotates piece to the given direction
* @param pBucket bucket to perform action on
* @param r type of rotation (see tetris_piece_rotation_t)
* @return 1 if piece could be rotated, 0 otherwise
*/
uint8_t tetris_bucket_rotatePiece(tetris_bucket_t *pBucket,
tetris_piece_rotation_t rotation);
/**
* removes completed lines (if any) and lowers the dump
* @param pBucket bucket to perform action on
*/
void tetris_bucket_removeCompleteLines(tetris_bucket_t *pBucket);
/*****************
* get functions *
*****************/
/**
* returns the width of the bucket
* @param pBucket the bucket we want information from
* @return width of the bucket
*/
int8_t tetris_bucket_getWidth(tetris_bucket_t *pBucket);
/**
* returns the height of the bucket
* @param pBucket the bucket we want information from
* @return height of the bucket
*/
int8_t tetris_bucket_getHeight(tetris_bucket_t *pBucket);
/**
* returns the currently falling piece
* @param pBucket the bucket we want information from
* @return pointer to the currently falling piece
*/
tetris_piece_t *tetris_bucket_getPiece(tetris_bucket_t *pBucket);
/**
* returns the column of the currently falling piece
* @param pBucket the bucket we want information from
* @return column of the currently falling piece
*/
int8_t tetris_bucket_getColumn(tetris_bucket_t *pBucket);
/**
* returns the row of the currently falling piece
* @param pBucket the bucket we want information from
* @return row of the currently falling piece
*/
int8_t tetris_bucket_getRow(tetris_bucket_t *pBucket);
/**
* returns the row of the currently falling piece
* @param pBucket the bucket we want information from
* @return highest row with matter
*/
int8_t tetris_bucket_getFirstMatterRow(tetris_bucket_t *pBucket);
/**
* returns the row mask relative to nRow
* @param pBucket the bucket we want information from
* @return bit mask of removed lines (relative to current position)
*/
uint8_t tetris_bucket_getRowMask(tetris_bucket_t *pBucket);
/**
* returns the status of the bucket
* @param pBucket the bucket we want information from
* @return status of the bucket (see tetris_bucket_status_t)
*/
tetris_bucket_status_t tetris_bucket_getStatus(tetris_bucket_t *pBucket);
/**
* returns the given row of the dump (as bitmap)
* @param pBucket the bucket we want information from
* @param nRow the number of the row (0 <= nRow <= 124)
* @return bitmap of the requested row (LSB is leftmost column)
*/
uint16_t tetris_bucket_getDumpRow(tetris_bucket_t *pBucket,
int8_t nRow);
#ifdef GAME_BASTET
/**
* returns the deepest possible row for a given piece
* @param pBucket the bucket on which we want to test a piece
* @param pPiece the piece which should be tested
* @param nColumn the column where the piece should be dropped
* @return the row of the piece (bucket compliant coordinates)
*/
int8_t tetris_bucket_predictDeepestRow(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nColumn);
/**
* predicts the number of complete lines for a piece at a given column
* @param pBucket the bucket on which we want to test a piece
* @param pPiece the piece which should be tested
* @param nRow the row where the given piece collides
* @param nColumn the column where the piece should be dropped
* @return amount of complete lines
*/
int8_t tetris_bucket_predictCompleteLines(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nRow,
int8_t nColumn);
/**
* predicts appearance of the bottom row and initializes an iterator structure
* @param pIt a pointer to an iterator which should be initialized
* @param pBucket the bucket on which we want to test a piece
* @param pPiece the piece which should be tested
* @param nRow the row where the given piece collides
* @param nColumn the column where the piece should be dropped
* @return appearance of the bottom row of the predicted dump (bit mask)
*/
uint16_t *tetris_bucket_predictBottomRow(tetris_bucket_iterator_t *pIt,
tetris_bucket_t *pBucket,
tetris_piece_t *pPiece,
int8_t nRow,
int8_t nColumn);
/**
* predicts appearance of the next row (via iterator) of the bucket
* @param pIt a pointer to a dump iterator
* @return appearance of next predicted row (or NULL -> no next line)
*/
uint16_t *tetris_bucket_predictNextRow(tetris_bucket_iterator_t *pIt);
#endif /* GAME_BASTET */
#endif /*BUCKET_H_*/

325
games/tetris/highscore.c

@ -1,163 +1,162 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#include "highscore.h"
#include "../../config.h"
#include "../../scrolltext/scrolltext.h"
#include "../../joystick/joystick.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;
uint16_t tetris_highscore_inputName(void)
{
#ifdef SCROLLTEXT_SUPPORT
char pszNick[4], pszTmp[40];
uint8_t nOffset;
uint8_t nPos = 0, nBlink = 0, nDone = 0, nHadfire = 0;
sprintf(pszNick, "AAA");
while (!nDone)
{
// we need our own blink interval
nBlink = (nBlink + 1) % 4;
// determine start position on screen depending on active character
switch (nPos)
{
case 0:
nOffset = 15;
break;
case 1:
nOffset = 19;
break;
default:
nOffset = 23;
break;
}
// construct command for scrolltext and execute
sprintf(pszTmp, "x%d+p1#%c#x%d+p1#%c#x%dp1#%c", nOffset,
(!nBlink && nPos == 0) ? ' ' : pszNick[0], nOffset - 8,
(!nBlink && nPos == 1) ? ' ' : pszNick[1], nOffset - 15,
(!nBlink && nPos == 2) ? ' ' : pszNick[2]);
scrolltext(pszTmp);
// up and down control current char
if (JOYISUP)
{
pszNick[nPos]++;
if (pszNick[nPos] == '`')
{
pszNick[nPos] = 'A';
}
if (pszNick[nPos] == '[')
{
pszNick[nPos] = '_';
}
}
else if (JOYISDOWN)
{
pszNick[nPos]--;
if (pszNick[nPos] == '@')
{
pszNick[nPos] = '_';
}
if (pszNick[nPos] == '^')
{
pszNick[nPos] = 'Z';
}
}
// left and right control char selections
else if (JOYISLEFT && nPos > 0)
{
nPos--;
}
else if (JOYISRIGHT && nPos < 2)
{
nPos++;
}
// fire switches to next char or exits
if (JOYISFIRE && !nHadfire)
{
nHadfire = 1;
switch (nPos)
{
case 0:
nPos = 1;
break;
case 1:
nPos = 2;
break;
case 2:
nDone = 1;
break;
}
}
if (nHadfire && !JOYISFIRE)
{
nHadfire = 0;
}
}
// return result
return (pszNick[0] - 65) << 10 | (pszNick[1] - 65) << 5 | (pszNick[2] - 65);
#else
return (0);
#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);
}
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#include "highscore.h"
#include "../../config.h"
#include "../../scrolltext/scrolltext.h"
#include "../../joystick/joystick.h"
#include "../../compat/eeprom.h"
// global array for the high score
uint16_t tetris_highscore[TETRIS_HISCORE_END] EEMEM;
// global array for the champion's initials
uint16_t tetris_highscore_name[TETRIS_HISCORE_END] EEMEM;
uint16_t tetris_highscore_inputName(void)
{
#ifdef SCROLLTEXT_SUPPORT
char pszNick[4], pszTmp[26];
unsigned int nOffset;
uint8_t nPos = 0, nBlink = 0, nDone = 0, nHadfire = 0;
strncpy(pszNick, "AAA", sizeof(pszNick));
while (!nDone)
{
// we need our own blink interval
nBlink = (nBlink + 1) % 4;
// determine start position on screen depending on active character
switch (nPos)
{
case 0:
nOffset = 15;
break;
case 1:
nOffset = 19;
break;
default:
nOffset = 23;
break;
}
// construct command for scrolltext and execute
snprintf(pszTmp, sizeof(pszTmp), "x%u+p1#%c#x%u+p1#%c#x%up1#%c",
nOffset , (!nBlink && nPos == 0) ? ' ' : pszNick[0],
nOffset - 8, (!nBlink && nPos == 1) ? ' ' : pszNick[1],
nOffset - 15, (!nBlink && nPos == 2) ? ' ' : pszNick[2]);
scrolltext(pszTmp);
// up and down control current char
if (JOYISUP)
{
pszNick[nPos]++;
if (pszNick[nPos] == '`')
{
pszNick[nPos] = 'A';
}
else if (pszNick[nPos] == '[')
{
pszNick[nPos] = '_';
}
}
else if (JOYISDOWN)
{
pszNick[nPos]--;
if (pszNick[nPos] == '@')
{
pszNick[nPos] = '_';
}
else if (pszNick[nPos] == '^')
{
pszNick[nPos] = 'Z';
}
}
// left and right control char selections
else if (JOYISLEFT && nPos > 0)
{
nPos--;
}
else if (JOYISRIGHT && nPos < 2)
{
nPos++;
}
// fire switches to next char or exits
if (JOYISFIRE && !nHadfire)
{
nHadfire = 1;
switch (nPos)
{
case 0:
nPos = 1;
break;
case 1:
nPos = 2;
break;
case 2:
nDone = 1;
break;
}
}
if (nHadfire && !JOYISFIRE)
{
nHadfire = 0;
}
}
// return result
return (pszNick[0] - 65) << 10 | (pszNick[1] - 65) << 5 | (pszNick[2] - 65);
#else
return (0);
#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);
}

114
games/tetris/highscore.h

@ -1,57 +1,57 @@
#ifndef TETRIS_HIGHSCORE_H_
#define TETRIS_HIGHSCORE_H_
/**
* indexes for different tetris variants
*/
typedef enum tetris_highscore_index_t
{
TETRIS_HISCORE_TETRIS, /**< highscore index for the standard variant */
TETRIS_HISCORE_BASTET, /**< highscore index for the bastet variant */
TETRIS_HISCORE_FP, /**< highscore index for the first person variant */
TETRIS_HISCORE_PAD, /**< don't use (padding for an even array boundary)*/
TETRIS_HISCORE_END /**< boundary for the highscore array */
} tetris_highscore_index_t;
/**
* let user input a three character name
* @return name packed into a uint16_t
*/
uint16_t tetris_highscore_inputName(void);
/**
* retrieves the highscore from storage
* @param nIndex the variant dependent index of the highscore
* @return the highscore
*/
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex);
/**
* saves the highscore into the storage
* @param nIndex the variant dependent index of the highscore
* @param nHighscoreName the highscore
*/
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
uint16_t nHighscore);
/**
* retrieves the initials of the champion from storage
* @param nIdx the variant dependent index of the highscore
* @return the initials of the champion packed into a uint16_t
*/
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx);
/**
* saves the initials of the champion
* @param nIndex the variant dependent index of the highscore
* @param nHighscoreName the initials of the champion packed into a uint16_t
*/
void tetris_highscore_saveHighscoreName(tetris_highscore_index_t nIndex,
uint16_t nHighscoreName);
#endif /*TETRIS_HIGHSCORE_H_*/
#ifndef TETRIS_HIGHSCORE_H_
#define TETRIS_HIGHSCORE_H_
/**
* indexes for different tetris variants
*/
typedef enum tetris_highscore_index_t
{
TETRIS_HISCORE_TETRIS, /**< high score index for the standard variant */
TETRIS_HISCORE_BASTET, /**< high score index for the bastet variant */
TETRIS_HISCORE_FP, /**< high score index for the first person variant */
TETRIS_HISCORE_PAD, /**< don't use (padding for an even array boundary)*/
TETRIS_HISCORE_END /**< boundary for the high score array */
} tetris_highscore_index_t;
/**
* lets the user enter his initials (three characters)
* @return name packed into a uint16_t
*/
uint16_t tetris_highscore_inputName(void);
/**
* retrieves the high score from storage (EEPROM)
* @param nIndex the variant dependent index of the high score
* @return the high score
*/
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex);
/**
* saves the high score into the storage (EEPROM)
* @param nIndex the variant dependent index of the high score
* @param nHighscoreName the high score
*/
void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
uint16_t nHighscore);
/**
* retrieves the champion's initials from storage (EEPROM)
* @param nIdx the variant dependent index of the high score
* @return the initials of the champion packed into a uint16_t
*/
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx);
/**
* saves the champion's initials into the storage (EEPROM)
* @param nIndex the variant dependent index of the high score
* @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_*/

31
games/tetris/input.c

@ -7,7 +7,7 @@
#include "../../util.h"
#include "../../scrolltext/scrolltext.h"
#include "input.h"
#include "orientation.h"
#include "bearing.h"
#include "../../compat/pgmspace.h"
#define WAIT(ms) wait(ms)
@ -134,13 +134,13 @@ void tetris_input_chatterProtect(tetris_input_t *pIn,
/**
* remaps tetris commands according to current orientation
* @param pIn pointer to an input object
* remaps tetris commands according to current bearing of the bucket
* @param nBearing bearing of the bucket
* @param nCmd command which has to be mapped
* @return mapped tetris command
* @see tetris_input_command_t
*/
tetris_input_command_t tetris_input_mapCommand(tetris_orientation_t nOrient,
tetris_input_command_t tetris_input_mapCommand(tetris_bearing_t nBearing,
tetris_input_command_t nCmd)
{
const tetris_input_command_t nMapping[] =
@ -155,8 +155,8 @@ tetris_input_command_t tetris_input_mapCommand(tetris_orientation_t nOrient,
TETRIS_INCMD_RIGHT
};
return (nOrient == TETRIS_ORIENTATION_0) || (nCmd >= TETRIS_INCMD_ROT_CCW) ?
nCmd : (nMapping[(nOrient - 1) * 4 + nCmd]);
return (nBearing == TETRIS_BEARING_0) || (nCmd >= TETRIS_INCMD_ROT_CCW) ?
nCmd : (nMapping[(nBearing - 1) * 4 + nCmd]);
}
@ -225,8 +225,8 @@ tetris_input_command_t tetris_input_queryJoystick(tetris_input_t *pIn)
pIn->cmdRawLast = cmdJoystick;
tetris_input_command_t cmdReturn =
tetris_input_mapCommand(pIn->nOrientation, cmdJoystick);
// remap command according to current orientation
tetris_input_mapCommand(pIn->nBearing, cmdJoystick);
// remap command according to current bearing
return cmdReturn;
}
@ -243,7 +243,7 @@ tetris_input_t *tetris_input_construct(void)
assert(pIn != NULL);
pIn->cmdRawLast = pIn->cmdLast = TETRIS_INCMD_NONE;
pIn->nOrientation = TETRIS_ORIENTATION_0;
pIn->nBearing = TETRIS_BEARING_0;
pIn->nLevel = 0xFF;
tetris_input_setLevel(pIn, 0);
pIn->nLoopCycles = 0;
@ -440,17 +440,16 @@ void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn)
}
void tetris_input_setOrientation(tetris_input_t *pIn,
tetris_orientation_t nOrient)
void tetris_input_setBearing(tetris_input_t *pIn,
tetris_bearing_t nBearing)
{
if (pIn->nOrientation != nOrient)
if (pIn->nBearing != nBearing)
{
pIn->nOrientation = nOrient;
pIn->nBearing = nBearing;
// 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);
// button changes its meaning as soon as the bearing changes
pIn->cmdLast = tetris_input_mapCommand(pIn->nBearing, pIn->cmdRawLast);
pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY;
}
}

16
games/tetris/input.h

@ -2,7 +2,7 @@
#define INPUT_H_
#include <inttypes.h>
#include "orientation.h"
#include "bearing.h"
/**
* \defgroup TetrisInputDefinesPublic Input: Public constants
@ -123,9 +123,9 @@ typedef struct tetris_input_t
uint8_t nIgnoreCmdCounter[TETRIS_INCMD_NONE];
/**
* orientation of the direction mapping
* bearing of the bucket (for mapping directions)
*/
tetris_orientation_t nOrientation;
tetris_bearing_t nBearing;
}
tetris_input_t;
@ -173,7 +173,7 @@ tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn,
/**
* modifies time interval of input events
* @param pIn pointer to an input object
* @param nLvl desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1)
* @param nLvl requested level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1)
*/
void tetris_input_setLevel(tetris_input_t *pIn,
uint8_t nLvl);
@ -187,12 +187,12 @@ void tetris_input_resetDownKeyRepeat(tetris_input_t *pIn);
/**
* set the orientation of the direction control mapping
* set the bearing for mapping the direction controls
* @param pIn pointer to an input object
* @param nOrient desired orientation
* @param nBearing requested bearing
*/
void tetris_input_setOrientation(tetris_input_t *pIn,
tetris_orientation_t nOrient);
void tetris_input_setBearing(tetris_input_t *pIn,
tetris_bearing_t nBearing);
/*@}*/

72
games/tetris/tetris_main.c

@ -6,7 +6,7 @@
#include "tetris_main.h"
#include "variants.h"
#include "piece.h"
#include "playfield.h"
#include "bucket.h"
#include "view.h"
#include "input.h"
#include "highscore.h"
@ -14,7 +14,7 @@
void tetris_main(const tetris_variant_t *const pVariantMethods)
{
// get view dependent dimensions of the playfield
// get view dependent dimensions of the bucket
int8_t nWidth;
int8_t nHeight;
tetris_view_getDimensions(&nWidth, &nHeight);
@ -23,11 +23,11 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
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_bucket_t *pBucket = tetris_bucket_construct(nWidth, nHeight);
void *pVariantData = pVariantMethods->construct(pBucket);
tetris_input_t *pIn = tetris_input_construct();
tetris_view_t *pView = tetris_view_construct(pVariantMethods,
pVariantData, pPl);
pVariantData, pBucket);
// retrieve highscore
tetris_highscore_index_t nHighscoreIndex =
@ -37,7 +37,7 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
uint16_t nHighscoreName =
tetris_highscore_retrieveHighscoreName(nHighscoreIndex);
// the view only monitors the variant data and the playfield object for the
// the view only monitors the variant data and the bucket 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);
@ -48,16 +48,16 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
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)
while (tetris_bucket_getStatus(pBucket) != TETRIS_BUS_GAMEOVER)
{
// what we do strongly depends on the status of the playfield
switch (tetris_playfield_getStatus(pPl))
// what we do strongly depends on the status of the bucket
switch (tetris_bucket_getStatus(pBucket))
{
// the playfield awaits a new piece
case TETRIS_PFS_READY:
// the bucket awaits a new piece
case TETRIS_BUS_READY:
pPiece = pVariantMethods->choosePiece(pVariantData);
tetris_piece_t *pOldPiece;
tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece);
tetris_bucket_insertPiece(pBucket, pPiece, &pOldPiece);
// destruct old piece (if it exists) since we don't need it anymore
if (pOldPiece != NULL)
{
@ -67,11 +67,11 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
break;
// a piece is hovering and can be controlled by the player
case TETRIS_PFS_HOVERING:
case TETRIS_PFS_GLIDING:
case TETRIS_BUS_HOVERING:
case TETRIS_BUS_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)
if (tetris_bucket_getStatus(pBucket) == TETRIS_BUS_GLIDING)
{
inPace = TETRIS_INPACE_GLIDING;
}
@ -98,14 +98,14 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
// the piece was pulled down by the almighty gravity
case TETRIS_INCMD_GRAVITY:
tetris_playfield_advancePiece(pPl);
tetris_bucket_advancePiece(pBucket);
break;
// the player has pulled down the piece herself/himself
case TETRIS_INCMD_DOWN:
tetris_playfield_advancePiece(pPl);
tetris_bucket_advancePiece(pBucket);
// if the game still runs, reward the player with extra points
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER)
if (tetris_bucket_getStatus(pBucket) != TETRIS_BUS_GAMEOVER)
{
pVariantMethods->singleDrop(pVariantData, 1);
}
@ -113,38 +113,38 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
// player shifted the piece to the left
case TETRIS_INCMD_LEFT:
tetris_playfield_movePiece(pPl, TETRIS_PFD_LEFT);
tetris_bucket_movePiece(pBucket, TETRIS_BUD_LEFT);
break;
// player shifted the piece to the right
case TETRIS_INCMD_RIGHT:
tetris_playfield_movePiece(pPl, TETRIS_PFD_RIGHT);
tetris_bucket_movePiece(pBucket, TETRIS_BUD_RIGHT);
break;
// player rotated the piece clockwise
case TETRIS_INCMD_ROT_CW:
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CW);
tetris_bucket_rotatePiece(pBucket, TETRIS_PC_ROT_CW);
break;
// player rotated the piece counter clockwise
case TETRIS_INCMD_ROT_CCW:
tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CCW);
tetris_bucket_rotatePiece(pBucket, TETRIS_PC_ROT_CCW);
break;
// the player decided to make an immediate drop
case TETRIS_INCMD_DROP:
nPieceRow = tetris_playfield_getRow(pPl);
nPieceRow = tetris_bucket_getRow(pBucket);
// emulate immediate drop
while((tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) ||
(tetris_playfield_getStatus(pPl) == TETRIS_PFS_HOVERING))
while(tetris_bucket_getStatus(pBucket) == TETRIS_BUS_GLIDING ||
tetris_bucket_getStatus(pBucket) == TETRIS_BUS_HOVERING)
{
tetris_playfield_advancePiece(pPl);
tetris_bucket_advancePiece(pBucket);
}
// if the game still runs, reward the player with extra points
if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER)
if (tetris_bucket_getStatus(pBucket) != TETRIS_BUS_GAMEOVER)
{
pVariantMethods->completeDrop(pVariantData,
tetris_playfield_getRow(pPl) - nPieceRow);
tetris_bucket_getRow(pBucket) - nPieceRow);
}
break;
@ -153,24 +153,28 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
break;
}
// inform variant object about the user's last move
pVariantMethods->setLastInput(pVariantData, inCmd);
tetris_input_setOrientation(pIn,
pVariantMethods->getOrientation(pVariantData));
// inform the input module about the requested bearing of the
// variant object
tetris_input_setBearing(pIn,
pVariantMethods->getBearing(pVariantData));
break;
// the piece has irrevocably hit the ground
case TETRIS_PFS_DOCKED:
case TETRIS_BUS_DOCKED:
// avoid accidentally issued "down" commands
tetris_input_resetDownKeyRepeat(pIn);
// remove complete lines (if any)
tetris_playfield_removeCompleteLines(pPl);
tetris_bucket_removeCompleteLines(pBucket);
// 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_bucket_getRowMask(pBucket));
tetris_input_setLevel(pIn, pVariantMethods->getLevel(pVariantData));
break;
@ -200,6 +204,6 @@ void tetris_main(const tetris_variant_t *const pVariantMethods)
tetris_view_destruct(pView);
tetris_input_destruct(pIn);
pVariantMethods->destruct(pVariantData);
tetris_playfield_destruct(pPl);
tetris_bucket_destruct(pBucket);
tetris_piece_destruct(pPiece);
}

45
games/tetris/variant_bastet.c

@ -11,8 +11,8 @@
#include "tetris_main.h"
#include "input.h"
#include "piece.h"
#include "playfield.h"
#include "orientation.h"
#include "bucket.h"
#include "bearing.h"
#include "input.h"
@ -43,12 +43,12 @@ void tetris_bastet_clearColHeights(tetris_bastet_variant_t *pBastet,
*/
void tetris_bastet_calcActualColHeights(tetris_bastet_variant_t *pBastet)
{
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nStartRow = tetris_playfield_getHeight(pBastet->pPlayfield) - 1;
int8_t nStopRow = tetris_playfield_getFirstMatterRow(pBastet->pPlayfield);
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
int8_t nStartRow = tetris_bucket_getHeight(pBastet->pBucket) - 1;
int8_t nStopRow = tetris_bucket_getFirstMatterRow(pBastet->pBucket);
for (int8_t y = nStartRow; y >= nStopRow; --y)
{
uint16_t nDumpRow = tetris_playfield_getDumpRow(pBastet->pPlayfield, y);
uint16_t nDumpRow = tetris_bucket_getDumpRow(pBastet->pBucket, y);
uint16_t nColMask = 0x0001;
for (int8_t x = 0; x < nWidth; ++x)
{
@ -79,10 +79,10 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
int8_t nStopCol)
{
// go through every row and calculate column heights
tetris_playfield_iterator_t iterator;
tetris_bucket_iterator_t iterator;
int8_t nHeight = 1;
uint16_t *pDump = tetris_playfield_predictBottomRow(&iterator,
pBastet->pPlayfield, pPiece, nDeepestRow, nColumn);
uint16_t *pDump = tetris_bucket_predictBottomRow(&iterator,
pBastet->pBucket, pPiece, nDeepestRow, nColumn);
if (pDump == NULL)
{
// an immediately returned NULL is caused by a full dump -> low score
@ -99,7 +99,7 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
}
nColMask <<= 1;
}
pDump = tetris_playfield_predictNextRow(&iterator);
pDump = tetris_bucket_predictNextRow(&iterator);
++nHeight;
}
return 1;
@ -111,7 +111,8 @@ uint8_t tetris_bastet_calcPredictedColHeights(tetris_bastet_variant_t *pBastet,
* @param pa the first value to compare
* @param pb the second value to compare
*/
int tetris_bastet_qsortCompare(const void *pa, const void *pb)
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;
@ -175,19 +176,19 @@ const tetris_variant_t tetrisBastetVariant =
&tetris_bastet_getPreviewPiece,
&tetris_bastet_getHighscoreIndex,
&tetris_bastet_setLastInput,
&tetris_bastet_getOrientation
&tetris_bastet_getBearing
};
void *tetris_bastet_construct(tetris_playfield_t *pPl)
void *tetris_bastet_construct(tetris_bucket_t *pBucket)
{
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;
pBastet->pBucket = pBucket;
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
pBastet->pActualColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
pBastet->pColHeights = (int8_t*) calloc(nWidth, sizeof(int8_t));
tetris_bastet_clearColHeights(pBastet, 0, nWidth - 1);
@ -230,16 +231,16 @@ int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
int16_t nScore = -32000;
// the row where the given piece collides
int8_t nDeepestRow = tetris_playfield_predictDeepestRow(pBastet->pPlayfield,
int8_t nDeepestRow = tetris_bucket_predictDeepestRow(pBastet->pBucket,
pPiece, nColumn);
// modify score based on complete lines
int8_t nLines = tetris_playfield_predictCompleteLines(pBastet->pPlayfield,
int8_t nLines = tetris_bucket_predictCompleteLines(pBastet->pBucket,
pPiece, nDeepestRow, nColumn);
nScore += 5000 * nLines;
// determine a sane range of columns whose heights we want to predict
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
int8_t nStartCol, nStopCol;
// if lines have been removed, we need to recalculate all column heights
if (nLines != 0)
@ -283,7 +284,7 @@ void tetris_bastet_evaluatePieces(tetris_bastet_variant_t *pBastet)
{
// precache actual column heights
tetris_bastet_calcActualColHeights(pBastet);
int8_t nWidth = tetris_playfield_getWidth(pBastet->pPlayfield);
int8_t nWidth = tetris_bucket_getWidth(pBastet->pBucket);
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)
@ -371,7 +372,7 @@ void tetris_bastet_removedLines(void *pVariantData,
assert(pVariantData != 0);
tetris_bastet_variant_t *pBastet =
(tetris_bastet_variant_t *)pVariantData;
uint8_t nLines = tetris_playfield_calculateLines(nRowMask);
uint8_t nLines = tetris_bucket_calculateLines(nRowMask);
pBastet->nLines += nLines;
pBastet->nLevel = ((pBastet->nLines / 10) < TETRIS_INPUT_LEVELS) ?
@ -473,7 +474,7 @@ void tetris_bastet_setLastInput(void *pVariantData,
}
tetris_orientation_t tetris_bastet_getOrientation(void *pVariantData)
tetris_bearing_t tetris_bastet_getBearing(void *pVariantData)
{
return TETRIS_ORIENTATION_0;
return TETRIS_BEARING_0;
}

24
games/tetris/variant_bastet.h

@ -3,9 +3,9 @@
#include <inttypes.h>
#include "variants.h"
#include "playfield.h"
#include "bucket.h"
#include "piece.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"
/***************
@ -38,7 +38,7 @@ typedef struct tetris_bastet_variant_t
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 */
tetris_bucket_t *pBucket; /** bucket to be examined */
int8_t *pActualColHeights; /** actual columns heights */
int8_t *pColHeights; /** predicted column heights */
tetris_bastet_scorepair_t nPieceScores[7]; /** score for every piece */
@ -53,11 +53,11 @@ const tetris_variant_t tetrisBastetVariant;
****************************/
/**
* constructs a bastet instance for a given playfield
* @param pPlayfield the playfield to be observed
* constructs a bastet instance for a given bucket
* @param pBucket the bucket to be observed
* @return pointer to a newly created bastet instance
*/
void* tetris_bastet_construct(tetris_playfield_t *pPl);
void* tetris_bastet_construct(tetris_bucket_t *pBucket);
/**
@ -210,10 +210,20 @@ tetris_piece_t* tetris_bastet_getPreviewPiece(void *pVariantData);
tetris_highscore_index_t tetris_bastet_getHighscoreIndex(void *pVariantData);
/**
* informs the bastet instance about the player's last move
* @param pVariantData the variant data object we want to modify
* @param inCmd player's last command
*/
void tetris_bastet_setLastInput(void *pVariantData,
tetris_input_command_t inCmd);
tetris_orientation_t tetris_bastet_getOrientation(void *pVariantData);
/**
* returns the bearing which is requested by the Bastet instance (always 0)
* @param pVariantData the variant data object we want information from
* @return always TETRIS_BEARING_0 as we don't change the bearing in Bastet
*/
tetris_bearing_t tetris_bastet_getBearing(void *pVariantData);
#endif /* BAST_H_ */

10
games/tetris/variant_fp.c

@ -11,9 +11,9 @@
#include "variants.h"
#include "tetris_main.h"
#include "piece.h"
#include "playfield.h"
#include "bucket.h"
#include "highscore.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"
@ -62,7 +62,7 @@ const tetris_variant_t tetrisFpVariant =
&tetris_std_getPreviewPiece,
&tetris_fp_getHighscoreIndex,
&tetris_fp_setLastInput,
&tetris_std_getOrientation
&tetris_std_getBearing
};
@ -85,10 +85,10 @@ void tetris_fp_setLastInput(void *pVariantData,
if (inCmd == TETRIS_INCMD_ROT_CW)
{
pStdVariant->nOrient = (pStdVariant->nOrient + 1) % 4;
pStdVariant->nBearing = (pStdVariant->nBearing + 1) % 4;
}
else if (inCmd == TETRIS_INCMD_ROT_CCW)
{
pStdVariant->nOrient = (pStdVariant->nOrient + 3) % 4;
pStdVariant->nBearing = (pStdVariant->nBearing + 3) % 4;
}
}

2
games/tetris/variant_fp.h

@ -6,7 +6,7 @@
#include "variants.h"
#include "highscore.h"
#include "piece.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"

14
games/tetris/variant_std.c

@ -16,9 +16,9 @@
#include "variants.h"
#include "tetris_main.h"
#include "piece.h"
#include "playfield.h"
#include "bucket.h"
#include "highscore.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"
@ -69,12 +69,12 @@ const tetris_variant_t tetrisStdVariant =
&tetris_std_getPreviewPiece,
&tetris_std_getHighscoreIndex,
&tetris_std_setLastInput,
&tetris_std_getOrientation
&tetris_std_getBearing
};
#endif
void *tetris_std_construct(tetris_playfield_t *pPl)
void *tetris_std_construct(tetris_bucket_t *pBucket)
{
tetris_standard_variant_t *pStdVariant = (tetris_standard_variant_t *)
malloc(sizeof(tetris_standard_variant_t));
@ -150,7 +150,7 @@ void tetris_std_removedLines(void *pVariantData,
assert(pVariantData != 0);
tetris_standard_variant_t *pStdVariant =
(tetris_standard_variant_t *)pVariantData;
uint8_t nLines = tetris_playfield_calculateLines(nRowMask);
uint8_t nLines = tetris_bucket_calculateLines(nRowMask);
pStdVariant->nLines += nLines;
pStdVariant->nLevel = ((pStdVariant->nLines / 10) < TETRIS_INPUT_LEVELS) ?
(pStdVariant->nLines / 10) : (TETRIS_INPUT_LEVELS - 1);
@ -263,11 +263,11 @@ void tetris_std_setLastInput(void *pVariantData,
}
tetris_orientation_t tetris_std_getOrientation(void *pVariantData)
tetris_bearing_t tetris_std_getBearing(void *pVariantData)
{
assert (pVariantData != NULL);
tetris_standard_variant_t *pStdVariant =
(tetris_standard_variant_t *)pVariantData;
return pStdVariant->nOrient;
return pStdVariant->nBearing;
}

10
games/tetris/variant_std.h

@ -5,7 +5,7 @@
#include "../../autoconf.h"
#include "variants.h"
#include "piece.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"
@ -34,7 +34,7 @@ typedef struct tetris_standard_variant_t
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_bearing_t nBearing; /** bearing of the bucket */
}
tetris_standard_variant_t;
@ -48,10 +48,10 @@ const tetris_variant_t tetrisStdVariant;
/**
* constructs a variant data object
* @param pPl related playfield object
* @param pBucket related bucket object
* @return pointer to a newly created variant data object
*/
void *tetris_std_construct(tetris_playfield_t *pPl);
void *tetris_std_construct(tetris_bucket_t *pBucket);
/**
@ -181,6 +181,6 @@ void tetris_std_setLastInput(void *pVariantData,
tetris_input_command_t inCmd);
tetris_orientation_t tetris_std_getOrientation(void *pVariantData);
tetris_bearing_t tetris_std_getBearing(void *pVariantData);
#endif /*VARIANT_STD_H_*/

19
games/tetris/variants.h

@ -2,20 +2,20 @@
#define VARIANTS_H_
#include <inttypes.h>
#include "playfield.h"
#include "bucket.h"
#include "piece.h"
#include "highscore.h"
#include "orientation.h"
#include "bearing.h"
#include "input.h"
typedef struct tetris_variant_t
{
/**
* constructs a variant data object
* @param pPl related playfield object
* @param pBucket related bucket object
* @return pointer to a newly created variant data object
*/
void* (*construct)(tetris_playfield_t *pPl);
void* (*construct)(tetris_bucket_t *pBucket);
/**
@ -132,10 +132,19 @@ typedef struct tetris_variant_t
*/
tetris_highscore_index_t (*getHighscoreIndex)(void *pVariantData);
/**
* inform the variant about the player's last input
* @param pVariantData the variant data object we want to modify
* @param inCmd the last issued command
*/
void (*setLastInput)(void *pVariantData,
tetris_input_command_t inCmd);
tetris_orientation_t (*getOrientation)(void *pVariantData);
/**
* retrieves the variant's preferred bearing of the bucket
* @param pVariantData the variant data object we want information from
*/
tetris_bearing_t (*getBearing)(void *pVariantData);
}
tetris_variant_t;

128
games/tetris/view.c

@ -9,7 +9,7 @@
#include "../../scrolltext/scrolltext.h"
#include "variants.h"
#include "piece.h"
#include "playfield.h"
#include "bucket.h"
#include "view.h"
#define WAIT(ms) wait(ms)
@ -118,30 +118,30 @@
/**
* setpixel replacement which may transform the pixel coordinates
* @param pV pointer to the view we want to draw on
* @param nBearing bearing of the view
* @param x x-coordinate of the pixel
* @param y y-coordinate of the pixel
* @param nColor Color of the pixel
*/
void tetris_view_setpixel(tetris_orientation_t nOrientation,
void tetris_view_setpixel(tetris_bearing_t nBearing,
uint8_t x,
uint8_t y,
uint8_t nColor)
{
x = VIEWCOLS - 1 - x;
switch (nOrientation)
switch (nBearing)
{
case TETRIS_ORIENTATION_0:
case TETRIS_BEARING_0:
setpixel((pixel){x, y}, nColor);
break;
case TETRIS_ORIENTATION_90:
case TETRIS_BEARING_90:
setpixel((pixel){y, VIEWCOLS - 1 - x}, nColor);
break;
case TETRIS_ORIENTATION_180:
case TETRIS_BEARING_180:
setpixel((pixel){VIEWCOLS - 1 - x, VIEWROWS - 1 - y}, nColor);
break;
case TETRIS_ORIENTATION_270:
case TETRIS_BEARING_270:
setpixel((pixel){VIEWROWS - 1 - y, x}, nColor);
break;
}
@ -150,13 +150,13 @@ void tetris_view_setpixel(tetris_orientation_t nOrientation,
/**
* draws a horizontal line
* @param nOrient orientation of the view
* @param nBearing bearing 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,
void tetris_view_drawHLine(tetris_bearing_t nBearing,
uint8_t x1,
uint8_t x2,
uint8_t y,
@ -166,20 +166,20 @@ void tetris_view_drawHLine(tetris_orientation_t nOrient,
for (uint8_t x = x1; x <= x2; ++x)
{
tetris_view_setpixel(nOrient, x, y, nColor);
tetris_view_setpixel(nBearing, x, y, nColor);
}
}
/**
* draws a vertical line
* @param nOrient orientation of the view
* @param nBearing bearing 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,
void tetris_view_drawVLine(tetris_bearing_t nBearing,
uint8_t x,
uint8_t y1,
uint8_t y2,
@ -189,7 +189,7 @@ void tetris_view_drawVLine(tetris_orientation_t nOrient,
for (uint8_t y = y1; y <= y2; ++y)
{
tetris_view_setpixel(nOrient, x, y, nColor);
tetris_view_setpixel(nBearing, x, y, nColor);
}
}
@ -217,34 +217,34 @@ uint8_t tetris_view_getPieceColor(tetris_view_t *pV)
*/
void tetris_view_drawDump(tetris_view_t *pV)
{
assert(pV->pPl != NULL);
if (tetris_playfield_getRow(pV->pPl) <= -4)
assert(pV->pBucket != NULL);
if (tetris_bucket_getRow(pV->pBucket) <= -4)
{
return;
}
tetris_orientation_t nOrient =
pV->pVariantMethods->getOrientation(pV->pVariant);
tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant);
int8_t nPieceRow = tetris_playfield_getRow(pV->pPl);
int8_t nPieceRow = tetris_bucket_getRow(pV->pBucket);
uint16_t nRowMap;
uint16_t nElementMask;
tetris_playfield_status_t status = tetris_playfield_getStatus(pV->pPl);
tetris_bucket_status_t status = tetris_bucket_getStatus(pV->pBucket);
for (int8_t nRow = TETRIS_VIEW_HEIGHT_DUMP - 1; nRow >= 0; --nRow)
{
nRowMap = tetris_playfield_getDumpRow(pV->pPl, nRow);
nRowMap = tetris_bucket_getDumpRow(pV->pBucket, nRow);
// if a piece is hovering or gliding it needs to be drawn
if ((status == TETRIS_PFS_HOVERING) || (status == TETRIS_PFS_GLIDING) ||
(status == TETRIS_PFS_GAMEOVER))
if ((status == TETRIS_BUS_HOVERING) || (status == TETRIS_BUS_GLIDING) ||
(status == TETRIS_BUS_GAMEOVER))
{
if ((nRow >= nPieceRow) && (nRow <= nPieceRow + 3))
{
int8_t y = nRow - nPieceRow;
int8_t nColumn = tetris_playfield_getColumn(pV->pPl);
int8_t nColumn = tetris_bucket_getColumn(pV->pBucket);
uint16_t nPieceMap =
tetris_piece_getBitmap(tetris_playfield_getPiece(pV->pPl));
tetris_piece_getBitmap(tetris_bucket_getPiece(pV->pBucket));
// clear all bits of the piece we are not interested in and
// align the remaining row to LSB
nPieceMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2);
@ -277,7 +277,7 @@ void tetris_view_drawDump(tetris_view_t *pV)
{
nColor = TETRIS_VIEW_COLORSPACE;
}
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_DUMP + x,
tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_DUMP + x,
TETRIS_VIEW_YOFFSET_DUMP + nRow, nColor);
nElementMask <<= 1;
}
@ -292,8 +292,8 @@ void tetris_view_drawDump(tetris_view_t *pV)
*/
void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
{
tetris_orientation_t nOrient =
pV->pVariantMethods->getOrientation(pV->pVariant);
tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant);
if (pPc != NULL)
{
@ -322,7 +322,7 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
{
nColor = TETRIS_VIEW_COLORSPACE;
}
tetris_view_setpixel(nOrient,
tetris_view_setpixel(nBearing,
TETRIS_VIEW_XOFFSET_PREVIEW + x,
TETRIS_VIEW_YOFFSET_PREVIEW + y,
nColor);
@ -336,7 +336,7 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
{
for (uint8_t x = 0; x < 4; ++x)
{
tetris_view_setpixel(nOrient,
tetris_view_setpixel(nBearing,
TETRIS_VIEW_XOFFSET_PREVIEW + x,
TETRIS_VIEW_YOFFSET_PREVIEW + y,
TETRIS_VIEW_COLORSPACE);
@ -354,14 +354,14 @@ void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc)
void tetris_view_drawBorders(tetris_view_t *pV,
uint8_t nColor)
{
tetris_orientation_t nOrient =
pV->pVariantMethods->getOrientation(pV->pVariant);
tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant);
#if TETRIS_VIEW_YOFFSET_DUMP != 0
// fill upper space if required
for (uint8_t y = 0; y < TETRIS_VIEW_YOFFSET_DUMP; ++y)
{
tetris_view_drawHLine(nOrient, 0, VIEWCOLS - 1, y, nColor);
tetris_view_drawHLine(nBearing, 0, VIEWCOLS - 1, y, nColor);
}
#endif
@ -370,7 +370,7 @@ void tetris_view_drawBorders(tetris_view_t *pV,
uint8_t y = TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP;
for (; y < VIEWROWS; ++y)
{
tetris_view_drawHLine(nOrient, 0, VIEWCOLS - 1, y, nColor);
tetris_view_drawHLine(nBearing, 0, VIEWCOLS - 1, y, nColor);
}
#endif
@ -378,7 +378,7 @@ void tetris_view_drawBorders(tetris_view_t *pV,
// 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_drawVLine(nBearing, x, TETRIS_VIEW_YOFFSET_DUMP,
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
}
#endif
@ -388,62 +388,62 @@ void tetris_view_drawBorders(tetris_view_t *pV,
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_drawVLine(nBearing, 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_drawVLine(nBearing, 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_drawVLine(nBearing, x, TETRIS_VIEW_YOFFSET_DUMP,
TETRIS_VIEW_YOFFSET_COUNT100 - 1, nColor);
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
tetris_view_drawVLine(nBearing, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
}
tetris_view_drawVLine(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + 3,
tetris_view_drawVLine(nBearing, 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_drawVLine(nBearing, 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_drawHLine(nBearing, 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_drawHLine(nBearing, 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_drawHLine(nBearing, 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_drawVLine(nBearing, 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)
{
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
tetris_view_drawVLine(nBearing, x, TETRIS_VIEW_YOFFSET_DUMP,
TETRIS_VIEW_YOFFSET_PREVIEW - 1, nColor);
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_PREVIEW + 4,
tetris_view_drawVLine(nBearing, 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)
{
tetris_view_drawVLine(nOrient, x, TETRIS_VIEW_YOFFSET_DUMP,
tetris_view_drawVLine(nBearing, x, TETRIS_VIEW_YOFFSET_DUMP,
TETRIS_VIEW_YOFFSET_DUMP + TETRIS_VIEW_HEIGHT_DUMP - 1, nColor);
}
#endif
@ -468,17 +468,17 @@ void tetris_view_blinkBorders(tetris_view_t *pV)
/**
* lets complete lines blink to emphasize their removal
* @param pPl pointer to the view whose complete lines should blink
* @param pV pointer to the view whose complete lines should blink
*/
void tetris_view_blinkLines(tetris_view_t *pV)
{
// reduce necessity of pointer arithmetic
int8_t nRow = tetris_playfield_getRow(pV->pPl);
uint8_t nRowMask = tetris_playfield_getRowMask(pV->pPl);
int8_t nRow = tetris_bucket_getRow(pV->pBucket);
uint8_t nRowMask = tetris_bucket_getRowMask(pV->pBucket);
tetris_orientation_t nOrient =
pV->pVariantMethods->getOrientation(pV->pVariant);
tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant);
// don't try to draw below the border
int8_t nDeepestRowOffset = ((nRow + 3) < TETRIS_VIEW_HEIGHT_DUMP ?
@ -504,7 +504,7 @@ void tetris_view_blinkLines(tetris_view_t *pV)
uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE
: TETRIS_VIEW_COLORPIECE);
// setpixel((pixel){14 - x, y}, nColor);
tetris_view_setpixel(nOrient,
tetris_view_setpixel(nBearing,
TETRIS_VIEW_XOFFSET_DUMP + x,
TETRIS_VIEW_YOFFSET_DUMP + y,
nColor);
@ -526,8 +526,8 @@ void tetris_view_blinkLines(tetris_view_t *pV)
void tetris_view_showLineNumbers(tetris_view_t *pV)
{
tetris_orientation_t nOrient =
pV->pVariantMethods->getOrientation(pV->pVariant);
tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant);
// get number of completed lines
uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);
@ -543,13 +543,13 @@ void tetris_view_showLineNumbers(tetris_view_t *pV)
// pick drawing color for the ones
uint8_t nOnesPen = nOnes > i ?
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_COUNTER + x,
TETRIS_VIEW_YOFFSET_COUNT1 + y, nOnesPen);
// pick drawing color for the tens
uint8_t nTensPen = nTens > i ?
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_COUNTER + x,
TETRIS_VIEW_YOFFSET_COUNT10 + y, nTensPen);
// a maximum of 399 lines can be displayed
@ -558,7 +558,7 @@ void tetris_view_showLineNumbers(tetris_view_t *pV)
// pick drawing color for the hundreds
uint8_t nHundredsPen = nHundreds > i ?
TETRIS_VIEW_COLORCOUNTER : TETRIS_VIEW_COLORSPACE;
tetris_view_setpixel(nOrient, TETRIS_VIEW_XOFFSET_COUNTER + x,
tetris_view_setpixel(nBearing, TETRIS_VIEW_XOFFSET_COUNTER + x,
TETRIS_VIEW_YOFFSET_COUNT100 + y, nHundredsPen);
}
@ -611,10 +611,10 @@ void tetris_view_formatHighscoreName(uint16_t nHighscoreName,
tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods,
void *pVariantData,
tetris_playfield_t *pPl)
tetris_bucket_t *pBucket)
{
// memory allocation
assert((pVariantData != NULL) && (pPl != NULL));
assert((pVariantData != NULL) && (pBucket != NULL));
tetris_view_t *pView =
(tetris_view_t *) malloc(sizeof(tetris_view_t));
assert(pView != NULL);
@ -623,7 +623,7 @@ tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods,
memset(pView, 0, sizeof(tetris_view_t));
pView->pVariantMethods = pVarMethods;
pView->pVariant = pVariantData;
pView->pPl = pPl;
pView->pBucket = pBucket;
pView->modeCurrent = pView->modeOld = TETRIS_VIMO_RUNNING;
// drawing some first stuff
@ -674,7 +674,7 @@ void tetris_view_update(tetris_view_t *pV)
#endif
// let complete lines blink (if there are any)
if (tetris_playfield_getRowMask(pV->pPl) != 0)
if (tetris_bucket_getRowMask(pV->pBucket) != 0)
{
tetris_view_blinkLines(pV);
}
@ -701,7 +701,7 @@ void tetris_view_update(tetris_view_t *pV)
void tetris_view_showResults(tetris_view_t *pV)
{
#ifdef SCROLLTEXT_SUPPORT
char pszResults[54], pszHighscoreName[4];
char pszResults[55], pszHighscoreName[4];
uint16_t nScore = pV->pVariantMethods->getScore(pV->pVariant);
uint16_t nHighscore = pV->pVariantMethods->getHighscore(pV->pVariant);
uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);

24
games/tetris/view.h

@ -4,7 +4,7 @@
#include <inttypes.h>
#include "variants.h"
#include "piece.h"
#include "playfield.h"
#include "bucket.h"
/**
@ -28,13 +28,13 @@ tetris_view_mode_t;
/** data structure that drives the view module */
typedef struct tetris_view_t
{
const tetris_variant_t *pVariantMethods; /** variant function pointers */
void *pVariant; /** associated variant object */
tetris_playfield_t *pPl; /** associated playfield */
tetris_view_mode_t modeCurrent; /** current presentation mode */
tetris_view_mode_t modeOld; /** old presentation mode */
uint8_t nOldLevel; /** for detecting level changes */
tetris_orientation_t nOrient; /** orientation for the playfield */
const tetris_variant_t *pVariantMethods; /** variant function pointers */
void *pVariant; /** associated variant object */
tetris_bucket_t *pBucket; /** associated bucket */
tetris_view_mode_t modeCurrent; /** current presentation mode */
tetris_view_mode_t modeOld; /** old presentation mode */
uint8_t nOldLevel; /** for detecting level changes */
tetris_bearing_t nBearing; /** bearing of the bucket */
}
tetris_view_t;
@ -54,12 +54,12 @@ tetris_view_t;
* constructs a view for André's borg
* @param pVarMethods associated variant method pointers
* @param pVariantData pointer to variant data object which should be observed
* @param pPl pointer to playfield which should be observed
* @param pBucket pointer to bucket which should be observed
* @return pointer to a newly created view
*/
tetris_view_t *tetris_view_construct(const tetris_variant_t *const pVarMethods,
void *pVariantData,
tetris_playfield_t *pPl);
tetris_bucket_t *pBucket);
/**
@ -75,8 +75,8 @@ void tetris_view_destruct(tetris_view_t *pView);
/**
* destructs a view
* @param w pointer to an int8_t to store the playfield width
* @param h pointer to an int8_t to store the playfield height
* @param w pointer to an int8_t to store the bucket width
* @param h pointer to an int8_t to store the bucket height
*/
void tetris_view_getDimensions(int8_t *w,
int8_t *h);

Loading…
Cancel
Save