squeezed another 680 bytes
This commit is contained in:
parent
af4ff63f2b
commit
3affa5c9a3
|
@ -73,8 +73,8 @@ void matrix() {
|
|||
}
|
||||
}
|
||||
|
||||
for(y=0;y<NUM_ROWS;y++)
|
||||
for(x=0;x<NUM_COLS;x++){
|
||||
for(y=NUM_ROWS;y--;)
|
||||
for(x=NUM_COLS;x--;){
|
||||
setpixel((pixel){x,y}, get_bright(&matrix_bright,x,y));
|
||||
}
|
||||
|
||||
|
|
|
@ -286,9 +286,9 @@ void off()
|
|||
|
||||
#ifdef ANIMATION_SPIRALE
|
||||
|
||||
void walk(cursor* cur, unsigned char steps, unsigned int delay){
|
||||
static void walk(cursor* cur, unsigned char steps, unsigned int delay){
|
||||
unsigned char x;
|
||||
for(x=0;x<steps;x++){
|
||||
for(x=steps;x--;){
|
||||
set_cursor(cur, next_pixel(cur->pos, cur->dir));
|
||||
wait(delay);
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ unsigned char i, j, x;
|
|||
#ifdef ANIMATION_SCHACHBRETT
|
||||
void schachbrett(unsigned char times){
|
||||
clear_screen(0);
|
||||
for (unsigned char i = 0; i < times; ++i) {
|
||||
for (unsigned char i = times; i--;) {
|
||||
for (unsigned char row = 0; row < NUM_ROWS; ++row) {
|
||||
for (unsigned char col = 0; col < LINEBYTES; ++col) {
|
||||
pixmap[2][row][col] = ((i ^ row) & 0x01) ? 0x55 : 0xAA;
|
||||
|
|
|
@ -50,17 +50,17 @@ void borg_breakout(uint8_t demomode)
|
|||
ball_spawn_default(&(balls[0]));
|
||||
balls[0].strength = START_LIFES;
|
||||
level_init(level);
|
||||
uint8_t tick_divider = 0;
|
||||
uint8_t tick_divider = 1;
|
||||
rebound_init();
|
||||
|
||||
while (cycles != 0)
|
||||
{
|
||||
wait(25);
|
||||
|
||||
if ((tick_divider % 2) || JOYISFIRE)
|
||||
if (tick_divider || JOYISFIRE)
|
||||
rebound_tick(demomode ? &balls[0] : NULL);
|
||||
|
||||
if (tick_divider % 2)
|
||||
if (tick_divider)
|
||||
{
|
||||
ball_think(&(balls[0]));
|
||||
playfield_draw();
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "../../config.h"
|
||||
#include "../../compat/pgmspace.h"
|
||||
#include "../../menu/menu.h"
|
||||
|
@ -17,64 +16,68 @@ void snake_game();
|
|||
#ifdef MENU_SUPPORT
|
||||
// MSB is leftmost pixel
|
||||
static uint8_t icon[8] PROGMEM =
|
||||
{0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xad, 0xa1, 0xbf}; // Snake icon
|
||||
{0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xad, 0xa1, 0xbf}; // Snake icon
|
||||
|
||||
game_descriptor_t snake_game_descriptor __attribute__((section(".game_descriptors"))) ={
|
||||
&snake_game,
|
||||
icon,
|
||||
};
|
||||
game_descriptor_t snake_game_descriptor __attribute__((section(".game_descriptors"))) =
|
||||
{&snake_game, icon};
|
||||
#endif
|
||||
|
||||
void snake_game() {
|
||||
pixel pixels[64] = {{4, NUM_ROWS-2},{4, NUM_ROWS-3}};
|
||||
pixel * head = &pixels[1];
|
||||
pixel * tail = &pixels[0];
|
||||
void snake_game()
|
||||
{
|
||||
pixel pixels[64] = {{4, NUM_ROWS - 2}, {4, NUM_ROWS - 3}};
|
||||
pixel *head = &pixels[1];
|
||||
pixel *tail = &pixels[0];
|
||||
pixel old_head;
|
||||
pixel apples[10];
|
||||
uint8_t joy, joy_old=0xff, joy_cmd=0xff;
|
||||
|
||||
unsigned char x, y, dead = 0;
|
||||
pixel apples[10];
|
||||
unsigned char apple_num = 0;
|
||||
direction dir = up;
|
||||
|
||||
clear_screen(0);
|
||||
|
||||
unsigned char apple_found = 0;
|
||||
unsigned char j;
|
||||
|
||||
clear_screen(0);
|
||||
unsigned char x, y, dead = 0;
|
||||
uint8_t joy, joy_old = 0xff, joy_cmd = 0xff;
|
||||
|
||||
// zeichne Rahmen
|
||||
for (x = 0; x < NUM_COLS; x++) {
|
||||
for (y = 0; y < NUM_ROWS; y++) {
|
||||
if (((x == 0) || (x == NUM_COLS-1)) ||
|
||||
((y == 0) || (y == NUM_ROWS-1))) {
|
||||
for (x = 0; x < NUM_COLS; x++)
|
||||
{
|
||||
for (y = 0; y < NUM_ROWS; y++)
|
||||
{
|
||||
if (((x == 0) || (x == NUM_COLS - 1)) || ((y == 0) || (y
|
||||
== NUM_ROWS - 1)))
|
||||
{
|
||||
setpixel((pixel) {x, y}, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = 0;
|
||||
while (1) {
|
||||
|
||||
while (1)
|
||||
{
|
||||
x++;
|
||||
old_head = *head;
|
||||
++head;
|
||||
if (head == pixels + 64)
|
||||
if (++head == pixels + 64)
|
||||
head = pixels;
|
||||
|
||||
#ifdef GAME_SNAKE_NEWCONTROL
|
||||
if (joy_cmd != 0xff)
|
||||
{
|
||||
if ( (dir == left && joy_cmd != right) ||
|
||||
(dir == right && joy_cmd != left) ||
|
||||
(dir == up && joy_cmd != down) ||
|
||||
(dir == down && joy_cmd != up) )
|
||||
if ((dir == left && joy_cmd != right) || (dir == right && joy_cmd
|
||||
!= left) || (dir == up && joy_cmd != down) || (dir == down
|
||||
&& joy_cmd != up))
|
||||
dir = joy_cmd;
|
||||
}
|
||||
#else
|
||||
if (joy_cmd == right) {
|
||||
if (joy_cmd == right)
|
||||
{
|
||||
dir = direction_r(dir);
|
||||
joy_cmd = 0xff;
|
||||
} else if (joy_cmd == left) {
|
||||
}
|
||||
else if (joy_cmd == left)
|
||||
{
|
||||
dir = direction_r(dir);
|
||||
dir = direction_r(dir);
|
||||
dir = direction_r(dir);
|
||||
|
@ -88,75 +91,100 @@ void snake_game() {
|
|||
apple_found = 0;
|
||||
|
||||
// pr?fen ob man auf nen Apfel drauf ist
|
||||
for (j = 0; j < apple_num; j++) {
|
||||
if ( ( head->x == apples[j].x) &&
|
||||
(head->y == apples[j].y) ){
|
||||
for (j = 0; j < apple_num; j++)
|
||||
{
|
||||
if ((head->x == apples[j].x) && (head->y == apples[j].y))
|
||||
{
|
||||
apple_found = 1;
|
||||
for(; j < apple_num - 1; j++) {
|
||||
apples[j] = apples[j+1];
|
||||
for (; j < apple_num - 1; j++)
|
||||
{
|
||||
apples[j] = apples[j + 1];
|
||||
}
|
||||
apple_num--;
|
||||
goto apple_se;
|
||||
}
|
||||
}
|
||||
if (get_pixel(*head)) {
|
||||
if (get_pixel(*head))
|
||||
{
|
||||
dead = 1;
|
||||
}
|
||||
apple_se:
|
||||
|
||||
if (!dead) {
|
||||
if (!dead)
|
||||
{
|
||||
setpixel(*head, 3);
|
||||
|
||||
// setze neue ?pfel
|
||||
if ( (apple_num < 9) && (random8() < 10) ) {
|
||||
if ((apple_num < 9) && (random8() < 10))
|
||||
{
|
||||
pixel new_apple = (pixel) {(random8() % (NUM_COLS-2))+1,
|
||||
(random8() % (NUM_ROWS-2))+1};
|
||||
if (!get_pixel(new_apple)){
|
||||
if (!get_pixel(new_apple))
|
||||
{
|
||||
apples[apple_num++] = new_apple;
|
||||
}
|
||||
}
|
||||
// l?sche Ende
|
||||
if (!apple_found && !dead) {
|
||||
if (!apple_found && !dead)
|
||||
{
|
||||
clearpixel(*tail);
|
||||
if (++tail == pixels + 64)
|
||||
tail = pixels;
|
||||
}
|
||||
} else {
|
||||
while (tail != head) {
|
||||
}
|
||||
else
|
||||
{
|
||||
while (tail != head)
|
||||
{
|
||||
clearpixel(*tail);
|
||||
if ((++tail) > pixels + 64)
|
||||
tail = pixels;
|
||||
wait (60);
|
||||
wait(60);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < apple_num; j++) {
|
||||
if (x % 2) {
|
||||
for (j = 0; j < apple_num; j++)
|
||||
{
|
||||
if (x % 2)
|
||||
{
|
||||
setpixel(apples[j], 3);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
clearpixel(apples[j]);
|
||||
}
|
||||
}
|
||||
for(j=0;j<20;j++){
|
||||
if(JOYISLEFT){
|
||||
for (j = 0; j < 20; j++)
|
||||
{
|
||||
if (JOYISLEFT)
|
||||
{
|
||||
joy = left;
|
||||
}else if(JOYISRIGHT){
|
||||
}
|
||||
else if (JOYISRIGHT)
|
||||
{
|
||||
joy = right;
|
||||
#ifdef GAME_SNAKE_NEWCONTROL
|
||||
}else if(JOYISUP) {
|
||||
}
|
||||
else if (JOYISUP)
|
||||
{
|
||||
joy = up;
|
||||
} else if(JOYISDOWN) {
|
||||
}
|
||||
else if (JOYISDOWN)
|
||||
{
|
||||
joy = down;
|
||||
#endif
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
joy = 0xff;
|
||||
}
|
||||
if(joy != joy_old){
|
||||
if (joy != joy_old)
|
||||
{
|
||||
joy_cmd = joy;
|
||||
}
|
||||
joy_old = joy;
|
||||
wait (5);
|
||||
wait(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
|
|||
{
|
||||
clearScreen ();
|
||||
|
||||
int x, y;
|
||||
unsigned char x, y;
|
||||
|
||||
/*---SPACESHIP---*/
|
||||
if (sc->pos < RIGHT_BORDER)
|
||||
|
@ -56,9 +56,11 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
|
|||
}
|
||||
|
||||
/*---INVADERS--*/
|
||||
for (y = 0; y < MAX_INVADER_HEIGHT; y++)
|
||||
// for (y = 0; y < MAX_INVADER_HEIGHT; y++)
|
||||
for (y = MAX_INVADER_HEIGHT; y--;)
|
||||
{
|
||||
for (x = 0; x < MAX_INVADER_WIDTH; x++)
|
||||
// for (x = 0; x < MAX_INVADER_WIDTH; x++)
|
||||
for (x = MAX_INVADER_WIDTH; x--;)
|
||||
{
|
||||
//mal in oder statement umwandeln ;-)
|
||||
if (iv->map[x][y] == 0)
|
||||
|
@ -73,7 +75,7 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
|
|||
}
|
||||
|
||||
/*---GUARDS---*/
|
||||
for (x = 0; x < BORG_WIDTH; ++x)
|
||||
for (x = BORG_WIDTH; x--;)
|
||||
{
|
||||
if (guards[x] != 0)
|
||||
{
|
||||
|
@ -82,8 +84,8 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
|
|||
}
|
||||
|
||||
/*---SHOTS--*/
|
||||
int i;
|
||||
for (i = 0; i < MAX_SHOTS; ++i)
|
||||
unsigned char i;
|
||||
for (i = MAX_SHOTS; i--;)
|
||||
{
|
||||
if (st[i].x < BORG_WIDTH && st[i].y < BORG_HEIGHT)
|
||||
{
|
||||
|
|
|
@ -26,8 +26,8 @@ uint8_t const hans[8][11] PROGMEM =
|
|||
|
||||
void initGuards(unsigned char guards[BORG_WIDTH])
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < BORG_WIDTH; ++x)
|
||||
unsigned char x;
|
||||
for (x = BORG_WIDTH; x--;)
|
||||
{
|
||||
guards[x] = 0;
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
|
|||
unsigned char x, y;
|
||||
|
||||
// first zero out map!
|
||||
for (x = 0; x < MAX_INVADER_WIDTH; ++x)
|
||||
for (x = MAX_INVADER_WIDTH; x--;)
|
||||
{
|
||||
for (y = 0; y < MAX_INVADER_HEIGHT; ++y)
|
||||
for (y = MAX_INVADER_HEIGHT; y--;)
|
||||
{
|
||||
iv->map[x][y] = 0;
|
||||
}
|
||||
|
@ -112,9 +112,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
|
|||
break;
|
||||
|
||||
case 3:
|
||||
for (x = 0; x < 11; ++x)
|
||||
for (x = 11; x--;)
|
||||
{
|
||||
for (y = 0; y < 8; ++y)
|
||||
for (y = 8; y--;)
|
||||
{
|
||||
if (pgm_read_byte(&hans[y][x]) != 0)
|
||||
{
|
||||
|
@ -132,9 +132,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
|
|||
break;
|
||||
|
||||
case 4:
|
||||
for (x = 0; x < 11; ++x)
|
||||
for (x = 11; x--;)
|
||||
{
|
||||
for (y = 0; y < 8; ++y)
|
||||
for (y = 8; y--;)
|
||||
{
|
||||
if (pgm_read_byte(&peter[y][x]) != 0)
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@ void procCannon(Cannon * cn, uPixel * shot)
|
|||
|
||||
unsigned char areAtBorder(Invaders * iv)
|
||||
{
|
||||
int y;
|
||||
unsigned char y;
|
||||
for (y = SPACESHIP_LINE + 1; y <= GUARD_LINE; ++y)
|
||||
{
|
||||
if (getInvaderPixel(iv, LEFT_BORDER, y) || getInvaderPixel(iv,
|
||||
|
@ -113,8 +113,7 @@ void procInvaders(Invaders * iv, uPixel st[MAX_SHOTS])
|
|||
void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc,
|
||||
unsigned char guards[BORG_WIDTH], uPixel st[MAX_SHOTS], uPixel * shot)
|
||||
{
|
||||
|
||||
int i;
|
||||
unsigned char i;
|
||||
static unsigned char cmv = 0, imv = 0;
|
||||
|
||||
// shuß mit einen struct mit dem shuß!!
|
||||
|
@ -136,7 +135,7 @@ void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc,
|
|||
{
|
||||
imv = 0;
|
||||
|
||||
for (i = 0; i < MAX_SHOTS; ++i)
|
||||
for (i = MAX_SHOTS; i--;)
|
||||
{
|
||||
if ( /*st[i].x < BORG_WIDTH && */st[i].y < BORG_HEIGHT)
|
||||
{
|
||||
|
@ -157,7 +156,7 @@ void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc,
|
|||
unsigned char tmp;
|
||||
if (!(cn->ready))
|
||||
{
|
||||
for (i = 0; i < MAX_SHOTS; ++i)
|
||||
for (i = MAX_SHOTS; i--;)
|
||||
{
|
||||
if (shot->x == st[i].x && shot->y == st[i].y)
|
||||
{
|
||||
|
@ -282,9 +281,9 @@ unsigned char getStatus(Invaders * iv)
|
|||
|
||||
//count Invader!
|
||||
unsigned char x, y, inv = 0;
|
||||
for (x = 0; x < MAX_INVADER_WIDTH; ++x)
|
||||
for (x = MAX_INVADER_WIDTH; x--;)
|
||||
{
|
||||
for (y = 0; y < MAX_INVADER_HEIGHT; ++y)
|
||||
for (y = MAX_INVADER_HEIGHT; y--;)
|
||||
{
|
||||
if (iv->map[x][y] != 0)
|
||||
inv++;
|
||||
|
@ -296,7 +295,7 @@ unsigned char getStatus(Invaders * iv)
|
|||
return 1;
|
||||
|
||||
//INVADERS REACHED EARTH
|
||||
for (x = 0; x < BORG_WIDTH; ++x)
|
||||
for (x = BORG_WIDTH; x--;)
|
||||
{
|
||||
if (getInvaderPixel(iv, x, GUARD_LINE + 1))
|
||||
return 2;
|
||||
|
|
|
@ -12,11 +12,83 @@
|
|||
* non-interface functions *
|
||||
***************************/
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static uint8_t tetris_bucket_collision(tetris_bucket_t *pBucket,
|
||||
int8_t nCol,
|
||||
int8_t nRow)
|
||||
{
|
||||
// A piece is represented by 16 bits (4 bits per row where the LSB marks the
|
||||
// left most position). The part of the bucket which is covered by the piece
|
||||
// is converted to this format (including the bucket borders) so that a
|
||||
// simple bitwise 'AND' tells us if the piece and the dump overlap.
|
||||
|
||||
// only allow coordinates which are within sane ranges
|
||||
assert(pBucket != NULL);
|
||||
assert((nCol > -4) && (nCol < pBucket->nWidth));
|
||||
assert((nRow > -4) && (nRow < pBucket->nHeight));
|
||||
|
||||
// left and right borders
|
||||
uint16_t const nPieceMap = tetris_piece_getBitmap(pBucket->pPiece);
|
||||
uint16_t nBucketPart = 0;
|
||||
if (nCol < 0)
|
||||
{
|
||||
static uint16_t const nLeftPart[] PROGMEM = {0x7777, 0x3333, 0x1111};
|
||||
nBucketPart = pgm_read_word(&nLeftPart[nCol + 3]);
|
||||
}
|
||||
else if (nCol >= pBucket->nWidth - 3)
|
||||
{
|
||||
static uint16_t const nRightPart[] PROGMEM = {0xEEEE, 0xCCCC, 0x8888};
|
||||
nBucketPart = pgm_read_word(&nRightPart[pBucket->nWidth - nCol - 1]);
|
||||
}
|
||||
// lower border
|
||||
if (nRow > pBucket->nHeight - 4)
|
||||
{
|
||||
nBucketPart |= 0xFFFF << ((pBucket->nHeight - nRow) * 4);
|
||||
}
|
||||
|
||||
// return if the piece already collides with the border
|
||||
if (nPieceMap & nBucketPart)
|
||||
{
|
||||
// collision
|
||||
return 1;
|
||||
}
|
||||
|
||||
// range for inspecting the piece row by row (starting at the bottom)
|
||||
int8_t const nStart = nRow + tetris_piece_getBottomOffset(nPieceMap);
|
||||
int8_t const nStop = nRow >= 0 ? nRow : 0;
|
||||
// mask those blocks which are not covered by the piece
|
||||
uint16_t const nDumpMask = nCol >= 0 ? 0x000F << nCol : 0x000F >> -nCol;
|
||||
// value for shifting blocks to the corresponding part of the piece
|
||||
int8_t nShift = 12 - nCol - 4 * (nRow + 3 - nStart);
|
||||
// compare piece with dump
|
||||
for (int8_t y = nStart; y >= nStop; --y)
|
||||
{
|
||||
uint16_t nTemp = pBucket->dump[y] & nDumpMask;
|
||||
nBucketPart |= nShift >= 0 ? nTemp << nShift : nTemp >> -nShift;
|
||||
if (nPieceMap & nBucketPart)
|
||||
{
|
||||
// collision
|
||||
return 1;
|
||||
}
|
||||
nShift -= 4;
|
||||
}
|
||||
|
||||
// if we reach here, no collision was detected
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* determines if piece is either hovering or gliding and sets the bucket's state
|
||||
* @param pBucket the bucket we want information from
|
||||
*/
|
||||
inline static void tetris_bucket_hoverStatus(tetris_bucket_t *pBucket)
|
||||
static void tetris_bucket_hoverStatus(tetris_bucket_t *pBucket)
|
||||
{
|
||||
assert(pBucket != NULL);
|
||||
|
||||
|
@ -109,11 +181,10 @@ void tetris_bucket_reset(tetris_bucket_t *pBucket)
|
|||
}
|
||||
|
||||
|
||||
void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
||||
tetris_piece_t *pPiece,
|
||||
tetris_piece_t **ppOldPiece)
|
||||
tetris_piece_t *tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
||||
tetris_piece_t *pPiece)
|
||||
{
|
||||
assert((pBucket != NULL) && (pPiece != NULL) && (ppOldPiece != NULL));
|
||||
assert((pBucket != NULL) && (pPiece != NULL));
|
||||
|
||||
// a piece can only be inserted in state TETRIS_BUS_READY
|
||||
assert(pBucket->status == TETRIS_BUS_READY);
|
||||
|
@ -121,10 +192,6 @@ void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
|||
// 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;
|
||||
|
||||
|
@ -132,6 +199,10 @@ void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
|||
pBucket->nRow =
|
||||
1 - tetris_piece_getBottomOffset(tetris_piece_getBitmap(pPiece));
|
||||
|
||||
// replace old piece
|
||||
tetris_piece_t *pOldPiece = pBucket->pPiece;
|
||||
pBucket->pPiece = pPiece;
|
||||
|
||||
// did we already collide with something?
|
||||
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow) == 1)
|
||||
{
|
||||
|
@ -143,71 +214,7 @@ void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
|||
// bring it on!
|
||||
tetris_bucket_hoverStatus(pBucket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t tetris_bucket_collision(tetris_bucket_t *pBucket,
|
||||
int8_t nCol,
|
||||
int8_t nRow)
|
||||
{
|
||||
// A piece is represented by 16 bits (4 bits per row where the LSB marks the
|
||||
// left most position). The part of the bucket which is covered by the piece
|
||||
// is converted to this format (including the bucket borders) so that a
|
||||
// simple bitwise 'AND' tells us if the piece and the dump overlap.
|
||||
|
||||
// only allow coordinates which are within sane ranges
|
||||
assert(pBucket != NULL);
|
||||
assert((nCol > -4) && (nCol < pBucket->nWidth));
|
||||
assert((nRow > -4) && (nRow < pBucket->nHeight));
|
||||
|
||||
// left and right borders
|
||||
uint16_t const nPieceMap = tetris_piece_getBitmap(pBucket->pPiece);
|
||||
uint16_t nBucketPart = 0;
|
||||
if (nCol < 0)
|
||||
{
|
||||
static uint16_t const nLeftPart[] PROGMEM = {0x7777, 0x3333, 0x1111};
|
||||
nBucketPart = pgm_read_word(&nLeftPart[nCol + 3]);
|
||||
}
|
||||
else if (nCol >= pBucket->nWidth - 3)
|
||||
{
|
||||
static uint16_t const nRightPart[] PROGMEM = {0xEEEE, 0xCCCC, 0x8888};
|
||||
nBucketPart = pgm_read_word(&nRightPart[pBucket->nWidth - nCol - 1]);
|
||||
}
|
||||
// lower border
|
||||
if (nRow > pBucket->nHeight - 4)
|
||||
{
|
||||
nBucketPart |= 0xFFFF << ((pBucket->nHeight - nRow) * 4);
|
||||
}
|
||||
|
||||
// return if the piece already collides with the border
|
||||
if (nPieceMap & nBucketPart)
|
||||
{
|
||||
// collision
|
||||
return 1;
|
||||
}
|
||||
|
||||
// range for inspecting the piece row by row (starting at the bottom)
|
||||
int8_t const nStart = nRow + tetris_piece_getBottomOffset(nPieceMap);
|
||||
int8_t const nStop = nRow >= 0 ? nRow : 0;
|
||||
// mask those blocks which are not covered by the piece
|
||||
uint16_t const nDumpMask = nCol >= 0 ? 0x000F << nCol : 0x000F >> -nCol;
|
||||
// value for shifting blocks to the corresponding part of the piece
|
||||
int8_t nShift = 12 - nCol - 4 * (nRow + 3 - nStart);
|
||||
// compare piece with dump
|
||||
for (int8_t y = nStart; y >= nStop; --y)
|
||||
{
|
||||
uint16_t nTemp = pBucket->dump[y] & nDumpMask;
|
||||
nBucketPart |= nShift >= 0 ? nTemp << nShift : nTemp >> -nShift;
|
||||
if (nPieceMap & nBucketPart)
|
||||
{
|
||||
// collision
|
||||
return 1;
|
||||
}
|
||||
nShift -= 4;
|
||||
}
|
||||
|
||||
// if we reach here, no collision was detected
|
||||
return 0;
|
||||
return pOldPiece;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -134,23 +134,10 @@ 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
|
||||
* @return 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);
|
||||
tetris_piece_t *tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
|
||||
tetris_piece_t *pPiece);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,35 +17,21 @@ 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;
|
||||
char pszNick[4] = {'A', 'A', 'A', '\0'};
|
||||
char pszTmp[26];
|
||||
uint8_t nPos = 0, nBlink = 0, nHadfire = 0;
|
||||
|
||||
strncpy(pszNick, "AAA", sizeof(pszNick));
|
||||
while (!nDone)
|
||||
while (1)
|
||||
{
|
||||
// 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
|
||||
static uint8_t const nOffset[3] = {15, 19, 23};
|
||||
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]);
|
||||
nOffset[nPos] , (!nBlink && nPos == 0) ? ' ' : pszNick[0],
|
||||
nOffset[nPos] - 8, (!nBlink && nPos == 1) ? ' ' : pszNick[1],
|
||||
nOffset[nPos] - 15, (!nBlink && nPos == 2) ? ' ' : pszNick[2]);
|
||||
scrolltext(pszTmp);
|
||||
|
||||
// up and down control current char
|
||||
|
@ -73,8 +59,9 @@ uint16_t tetris_highscore_inputName(void)
|
|||
pszNick[nPos] = 'Z';
|
||||
}
|
||||
}
|
||||
|
||||
// left and right control char selections
|
||||
else if (JOYISLEFT && nPos > 0)
|
||||
if (JOYISLEFT && nPos > 0)
|
||||
{
|
||||
nPos--;
|
||||
}
|
||||
|
@ -87,21 +74,13 @@ uint16_t tetris_highscore_inputName(void)
|
|||
if (JOYISFIRE && !nHadfire)
|
||||
{
|
||||
nHadfire = 1;
|
||||
switch (nPos)
|
||||
if (nPos++ == 2)
|
||||
{
|
||||
case 0:
|
||||
nPos = 1;
|
||||
break;
|
||||
case 1:
|
||||
nPos = 2;
|
||||
break;
|
||||
case 2:
|
||||
nDone = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nHadfire && !JOYISFIRE)
|
||||
if (!JOYISFIRE)
|
||||
{
|
||||
nHadfire = 0;
|
||||
}
|
||||
|
@ -117,8 +96,8 @@ uint16_t tetris_highscore_inputName(void)
|
|||
|
||||
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex)
|
||||
{
|
||||
uint16_t nHighscore = 0;
|
||||
nHighscore = eeprom_read_word(&tetris_highscore[nIndex]);
|
||||
uint16_t nHighscore =
|
||||
eeprom_read_word(&tetris_highscore[nIndex]);
|
||||
|
||||
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||
if (nHighscore == 65535)
|
||||
|
@ -142,10 +121,10 @@ void tetris_highscore_saveHighscore(tetris_highscore_index_t nIndex,
|
|||
|
||||
uint16_t tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx)
|
||||
{
|
||||
uint16_t nHighscoreName = 0;
|
||||
nHighscoreName = eeprom_read_word(&tetris_highscore_name[nIdx]);
|
||||
uint16_t nHighscoreName =
|
||||
eeprom_read_word(&tetris_highscore_name[nIdx]);
|
||||
|
||||
// a score of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||
// a value of 65535 is most likely caused by uninitialized EEPROM addresses
|
||||
if (nHighscoreName == 65535)
|
||||
{
|
||||
nHighscoreName = 0;
|
||||
|
|
|
@ -124,8 +124,8 @@ static void tetris_input_chatterProtect(tetris_input_t *pIn,
|
|||
if ((cmd == TETRIS_INCMD_ROT_CW) || (cmd == TETRIS_INCMD_DOWN))
|
||||
{
|
||||
// helper variables (which the compiler hopefully optimizes away)
|
||||
uint8_t nRotCw = pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW];
|
||||
uint8_t nDown = pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN];
|
||||
uint8_t const nRotCw = pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW];
|
||||
uint8_t const nDown = pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN];
|
||||
|
||||
pIn->nIgnoreCmdCounter[TETRIS_INCMD_PAUSE] =
|
||||
(nRotCw > nDown ? nRotCw : nDown);
|
||||
|
|
|
@ -66,7 +66,7 @@ void tetris_piece_rotate(tetris_piece_t *pPc,
|
|||
}
|
||||
|
||||
|
||||
int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc)
|
||||
uint8_t tetris_piece_getAngleCount(tetris_piece_t *pPc)
|
||||
{
|
||||
assert(pPc != NULL);
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ inline static void tetris_piece_setAngle(tetris_piece_t *pPc,
|
|||
* @param pPc piece whose angle count we want to know
|
||||
* @return number of different angles
|
||||
*/
|
||||
int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc);
|
||||
uint8_t tetris_piece_getAngleCount(tetris_piece_t *pPc);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,13 +55,11 @@ void tetris_main(tetris_variant_t const *const pVariantMethods)
|
|||
// the bucket awaits a new piece
|
||||
case TETRIS_BUS_READY:
|
||||
pPiece = pVariantMethods->choosePiece(pVariantData);
|
||||
tetris_piece_t *pOldPiece;
|
||||
tetris_bucket_insertPiece(pBucket, pPiece, &pOldPiece);
|
||||
// destruct old piece (if it exists) since we don't need it anymore
|
||||
if (pOldPiece != NULL)
|
||||
tetris_piece_t *pOld;
|
||||
if ((pOld = tetris_bucket_insertPiece(pBucket, pPiece)) != NULL)
|
||||
{
|
||||
tetris_piece_destruct(pOldPiece);
|
||||
pOldPiece = NULL;
|
||||
tetris_piece_destruct(pOld);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ static void tetris_bastet_predictColHeights(tetris_bastet_variant_t *pBastet,
|
|||
while (pDump != NULL)
|
||||
{
|
||||
uint16_t nColMask = 0x0001 << nStartCol;
|
||||
for (uint8_t x = nStartCol; x <= nStopCol; ++x)
|
||||
for (int8_t x = nStartCol; x <= nStopCol; ++x)
|
||||
{
|
||||
if ((*pDump & nColMask) != 0)
|
||||
{
|
||||
|
@ -131,63 +131,23 @@ static void tetris_bastet_predictColHeights(tetris_bastet_variant_t *pBastet,
|
|||
|
||||
|
||||
/**
|
||||
* this function is part of the heapsort algorithm for sorting pieces by score
|
||||
* @param pBastet the Bastet instance whose evaluated pieces should be sorted
|
||||
* @param nRoot start of the sift
|
||||
* @param nEnd how far down the heap to sift
|
||||
*/
|
||||
static void tetris_bastet_siftDownPieces(tetris_bastet_variant_t *pBastet,
|
||||
int8_t nRoot,
|
||||
int8_t nEnd)
|
||||
{
|
||||
while ((nRoot * 2 + 1) <= nEnd)
|
||||
{
|
||||
int8_t nChild = nRoot * 2 + 1;
|
||||
int8_t nSwap = nRoot;
|
||||
if (pBastet->nPieceScore[nSwap].nScore <
|
||||
pBastet->nPieceScore[nChild].nScore)
|
||||
{
|
||||
nSwap = nChild;
|
||||
}
|
||||
if ((nChild < nEnd) && (pBastet->nPieceScore[nSwap].nScore <
|
||||
pBastet->nPieceScore[nChild + 1].nScore))
|
||||
{
|
||||
nSwap = nChild + 1;
|
||||
}
|
||||
if (nSwap != nRoot)
|
||||
{
|
||||
tetris_bastet_scorepair_t scTmp = pBastet->nPieceScore[nRoot];
|
||||
pBastet->nPieceScore[nRoot] = pBastet->nPieceScore[nSwap];
|
||||
pBastet->nPieceScore[nSwap] = scTmp;
|
||||
nRoot = nSwap;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sorts the evaluated pieces by score in ascending order (via heapsort algo)
|
||||
* sorts the evaluated pieces by score in ascending order (via bubble sort)
|
||||
* @param pBastet the Bastet instance whose evaluated pieces should be sorted
|
||||
*/
|
||||
static void tetris_bastet_sortPieces(tetris_bastet_variant_t *pBastet)
|
||||
{
|
||||
int8_t const nCount = 7;
|
||||
// heapify
|
||||
for (int8_t nStart = nCount / 2 - 1; nStart >= 0; --nStart)
|
||||
for (uint8_t i = 7; i--;)
|
||||
{
|
||||
tetris_bastet_siftDownPieces(pBastet, nStart, nCount - 1);
|
||||
for (uint8_t j = 0; j < i; ++j)
|
||||
{
|
||||
if (pBastet->nPieceScore[j].nScore >
|
||||
pBastet->nPieceScore[j + 1].nScore)
|
||||
{
|
||||
tetris_bastet_scorepair_t tmp = pBastet->nPieceScore[j];
|
||||
pBastet->nPieceScore[j] = pBastet->nPieceScore[j + 1];
|
||||
pBastet->nPieceScore[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
// sorting the heap
|
||||
for (int8_t nEnd = nCount - 1; nEnd > 0; --nEnd)
|
||||
{
|
||||
tetris_bastet_scorepair_t scTmp = pBastet->nPieceScore[nEnd];
|
||||
pBastet->nPieceScore[nEnd] = pBastet->nPieceScore[0];
|
||||
pBastet->nPieceScore[0] = scTmp;
|
||||
tetris_bastet_siftDownPieces(pBastet, 0, nEnd - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +202,7 @@ static int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
|
|||
nStartCol, nStopCol);
|
||||
|
||||
// modify score based on predicted column heights
|
||||
for (uint8_t x = 0; x < nWidth; ++x)
|
||||
for (int8_t x = nWidth; x--;)
|
||||
{
|
||||
if ((x >= nStartCol) && (x <= nStopCol))
|
||||
{
|
||||
|
|
|
@ -132,6 +132,7 @@ static void tetris_view_setpixel(tetris_bearing_t nBearing,
|
|||
pixel px;
|
||||
switch (nBearing)
|
||||
{
|
||||
default:
|
||||
case TETRIS_BEARING_0:
|
||||
px = (pixel){x, y};
|
||||
break;
|
||||
|
@ -434,11 +435,10 @@ static void tetris_view_drawBorders(tetris_view_t *pV,
|
|||
*/
|
||||
static void tetris_view_blinkBorders(tetris_view_t *pV)
|
||||
{
|
||||
for (uint8_t i = 0; i < TETRIS_VIEW_BORDER_BLINK_COUNT; ++i)
|
||||
for (uint8_t i = TETRIS_VIEW_BORDER_BLINK_COUNT * 2; i--;)
|
||||
{
|
||||
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORPIECE);
|
||||
wait(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
||||
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORBORDER);
|
||||
tetris_view_drawBorders(pV, (i & 0x01) ?
|
||||
TETRIS_VIEW_COLORBORDER : TETRIS_VIEW_COLORPIECE);
|
||||
wait(TETRIS_VIEW_BORDER_BLINK_DELAY);
|
||||
}
|
||||
}
|
||||
|
@ -453,8 +453,6 @@ static void tetris_view_blinkLines(tetris_view_t *pV)
|
|||
|
||||
// reduce necessity of pointer arithmetic
|
||||
int8_t nRow = tetris_bucket_getRow(pV->pBucket);
|
||||
uint8_t nRowMask = tetris_bucket_getRowMask(pV->pBucket);
|
||||
int8_t nMask = 0x01;
|
||||
|
||||
tetris_bearing_t nBearing =
|
||||
pV->pVariantMethods->getBearing(pV->pVariant);
|
||||
|
@ -470,14 +468,14 @@ static void tetris_view_blinkLines(tetris_view_t *pV)
|
|||
for (uint8_t nColIdx = 0; nColIdx < 2; ++nColIdx)
|
||||
{
|
||||
// iterate through the possibly complete lines
|
||||
for (uint8_t j = 0; j <= nDeepestRowOffset; ++j)
|
||||
for (uint8_t j = 0, nMask = 0x01; j <= nDeepestRowOffset; ++j)
|
||||
{
|
||||
// is current line a complete line?
|
||||
if ((nRowMask & (nMask << j)) != 0)
|
||||
if ((tetris_bucket_getRowMask(pV->pBucket) & nMask) != 0)
|
||||
{
|
||||
// draw line in current color
|
||||
uint8_t y = nRow + j;
|
||||
for (uint8_t x = 0; x < 10; ++x)
|
||||
int8_t y = nRow + j;
|
||||
for (int8_t x = tetris_bucket_getWidth(pV->pBucket); x--;)
|
||||
{
|
||||
|
||||
uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE
|
||||
|
@ -488,6 +486,7 @@ static void tetris_view_blinkLines(tetris_view_t *pV)
|
|||
nColor);
|
||||
}
|
||||
}
|
||||
nMask <<= 1;
|
||||
}
|
||||
// wait a few ms to make the blink effect visible
|
||||
wait(TETRIS_VIEW_LINE_BLINK_DELAY);
|
||||
|
@ -511,9 +510,9 @@ static void tetris_view_drawLineCounter(tetris_view_t *pV)
|
|||
uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);
|
||||
|
||||
// get decimal places
|
||||
int8_t nOnes = nLines % 10;
|
||||
int8_t nTens = (nLines / 10) % 10;
|
||||
int8_t nHundreds = (nLines / 100) % 10;
|
||||
uint8_t nOnes = nLines % 10;
|
||||
uint8_t nTens = (nLines / 10) % 10;
|
||||
uint8_t nHundreds = (nLines / 100) % 10;
|
||||
|
||||
// draws the decimal places as 3x3 squares with 9 pixels
|
||||
for (uint8_t i = 0, x = 0, y = 0; i < 9; ++i)
|
||||
|
@ -560,24 +559,13 @@ static void tetris_view_drawLineCounter(tetris_view_t *pV)
|
|||
static void tetris_view_formatHighscoreName(uint16_t nHighscoreName,
|
||||
char *pszName)
|
||||
{
|
||||
pszName[0] = ((nHighscoreName >> 10) & 0x1F) + 65;
|
||||
if (pszName[0] == '_')
|
||||
for (uint8_t i = 3; i--; nHighscoreName >>= 5)
|
||||
{
|
||||
pszName[0] = ' ';
|
||||
}
|
||||
|
||||
pszName[1] = ((nHighscoreName >> 5) & 0x1F) + 65;
|
||||
if (pszName[1] == '_')
|
||||
if ((pszName[i] = (nHighscoreName & 0x1F) + 65) == '_')
|
||||
{
|
||||
pszName[1] = ' ';
|
||||
pszName[i] = ' ';
|
||||
}
|
||||
|
||||
pszName[2] = (nHighscoreName & 0x1F) + 65;
|
||||
if (pszName[2] == '_')
|
||||
{
|
||||
pszName[2] = ' ';
|
||||
}
|
||||
|
||||
pszName[3] = '\0';
|
||||
}
|
||||
/*@}*/
|
||||
|
@ -665,7 +653,6 @@ void tetris_view_update(tetris_view_t *pV)
|
|||
tetris_view_blinkBorders(pV);
|
||||
pV->nOldLevel = nLevel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
288
menu/menu.c
288
menu/menu.c
|
@ -35,6 +35,150 @@ extern game_descriptor_t _game_descriptors_end__[];
|
|||
#define MENU_NEXTITEM(item) ((item + 1) % MENU_ITEM_MAX)
|
||||
#define MENU_PREVITEM(item) ((item + MENU_ITEM_MAX - 1) % MENU_ITEM_MAX)
|
||||
|
||||
|
||||
typedef enum menu_direction_t
|
||||
{
|
||||
MENU_DIRECTION_LEFT,
|
||||
MENU_DIRECTION_RIGHT,
|
||||
MENU_DIRECTION_STILL
|
||||
}
|
||||
menu_direction_t;
|
||||
|
||||
|
||||
static void menu_setpixel(uint8_t x, uint8_t y, uint8_t isSet)
|
||||
{
|
||||
uint8_t nColor;
|
||||
|
||||
// mirror mirror on the wall, what's the quirkiest API of them all...
|
||||
x = NUM_COLS - 1 - x;
|
||||
uint8_t nMiddle = (NUM_COLS - MENU_WIDTH_ICON) / 2;
|
||||
|
||||
if (isSet != 0)
|
||||
{
|
||||
if ((x >= nMiddle - MENU_WIDTH_DELIMITER) && (x < (nMiddle
|
||||
+ MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
{
|
||||
nColor = 3;
|
||||
}
|
||||
else if ((x == (nMiddle - MENU_WIDTH_DELIMITER - 1)) || (x == (nMiddle
|
||||
+ MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
{
|
||||
nColor = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
nColor = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nColor = 0;
|
||||
}
|
||||
|
||||
setpixel((pixel){x, y}, nColor);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t menu_getIconPixel(uint8_t item, uint8_t x, uint8_t y)
|
||||
{
|
||||
// is x within the icon or do we have reached the delimiter?
|
||||
if (x < MENU_WIDTH_ICON)
|
||||
{
|
||||
// return pixel
|
||||
return (0x80 >> x) &
|
||||
pgm_read_word(&_game_descriptors_start__[item].icon[y]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// delimiter
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void menu_animate(uint8_t miInitial, menu_direction_t direction)
|
||||
{
|
||||
int16_t nWait = MENU_WAIT_INITIAL;
|
||||
|
||||
// space between left border and the icon in the middle
|
||||
uint8_t nWidthSide = (NUM_COLS - MENU_WIDTH_ICON) / 2;
|
||||
|
||||
// determine the icon at the leftmost position
|
||||
uint8_t mi = miInitial + MENU_ITEM_MAX;
|
||||
uint8_t nBack = nWidthSide / (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
|
||||
if ((nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) != 0)
|
||||
{
|
||||
++nBack;
|
||||
}
|
||||
mi = (mi + MENU_ITEM_MAX - (nBack % MENU_ITEM_MAX)) % MENU_ITEM_MAX;
|
||||
|
||||
// start and stop offsets for the scrolling icons (both are 0 for stills)
|
||||
uint8_t nStart, nStop;
|
||||
if (direction == MENU_DIRECTION_STILL)
|
||||
{
|
||||
nStart = 0;
|
||||
nStop = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nStart = 1;
|
||||
nStop = MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER;
|
||||
}
|
||||
|
||||
// draw menu screen for each offset within the nStart/nStop range
|
||||
uint8_t i;
|
||||
for (i = nStart; i <= nStop; ++i)
|
||||
{
|
||||
// offset of the left most icon if it is cut by the left border
|
||||
uint8_t nInitialSideOffset = (((MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)
|
||||
- (nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
+ (direction == MENU_DIRECTION_LEFT ? i : -i)
|
||||
+ (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))
|
||||
% (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
|
||||
|
||||
// an initial side offset of 0 means the leftmost icon was changed
|
||||
// if we are scrolling to the left, increment value for leftmost item
|
||||
if (direction == MENU_DIRECTION_LEFT && nInitialSideOffset == 0)
|
||||
{
|
||||
mi = MENU_NEXTITEM(mi);
|
||||
}
|
||||
|
||||
// draw the icons from the leftmost position (line by line)
|
||||
uint8_t y;
|
||||
for (y = 0; y < MENU_HEIGHT_ICON; ++y)
|
||||
{
|
||||
uint8_t miCurrent = mi;
|
||||
uint8_t nIconOffset = nInitialSideOffset;
|
||||
uint8_t x;
|
||||
for (x = 0; x < NUM_COLS; ++x)
|
||||
{
|
||||
uint8_t nPixel = menu_getIconPixel(miCurrent, nIconOffset, y);
|
||||
|
||||
menu_setpixel(x, ((NUM_ROWS - MENU_HEIGHT_ICON) / 2) + y,
|
||||
nPixel);
|
||||
if (++nIconOffset >= (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))
|
||||
{
|
||||
nIconOffset = 0;
|
||||
miCurrent = MENU_NEXTITEM(miCurrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// an initial side offset of 0 means the leftmost icon was changed
|
||||
// if we are scrolling to the right, decrement value for leftmost item
|
||||
if (direction == MENU_DIRECTION_RIGHT && nInitialSideOffset == 0)
|
||||
{
|
||||
mi = MENU_PREVITEM(mi);
|
||||
}
|
||||
|
||||
// wait between the frames so that the animation can be seen
|
||||
wait(nWait);
|
||||
// animation speed can be throttled
|
||||
nWait += MENU_WAIT_INCREMENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void menu()
|
||||
{
|
||||
if (MENU_ITEM_MAX != 0)
|
||||
|
@ -107,147 +251,3 @@ void menu()
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint8_t menu_getIconPixel(uint8_t item, int8_t x, int8_t y)
|
||||
{
|
||||
// is x within the icon or do we have reached the delimiter?
|
||||
if (x < MENU_WIDTH_ICON)
|
||||
{
|
||||
// return pixel
|
||||
return (0x80 >> x) &
|
||||
pgm_read_word(&_game_descriptors_start__[item].icon[y]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// delimiter
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void menu_animate(uint8_t miInitial, menu_direction_t direction)
|
||||
{
|
||||
int16_t nWait= MENU_WAIT_INITIAL;
|
||||
|
||||
// space between left border and the icon in the middle
|
||||
int8_t nWidthSide = (NUM_COLS - MENU_WIDTH_ICON) / 2;
|
||||
|
||||
// determine the icon at the leftmost position
|
||||
uint8_t mi = miInitial + MENU_ITEM_MAX;
|
||||
int8_t nBack = nWidthSide / (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
|
||||
if ((nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) != 0)
|
||||
{
|
||||
++nBack;
|
||||
}
|
||||
mi = (mi + MENU_ITEM_MAX - (nBack % MENU_ITEM_MAX)) % MENU_ITEM_MAX;
|
||||
|
||||
// start and stop offsets for the scrolling icons (both are 0 for stills)
|
||||
int8_t nStart, nStop;
|
||||
if (direction == MENU_DIRECTION_STILL)
|
||||
{
|
||||
nStart = 0;
|
||||
nStop = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nStart = 1;
|
||||
nStop = MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER;
|
||||
}
|
||||
|
||||
// draw menu screen for each offset within the nStart/nStop range
|
||||
int8_t i;
|
||||
for (i = nStart; i <= nStop; ++i)
|
||||
{
|
||||
int8_t nOffset;
|
||||
if (direction == MENU_DIRECTION_LEFT)
|
||||
nOffset = i;
|
||||
else
|
||||
nOffset = -i;
|
||||
|
||||
// offset of the left most icon if it is cut by the left border
|
||||
int8_t nInitialSideOffset = (((MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)
|
||||
- (nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
+ nOffset + (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))
|
||||
% (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
|
||||
|
||||
// an initial side offset of 0 means the leftmost icon was changed
|
||||
// if we are scrolling to the left, increment value for leftmost item
|
||||
if (direction == MENU_DIRECTION_LEFT)
|
||||
{
|
||||
if (nInitialSideOffset == 0)
|
||||
{
|
||||
mi = MENU_NEXTITEM(mi);
|
||||
}
|
||||
}
|
||||
|
||||
// draw the icons from the leftmost position (line by line)
|
||||
int8_t y;
|
||||
for (y = 0; y < MENU_HEIGHT_ICON; ++y)
|
||||
{
|
||||
uint8_t miCurrent = mi;
|
||||
int8_t nIconOffset = nInitialSideOffset;
|
||||
int8_t x;
|
||||
for (x = 0; x < NUM_COLS; ++x)
|
||||
{
|
||||
int8_t nPixel = menu_getIconPixel(miCurrent, nIconOffset, y);
|
||||
|
||||
menu_setpixel(x, ((NUM_ROWS - MENU_HEIGHT_ICON) / 2) + y,
|
||||
nPixel);
|
||||
if (++nIconOffset >= (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))
|
||||
{
|
||||
nIconOffset = 0;
|
||||
miCurrent = MENU_NEXTITEM(miCurrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// an initial side offset of 0 means the leftmost icon was changed
|
||||
// if we are scrolling to the right, decrement value for leftmost item
|
||||
if (direction == MENU_DIRECTION_RIGHT)
|
||||
{
|
||||
if (nInitialSideOffset == 0)
|
||||
{
|
||||
mi = MENU_PREVITEM(mi);
|
||||
}
|
||||
}
|
||||
|
||||
// wait between the frames so that the animation can be seen
|
||||
wait(nWait);
|
||||
// animation speed can be throttled
|
||||
nWait += MENU_WAIT_INCREMENT;
|
||||
}
|
||||
}
|
||||
|
||||
void menu_setpixel(int8_t x, int8_t y, int8_t isSet)
|
||||
{
|
||||
uint8_t nColor;
|
||||
|
||||
// mirror mirror on the wall, what's the quirkiest API of them all...
|
||||
x = NUM_COLS - 1 - x;
|
||||
uint8_t nMiddle = (NUM_COLS - MENU_WIDTH_ICON) / 2;
|
||||
|
||||
if (isSet != 0)
|
||||
{
|
||||
if ((x >= nMiddle - MENU_WIDTH_DELIMITER) && (x < (nMiddle
|
||||
+ MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
{
|
||||
nColor = 3;
|
||||
}
|
||||
else if ((x == (nMiddle - MENU_WIDTH_DELIMITER - 1)) || (x == (nMiddle
|
||||
+ MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
|
||||
{
|
||||
nColor = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
nColor = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nColor = 0;
|
||||
}
|
||||
|
||||
setpixel((pixel){x, y}, nColor);
|
||||
}
|
||||
|
||||
|
|
21
menu/menu.h
21
menu/menu.h
|
@ -8,24 +8,6 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
typedef enum menu_item_t
|
||||
{
|
||||
MENU_ITEM_SNAKE,
|
||||
MENU_ITEM_SPACEINVADERS,
|
||||
MENU_ITEM_TETRIS,
|
||||
MENU_ITEM_MAX // fake entry to mark the end
|
||||
}
|
||||
menu_item_t;
|
||||
*/
|
||||
|
||||
typedef enum menu_direction_t
|
||||
{
|
||||
MENU_DIRECTION_LEFT,
|
||||
MENU_DIRECTION_RIGHT,
|
||||
MENU_DIRECTION_STILL
|
||||
}
|
||||
menu_direction_t;
|
||||
|
||||
typedef struct{
|
||||
void(*run)(void);
|
||||
|
@ -34,9 +16,6 @@ typedef struct{
|
|||
|
||||
|
||||
void menu();
|
||||
void menu_animate(uint8_t currentItem, menu_direction_t direction);
|
||||
uint8_t menu_getIconPixel(uint8_t item, int8_t x, int8_t y);
|
||||
void menu_setpixel(int8_t x, int8_t y, int8_t isSet);
|
||||
|
||||
#endif /*MENU_H_*/
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ void text_setpixel(pixel p, unsigned char value ){
|
|||
|
||||
void clear_text_pixmap(unsigned char value){
|
||||
unsigned char y, z;
|
||||
for(y=0;y<NUM_ROWS;y++){
|
||||
for(z=0;z<LINEBYTES;z++){
|
||||
for(y=NUM_ROWS;y--;){
|
||||
for(z=LINEBYTES;z--;){
|
||||
(*text_pixmap)[y][z] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ void clear_text_pixmap(unsigned char value){
|
|||
|
||||
void update_pixmap(){
|
||||
unsigned char x, y, z;
|
||||
for(x=0;x<NUMPLANE;x++){
|
||||
for(y=0;y<NUM_ROWS;y++){
|
||||
for(z=0;z<LINEBYTES;z++){
|
||||
for(x=NUMPLANE;x--;){
|
||||
for(y=NUM_ROWS;y--;){
|
||||
for(z=LINEBYTES;z--;){
|
||||
pixmap[x][y][z] = (*text_pixmap)[y][z];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue