renamed some modules
This commit is contained in:
parent
159b7e79fa
commit
59b18f30d0
|
@ -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
|
||||
|
|
|
@ -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_ */
|
|
@ -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 */
|
|
@ -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_*/
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "variants.h"
|
||||
#include "highscore.h"
|
||||
#include "piece.h"
|
||||
#include "orientation.h"
|
||||
#include "bearing.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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…
Reference in New Issue