Browse Source

squeezed another 680 bytes

feature/2015
Christian Kroll 14 years ago
parent
commit
3affa5c9a3
  1. 4
      animations/matrix.c
  2. 6
      animations/programm.c
  3. 6
      games/breakout/breakout.c
  4. 172
      games/snake/snake_game.c
  5. 14
      games/space_invaders/invader_draw.c
  6. 16
      games/space_invaders/invader_init.c
  7. 15
      games/space_invaders/invader_proc.c
  8. 155
      games/tetris/bucket.c
  9. 19
      games/tetris/bucket.h
  10. 55
      games/tetris/highscore.c
  11. 4
      games/tetris/input.c
  12. 2
      games/tetris/piece.c
  13. 2
      games/tetris/piece.h
  14. 8
      games/tetris/tetris_main.c
  15. 68
      games/tetris/variant_bastet.c
  16. 55
      games/tetris/view.c
  17. 232
      menu/menu.c
  18. 21
      menu/menu.h
  19. 10
      scrolltext/scrolltext3.c

4
animations/matrix.c

@ -73,8 +73,8 @@ void matrix() {
} }
} }
for(y=0;y<NUM_ROWS;y++) for(y=NUM_ROWS;y--;)
for(x=0;x<NUM_COLS;x++){ for(x=NUM_COLS;x--;){
setpixel((pixel){x,y}, get_bright(&matrix_bright,x,y)); setpixel((pixel){x,y}, get_bright(&matrix_bright,x,y));
} }

6
animations/programm.c

