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(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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,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
|
* sorts the evaluated pieces by score in ascending order (via bubble sort)
|
||||||
* @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)
|
|
||||||
* @param pBastet the Bastet instance whose evaluated pieces should be sorted
|
* @param pBastet the Bastet instance whose evaluated pieces should be sorted
|
||||||
*/
|
*/
|
||||||
static void tetris_bastet_sortPieces(tetris_bastet_variant_t *pBastet)
|
static void tetris_bastet_sortPieces(tetris_bastet_variant_t *pBastet)
|
||||||
{
|
{
|
||||||
int8_t const nCount = 7;
|
for (uint8_t i = 7; i--;)
|
||||||
// heapify
|
|
||||||
for (int8_t nStart = nCount / 2 - 1; nStart >= 0; --nStart)
|
|
||||||
{
|
{
|
||||||
tetris_bastet_siftDownPieces(pBastet, nStart, nCount - 1);
|
for (uint8_t j = 0; j < i; ++j)
|
||||||
}
|
{
|
||||||
// sorting the heap
|
if (pBastet->nPieceScore[j].nScore >
|
||||||
for (int8_t nEnd = nCount - 1; nEnd > 0; --nEnd)
|
pBastet->nPieceScore[j + 1].nScore)
|
||||||
{
|
{
|
||||||
tetris_bastet_scorepair_t scTmp = pBastet->nPieceScore[nEnd];
|
tetris_bastet_scorepair_t tmp = pBastet->nPieceScore[j];
|
||||||
pBastet->nPieceScore[nEnd] = pBastet->nPieceScore[0];
|
pBastet->nPieceScore[j] = pBastet->nPieceScore[j + 1];
|
||||||
pBastet->nPieceScore[0] = scTmp;
|
pBastet->nPieceScore[j + 1] = tmp;
|
||||||
tetris_bastet_siftDownPieces(pBastet, 0, nEnd - 1);
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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] = ' ';
|
if ((pszName[i] = (nHighscoreName & 0x1F) + 65) == '_')
|
||||||
|
{
|
||||||
|
pszName[i] = ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pszName[1] = ((nHighscoreName >> 5) & 0x1F) + 65;
|
|
||||||
if (pszName[1] == '_')
|
|
||||||
{
|
|
||||||
pszName[1] = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
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_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)
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
void menu()
|
||||||
{
|
{
|
||||||
if (MENU_ITEM_MAX != 0)
|
if (MENU_ITEM_MAX != 0)
|
||||||
|
@ -107,147 +251,3 @@ void menu()
|
||||||
}
|
}
|
||||||
return;
|
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>
|
#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_*/
|
||||||
|
|
||||||
|
|
|
@ -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…
Reference in New Issue