diff --git a/games/tetris/Makefile b/games/tetris/Makefile index 1c909f8..78ca3bd 100644 --- a/games/tetris/Makefile +++ b/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 diff --git a/games/tetris/bearing.h b/games/tetris/bearing.h new file mode 100644 index 0000000..bde53cd --- /dev/null +++ b/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_ */ diff --git a/games/tetris/bucket.c b/games/tetris/bucket.c new file mode 100644 index 0000000..49e845e --- /dev/null +++ b/games/tetris/bucket.c @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#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 */ diff --git a/games/tetris/bucket.h b/games/tetris/bucket.h new file mode 100644 index 0000000..a32cc54 --- /dev/null +++ b/games/tetris/bucket.h @@ -0,0 +1,295 @@ +#ifndef BUCKET_H_ +#define BUCKET_H_ + +#include +#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_*/ diff --git a/games/tetris/highscore.c b/games/tetris/highscore.c index 66261d3..fe96451 100644 --- a/games/tetris/highscore.c +++ b/games/tetris/highscore.c @@ -1,163 +1,162 @@ -#include -#include -#include -#include -#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 +#include +#include +#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); +} diff --git a/games/tetris/highscore.h b/games/tetris/highscore.h index a14997d..b7f5141 100644 --- a/games/tetris/highscore.h +++ b/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_*/ diff --git a/games/tetris/input.c b/games/tetris/input.c index 5831f83..444169f 100644 --- a/games/tetris/input.c +++ b/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; } } diff --git a/games/tetris/input.h b/games/tetris/input.h index 66f0d93..604280d 100644 --- a/games/tetris/input.h +++ b/games/tetris/input.h @@ -2,7 +2,7 @@ #define INPUT_H_ #include -#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); /*@}*/ diff --git a/games/tetris/tetris_main.c b/games/tetris/tetris_main.c index 4c02a5c..33be32d 100644 --- a/games/tetris/tetris_main.c +++ b/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); } diff --git a/games/tetris/variant_bastet.c b/games/tetris/variant_bastet.c index 3d0c3eb..236f87b 100644 --- a/games/tetris/variant_bastet.c +++ b/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; } diff --git a/games/tetris/variant_bastet.h b/games/tetris/variant_bastet.h index c9f4b28..0cb2965 100644 --- a/games/tetris/variant_bastet.h +++ b/games/tetris/variant_bastet.h @@ -3,9 +3,9 @@ #include #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_ */ diff --git a/games/tetris/variant_fp.c b/games/tetris/variant_fp.c index c00e907..1d19546 100644 --- a/games/tetris/variant_fp.c +++ b/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; } } diff --git a/games/tetris/variant_fp.h b/games/tetris/variant_fp.h index 269cfb2..6164c25 100644 --- a/games/tetris/variant_fp.h +++ b/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" diff --git a/games/tetris/variant_std.c b/games/tetris/variant_std.c index 2b27fdd..75cf0a9 100644 --- a/games/tetris/variant_std.c +++ b/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; } diff --git a/games/tetris/variant_std.h b/games/tetris/variant_std.h index 6609080..3c209d8 100644 --- a/games/tetris/variant_std.h +++ b/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_*/ diff --git a/games/tetris/variants.h b/games/tetris/variants.h index da68d16..71d71d7 100644 --- a/games/tetris/variants.h +++ b/games/tetris/variants.h @@ -2,20 +2,20 @@ #define VARIANTS_H_ #include -#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; diff --git a/games/tetris/view.c b/games/tetris/view.c index 5a098f0..d7b7dd8 100644 --- a/games/tetris/view.c +++ b/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); diff --git a/games/tetris/view.h b/games/tetris/view.h index e4455e2..a5e40c1 100644 --- a/games/tetris/view.h +++ b/games/tetris/view.h @@ -4,7 +4,7 @@ #include #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);