summaryrefslogtreecommitdiff
path: root/apps/plugins/wormlet.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/wormlet.c')
-rw-r--r--apps/plugins/wormlet.c924
1 files changed, 667 insertions, 257 deletions
diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c
index d6929f2bd7..d872e8be19 100644
--- a/apps/plugins/wormlet.c
+++ b/apps/plugins/wormlet.c
@@ -17,6 +17,7 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "plugin.h" 19#include "plugin.h"
20#include "configfile.h"
20 21
21PLUGIN_HEADER 22PLUGIN_HEADER
22 23
@@ -26,11 +27,6 @@ PLUGIN_HEADER
26#define FIELD_RECT_WIDTH (LCD_WIDTH - 45) 27#define FIELD_RECT_WIDTH (LCD_WIDTH - 45)
27#define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2) 28#define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2)
28 29
29/* size of the ring of the worm
30 choos a value that is a power of 2 to help
31 the compiler optimize modul operations*/
32#define MAX_WORM_SEGMENTS 64
33
34/* when the game starts */ 30/* when the game starts */
35#define INITIAL_WORM_LENGTH 10 31#define INITIAL_WORM_LENGTH 10
36 32
@@ -109,26 +105,40 @@ PLUGIN_HEADER
109#define FOOD_SIZE 3 105#define FOOD_SIZE 3
110#define ARGH_SIZE 4 106#define ARGH_SIZE 4
111#define SPEED 14 107#define SPEED 14
108#define MAX_WORM_SEGMENTS 128
112#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110) 109#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
113#define FOOD_SIZE 4 110#define FOOD_SIZE 4
114#define ARGH_SIZE 5 111#define ARGH_SIZE 5
115#define SPEED 10 112#define SPEED 10
113#define MAX_WORM_SEGMENTS 128
116#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128) 114#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
117#define FOOD_SIZE 4 115#define FOOD_SIZE 4
118#define ARGH_SIZE 5 116#define ARGH_SIZE 5
119#define SPEED 8 117#define SPEED 8
118#define MAX_WORM_SEGMENTS 256
120#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132) 119#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
121#define FOOD_SIZE 4 120#define FOOD_SIZE 4
122#define ARGH_SIZE 5 121#define ARGH_SIZE 5
123#define SPEED 6 122#define SPEED 6
123#define MAX_WORM_SEGMENTS 256
124#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176) 124#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
125#define FOOD_SIZE 5 125#define FOOD_SIZE 5
126#define ARGH_SIZE 6 126#define ARGH_SIZE 6
127#define SPEED 4 127#define SPEED 4
128#define MAX_WORM_SEGMENTS 512
128#elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240) 129#elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
129#define FOOD_SIZE 7 130#define FOOD_SIZE 7
130#define ARGH_SIZE 8 131#define ARGH_SIZE 8
131#define SPEED 4 132#define SPEED 4
133#define MAX_WORM_SEGMENTS 512
134#endif
135
136#ifdef HAVE_LCD_COLOR
137#define COLOR_WORM LCD_RGBPACK(80, 40, 0)
138#define COLOR_ARGH LCD_RGBPACK(175, 0, 0)
139#define COLOR_FOOD LCD_RGBPACK(0, 150, 0)
140#define COLOR_FG LCD_RGBPACK(0, 0, 0)
141#define COLOR_BG LCD_RGBPACK(181, 199, 231)
132#endif 142#endif
133 143
134/** 144/**
@@ -162,19 +172,32 @@ static int highscore;
162#define MAX_FOOD 5 /* maximal number of food items */ 172#define MAX_FOOD 5 /* maximal number of food items */
163 173
164/* The arrays store the food coordinates */ 174/* The arrays store the food coordinates */
165static char foodx[MAX_FOOD]; 175static int foodx[MAX_FOOD];
166static char foody[MAX_FOOD]; 176static int foody[MAX_FOOD];
167 177
168#define MAX_ARGH 100 /* maximal number of argh items */ 178#define MAX_ARGH 100 /* maximal number of argh items */
169#define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */ 179#define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */
170 180
171/* The arrays store the argh coordinates */ 181/* The arrays store the argh coordinates */
172static char arghx[MAX_ARGH]; 182static int arghx[MAX_ARGH];
173static char arghy[MAX_ARGH]; 183static int arghy[MAX_ARGH];
174 184
175/* the number of arghs that are currently in use */ 185/* the number of arghs that are currently in use */
176static int argh_count; 186static int argh_count;
177 187
188/* the number of arghs per food, settable by user */
189static int arghs_per_food = ARGHS_PER_FOOD;
190/* the size of the argh, settable by user */
191static int argh_size = ARGH_SIZE;
192/* the size of the food, settable by user */
193static int food_size = FOOD_SIZE;
194/* the speed of the worm, settable by user */
195static int speed = SPEED;
196/* the amount a worm grows by eating a food, settable by user */
197static int worm_food = WORM_PER_FOOD;
198
199/* End additional variables */
200
178#ifdef DEBUG_WORMLET 201#ifdef DEBUG_WORMLET
179/* just a buffer used for debug output */ 202/* just a buffer used for debug output */
180static char debugout[15]; 203static char debugout[15];
@@ -217,6 +240,23 @@ static int players = 1;
217/* the rockbox plugin api */ 240/* the rockbox plugin api */
218static struct plugin_api* rb; 241static struct plugin_api* rb;
219 242
243#define SETTINGS_VERSION 1
244#define SETTINGS_MIN_VERSION 1
245#define SETTINGS_FILENAME "wormlet.cfg"
246
247static struct configdata config[] =
248{
249 {TYPE_INT, 0, 1024, &highscore, "highscore", NULL, NULL},
250 {TYPE_INT, 0, 15, &arghs_per_food, "arghs per food", NULL, NULL},
251 {TYPE_INT, 0, 15, &argh_size, "argh size", NULL, NULL},
252 {TYPE_INT, 0, 15, &food_size, "food size", NULL, NULL},
253 {TYPE_INT, 0, 3, &players, "players", NULL, NULL},
254 {TYPE_INT, 0, 3, &worm_count, "worms", NULL, NULL},
255 {TYPE_INT, 0, 20, &speed, "speed", NULL, NULL},
256 {TYPE_INT, 0, 15, &worm_food, "Worm Growth Per Food", NULL, NULL}//,
257 //{TYPE_INT, 0, 3, &use_remote, "use remote", NULL, NULL}
258};
259
220#ifdef DEBUG_WORMLET 260#ifdef DEBUG_WORMLET
221static void set_debug_out(char *str){ 261static void set_debug_out(char *str){
222 strcpy(debugout, str); 262 strcpy(debugout, str);
@@ -432,9 +472,9 @@ static bool worm_in_rect(struct worm *w, int x, int y, int width, int height) {
432static bool specific_food_collision(int foodIndex, int x, int y) { 472static bool specific_food_collision(int foodIndex, int x, int y) {
433 bool retVal = false; 473 bool retVal = false;
434 if (x >= foodx[foodIndex] && 474 if (x >= foodx[foodIndex] &&
435 x < foodx[foodIndex] + FOOD_SIZE && 475 x < foodx[foodIndex] + food_size &&
436 y >= foody[foodIndex] && 476 y >= foody[foodIndex] &&
437 y < foody[foodIndex] + FOOD_SIZE) { 477 y < foody[foodIndex] + food_size) {
438 478
439 retVal = true; 479 retVal = true;
440 } 480 }
@@ -472,8 +512,8 @@ static bool specific_argh_collision(int arghIndex, int x, int y) {
472 512
473 if ( x >= arghx[arghIndex] && 513 if ( x >= arghx[arghIndex] &&
474 y >= arghy[arghIndex] && 514 y >= arghy[arghIndex] &&
475 x < arghx[arghIndex] + ARGH_SIZE && 515 x < arghx[arghIndex] + argh_size &&
476 y < arghy[arghIndex] + ARGH_SIZE ) 516 y < arghy[arghIndex] + argh_size )
477 { 517 {
478 return true; 518 return true;
479 } 519 }
@@ -514,7 +554,7 @@ static bool worm_food_collision(struct worm *w, int foodIndex)
514 bool retVal = false; 554 bool retVal = false;
515 555
516 retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex], 556 retVal = worm_in_rect(w, foodx[foodIndex], foody[foodIndex],
517 FOOD_SIZE - 1, FOOD_SIZE - 1); 557 food_size - 1, food_size - 1);
518 558
519 return retVal; 559 return retVal;
520} 560}
@@ -538,7 +578,7 @@ static bool worm_argh_collision_in_moves(struct worm *w, int argh_idx, int moves
538 y2 = w->y[w->head] + moves * w->diry; 578 y2 = w->y[w->head] + moves * w->diry;
539 579
540 retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx], 580 retVal = line_in_rect(x1, y1, x2, y2, arghx[argh_idx], arghy[argh_idx],
541 ARGH_SIZE, ARGH_SIZE); 581 argh_size, argh_size);
542 return retVal; 582 return retVal;
543} 583}
544 584
@@ -553,7 +593,7 @@ static bool worm_argh_collision(struct worm *w, int arghIndex)
553 bool retVal = false; 593 bool retVal = false;
554 594
555 retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex], 595 retVal = worm_in_rect(w, arghx[arghIndex], arghy[arghIndex],
556 ARGH_SIZE - 1, ARGH_SIZE - 1); 596 argh_size - 1, argh_size - 1);
557 597
558 return retVal; 598 return retVal;
559} 599}
@@ -564,20 +604,18 @@ static bool worm_argh_collision(struct worm *w, int arghIndex)
564 * @param int index 604 * @param int index
565 * Ensure that 0 <= index < MAX_FOOD. 605 * Ensure that 0 <= index < MAX_FOOD.
566 */ 606 */
567static int make_food(int index) { 607static void make_food(int index) {
568 608
569 int x = 0; 609 int x = 0;
570 int y = 0; 610 int y = 0;
571 bool collisionDetected = false; 611 bool collisionDetected = false;
572 int tries = 0;
573 int i; 612 int i;
574 613
575 do { 614 do {
576 /* make coordinates for a new food so that 615 /* make coordinates for a new food so that
577 the entire food lies within the FIELD */ 616 the entire food lies within the FIELD */
578 x = rb->rand() % (FIELD_RECT_WIDTH - FOOD_SIZE); 617 x = rb->rand() % (FIELD_RECT_WIDTH - food_size);
579 y = rb->rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE); 618 y = rb->rand() % (FIELD_RECT_HEIGHT - food_size);
580 tries ++;
581 619
582 /* Ensure that the new food doesn't collide with any 620 /* Ensure that the new food doesn't collide with any
583 existing foods or arghs. 621 existing foods or arghs.
@@ -586,13 +624,13 @@ static int make_food(int index) {
586 */ 624 */
587 collisionDetected = 625 collisionDetected =
588 food_collision(x , y ) >= 0 || 626 food_collision(x , y ) >= 0 ||
589 food_collision(x , y + FOOD_SIZE - 1) >= 0 || 627 food_collision(x , y + food_size - 1) >= 0 ||
590 food_collision(x + FOOD_SIZE - 1, y ) >= 0 || 628 food_collision(x + food_size - 1, y ) >= 0 ||
591 food_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || 629 food_collision(x + food_size - 1, y + food_size - 1) >= 0 ||
592 argh_collision(x , y ) >= 0 || 630 argh_collision(x , y ) >= 0 ||
593 argh_collision(x , y + FOOD_SIZE - 1) >= 0 || 631 argh_collision(x , y + food_size - 1) >= 0 ||
594 argh_collision(x + FOOD_SIZE - 1, y ) >= 0 || 632 argh_collision(x + food_size - 1, y ) >= 0 ||
595 argh_collision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; 633 argh_collision(x + food_size - 1, y + food_size - 1) >= 0;
596 634
597 /* use coordinates for further testing */ 635 /* use coordinates for further testing */
598 foodx[index] = x; 636 foodx[index] = x;
@@ -605,7 +643,7 @@ static int make_food(int index) {
605 } 643 }
606 } 644 }
607 while (collisionDetected); 645 while (collisionDetected);
608 return tries; 646 return;
609} 647}
610 648
611/** 649/**
@@ -620,7 +658,7 @@ static void clear_food(int index)
620 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 658 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
621 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, 659 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X,
622 foody[index] + FIELD_RECT_Y, 660 foody[index] + FIELD_RECT_Y,
623 FOOD_SIZE, FOOD_SIZE); 661 food_size, food_size);
624 rb->lcd_set_drawmode(DRMODE_SOLID); 662 rb->lcd_set_drawmode(DRMODE_SOLID);
625} 663}
626 664
@@ -634,18 +672,18 @@ static void draw_food(int index)
634{ 672{
635 /* draw the food object */ 673 /* draw the food object */
636#ifdef HAVE_LCD_COLOR 674#ifdef HAVE_LCD_COLOR
637 rb->lcd_set_foreground(LCD_RGBPACK(0, 150, 0)); 675 rb->lcd_set_foreground(COLOR_FOOD);
638#endif 676#endif
639 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X, 677 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X,
640 foody[index] + FIELD_RECT_Y, 678 foody[index] + FIELD_RECT_Y,
641 FOOD_SIZE, FOOD_SIZE); 679 food_size, food_size);
642 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 680 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
643 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X + 1, 681 rb->lcd_fillrect(foodx[index] + FIELD_RECT_X + 1,
644 foody[index] + FIELD_RECT_Y + 1, 682 foody[index] + FIELD_RECT_Y + 1,
645 FOOD_SIZE - 2, FOOD_SIZE - 2); 683 food_size - 2, food_size - 2);
646 rb->lcd_set_drawmode(DRMODE_SOLID); 684 rb->lcd_set_drawmode(DRMODE_SOLID);
647#ifdef HAVE_LCD_COLOR 685#ifdef HAVE_LCD_COLOR
648 rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0)); 686 rb->lcd_set_foreground(COLOR_FG);
649#endif 687#endif
650} 688}
651 689
@@ -655,20 +693,18 @@ static void draw_food(int index)
655 * @param int index 693 * @param int index
656 * Ensure that 0 <= index < argh_count < MAX_ARGH. 694 * Ensure that 0 <= index < argh_count < MAX_ARGH.
657 */ 695 */
658static int make_argh(int index) 696static void make_argh(int index)
659{ 697{
660 int x = -1; 698 int x = -1;
661 int y = -1; 699 int y = -1;
662 bool collisionDetected = false; 700 bool collisionDetected = false;
663 int tries = 0;
664 int i; 701 int i;
665 702
666 do { 703 do {
667 /* make coordinates for a new argh so that 704 /* make coordinates for a new argh so that
668 the entire food lies within the FIELD */ 705 the entire food lies within the FIELD */
669 x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); 706 x = rb->rand() % (FIELD_RECT_WIDTH - argh_size);
670 y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); 707 y = rb->rand() % (FIELD_RECT_HEIGHT - argh_size);
671 tries ++;
672 708
673 /* Ensure that the new argh doesn't intersect with any 709 /* Ensure that the new argh doesn't intersect with any
674 existing foods or arghs. 710 existing foods or arghs.
@@ -677,13 +713,13 @@ static int make_argh(int index)
677 */ 713 */
678 collisionDetected = 714 collisionDetected =
679 food_collision(x , y ) >= 0 || 715 food_collision(x , y ) >= 0 ||
680 food_collision(x , y + ARGH_SIZE - 1) >= 0 || 716 food_collision(x , y + argh_size - 1) >= 0 ||
681 food_collision(x + ARGH_SIZE - 1, y ) >= 0 || 717 food_collision(x + argh_size - 1, y ) >= 0 ||
682 food_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || 718 food_collision(x + argh_size - 1, y + argh_size - 1) >= 0 ||
683 argh_collision(x , y ) >= 0 || 719 argh_collision(x , y ) >= 0 ||
684 argh_collision(x , y + ARGH_SIZE - 1) >= 0 || 720 argh_collision(x , y + argh_size - 1) >= 0 ||
685 argh_collision(x + ARGH_SIZE - 1, y ) >= 0 || 721 argh_collision(x + argh_size - 1, y ) >= 0 ||
686 argh_collision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; 722 argh_collision(x + argh_size - 1, y + argh_size - 1) >= 0;
687 723
688 /* use the candidate coordinates to make a real argh */ 724 /* use the candidate coordinates to make a real argh */
689 arghx[index] = x; 725 arghx[index] = x;
@@ -697,7 +733,7 @@ static int make_argh(int index)
697 } 733 }
698 } 734 }
699 while (collisionDetected); 735 while (collisionDetected);
700 return tries; 736 return;
701} 737}
702 738
703/** 739/**
@@ -710,13 +746,13 @@ static void draw_argh(int index)
710{ 746{
711 /* draw the new argh */ 747 /* draw the new argh */
712#ifdef HAVE_LCD_COLOR 748#ifdef HAVE_LCD_COLOR
713 rb->lcd_set_foreground(LCD_RGBPACK(175, 0, 0)); 749 rb->lcd_set_foreground(COLOR_ARGH);
714#endif 750#endif
715 rb->lcd_fillrect(arghx[index] + FIELD_RECT_X, 751 rb->lcd_fillrect(arghx[index] + FIELD_RECT_X,
716 arghy[index] + FIELD_RECT_Y, 752 arghy[index] + FIELD_RECT_Y,
717 ARGH_SIZE, ARGH_SIZE); 753 argh_size, argh_size);
718#ifdef HAVE_LCD_COLOR 754#ifdef HAVE_LCD_COLOR
719 rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0)); 755 rb->lcd_set_foreground(COLOR_FG);
720#endif 756#endif
721} 757}
722 758
@@ -935,7 +971,7 @@ static void move_worm(struct worm *w)
935static void draw_worm(struct worm *w) 971static void draw_worm(struct worm *w)
936{ 972{
937#ifdef HAVE_LCD_COLOR 973#ifdef HAVE_LCD_COLOR
938 rb->lcd_set_foreground(LCD_RGBPACK(80, 40, 0)); 974 rb->lcd_set_foreground(COLOR_WORM);
939#endif 975#endif
940 /* draw the new head */ 976 /* draw the new head */
941 int x = w->x[w->head]; 977 int x = w->x[w->head];
@@ -954,7 +990,7 @@ static void draw_worm(struct worm *w)
954 } 990 }
955 rb->lcd_set_drawmode(DRMODE_SOLID); 991 rb->lcd_set_drawmode(DRMODE_SOLID);
956#ifdef HAVE_LCD_COLOR 992#ifdef HAVE_LCD_COLOR
957 rb->lcd_set_foreground(LCD_RGBPACK(0, 0, 0)); 993 rb->lcd_set_foreground(COLOR_FG);
958#endif 994#endif
959} 995}
960 996
@@ -1351,7 +1387,7 @@ static bool process_collisions(struct worm *w)
1351 make_food(index); 1387 make_food(index);
1352 draw_food(index); 1388 draw_food(index);
1353 1389
1354 for (i = 0; i < ARGHS_PER_FOOD; i++) { 1390 for (i = 0; i < arghs_per_food; i++) {
1355 argh_count++; 1391 argh_count++;
1356 if (argh_count > MAX_ARGH) 1392 if (argh_count > MAX_ARGH)
1357 argh_count = MAX_ARGH; 1393 argh_count = MAX_ARGH;
@@ -1359,7 +1395,7 @@ static bool process_collisions(struct worm *w)
1359 draw_argh(argh_count - 1); 1395 draw_argh(argh_count - 1);
1360 } 1396 }
1361 1397
1362 add_growing(w, WORM_PER_FOOD); 1398 add_growing(w, worm_food);
1363 1399
1364 draw_worm(w); 1400 draw_worm(w);
1365 } 1401 }
@@ -1386,10 +1422,11 @@ static bool process_collisions(struct worm *w)
1386 * with a dead worm. Returns false if the user 1422 * with a dead worm. Returns false if the user
1387 * aborted the game manually. 1423 * aborted the game manually.
1388 */ 1424 */
1389static bool run(void) 1425static int run(void)
1390{ 1426{
1391 int button = 0; 1427 int button = 0;
1392 int wormDead = false; 1428 int wormDead = false;
1429 bool paused = false;
1393 1430
1394 /* ticks are counted to compensate speed variations */ 1431 /* ticks are counted to compensate speed variations */
1395 long cycle_start = 0, cycle_end = 0; 1432 long cycle_start = 0, cycle_end = 0;
@@ -1404,116 +1441,130 @@ static bool run(void)
1404 1441
1405 cycle_start = *rb->current_tick; 1442 cycle_start = *rb->current_tick;
1406 /* change the direction of the worm */ 1443 /* change the direction of the worm */
1407 while (button != BTN_QUIT && ! wormDead) 1444 while (!wormDead)
1408 { 1445 {
1409 int i; 1446 int i;
1410 long cycle_duration ; 1447 long cycle_duration=0;
1448
1411 switch (button) { 1449 switch (button) {
1412 case BTN_DIR_UP: 1450 case BTN_STARTPAUSE:
1413 if (players == 1 && !use_remote) { 1451 paused = !paused;
1414 player1_dir = NORTH;
1415 }
1416 break; 1452 break;
1417 1453 case BTN_STOPRESET:
1418 case BTN_DIR_DOWN: 1454 if (paused)
1419 if (players == 1 && !use_remote) { 1455 return 1; /* restart game */
1420 player1_dir = SOUTH; 1456 else
1421 } 1457 paused = true;
1422 break; 1458 break;
1423 1459 case BTN_QUIT:
1424 case BTN_DIR_LEFT: 1460 return 2; /* back to menu */
1425 if (players != 1 || use_remote) {
1426 player1_dir = (player1_dir + 3) % 4;
1427 } else {
1428 player1_dir = WEST;
1429 }
1430 break; 1461 break;
1462 }
1463 if (!paused)
1464 {
1465 switch (button) {
1466 case BTN_DIR_UP:
1467 if (players == 1 && !use_remote) {
1468 player1_dir = NORTH;
1469 }
1470 break;
1431 1471
1432 case BTN_DIR_RIGHT: 1472 case BTN_DIR_DOWN:
1433 if (players != 1 || use_remote) { 1473 if (players == 1 && !use_remote) {
1434 player1_dir = (player1_dir + 1) % 4; 1474 player1_dir = SOUTH;
1435 } else { 1475 }
1436 player1_dir = EAST; 1476 break;
1437 } 1477
1438 break; 1478 case BTN_DIR_LEFT:
1479 if (players != 1 || use_remote) {
1480 player1_dir = (player1_dir + 3) % 4;
1481 } else {
1482 player1_dir = WEST;
1483 }
1484 break;
1485
1486 case BTN_DIR_RIGHT:
1487 if (players != 1 || use_remote) {
1488 player1_dir = (player1_dir + 1) % 4;
1489 } else {
1490 player1_dir = EAST;
1491 }
1492 break;
1439 1493
1440#ifdef MULTIPLAYER 1494#ifdef MULTIPLAYER
1441 case BTN_PLAYER2_DIR1: 1495 case BTN_PLAYER2_DIR1:
1442 player2_dir = (player2_dir + 3) % 4; 1496 player2_dir = (player2_dir + 3) % 4;
1443 break; 1497 break;
1444 1498
1445 case BTN_PLAYER2_DIR2: 1499 case BTN_PLAYER2_DIR2:
1446 player2_dir = (player2_dir + 1) % 4; 1500 player2_dir = (player2_dir + 1) % 4;
1447 break; 1501 break;
1448#endif 1502#endif
1449 1503
1450#ifdef REMOTE 1504#ifdef REMOTE
1451 case BTN_RC_UP: 1505 case BTN_RC_UP:
1452 player3_dir = (player3_dir + 1) % 4; 1506 player3_dir = (player3_dir + 1) % 4;
1453 break; 1507 break;
1454 1508
1455 case BTN_RC_DOWN: 1509 case BTN_RC_DOWN:
1456 player3_dir = (player3_dir + 3) % 4; 1510 player3_dir = (player3_dir + 3) % 4;
1457 break; 1511 break;
1458#endif 1512#endif
1513 }
1459 1514
1460 case BTN_STARTPAUSE:
1461 do {
1462 button = rb->button_get(true);
1463 } while (button != BTN_STARTPAUSE &&
1464 button != BTN_QUIT &&
1465 button != BTN_STOPRESET);
1466 break;
1467 }
1468 1515
1469 for (i = 0; i < worm_count; i++) { 1516 for (i = 0; i < worm_count; i++) {
1470 worms[i].fetch_worm_direction(&worms[i]); 1517 worms[i].fetch_worm_direction(&worms[i]);
1471 } 1518 }
1472 1519
1473 wormDead = true;
1474 for (i = 0; i < worm_count; i++){
1475 struct worm *w = &worms[i];
1476 move_worm(w);
1477 wormDead &= process_collisions(w);
1478 draw_worm(w);
1479 }
1480 score_board();
1481 rb->lcd_update();
1482 if (button == BTN_STOPRESET) {
1483 wormDead = true; 1520 wormDead = true;
1484 } 1521 for (i = 0; i < worm_count; i++){
1522 struct worm *w = &worms[i];
1523 move_worm(w);
1524 wormDead &= process_collisions(w);
1525 draw_worm(w);
1526 }
1527 score_board();
1528 rb->lcd_update();
1529 if (button == BTN_STOPRESET) {
1530 wormDead = true;
1531 }
1485 1532
1486 /* here the wormlet game cycle ends 1533 /* here the wormlet game cycle ends
1487 thus the current tick is stored 1534 thus the current tick is stored
1488 as end time */ 1535 as end time */
1489 cycle_end = *rb->current_tick; 1536 cycle_end = *rb->current_tick;
1490 1537
1491 /* The duration of the game cycle */ 1538 /* The duration of the game cycle */
1492 cycle_duration = cycle_end - cycle_start; 1539 cycle_duration = cycle_end - cycle_start;
1493 cycle_duration = MAX(0, cycle_duration); 1540 cycle_duration = MAX(0, cycle_duration);
1494 cycle_duration = MIN(SPEED -1, cycle_duration); 1541 cycle_duration = MIN(speed -1, cycle_duration);
1495 1542
1496 1543
1497#ifdef DEBUG_WORMLET 1544#ifdef DEBUG_WORMLET
1498 ticks_to_max_cycle_reset--; 1545 ticks_to_max_cycle_reset--;
1499 if (ticks_to_max_cycle_reset <= 0) { 1546 if (ticks_to_max_cycle_reset <= 0) {
1500 max_cycle = 0; 1547 max_cycle = 0;
1501 } 1548 }
1502 1549
1503 if (max_cycle < cycle_duration) { 1550 if (max_cycle < cycle_duration) {
1504 max_cycle = cycle_duration; 1551 max_cycle = cycle_duration;
1505 ticks_to_max_cycle_reset = 20; 1552 ticks_to_max_cycle_reset = 20;
1506 } 1553 }
1507 rb->snprintf(buf, sizeof buf, "ticks %d", max_cycle); 1554 rb->snprintf(buf, sizeof buf, "ticks %d", max_cycle);
1508 set_debug_out(buf); 1555 set_debug_out(buf);
1509#endif 1556#endif
1557 }
1510 /* adjust the number of ticks to wait for a button. 1558 /* adjust the number of ticks to wait for a button.
1511 This ensures that a complete game cycle including 1559 This ensures that a complete game cycle including
1512 user input runs in constant time */ 1560 user input runs in constant time */
1513 button = rb->button_get_w_tmo(SPEED - cycle_duration); 1561 button = rb->button_get_w_tmo(speed - cycle_duration);
1514 cycle_start = *rb->current_tick; 1562 cycle_start = *rb->current_tick;
1515 } 1563 }
1516 return wormDead; 1564
1565 rb->splash(HZ*2, true, "Game Over!");
1566
1567 return 2; /* back to menu */
1517} 1568}
1518 1569
1519#ifdef DEBUG_WORMLET 1570#ifdef DEBUG_WORMLET
@@ -1555,7 +1606,7 @@ static void test_worm_food_collision(void) {
1555 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); 1606 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1556 rb->lcd_update(); 1607 rb->lcd_update();
1557 } 1608 }
1558 if (collision_count != FOOD_SIZE) { 1609 if (collision_count != food_size) {
1559 rb->button_get(true); 1610 rb->button_get(true);
1560 } 1611 }
1561 1612
@@ -1574,7 +1625,7 @@ static void test_worm_food_collision(void) {
1574 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); 1625 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1575 rb->lcd_update(); 1626 rb->lcd_update();
1576 } 1627 }
1577 if (collision_count != FOOD_SIZE * 2) { 1628 if (collision_count != food_size * 2) {
1578 rb->button_get(true); 1629 rb->button_get(true);
1579 } 1630 }
1580 1631
@@ -1609,7 +1660,7 @@ static void test_worm_argh_collision(void) {
1609 } 1660 }
1610 1661
1611 arghx[0] = 12; 1662 arghx[0] = 12;
1612 for (arghy[0] = 0; arghy[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghy[0]++){ 1663 for (arghy[0] = 0; arghy[0] < FIELD_RECT_HEIGHT - argh_size; arghy[0]++){
1613 char buf[20]; 1664 char buf[20];
1614 bool collision; 1665 bool collision;
1615 draw_argh(0); 1666 draw_argh(0);
@@ -1621,12 +1672,12 @@ static void test_worm_argh_collision(void) {
1621 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); 1672 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1622 rb->lcd_update(); 1673 rb->lcd_update();
1623 } 1674 }
1624 if (collision_count != ARGH_SIZE * 2) { 1675 if (collision_count != argh_size * 2) {
1625 rb->button_get(true); 1676 rb->button_get(true);
1626 } 1677 }
1627 1678
1628 arghy[0] = 12; 1679 arghy[0] = 12;
1629 for (arghx[0] = 0; arghx[0] < FIELD_RECT_HEIGHT - ARGH_SIZE; arghx[0]++){ 1680 for (arghx[0] = 0; arghx[0] < FIELD_RECT_HEIGHT - argh_size; arghx[0]++){
1630 char buf[20]; 1681 char buf[20];
1631 bool collision; 1682 bool collision;
1632 draw_argh(0); 1683 draw_argh(0);
@@ -1638,7 +1689,7 @@ static void test_worm_argh_collision(void) {
1638 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf); 1689 rb->lcd_putsxy(0, LCD_HEIGHT -8, buf);
1639 rb->lcd_update(); 1690 rb->lcd_update();
1640 } 1691 }
1641 if (collision_count != ARGH_SIZE * 4) { 1692 if (collision_count != argh_size * 4) {
1642 rb->button_get(true); 1693 rb->button_get(true);
1643 } 1694 }
1644} 1695}
@@ -1807,8 +1858,8 @@ static int testline_in_rect(void) {
1807 /* test 13 */ 1858 /* test 13 */
1808 rx = 9; 1859 rx = 9;
1809 ry = 15; 1860 ry = 15;
1810 rw = FOOD_SIZE; 1861 rw = food_size;
1811 rh = FOOD_SIZE; 1862 rh = food_size;
1812 1863
1813 x1 = 10; 1864 x1 = 10;
1814 y1 = 10; 1865 y1 = 10;
@@ -1923,11 +1974,11 @@ static void test_make_argh(void){
1923 char buf[20]; 1974 char buf[20];
1924 int x, y; 1975 int x, y;
1925 rb->srand(seed); 1976 rb->srand(seed);
1926 x = rb->rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); 1977 x = rb->rand() % (FIELD_RECT_WIDTH - argh_size);
1927 y = rb->rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); 1978 y = rb->rand() % (FIELD_RECT_HEIGHT - argh_size);
1928 1979
1929 for (worm_idx = 0; worm_idx < worm_count; worm_idx++){ 1980 for (worm_idx = 0; worm_idx < worm_count; worm_idx++){
1930 if (expensive_worm_in_rect(&worms[worm_idx], x, y, ARGH_SIZE, ARGH_SIZE)) { 1981 if (expensive_worm_in_rect(&worms[worm_idx], x, y, argh_size, argh_size)) {
1931 int tries = 0; 1982 int tries = 0;
1932 rb->srand(seed); 1983 rb->srand(seed);
1933 1984
@@ -1939,12 +1990,12 @@ static void test_make_argh(void){
1939 rb->snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries); 1990 rb->snprintf(buf, sizeof buf, "(%d;%d) fail%d try%d", x, y, failures, tries);
1940 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); 1991 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
1941 rb->lcd_update(); 1992 rb->lcd_update();
1942 rb->lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1993 rb->lcd_invertrect(x + FIELD_RECT_X, y+ FIELD_RECT_Y, argh_size, argh_size);
1943 rb->lcd_update(); 1994 rb->lcd_update();
1944 draw_argh(0); 1995 draw_argh(0);
1945 rb->lcd_update(); 1996 rb->lcd_update();
1946 rb->lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1997 rb->lcd_invertrect(x + FIELD_RECT_X, y + FIELD_RECT_Y, argh_size, argh_size);
1947 rb->lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, ARGH_SIZE, ARGH_SIZE); 1998 rb->lcd_clearrect(arghx[0] + FIELD_RECT_X, arghy[0] + FIELD_RECT_Y, argh_size, argh_size);
1948 1999
1949 if (failures > last_failures) { 2000 if (failures > last_failures) {
1950 rb->button_get(true); 2001 rb->button_get(true);
@@ -1978,7 +2029,7 @@ static void test_worm_argh_collision_in_moves(void) {
1978 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf); 2029 rb->lcd_putsxy(0, LCD_HEIGHT - 8, buf);
1979 rb->lcd_update(); 2030 rb->lcd_update();
1980 } 2031 }
1981 if (hit_count != ARGH_SIZE + 5) { 2032 if (hit_count != argh_size + 5) {
1982 rb->button_get(true); 2033 rb->button_get(true);
1983 } 2034 }
1984} 2035}
@@ -1987,20 +2038,252 @@ static void test_worm_argh_collision_in_moves(void) {
1987extern bool use_old_rect; 2038extern bool use_old_rect;
1988 2039
1989/** 2040/**
2041 * These are additional functions required to set various wormlet settings
2042 * and to enable saving of settings and high score
2043 */
2044
2045/*
2046Sets the total number of worms, both human and machine
2047*/
2048bool set_worm_num_worms(void)
2049{
2050 bool ret;
2051 static const struct opt_items num_worms_option[3] = {
2052 { "1", NULL },
2053 { "2", NULL },
2054 { "3", NULL },
2055 };
2056
2057 ret = rb->set_option("Number Of Worms", &worm_count,INT, num_worms_option, 3, NULL);
2058 if (worm_count < players) {
2059 worm_count=players;
2060 }
2061 return ret;
2062}
2063
2064/*
2065Sets the number of human players
2066*/
2067bool set_worm_num_players(void)
2068{
2069 bool ret;
2070 static const struct opt_items num_players_option[4] = {
2071 { "0", NULL },
2072 { "1", NULL },
2073 { "2", NULL },
2074 { "3", NULL }
2075 };
2076
2077 ret = rb->set_option("Number of Players", &players, INT,num_players_option , 4, NULL);
2078 if (players > worm_count) {
2079 worm_count = players;
2080 }
2081 if (players > 2) {
2082 use_remote = true;
2083 }
2084 return ret;
2085}
2086
2087/*
2088Sets the size of each argh block created
2089*/
2090bool set_worm_argh_size(void)
2091{
2092 static const struct opt_items argh_size_option[11] = {
2093 { "0", NULL },
2094 { "1", NULL },
2095 { "2", NULL },
2096 { "3", NULL },
2097 { "4", NULL },
2098 { "5", NULL },
2099 { "6", NULL },
2100 { "7", NULL },
2101 { "8", NULL },
2102 { "9", NULL },
2103 { "10", NULL }
2104 };
2105
2106 return rb->set_option("Argh Size", &argh_size,INT,argh_size_option , 11, NULL);
2107}
2108
2109/*
2110Sets the amount a worm grows per food
2111*/
2112bool set_worm_food(void)
2113{
2114 static const struct opt_items worm_food_option[11] = {
2115 { "0", NULL },
2116 { "1", NULL },
2117 { "2", NULL },
2118 { "3", NULL },
2119 { "4", NULL },
2120 { "5", NULL },
2121 { "6", NULL },
2122 { "7", NULL },
2123 { "8", NULL },
2124 { "9", NULL },
2125 { "10", NULL }
2126 };
2127 return rb->set_option("Worm Growth Per Food", &worm_food,INT,worm_food_option , 11, NULL);
2128}
2129
2130/*
2131Sets the number of arghs created per food
2132*/
2133bool set_argh_per_food(void)
2134{
2135 static const struct opt_items argh_food_option[5] = {
2136 { "0", NULL },
2137 { "1", NULL },
2138 { "2", NULL },
2139 { "3", NULL },
2140 { "4", NULL },
2141 };
2142 return rb->set_option("Arghs Per Food", &arghs_per_food,INT,argh_food_option , 5, NULL);
2143}
2144
2145/*
2146Sets the number of ticks per move
2147*/
2148bool set_worm_speed(void)
2149{
2150 bool ret;
2151 static const struct opt_items speed_option[19] = {
2152 { "0", NULL },
2153 { "1", NULL },
2154 { "2", NULL },
2155 { "3", NULL },
2156 { "4", NULL },
2157 { "5", NULL },
2158 { "6", NULL },
2159 { "7", NULL },
2160 { "8", NULL },
2161 { "9", NULL },
2162 { "10", NULL },
2163 { "11", NULL },
2164 { "12", NULL },
2165 { "13", NULL },
2166 { "14", NULL },
2167 { "15", NULL },
2168 { "16", NULL },
2169 { "17", NULL },
2170 { "18", NULL },
2171 };
2172
2173
2174 speed = 20 - speed;
2175 ret = rb->set_option("Worm Speed", &speed,INT,speed_option , 19, NULL);
2176 speed = 20 - speed;
2177 return ret;
2178}
2179
2180/*
2181Sets the control style, which depends on the number of players,
2182remote control existing, etc
2183bool set_bool_options(char* string, bool* variable,
2184 char* yes_str, char* no_str, void (*function)(bool))
2185*/
2186bool set_worm_control_style(void)
2187{
2188 static const struct opt_items key1_option[2] = {
2189 { "Remote Control", NULL },
2190 { "No Rem. Control", NULL },
2191 };
2192
2193 static const struct opt_items key2_option[2] = {
2194 { "2 Key Control", NULL },
2195 { "4 Key COntrol", NULL },
2196 };
2197
2198 static const struct opt_items key3_option[1] = {
2199 { "Out of Control", NULL },
2200 };
2201
2202 if (players > 1) {
2203 rb->set_option("Control Style",&use_remote,INT, key1_option, 2, NULL);
2204 } else {
2205 if (players > 0) {
2206 rb->set_option("Control Style",&use_remote,INT, key2_option, 2, NULL);
2207 }
2208 else {
2209 rb->set_option("Control Style",&use_remote,INT, key3_option, 1, NULL);
2210 }
2211 }
2212 return false;
2213}
2214
2215void default_settings(void)
2216{
2217 arghs_per_food = ARGHS_PER_FOOD;
2218 argh_size = ARGH_SIZE;
2219 food_size = FOOD_SIZE;
2220 speed = SPEED;
2221 worm_food = WORM_PER_FOOD;
2222 players = 1;
2223 worm_count = MAX_WORMS;
2224 use_remote = false;
2225 return;
2226}
2227
2228/*
2229Launches the wormlet game
2230*/
2231bool launch_wormlet(void)
2232{
2233 int game_result = 1;
2234
2235 rb->lcd_clear_display();
2236
2237 /* Permanently enable the backlight (unless the user has turned it off) */
2238 if (rb->global_settings->backlight_timeout > 0)
2239 rb->backlight_set_timeout(1);
2240
2241 /* start the game */
2242 while (game_result == 1)
2243 game_result = run();
2244
2245 switch (game_result)
2246 {
2247 case 2:
2248 /* Restore user's original backlight setting */
2249 rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
2250 return false;
2251 break;
2252 }
2253 return false;
2254}
2255
2256/* End of settings/changes etc */
2257
2258/**
1990 * Main entry point 2259 * Main entry point
1991 */ 2260 */
1992enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 2261enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1993{ 2262{
1994 bool worm_dead = false; 2263 int m;
1995 int button; 2264 int result;
2265 int menu_quit = 0;
2266 int new_setting;
1996 2267
1997 (void)(parameter); 2268 (void)(parameter);
1998
1999 rb = api; 2269 rb = api;
2000 rb->lcd_setfont(FONT_SYSFIXED); 2270
2271 default_settings();
2272 configfile_init(rb);
2273 if (configfile_load(SETTINGS_FILENAME, config,
2274 sizeof(config)/sizeof(*config),
2275 SETTINGS_MIN_VERSION ) < 0)
2276 {
2277 /* If the loading failed, save a new config file (as the disk is
2278 already spinning) */
2279 configfile_save(SETTINGS_FILENAME, config,
2280 sizeof(config)/sizeof(*config),
2281 SETTINGS_VERSION);
2282 }
2001 2283
2002#ifdef HAVE_LCD_COLOR 2284#ifdef HAVE_LCD_COLOR
2003 rb->lcd_set_background(LCD_RGBPACK(200, 210, 230)); 2285 rb->lcd_set_foreground(COLOR_FG);
2286 rb->lcd_set_background(COLOR_BG);
2004#endif 2287#endif
2005 2288
2006#ifdef DEBUG_WORMLET 2289#ifdef DEBUG_WORMLET
@@ -2013,132 +2296,259 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2013#endif 2296#endif
2014 2297
2015 /* Setup screen */ 2298 /* Setup screen */
2016 do {
2017 char buf[40];
2018#if defined MULTIPLAYER && defined REMOTE
2019 char* ptr;
2020#endif
2021 rb->lcd_clear_display();
2022 2299
2023 /* first line players */ 2300 static const struct opt_items noyes[2] = {
2301 { "No", NULL },
2302 { "Yes", NULL },
2303 };
2304
2305 static const struct opt_items num_worms_option[3] = {
2306 { "1", NULL },
2307 { "2", NULL },
2308 { "3", NULL }
2309 };
2310
2024#ifdef MULTIPLAYER 2311#ifdef MULTIPLAYER
2025 rb->snprintf(buf, sizeof buf, "%d Players (%s)", players, PLAYERS_TEXT); 2312 static const struct opt_items num_players_option[4] = {
2026#else 2313#else
2027 rb->snprintf(buf, sizeof buf, "1 Player"); 2314 static const struct opt_items num_players_option[2] = {
2028#endif 2315#endif
2029 rb->lcd_puts(0, 0, buf); 2316 { "0", NULL },
2030 2317 { "1", NULL }
2031 /* second line worms */ 2318#ifdef MULTIPLAYER
2032 rb->snprintf(buf, sizeof buf, "%d Worms (%s)", worm_count, WORMS_TEXT); 2319 ,{ "2", NULL },
2033 rb->lcd_puts(0, 1, buf); 2320 { "3", NULL }
2034
2035#if defined MULTIPLAYER && defined REMOTE
2036 /* third line control */
2037 if (players > 1) {
2038 if (use_remote) {
2039 rb->snprintf(buf, sizeof(buf), "Remote Control (%s)", KEY_CONTROL_TEXT);
2040 ptr = buf;
2041 } else {
2042 rb->snprintf(buf, sizeof(buf), "No Rem. Control (%s)", KEY_CONTROL_TEXT);
2043 ptr = buf;
2044 }
2045 } else {
2046 if (players > 0) {
2047 if (use_remote) {
2048 rb->snprintf(buf, sizeof(buf), "2 Key Control (%s)", KEY_CONTROL_TEXT);
2049 ptr = buf;
2050 } else {
2051 rb->snprintf(buf, sizeof(buf), "4 Key Control (%s)", KEY_CONTROL_TEXT);
2052 ptr = buf;
2053 }
2054 } else {
2055 ptr = "Out Of Control";
2056 }
2057 }
2058 rb->lcd_puts(0, 2, ptr);
2059#endif 2321#endif
2060 rb->lcd_update(); 2322 };
2061 2323
2062 /* user selection */ 2324 static const struct opt_items argh_size_option[9] = {
2063 button = rb->button_get(true); 2325 { "2", NULL },
2064 switch (button) { 2326 { "3", NULL },
2327 { "4", NULL },
2328 { "5", NULL },
2329 { "6", NULL },
2330 { "7", NULL },
2331 { "8", NULL },
2332 { "9", NULL },
2333 { "10", NULL }
2334 };
2335
2336 static const struct opt_items food_size_option[9] = {
2337 { "2", NULL },
2338 { "3", NULL },
2339 { "4", NULL },
2340 { "5", NULL },
2341 { "6", NULL },
2342 { "7", NULL },
2343 { "8", NULL },
2344 { "9", NULL },
2345 { "10", NULL }
2346 };
2347
2348 static const struct opt_items worm_food_option[16] = {
2349 { "0", NULL },
2350 { "1", NULL },
2351 { "2", NULL },
2352 { "3", NULL },
2353 { "4", NULL },
2354 { "5", NULL },
2355 { "6", NULL },
2356 { "7", NULL },
2357 { "8", NULL },
2358 { "9", NULL },
2359 { "10", NULL },
2360 { "11", NULL },
2361 { "12", NULL },
2362 { "13", NULL },
2363 { "14", NULL },
2364 { "15", NULL }
2365 };
2366
2367 static const struct opt_items argh_food_option[9] = {
2368 { "0", NULL },
2369 { "1", NULL },
2370 { "2", NULL },
2371 { "3", NULL },
2372 { "4", NULL },
2373 { "5", NULL },
2374 { "6", NULL },
2375 { "7", NULL },
2376 { "8", NULL }
2377 };
2378
2379 static const struct opt_items speed_option[21] = {
2380 { "0", NULL },
2381 { "1", NULL },
2382 { "2", NULL },
2383 { "3", NULL },
2384 { "4", NULL },
2385 { "5", NULL },
2386 { "6", NULL },
2387 { "7", NULL },
2388 { "8", NULL },
2389 { "9", NULL },
2390 { "10", NULL },
2391 { "11", NULL },
2392 { "12", NULL },
2393 { "13", NULL },
2394 { "14", NULL },
2395 { "15", NULL },
2396 { "16", NULL },
2397 { "17", NULL },
2398 { "18", NULL },
2399 { "19", NULL },
2400 { "20", NULL }
2401 };
2402
2403 static const struct opt_items remoteonly_option[1] = {
2404 { "Remote Control", NULL }
2405 };
2406
2407 static const struct opt_items key24_option[2] = {
2408 { "4 Key Control", NULL },
2409 { "2 Key Control", NULL }
2410 };
2411
2412#ifdef REMOTE
2413 static const struct opt_items remote_option[2] = {
2414 { "Remote Control", NULL },
2415 { "No Rem. Control", NULL }
2416 };
2417#else
2418 static const struct opt_items key2_option[1] = {
2419 { "2 Key Control", NULL }
2420 };
2421#endif
2422
2423 static const struct opt_items nokey_option[1] = {
2424 { "Out of Control", NULL }
2425 };
2426
2427 static const struct menu_item items[] = {
2428 { "Play Wormlet!", NULL },
2429 { "Number of Worms", NULL },
2430 { "Number of Players", NULL },
2431 { "Control Style", NULL },
2432 { "Worm Growth Per Food", NULL },
2433 { "Worm Speed", NULL },
2434 { "Arghs Per Food", NULL },
2435 { "Argh Size", NULL },
2436 { "Food Size", NULL },
2437 { "Revert to Default Settings", NULL },
2438 { "Quit", NULL }
2439 };
2440
2441 m = rb->menu_init(items, sizeof(items) / sizeof(*items),
2442 NULL, NULL, NULL, NULL);
2443
2444 rb->button_clear_queue();
2445
2446 while (!menu_quit) {
2447 result = rb->menu_show(m);
2448
2449 switch(result)
2450 {
2451 case 0:
2452 rb->lcd_setfont(FONT_SYSFIXED);
2453 launch_wormlet();
2454 break;
2455 case 1:
2456 new_setting = worm_count - 1;
2457 rb->set_option("Number of Worms", &new_setting, INT, num_worms_option, 3, NULL);
2458 if (new_setting != worm_count)
2459 worm_count = new_setting + 1;
2460 if (worm_count < players) {
2461 worm_count = players;
2462 }
2463 break;
2464 case 2:
2465 new_setting = players;
2065#ifdef MULTIPLAYER 2466#ifdef MULTIPLAYER
2066 case BTN_TOGGLE_KEYS: 2467 rb->set_option("Number of Players", &new_setting, INT, num_players_option , 4, NULL);
2067 use_remote = !use_remote; 2468#else
2469 rb->set_option("Number of Players", &new_setting, INT, num_players_option , 2, NULL);
2470#endif
2471 if (new_setting != players)
2472 players = new_setting;
2473 if (players > worm_count) {
2474 worm_count = players;
2475 }
2068 if (players > 2) { 2476 if (players > 2) {
2069 use_remote = true; 2477 use_remote = true;
2070 } 2478 }
2071 break; 2479 break;
2072 2480 case 3:
2073 case BTN_DIR_UP: 2481 new_setting = use_remote;
2074 if (players < 3) { 2482 switch(players) {
2075 players ++; 2483 case 0:
2076 if (players > worm_count) { 2484 rb->set_option("Control Style",&new_setting,INT, nokey_option, 1, NULL);
2077 worm_count = players; 2485 break;
2078 } 2486 case 1:
2079 if (players > 2) { 2487 rb->set_option("Control Style",&new_setting,INT, key24_option, 2, NULL);
2080 use_remote = true; 2488 break;
2081 } 2489 case 2:
2490#ifdef REMOTE
2491 rb->set_option("Control Style",&new_setting,INT, remote_option, 2, NULL);
2492#else
2493 rb->set_option("Control Style",&new_setting,INT, key2_option, 1, NULL);
2494#endif
2495 break;
2496 case 3:
2497 rb->set_option("Control Style",&new_setting,INT, remoteonly_option, 1, NULL);
2498 break;
2082 } 2499 }
2500 if (new_setting != use_remote)
2501 use_remote = new_setting;
2083 break; 2502 break;
2084 2503 case 4:
2085 case BTN_DIR_DOWN: 2504 new_setting = worm_food;
2086 if (players > 0) { 2505 rb->set_option("Worm Growth Per Food", &new_setting,INT,worm_food_option , 16, NULL);
2087 players --; 2506 if (new_setting != worm_food)
2088 } 2507 worm_food = new_setting;
2089 break; 2508 break;
2090#endif 2509 case 5:
2091 case BTN_DIR_LEFT: 2510 new_setting = speed;
2092 if (worm_count > 1) { 2511 new_setting = 20 - new_setting;
2093 worm_count--; 2512 rb->set_option("Worm Speed", &new_setting,INT,speed_option , 21, NULL);
2094 if (worm_count < players) { 2513 new_setting = 20 - new_setting;
2095 players = worm_count; 2514 if (new_setting != speed)
2096 } 2515 speed = new_setting;
2097 }
2098 break; 2516 break;
2099 2517 case 6:
2100 case BTN_DIR_RIGHT: 2518 new_setting = arghs_per_food;
2101 if (worm_count < MAX_WORMS) { 2519 rb->set_option("Arghs Per Food", &new_setting,INT,argh_food_option , 9, NULL);
2102 worm_count ++; 2520 if (new_setting != arghs_per_food)
2103 } 2521 arghs_per_food = new_setting;
2522 break;
2523 case 7:
2524 new_setting = argh_size-2;
2525 rb->set_option("Argh Size", &new_setting,INT,argh_size_option , 9, NULL);
2526 if (new_setting != argh_size)
2527 argh_size = new_setting+2;
2528 break;
2529 case 8:
2530 new_setting = food_size-2;
2531 rb->set_option("Food Size", &new_setting,INT,food_size_option, 9, NULL);
2532 if (new_setting != food_size)
2533 food_size = new_setting+2;
2534 break;
2535 case 9:
2536 new_setting = 0;
2537 rb->set_option("Reset Settings?", &new_setting,INT, noyes , 2, NULL);
2538 if (new_setting == 1)
2539 default_settings();
2104 break; 2540 break;
2105
2106 default: 2541 default:
2107 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) 2542 menu_quit=1;
2108 return PLUGIN_USB_CONNECTED;
2109 break; 2543 break;
2110 } 2544 }
2111 } while (button != BTN_STARTPAUSE && 2545 }
2112 button != BTN_QUIT && button != BTN_STOPRESET);
2113
2114 rb->lcd_clear_display();
2115 /* end of setup */
2116
2117 do {
2118
2119 /* button state will be overridden if
2120 the game quits with the death of the worm.
2121 Initializing button to BTN_QUIT ensures
2122 that the user can hit BTN_QUIT during the
2123 game to return to the menu.
2124 */
2125 button = BTN_QUIT;
2126 2546
2127 /* start the game */ 2547 rb->menu_exit(m);
2128 worm_dead = run();
2129 2548
2130 /* if worm isn't dead the game was quit 2549 configfile_save(SETTINGS_FILENAME, config,
2131 via BTN_QUIT -> no need to wait for buttons. */ 2550 sizeof(config)/sizeof(*config),
2132 if (worm_dead) { 2551 SETTINGS_VERSION);
2133 do {
2134 button = rb->button_get(true);
2135 }
2136 /* BTN_STOPRESET -> start new game */
2137 /* BTN_QUIT -> back to game menu */
2138 while (button != BTN_QUIT && button != BTN_STOPRESET);
2139 }
2140 }
2141 while (button != BTN_QUIT);
2142 2552
2143 return PLUGIN_OK; 2553 return PLUGIN_OK;
2144} 2554}