@ -286,9 +286,9 @@ void off()
#ifdef ANIMATION_SPIRALE #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; unsigned char x;
for(x=0;x<steps;x++){ for(x=steps;x--;){
set_cursor(cur, next_pixel(cur->pos, cur->dir)); set_cursor(cur, next_pixel(cur->pos, cur->dir));
wait(delay); wait(delay);
} }
@ -350,7 +350,7 @@ unsigned char i, j, x;
#ifdef ANIMATION_SCHACHBRETT #ifdef ANIMATION_SCHACHBRETT
void schachbrett(unsigned char times){ void schachbrett(unsigned char times){
clear_screen(0); 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 row = 0; row < NUM_ROWS; ++row) {
for (unsigned char col = 0; col < LINEBYTES; ++col) { for (unsigned char col = 0; col < LINEBYTES; ++col) {
pixmap[2][row][col] = ((i ^ row) & 0x01) ? 0x55 : 0xAA; pixmap[2][row][col] = ((i ^ row) & 0x01) ? 0x55 : 0xAA;

6
games/breakout/breakout.c

@ -50,17 +50,17 @@ void borg_breakout(uint8_t demomode)
ball_spawn_default(&(balls[0])); ball_spawn_default(&(balls[0]));
balls[0].strength = START_LIFES; balls[0].strength = START_LIFES;
level_init(level); level_init(level);
uint8_t tick_divider = 0; uint8_t tick_divider = 1;
rebound_init(); rebound_init();
while (cycles != 0) while (cycles != 0)
{ {
wait(25); wait(25);
if ((tick_divider % 2) || JOYISFIRE) if (tick_divider || JOYISFIRE)
rebound_tick(demomode ? &balls[0] : NULL); rebound_tick(demomode ? &balls[0] : NULL);
if (tick_divider % 2) if (tick_divider)
{ {
ball_think(&(balls[0])); ball_think(&(balls[0]));
playfield_draw(); playfield_draw();

172
games/snake/snake_game.c

@ -1,4 +1,3 @@
#include "../../config.h" #include "../../config.h"
#include "../../compat/pgmspace.h" #include "../../compat/pgmspace.h"
#include "../../menu/menu.h" #include "../../menu/menu.h"
@ -17,146 +16,175 @@ void snake_game();
#ifdef MENU_SUPPORT #ifdef MENU_SUPPORT
// MSB is leftmost pixel // MSB is leftmost pixel
static uint8_t icon[8] PROGMEM = 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"))) ={ game_descriptor_t snake_game_descriptor __attribute__((section(".game_descriptors"))) =
&snake_game, {&snake_game, icon};
icon,
};
#endif #endif
void snake_game() { void snake_game()
pixel pixels[64] = {{4, NUM_ROWS-2},{4, NUM_ROWS-3}}; {
pixel * head = &pixels[1]; pixel pixels[64] = {{4, NUM_ROWS - 2}, {4, NUM_ROWS - 3}};
pixel * tail = &pixels[0]; pixel *head = &pixels[1];
pixel *tail = &pixels[0];
pixel old_head; 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; unsigned char apple_num = 0;
direction dir = up; direction dir = up;
clear_screen(0);
unsigned char apple_found = 0; unsigned char apple_found = 0;
unsigned char j; unsigned char j;
clear_screen(0); unsigned char x, y, dead = 0;
uint8_t joy, joy_old = 0xff, joy_cmd = 0xff;
// zeichne Rahmen // zeichne Rahmen
for (x = 0; x < NUM_COLS; x++) { for (x = 0; x < NUM_COLS; x++)
for (y = 0; y < NUM_ROWS; y++) { {
if (((x == 0) || (x == NUM_COLS-1)) || for (y = 0; y < NUM_ROWS; y++)
((y == 0) || (y == NUM_ROWS-1))) { {
if (((x == 0) || (x == NUM_COLS - 1)) || ((y == 0) || (y
== NUM_ROWS - 1)))
{
setpixel((pixel) {x, y}, 3); setpixel((pixel) {x, y}, 3);
} }
} }
} }
x = 0;
while (1) {
x = 0;
while (1)
{
x++; x++;
old_head = *head; old_head = *head;
++head; if (++head == pixels + 64)
if (head == pixels + 64) head = pixels;
head = pixels;
#ifdef GAME_SNAKE_NEWCONTROL #ifdef GAME_SNAKE_NEWCONTROL
if (joy_cmd != 0xff) if (joy_cmd != 0xff)
{ {
if ( (dir == left && joy_cmd != right) || if ((dir == left && joy_cmd != right) || (dir == right && joy_cmd
(dir == right && joy_cmd != left) || != left) || (dir == up && joy_cmd != down) || (dir == down
(dir == up && joy_cmd != down) || && joy_cmd != up))
(dir == down && joy_cmd != up) )
dir = joy_cmd; dir = joy_cmd;
} }
#else #else
if (joy_cmd == right) { if (joy_cmd == right)
dir = direction_r(dir); {
joy_cmd = 0xff; dir = direction_r(dir);
} else if (joy_cmd == left) { joy_cmd = 0xff;
dir = direction_r(dir); }
dir = direction_r(dir); else if (joy_cmd == left)
dir = direction_r(dir); {
joy_cmd = 0xff; dir = direction_r(dir);
} dir = direction_r(dir);
dir = direction_r(dir);
joy_cmd = 0xff;
}
#endif #endif
// kopf einen weiter bewegen // kopf einen weiter bewegen
*head = next_pixel(old_head, dir); *head = next_pixel(old_head, dir);
apple_found = 0; apple_found = 0;
// pr?fen ob man auf nen Apfel drauf ist // pr?fen ob man auf nen Apfel drauf ist
for (j = 0; j < apple_num; j++) { for (j = 0; j < apple_num; j++)
if ( ( head->x == apples[j].x) && {
(head->y == apples[j].y) ){ if ((head->x == apples[j].x) && (head->y == apples[j].y))
{
apple_found = 1; apple_found = 1;
for(; j < apple_num - 1; j++) { for (; j < apple_num - 1; j++)
apples[j] = apples[j+1]; {
apples[j] = apples[j + 1];
} }
apple_num--; apple_num--;
goto apple_se; goto apple_se;
} }
} }
if (get_pixel(*head)) { if (get_pixel(*head))
{
dead = 1; dead = 1;
} }
apple_se: apple_se:
if (!dead) { if (!dead)
{
setpixel(*head, 3); setpixel(*head, 3);
// setze neue ?pfel // setze neue ?pfel
if ( (apple_num < 9) && (random8() < 10) ) { if ((apple_num < 9) && (random8() < 10))
{
pixel new_apple = (pixel) {(random8() % (NUM_COLS-2))+1, pixel new_apple = (pixel) {(random8() % (NUM_COLS-2))+1,
(random8() % (NUM_ROWS-2))+1}; (random8() % (NUM_ROWS-2))+1};
if (!get_pixel(new_apple)){ if (!get_pixel(new_apple))
{
apples[apple_num++] = new_apple; apples[apple_num++] = new_apple;
} }
} }
// l?sche Ende // l?sche Ende
if (!apple_found && !dead) { if (!apple_found && !dead)
{
clearpixel(*tail); clearpixel(*tail);
if (++tail == pixels + 64) if (++tail == pixels + 64)
tail = pixels; tail = pixels;
} }
} else { }
while (tail != head) { else
{
while (tail != head)
{
clearpixel(*tail); clearpixel(*tail);
if ((++tail) > pixels + 64) if ((++tail) > pixels + 64)
tail = pixels; tail = pixels;
wait (60); wait(60);
} }
break; break;
} }
for (j = 0; j < apple_num; j++) { for (j = 0; j < apple_num; j++)
if (x % 2) { {
if (x % 2)
{
setpixel(apples[j], 3); setpixel(apples[j], 3);
} else { }
else
{
clearpixel(apples[j]); clearpixel(apples[j]);
} }
} }
for(j=0;j<20;j++){ for (j = 0; j < 20; j++)
if(JOYISLEFT){ {
if (JOYISLEFT)
{
joy = left; joy = left;
}else if(JOYISRIGHT){ }
else if (JOYISRIGHT)
{
joy = right; joy = right;
#ifdef GAME_SNAKE_NEWCONTROL #ifdef GAME_SNAKE_NEWCONTROL
}else if(JOYISUP) { }
else if (JOYISUP)
{
joy = up; joy = up;
} else if(JOYISDOWN) { }
else if (JOYISDOWN)
{
joy = down; joy = down;
#endif #endif
}else{ }
else
{
joy = 0xff; joy = 0xff;
} }
if(joy != joy_old){ if (joy != joy_old)
{
joy_cmd = joy; joy_cmd = joy;
} }
joy_old = joy; joy_old = joy;
wait (5); wait(5);
} }
} }
} }

14
games/space_invaders/invader_draw.c

@ -43,7 +43,7 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
{ {
clearScreen (); clearScreen ();
int x, y; unsigned char x, y;
/*---SPACESHIP---*/ /*---SPACESHIP---*/
if (sc->pos < RIGHT_BORDER) if (sc->pos < RIGHT_BORDER)
@ -56,9 +56,11 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
} }
/*---INVADERS--*/ /*---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 ;-) //mal in oder statement umwandeln ;-)
if (iv->map[x][y] == 0) if (iv->map[x][y] == 0)
@ -73,7 +75,7 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
} }
/*---GUARDS---*/ /*---GUARDS---*/
for (x = 0; x < BORG_WIDTH; ++x) for (x = BORG_WIDTH; x--;)
{ {
if (guards[x] != 0) if (guards[x] != 0)
{ {
@ -82,8 +84,8 @@ void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn,
} }
/*---SHOTS--*/ /*---SHOTS--*/
int i; unsigned char i;
for (i = 0; i < MAX_SHOTS; ++i) for (i = MAX_SHOTS; i--;)
{ {
if (st[i].x < BORG_WIDTH && st[i].y < BORG_HEIGHT) if (st[i].x < BORG_WIDTH && st[i].y < BORG_HEIGHT)
{ {

16
games/space_invaders/invader_init.c

@ -26,8 +26,8 @@ uint8_t const hans[8][11] PROGMEM =
void initGuards(unsigned char guards[BORG_WIDTH]) void initGuards(unsigned char guards[BORG_WIDTH])
{ {
int x; unsigned char x;
for (x = 0; x < BORG_WIDTH; ++x) for (x = BORG_WIDTH; x--;)
{ {
guards[x] = 0; guards[x] = 0;
} }
@ -44,9 +44,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
unsigned char x, y; unsigned char x, y;
// first zero out map! // 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; iv->map[x][y] = 0;
} }
@ -112,9 +112,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
break; break;
case 3: 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) if (pgm_read_byte(&hans[y][x]) != 0)
{ {
@ -132,9 +132,9 @@ void initInvaders(Invaders * iv, unsigned char lv)
break; break;
case 4: 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) if (pgm_read_byte(&peter[y][x]) != 0)
{ {

15
games/space_invaders/invader_proc.c

@ -45,7 +45,7 @@ void procCannon(Cannon * cn, uPixel * shot)
unsigned char areAtBorder(Invaders * iv) unsigned char areAtBorder(Invaders * iv)
{ {
int y; unsigned char y;
for (y = SPACESHIP_LINE + 1; y <= GUARD_LINE; ++y) for (y = SPACESHIP_LINE + 1; y <= GUARD_LINE; ++y)
{ {
if (getInvaderPixel(iv, LEFT_BORDER, y) || getInvaderPixel(iv, 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, void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc,
unsigned char guards[BORG_WIDTH], uPixel st[MAX_SHOTS], uPixel * shot) unsigned char guards[BORG_WIDTH], uPixel st[MAX_SHOTS], uPixel * shot)
{ {
unsigned char i;
int i;
static unsigned char cmv = 0, imv = 0; static unsigned char cmv = 0, imv = 0;
// shuß mit einen struct mit dem shuß!! // shuß mit einen struct mit dem shuß!!
@ -136,7 +135,7 @@ void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc,
{ {
imv = 0; 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) 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; unsigned char tmp;
if (!(cn->ready)) 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) if (shot->x == st[i].x && shot->y == st[i].y)
{ {
@ -282,9 +281,9 @@ unsigned char getStatus(Invaders * iv)
//count Invader! //count Invader!
unsigned char x, y, inv = 0; 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) if (iv->map[x][y] != 0)
inv++; inv++;
@ -296,7 +295,7 @@ unsigned char getStatus(Invaders * iv)
return 1; return 1;
//INVADERS REACHED EARTH //INVADERS REACHED EARTH
for (x = 0; x < BORG_WIDTH; ++x) for (x = BORG_WIDTH; x--;)
{ {
if (getInvaderPixel(iv, x, GUARD_LINE + 1)) if (getInvaderPixel(iv, x, GUARD_LINE + 1))
return 2; return 2;

155
games/tetris/bucket.c

@ -12,11 +12,83 @@
* non-interface functions * * 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 * determines if piece is either hovering or gliding and sets the bucket's state
* @param pBucket the bucket we want information from * @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); 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 *tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece, tetris_piece_t *pPiece)
tetris_piece_t **ppOldPiece)
{ {
assert((pBucket != NULL) && (pPiece != NULL) && (ppOldPiece != NULL)); assert((pBucket != NULL) && (pPiece != NULL));
// a piece can only be inserted in state TETRIS_BUS_READY // a piece can only be inserted in state TETRIS_BUS_READY
assert(pBucket->status == 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 // row mask is now meaningless
pBucket->nRowMask = 0; pBucket->nRowMask = 0;
// replace old piece
*ppOldPiece = pBucket->pPiece;
pBucket->pPiece = pPiece;
// set horizontal start position (in the middle of the top line) // set horizontal start position (in the middle of the top line)
pBucket->nColumn = (pBucket->nWidth - 2) / 2; pBucket->nColumn = (pBucket->nWidth - 2) / 2;
@ -132,6 +199,10 @@ void tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
pBucket->nRow = pBucket->nRow =
1 - tetris_piece_getBottomOffset(tetris_piece_getBitmap(pPiece)); 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? // did we already collide with something?
if (tetris_bucket_collision(pBucket, pBucket->nColumn, pBucket->nRow) == 1) 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! // bring it on!
tetris_bucket_hoverStatus(pBucket); tetris_bucket_hoverStatus(pBucket);
} }
} return pOldPiece;
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;
} }

19
games/tetris/bucket.h

@ -134,23 +134,10 @@ void tetris_bucket_reset(tetris_bucket_t *pBucket);
* inserts a new piece * inserts a new piece
* @param pBucket bucket to perform action on * @param pBucket bucket to perform action on
* @param pPiece piece to be inserted * @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 *tetris_bucket_insertPiece(tetris_bucket_t *pBucket,
tetris_piece_t *pPiece, 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);
/** /**

55
games/tetris/highscore.c

@ -17,35 +17,21 @@ uint16_t tetris_highscore_name[TETRIS_HISCORE_END] EEMEM;
uint16_t tetris_highscore_inputName(void) uint16_t tetris_highscore_inputName(void)
{ {
#ifdef SCROLLTEXT_SUPPORT #ifdef SCROLLTEXT_SUPPORT
char pszNick[4], pszTmp[26]; char pszNick[4] = {'A', 'A', 'A', '\0'};
unsigned int nOffset; char pszTmp[26];
uint8_t nPos = 0, nBlink = 0, nDone = 0, nHadfire = 0; uint8_t nPos = 0, nBlink = 0, nHadfire = 0;
strncpy(pszNick, "AAA", sizeof(pszNick)); while (1)
while (!nDone)
{ {
// we need our own blink interval // we need our own blink interval
nBlink = (nBlink + 1) % 4; 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 // 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", snprintf(pszTmp, sizeof(pszTmp), "x%u+p1#%c#x%u+p1#%c#x%up1#%c",
nOffset , (!nBlink && nPos == 0) ? ' ' : pszNick[0], nOffset[nPos] , (!nBlink && nPos == 0) ? ' ' : pszNick[0],
nOffset - 8, (!nBlink && nPos == 1) ? ' ' : pszNick[1], nOffset[nPos] - 8, (!nBlink && nPos == 1) ? ' ' : pszNick[1],
nOffset - 15, (!nBlink && nPos == 2) ? ' ' : pszNick[2]); nOffset[nPos] - 15, (!nBlink && nPos == 2) ? ' ' : pszNick[2]);
scrolltext(pszTmp); scrolltext(pszTmp);
// up and down control current char // up and down control current char
@ -73,8 +59,9 @@ uint16_t tetris_highscore_inputName(void)
pszNick[nPos] = 'Z'; pszNick[nPos] = 'Z';
} }
} }
// left and right control char selections // left and right control char selections
else if (JOYISLEFT && nPos > 0) if (JOYISLEFT && nPos > 0)
{ {
nPos--; nPos--;
} }
@ -87,21 +74,13 @@ uint16_t tetris_highscore_inputName(void)
if (JOYISFIRE && !nHadfire) if (JOYISFIRE && !nHadfire)
{ {
nHadfire = 1; nHadfire = 1;
switch (nPos) if (nPos++ == 2)
{ {
case 0:
nPos = 1;
break;
case 1:
nPos = 2;
break;
case 2:
nDone = 1;
break; break;
} }
} }
if (nHadfire && !JOYISFIRE) if (!JOYISFIRE)
{ {
nHadfire = 0; nHadfire = 0;
} }
@ -117,8 +96,8 @@ uint16_t tetris_highscore_inputName(void)
uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex) uint16_t tetris_highscore_retrieveHighscore(tetris_highscore_index_t nIndex)
{ {
uint16_t nHighscore = 0; uint16_t nHighscore =
nHighscore = eeprom_read_word(&tetris_highscore[nIndex]); eeprom_read_word(&tetris_highscore[nIndex]);
// a score of 65535 is most likely caused by uninitialized EEPROM addresses // a score of 65535 is most likely caused by uninitialized EEPROM addresses
if (nHighscore == 65535) 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 tetris_highscore_retrieveHighscoreName(tetris_highscore_index_t nIdx)
{ {
uint16_t nHighscoreName = 0; uint16_t nHighscoreName =
nHighscoreName = eeprom_read_word(&tetris_highscore_name[nIdx]); 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) if (nHighscoreName == 65535)
{ {
nHighscoreName = 0; nHighscoreName = 0;

4
games/tetris/input.c

@ -124,8 +124,8 @@ static void tetris_input_chatterProtect(tetris_input_t *pIn,
if ((cmd == TETRIS_INCMD_ROT_CW) || (cmd == TETRIS_INCMD_DOWN)) if ((cmd == TETRIS_INCMD_ROT_CW) || (cmd == TETRIS_INCMD_DOWN))
{ {
// helper variables (which the compiler hopefully optimizes away) // helper variables (which the compiler hopefully optimizes away)
uint8_t nRotCw = pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW]; uint8_t const nRotCw = pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW];
uint8_t nDown = pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN]; uint8_t const nDown = pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN];
pIn->nIgnoreCmdCounter[TETRIS_INCMD_PAUSE] = pIn->nIgnoreCmdCounter[TETRIS_INCMD_PAUSE] =
(nRotCw > nDown ? nRotCw : nDown); (nRotCw > nDown ? nRotCw : nDown);

2
games/tetris/piece.c

@ -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); assert(pPc != NULL);

2
games/tetris/piece.h

@ -143,7 +143,7 @@ inline static void tetris_piece_setAngle(tetris_piece_t *pPc,
* @param pPc piece whose angle count we want to know * @param pPc piece whose angle count we want to know
* @return number of different angles * @return number of different angles
*/ */
int8_t tetris_piece_getAngleCount(tetris_piece_t *pPc); uint8_t tetris_piece_getAngleCount(tetris_piece_t *pPc);
/** /**

8
games/tetris/tetris_main.c

@ -55,13 +55,11 @@ void tetris_main(tetris_variant_t const *const pVariantMethods)
// the bucket awaits a new piece // the bucket awaits a new piece
case TETRIS_BUS_READY: case TETRIS_BUS_READY:
pPiece = pVariantMethods->choosePiece(pVariantData); 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 // 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); tetris_piece_destruct(pOld);
pOldPiece = NULL;
} }
break; break;

68
games/tetris/variant_bastet.c

@ -116,7 +116,7 @@ static void tetris_bastet_predictColHeights(tetris_bastet_variant_t *pBastet,
while (pDump != NULL) while (pDump != NULL)
{ {
uint16_t nColMask = 0x0001 << nStartCol; 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) if ((*pDump & nColMask) != 0)
{ {
@ -131,67 +131,27 @@ static void tetris_bastet_predictColHeights(tetris_bastet_variant_t *pBastet,
/** /**
* this function is part of the heapsort algorithm for sorting pieces by score * sorts the evaluated pieces by score in ascending order (via bubble sort)
* @param pBastet the Bastet instance whose evaluated pieces should be sorted * @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, static void tetris_bastet_sortPieces(tetris_bastet_variant_t *pBastet)
int8_t nRoot,
int8_t nEnd)
{ {
while ((nRoot * 2 + 1) <= nEnd) for (uint8_t i = 7; i--;)
{ {
int8_t nChild = nRoot * 2 + 1; for (uint8_t j = 0; j < i; ++j)
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; 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;
}
} }
} }
} }
/**
* sorts the evaluated pieces by score in ascending order (via heapsort algo)
* @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)
{
tetris_bastet_siftDownPieces(pBastet, nStart, nCount - 1);
}
// 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);
}
}
/** /**
* calculates a score for a piece at a given column * calculates a score for a piece at a given column
* @param pBastet the bastet instance of interest * @param pBastet the bastet instance of interest
@ -238,11 +198,11 @@ static int16_t tetris_bastet_evaluateMove(tetris_bastet_variant_t *pBastet,
} }
// predict column heights of this move // predict column heights of this move
tetris_bastet_predictColHeights(pBastet, pPiece, nDeepestRow, nColumn, tetris_bastet_predictColHeights(pBastet, pPiece, nDeepestRow, nColumn,
nStartCol, nStopCol); nStartCol, nStopCol);
// modify score based on predicted column heights // 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)) if ((x >= nStartCol) && (x <= nStopCol))
{ {

55
games/tetris/view.c

@ -132,6 +132,7 @@ static void tetris_view_setpixel(tetris_bearing_t nBearing,
pixel px; pixel px;
switch (nBearing) switch (nBearing)
{ {
default:
case TETRIS_BEARING_0: case TETRIS_BEARING_0:
px = (pixel){x, y}; px = (pixel){x, y};
break; break;
@ -158,10 +159,10 @@ static void tetris_view_setpixel(tetris_bearing_t nBearing,
* @param nColor Color of the line * @param nColor Color of the line
*/ */
inline static void tetris_view_drawHLine(tetris_bearing_t nBearing, inline static void tetris_view_drawHLine(tetris_bearing_t nBearing,
uint8_t x1, uint8_t x1,
uint8_t x2, uint8_t x2,
uint8_t y, uint8_t y,
uint8_t nColor) uint8_t nColor)
{ {
assert(x1 <= x2); assert(x1 <= x2);
@ -434,11 +435,10 @@ static void tetris_view_drawBorders(tetris_view_t *pV,
*/ */
static void tetris_view_blinkBorders(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); tetris_view_drawBorders(pV, (i & 0x01) ?
wait(TETRIS_VIEW_BORDER_BLINK_DELAY); TETRIS_VIEW_COLORBORDER : TETRIS_VIEW_COLORPIECE);
tetris_view_drawBorders(pV, TETRIS_VIEW_COLORBORDER);
wait(TETRIS_VIEW_BORDER_BLINK_DELAY); wait(TETRIS_VIEW_BORDER_BLINK_DELAY);
} }
} }
@ -453,8 +453,6 @@ static void tetris_view_blinkLines(tetris_view_t *pV)
// reduce necessity of pointer arithmetic // reduce necessity of pointer arithmetic
int8_t nRow = tetris_bucket_getRow(pV->pBucket); int8_t nRow = tetris_bucket_getRow(pV->pBucket);
uint8_t nRowMask = tetris_bucket_getRowMask(pV->pBucket);
int8_t nMask = 0x01;
tetris_bearing_t nBearing = tetris_bearing_t nBearing =
pV->pVariantMethods->getBearing(pV->pVariant); 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) for (uint8_t nColIdx = 0; nColIdx < 2; ++nColIdx)
{ {
// iterate through the possibly complete lines // 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? // is current line a complete line?
if ((nRowMask & (nMask << j)) != 0) if ((tetris_bucket_getRowMask(pV->pBucket) & nMask) != 0)
{ {
// draw line in current color // draw line in current color
uint8_t y = nRow + j; int8_t y = nRow + j;
for (uint8_t x = 0; x < 10; ++x) for (int8_t x = tetris_bucket_getWidth(pV->pBucket); x--;)
{ {
uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE
@ -488,6 +486,7 @@ static void tetris_view_blinkLines(tetris_view_t *pV)
nColor); nColor);
} }
} }
nMask <<= 1;
} }
// wait a few ms to make the blink effect visible // wait a few ms to make the blink effect visible
wait(TETRIS_VIEW_LINE_BLINK_DELAY); 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); uint16_t nLines = pV->pVariantMethods->getLines(pV->pVariant);
// get decimal places // get decimal places
int8_t nOnes = nLines % 10; uint8_t nOnes = nLines % 10;
int8_t nTens = (nLines / 10) % 10; uint8_t nTens = (nLines / 10) % 10;
int8_t nHundreds = (nLines / 100) % 10; uint8_t nHundreds = (nLines / 100) % 10;
// draws the decimal places as 3x3 squares with 9 pixels // draws the decimal places as 3x3 squares with 9 pixels
for (uint8_t i = 0, x = 0, y = 0; i < 9; ++i) 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, static void tetris_view_formatHighscoreName(uint16_t nHighscoreName,
char *pszName) char *pszName)
{ {
pszName[0] = ((nHighscoreName >> 10) & 0x1F) + 65; for (uint8_t i = 3; i--; nHighscoreName >>= 5)
if (pszName[0] == '_')
{
pszName[0] = ' ';
}
pszName[1] = ((nHighscoreName >> 5) & 0x1F) + 65;
if (pszName[1] == '_')
{ {
pszName[1] = ' '; if ((pszName[i] = (nHighscoreName & 0x1F) + 65) == '_')
} {
pszName[i] = ' ';
pszName[2] = (nHighscoreName & 0x1F) + 65; }
if (pszName[2] == '_')
{
pszName[2] = ' ';
} }
pszName[3] = '\0'; pszName[3] = '\0';
} }
/*@}*/ /*@}*/
@ -665,7 +653,6 @@ void tetris_view_update(tetris_view_t *pV)
tetris_view_blinkBorders(pV); tetris_view_blinkBorders(pV);
pV->nOldLevel = nLevel; pV->nOldLevel = nLevel;
} }
} }

232
menu/menu.c

@ -35,81 +35,51 @@ extern game_descriptor_t _game_descriptors_end__[];
#define MENU_NEXTITEM(item) ((item + 1) % MENU_ITEM_MAX) #define MENU_NEXTITEM(item) ((item + 1) % MENU_ITEM_MAX)
#define MENU_PREVITEM(item) ((item + MENU_ITEM_MAX - 1) % MENU_ITEM_MAX) #define MENU_PREVITEM(item) ((item + MENU_ITEM_MAX - 1) % MENU_ITEM_MAX)
void menu()
typedef enum menu_direction_t
{ {
if (MENU_ITEM_MAX != 0) MENU_DIRECTION_LEFT,
{ MENU_DIRECTION_RIGHT,
// don't let WAIT() query fire button to prevent endless circular jumps MENU_DIRECTION_STILL
waitForFire = 0; }
menu_direction_t;
clear_screen(0);
// wait as long as "fire" is pressed to prevent unwanted selections static void menu_setpixel(uint8_t x, uint8_t y, uint8_t isSet)
while (JOYISFIRE) {
{ uint8_t nColor;
wait(MENU_POLL_INTERVAL);
}
// set initial menu item
static uint8_t miSelection = 0;
// scroll in currently selected menu item
menu_animate(MENU_PREVITEM(miSelection), MENU_DIRECTION_LEFT);
uint16_t nMenuIterations= MENU_TIMEOUT_ITERATIONS; // 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;
while (1) if (isSet != 0)
{
if ((x >= nMiddle - MENU_WIDTH_DELIMITER) && (x < (nMiddle
+ MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
{ {
// the user has made her/his choice nColor = 3;
if (JOYISFIRE) }
{ else if ((x == (nMiddle - MENU_WIDTH_DELIMITER - 1)) || (x == (nMiddle
// prevent unwanted selections + MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
while (JOYISFIRE) {
{ nColor = 2;
wait(MENU_POLL_INTERVAL); }
} else
// work against the chatter effects of dump joysticks {
wait(MENU_WAIT_CHATTER); nColor = 1;
// call corresponding function
_game_descriptors_start__[miSelection].run();
break;
}
// change selected item and do some scrolling
else if (JOYISRIGHT)
{
menu_animate(miSelection, MENU_DIRECTION_LEFT);
miSelection = MENU_NEXTITEM(miSelection);
nMenuIterations = MENU_TIMEOUT_ITERATIONS;
}
else if (JOYISLEFT)
{
menu_animate(miSelection, MENU_DIRECTION_RIGHT);
miSelection = MENU_PREVITEM(miSelection);
nMenuIterations = MENU_TIMEOUT_ITERATIONS;
}
// exit menu
else if (JOYISUP)
{
break;
}
// return if timeout is reached
else
{
wait(MENU_POLL_INTERVAL);
if (--nMenuIterations == 0)
break;
}
} }
waitForFire = 1;
} }
return; else
{
nColor = 0;
}
setpixel((pixel){x, y}, nColor);
} }
uint8_t menu_getIconPixel(uint8_t item, int8_t x, int8_t y) 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? // is x within the icon or do we have reached the delimiter?
if (x < MENU_WIDTH_ICON) if (x < MENU_WIDTH_ICON)
@ -125,16 +95,17 @@ uint8_t menu_getIconPixel(uint8_t item, int8_t x, int8_t y)
} }
} }
void menu_animate(uint8_t miInitial, menu_direction_t direction)
static void menu_animate(uint8_t miInitial, menu_direction_t direction)
{ {
int16_t nWait= MENU_WAIT_INITIAL; int16_t nWait = MENU_WAIT_INITIAL;
// space between left border and the icon in the middle // space between left border and the icon in the middle
int8_t nWidthSide = (NUM_COLS - MENU_WIDTH_ICON) / 2; uint8_t nWidthSide = (NUM_COLS - MENU_WIDTH_ICON) / 2;
// determine the icon at the leftmost position // determine the icon at the leftmost position
uint8_t mi = miInitial + MENU_ITEM_MAX; uint8_t mi = miInitial + MENU_ITEM_MAX;
int8_t nBack = nWidthSide / (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER); uint8_t nBack = nWidthSide / (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
if ((nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) != 0) if ((nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) != 0)
{ {
++nBack; ++nBack;
@ -142,7 +113,7 @@ void menu_animate(uint8_t miInitial, menu_direction_t direction)
mi = (mi + MENU_ITEM_MAX - (nBack % MENU_ITEM_MAX)) % MENU_ITEM_MAX; 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) // start and stop offsets for the scrolling icons (both are 0 for stills)
int8_t nStart, nStop; uint8_t nStart, nStop;
if (direction == MENU_DIRECTION_STILL) if (direction == MENU_DIRECTION_STILL)
{ {
nStart = 0; nStart = 0;
@ -155,41 +126,33 @@ void menu_animate(uint8_t miInitial, menu_direction_t direction)
} }
// draw menu screen for each offset within the nStart/nStop range // draw menu screen for each offset within the nStart/nStop range
int8_t i; uint8_t i;
for (i = nStart; i <= nStop; ++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 // offset of the left most icon if it is cut by the left border
int8_t nInitialSideOffset = (((MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER) uint8_t nInitialSideOffset = (((MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)
- (nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))) - (nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)))
+ nOffset + (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) + (direction == MENU_DIRECTION_LEFT ? i : -i)
+ (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))
% (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER); % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER);
// an initial side offset of 0 means the leftmost icon was changed // 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 we are scrolling to the left, increment value for leftmost item
if (direction == MENU_DIRECTION_LEFT) if (direction == MENU_DIRECTION_LEFT && nInitialSideOffset == 0)
{ {
if (nInitialSideOffset == 0) mi = MENU_NEXTITEM(mi);
{
mi = MENU_NEXTITEM(mi);
}
} }
// draw the icons from the leftmost position (line by line) // draw the icons from the leftmost position (line by line)
int8_t y; uint8_t y;
for (y = 0; y < MENU_HEIGHT_ICON; ++y) for (y = 0; y < MENU_HEIGHT_ICON; ++y)
{ {
uint8_t miCurrent = mi; uint8_t miCurrent = mi;
int8_t nIconOffset = nInitialSideOffset; uint8_t nIconOffset = nInitialSideOffset;
int8_t x; uint8_t x;
for (x = 0; x < NUM_COLS; ++x) for (x = 0; x < NUM_COLS; ++x)
{ {
int8_t nPixel = menu_getIconPixel(miCurrent, nIconOffset, y); uint8_t nPixel = menu_getIconPixel(miCurrent, nIconOffset, y);
menu_setpixel(x, ((NUM_ROWS - MENU_HEIGHT_ICON) / 2) + y, menu_setpixel(x, ((NUM_ROWS - MENU_HEIGHT_ICON) / 2) + y,
nPixel); nPixel);
@ -203,12 +166,9 @@ void menu_animate(uint8_t miInitial, menu_direction_t direction)
// an initial side offset of 0 means the leftmost icon was changed // 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 we are scrolling to the right, decrement value for leftmost item
if (direction == MENU_DIRECTION_RIGHT) if (direction == MENU_DIRECTION_RIGHT && nInitialSideOffset == 0)
{ {
if (nInitialSideOffset == 0) mi = MENU_PREVITEM(mi);
{
mi = MENU_PREVITEM(mi);
}
} }
// wait between the frames so that the animation can be seen // wait between the frames so that the animation can be seen
@ -218,36 +178,76 @@ void menu_animate(uint8_t miInitial, menu_direction_t direction)
} }
} }
void menu_setpixel(int8_t x, int8_t y, int8_t isSet)
void menu()
{ {
uint8_t nColor; if (MENU_ITEM_MAX != 0)
{
// don't let WAIT() query fire button to prevent endless circular jumps
waitForFire = 0;
// mirror mirror on the wall, what's the quirkiest API of them all... clear_screen(0);
x = NUM_COLS - 1 - x;
uint8_t nMiddle = (NUM_COLS - MENU_WIDTH_ICON) / 2;
if (isSet != 0) // wait as long as "fire" is pressed to prevent unwanted selections
{ while (JOYISFIRE)
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; wait(MENU_POLL_INTERVAL);
} }
else
// set initial menu item
static uint8_t miSelection = 0;
// scroll in currently selected menu item
menu_animate(MENU_PREVITEM(miSelection), MENU_DIRECTION_LEFT);
uint16_t nMenuIterations= MENU_TIMEOUT_ITERATIONS;
while (1)
{ {
nColor = 1; // the user has made her/his choice
if (JOYISFIRE)
{
// prevent unwanted selections
while (JOYISFIRE)
{
wait(MENU_POLL_INTERVAL);
}
// work against the chatter effects of dump joysticks
wait(MENU_WAIT_CHATTER);
// call corresponding function
_game_descriptors_start__[miSelection].run();
break;
}
// change selected item and do some scrolling
else if (JOYISRIGHT)
{
menu_animate(miSelection, MENU_DIRECTION_LEFT);
miSelection = MENU_NEXTITEM(miSelection);
nMenuIterations = MENU_TIMEOUT_ITERATIONS;
}
else if (JOYISLEFT)
{
menu_animate(miSelection, MENU_DIRECTION_RIGHT);
miSelection = MENU_PREVITEM(miSelection);
nMenuIterations = MENU_TIMEOUT_ITERATIONS;
}
// exit menu
else if (JOYISUP)
{
break;
}
// return if timeout is reached
else
{
wait(MENU_POLL_INTERVAL);
if (--nMenuIterations == 0)
break;
}
} }
}
else
{
nColor = 0;
}
setpixel((pixel){x, y}, nColor); waitForFire = 1;
}
return;
} }

21
menu/menu.h

@ -8,24 +8,6 @@
#include <inttypes.h> #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{ typedef struct{
void(*run)(void); void(*run)(void);
@ -34,9 +16,6 @@ typedef struct{
void menu(); 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_*/ #endif /*MENU_H_*/

10
scrolltext/scrolltext3.c

@ -55,8 +55,8 @@ void text_setpixel(pixel p, unsigned char value ){
void clear_text_pixmap(unsigned char value){ void clear_text_pixmap(unsigned char value){
unsigned char y, z; unsigned char y, z;
for(y=0;y<NUM_ROWS;y++){ for(y=NUM_ROWS;y--;){
for(z=0;z<LINEBYTES;z++){ for(z=LINEBYTES;z--;){
(*text_pixmap)[y][z] = 0; (*text_pixmap)[y][z] = 0;
} }
} }
@ -65,9 +65,9 @@ void clear_text_pixmap(unsigned char value){
void update_pixmap(){ void update_pixmap(){
unsigned char x, y, z; unsigned char x, y, z;
for(x=0;x<NUMPLANE;x++){ for(x=NUMPLANE;x--;){
for(y=0;y<NUM_ROWS;y++){ for(y=NUM_ROWS;y--;){
for(z=0;z<LINEBYTES;z++){ for(z=LINEBYTES;z--;){
pixmap[x][y][z] = (*text_pixmap)[y][z]; pixmap[x][y][z] = (*text_pixmap)[y][z];
} }
} }

Loading…
Cancel
Save