summaryrefslogtreecommitdiff
path: root/apps/recorder/wormlet.c
diff options
context:
space:
mode:
authorEric Linenberg <elinenbe@umich.edu>2002-08-26 03:32:39 +0000
committerEric Linenberg <elinenbe@umich.edu>2002-08-26 03:32:39 +0000
commitb0a3984c5a3c76296b0fe84057b2d1051e11a699 (patch)
treed4af91d7489b16485974e48ef3e9e01e06f4e5ef /apps/recorder/wormlet.c
parent9a47cc4e7c45add4a8fc4f6f12698a5291a52c80 (diff)
Philpp Petermann's game wormlet
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1975 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/wormlet.c')
-rw-r--r--apps/recorder/wormlet.c779
1 files changed, 779 insertions, 0 deletions
diff --git a/apps/recorder/wormlet.c b/apps/recorder/wormlet.c
new file mode 100644
index 0000000000..ab8ef0aa91
--- /dev/null
+++ b/apps/recorder/wormlet.c
@@ -0,0 +1,779 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 Philipp Pertermann
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <sprintf.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lcd.h"
+#include "button.h"
+#include "kernel.h"
+#include "menu.h"
+
+#define MAX_WORM_LENGTH 500 // size of the ring of the worm
+#define INITIAL_WORM_LENGTH 10 // when the game starts
+#define WORM_PER_FOOD 7 // num of pixel the worm grows by eating a food
+
+// The worm is stored in a ring of xy coordinates
+short wormx[MAX_WORM_LENGTH];
+short wormy[MAX_WORM_LENGTH];
+
+int head; // index of the head within the buffer
+short headx;
+short heady;
+
+int tail; // index of the tail within the buffer
+int growing; // number of cyles the worm still keeps growing
+
+
+#define MAX_FOOD 5 // maximal number of food items
+#define FOOD_SIZE 3 // the width and height of a food
+short foodx[MAX_FOOD];
+short foody[MAX_FOOD];
+
+#define MAX_ARGH 100 // maximal number of argh items
+#define ARGH_SIZE 4 // the width and height of a argh
+#define ARGHS_PER_FOOD 2 // number of arghs produced each time a food was eaten
+short arghx[MAX_ARGH];
+short arghy[MAX_ARGH];
+int arghCount;
+
+// direction vector in which the worm moves
+short dirx; // only values -1 0 1 allowed
+short diry; // only values -1 0 1 allowed
+
+int speed = 10;
+
+// return values of checkCollision
+#define COLLISION_NONE 0
+#define COLLISION_WORM 1
+#define COLLISION_FOOD 2
+#define COLLISION_ARGH 3
+#define COLLISION_FIELD 4
+
+// size of the field the worm lives in
+#define FIELD_RECT_X 1
+#define FIELD_RECT_Y 1
+#define FIELD_RECT_WIDTH LCD_HEIGHT - 2
+#define FIELD_RECT_HEIGHT LCD_HEIGHT - 2
+
+/**
+ * Returns the current length of the worm.
+ * @return int a positive value
+ */
+int getWormLength(void) {
+ // initial simple calculation will be overwritten
+ // if wrong.
+ int retVal = head - tail;
+
+ // if the worm 'crosses' the boundaries of the ringbuffer
+ if (retVal < 0) {
+ retVal = head + MAX_WORM_LENGTH - tail;
+ }
+
+ return retVal;
+}
+
+/**
+ * Checks wether a specific food in the food arrays is at the
+ * specified coordinates.
+ * @param int foodIndex The index of the food in the food arrays
+ * @param int x the x coordinate.
+ * @param int y the y coordinate.
+ * @return Returns true if the coordinate hits the food specified by
+ * foodIndex.
+ */
+bool specificFoodCollision(int foodIndex, int x, int y) {
+ bool retVal = false;
+ if (x >= foodx[foodIndex] &&
+ x < foodx[foodIndex] + FOOD_SIZE &&
+ y >= foody[foodIndex] &&
+ y < foody[foodIndex] + FOOD_SIZE) {
+
+ retVal = true;
+ }
+ return retVal;
+}
+
+/**
+ * Returns the index of the food that is at the
+ * given coordinates. If no food is at the coordinates
+ * -1 is returned.
+ * @return int -1 <= value < MAX_FOOD
+ */
+int foodCollision(int x, int y) {
+ int i = 0;
+ int retVal = -1;
+ bool collisionDetected = false;
+ for (i = 0; i < MAX_FOOD && !collisionDetected; i++) {
+ if (specificFoodCollision(i, x, y)) {
+
+ collisionDetected = true;
+ retVal = i;
+ }
+ }
+ return retVal;
+}
+
+/**
+ * Checks wether a specific argh in the argh arrays is at the
+ * specified coordinates.
+ * @param int arghIndex The index of the argh in the argh arrays
+ * @param int x the x coordinate.
+ * @param int y the y coordinate.
+ * @return Returns true if the coordinate hits the argh specified by
+ * arghIndex.
+ */
+bool specificArghCollision(int arghIndex, int x, int y) {
+ bool retVal = false;
+ if (x >= arghx[arghIndex] &&
+ x < arghx[arghIndex] + ARGH_SIZE &&
+ y >= arghy[arghIndex] &&
+ y < arghy[arghIndex] + ARGH_SIZE) {
+
+ retVal = true;
+ }
+ return retVal;
+}
+
+/**
+ * Returns the index of the argh that is at the
+ * given coordinates. If no argh is at the coordinates
+ * -1 is returned.
+ * @param int x The x coordinate.
+ * @param int y The y coordinate.
+ * @return int -1 <= value < arghCount <= MAX_ARGH
+ */
+int arghCollision(int x, int y) {
+ int i = 0;
+ int retVal = -1;
+ bool collisionDetected = false;
+
+ // search for the argh that has the specified coords
+ for (i = 0; i < arghCount && !collisionDetected; i++) {
+ if (specificArghCollision(i, x, y)) {
+
+ collisionDetected = true;
+ retVal = i;
+ }
+ }
+ return retVal;
+}
+
+/**
+ * Checks wether the worm collides with the food at the specfied food-arrays.
+ * @param int foodIndex The index of the food in the arrays. Ensure the value is
+ * 0 <= foodIndex <= MAX_FOOD
+ * @return Returns true if the worm collides with the specified food.
+ */
+bool wormFoodCollision(int foodIndex) {
+ bool retVal = false;
+
+ // buffer wormLength because getWormLength is expensive
+ int wormLength = getWormLength();
+ int i;
+
+ // although all the worm gets iterated i is NOT the index
+ // of the worm arrays
+ for (i = 0; i < wormLength && !retVal; i++) {
+
+ // convert i to the true worm indices
+ int wormIndex = (tail + i) % MAX_WORM_LENGTH;
+
+ // The check
+ if (specificFoodCollision(foodIndex, wormx[wormIndex], wormy[wormIndex])) {
+ retVal = true;
+ }
+ }
+
+ return retVal;
+}
+
+/**
+ * Checks wether the worm collides with the argh at the specfied argh-arrays.
+ * @param int arghIndex The index of the argh in the arrays. Ensure the value is
+ * 0 <= arghIndex < arghCount <= MAX_ARGH
+ * @return Returns true if the worm collides with the specified argh.
+ */
+bool wormArghCollision(int arghIndex) {
+ bool retVal = false;
+
+ // buffer wormLength because getWormLength is expensive
+ int wormLength = getWormLength();
+ int i;
+
+ // although all the worm gets iterated i is NOT the index
+ // of the worm arrays
+ for (i = 0; i < wormLength && !retVal; i++) {
+
+ // convert i to the true worm indices
+ int wormIndex = (tail + i) % MAX_WORM_LENGTH;
+
+ // The check
+ if (specificArghCollision(arghIndex, wormx[wormIndex], wormy[wormIndex])) {
+ retVal = true;
+ }
+ }
+
+ return retVal;
+}
+
+/**
+ * Find new coordinates for the food stored in foodx[index], foody[index]
+ * that don't collide with any other food or argh
+ * @param int index
+ * Ensure that 0 <= index < MAX_FOOD.
+ */
+void makeFood(int index) {
+
+ int x = 0;
+ int y = 0;
+ bool collisionDetected = false;
+
+ do {
+ // make coordinates for a new food so that
+ // the entire food lies within the FIELD
+ x = rand() % (FIELD_RECT_WIDTH - FOOD_SIZE);
+ y = rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE);
+
+ // Ensure that the new food doesn't collide with any
+ // existing foods or arghs.
+ // If one or more corners of the new food hit any existing
+ // argh or food a collision is detected.
+ collisionDetected =
+ foodCollision(x , y ) >= 0 ||
+ foodCollision(x + FOOD_SIZE - 1, y ) >= 0 ||
+ foodCollision(x , y + FOOD_SIZE - 1) >= 0 ||
+ foodCollision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 ||
+ arghCollision(x , y ) >= 0 ||
+ arghCollision(x + FOOD_SIZE - 1, y ) >= 0 ||
+ arghCollision(x , y + FOOD_SIZE - 1) >= 0 ||
+ arghCollision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0;
+
+ // use coordinates for further testing
+ foodx[index] = x;
+ foody[index] = y;
+
+ // now test wether we accidently hit the worm with food ;)
+ collisionDetected |= wormFoodCollision(index);
+ }
+ while (collisionDetected);
+}
+
+/**
+ * Clears a food from the lcd buffer.
+ * @param int index The index of the food arrays under which
+ * the coordinates of the desired food can be found. Ensure
+ * that the value is 0 <= index <= MAX_FOOD.
+ */
+void clearFood(int index) {
+ // remove the old food from the screen
+ lcd_clearrect (foodx[index] + FIELD_RECT_X,
+ foody[index] + FIELD_RECT_Y,
+ FOOD_SIZE, FOOD_SIZE);
+}
+
+/**
+ * Draws a food in the lcd buffer.
+ * @param int index The index of the food arrays under which
+ * the coordinates of the desired food can be found. Ensure
+ * that the value is 0 <= index <= MAX_FOOD.
+ */
+void drawFood(int index) {
+ // draw the food object
+ lcd_fillrect (foodx[index] + FIELD_RECT_X,
+ foody[index] + FIELD_RECT_Y,
+ FOOD_SIZE, FOOD_SIZE);
+ lcd_clearrect(foodx[index] + FIELD_RECT_X + 1,
+ foody[index] + FIELD_RECT_Y + 1,
+ FOOD_SIZE - 2, FOOD_SIZE - 2);
+}
+
+/**
+ * Find new coordinates for the argh stored in arghx[index], arghy[index]
+ * that don't collide with any other food or argh.
+ * @param int index
+ * Ensure that 0 <= index < arghCount < MAX_ARGH.
+ */
+void makeArgh(int index) {
+ int x;
+ int y;
+ bool collisionDetected = false;
+
+ do {
+ // make coordinates for a new argh so that
+ // the entire food lies within the FIELD
+ x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE);
+ y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE);
+ // Ensure that the new argh doesn't intersect with any
+ // existing foods or arghs.
+ // If one or more corners of the new argh hit any existing
+ // argh or food an intersection is detected.
+ collisionDetected =
+ foodCollision(x , y ) >= 0 ||
+ foodCollision(x + ARGH_SIZE - 1, y ) >= 0 ||
+ foodCollision(x , y + ARGH_SIZE - 1) >= 0 ||
+ foodCollision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 ||
+ arghCollision(x , y ) >= 0 ||
+ arghCollision(x + ARGH_SIZE - 1, y ) >= 0 ||
+ arghCollision(x , y + ARGH_SIZE - 1) >= 0 ||
+ arghCollision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0;
+
+ // use the candidate coordinates to make a real argh
+ arghx[index] = x;
+ arghy[index] = y;
+
+ // now test wether we accidently hit the worm with argh ;)
+ collisionDetected |= wormArghCollision(index);
+ }
+ while (collisionDetected);
+}
+
+/**
+ * Draws an argh in the lcd buffer.
+ * @param int index The index of the argh arrays under which
+ * the coordinates of the desired argh can be found. Ensure
+ * that the value is 0 <= index < arghCount <= MAX_ARGH.
+ */
+void drawArgh(int index) {
+ // draw the new argh
+ lcd_fillrect (arghx[index] + FIELD_RECT_X,
+ arghy[index] + FIELD_RECT_Y,
+ ARGH_SIZE, ARGH_SIZE);
+}
+
+/**
+ * Initializes the worm-, food- and argh-arrays, draws a frame,
+ * makes some food and argh and display all that stuff.
+ */
+void initWormlet(void) {
+
+ // Needed when the game is restarted using BUTTON_ON
+ lcd_clear_display();
+
+ // Initialize all the worm coordinates to 0,0.
+ int i;
+ for (i = 0; i < MAX_WORM_LENGTH; i++){
+ wormx[i] = 0;
+ wormy[i] = 0;
+ }
+
+ // initialize the worm size
+ head = INITIAL_WORM_LENGTH;
+ tail = 0;
+
+ // initialize the worm start point
+ headx = 0;
+ heady = 0;
+
+ // set the initial direction the worm creeps to
+ dirx = 1;
+ diry = 0;
+
+ // make and display some food and argh
+ arghCount = MAX_FOOD;
+ for (i = 0; i < MAX_FOOD; i++) {
+ makeFood(i);
+ drawFood(i);
+ makeArgh(i);
+ drawArgh(i);
+ }
+
+ // draw the game field
+ lcd_invertrect (0 , 0 , FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2);
+ lcd_invertrect(0 + 1, 0 + 1, FIELD_RECT_WIDTH , FIELD_RECT_HEIGHT);
+
+ // make everything visible
+ lcd_update();
+}
+
+/**
+ * Move the worm one step further.
+ * The direction in which the worm moves is taken
+ * from dirx and diry. If the
+ * worm crosses the boundaries of the field the
+ * worm is wrapped (it enters the field from the
+ * opposite side). moveWorm decreases growing if > 0.
+ */
+void moveWorm(void) {
+ // find the next array index for the head
+ head++;
+ if (head >= MAX_WORM_LENGTH){
+ head = 0;
+ }
+
+ // find the next array index for the tail
+ tail++;
+ if (tail >= MAX_WORM_LENGTH){
+ tail = 0;
+ }
+
+ // determine the new head position
+ headx += dirx;
+ heady += diry;
+
+ // Wrap the new head position if necessary
+ if (headx >= FIELD_RECT_WIDTH) {
+ headx = 0;
+ }
+
+ if (headx < 0){
+ headx = FIELD_RECT_WIDTH - 1;
+ }
+
+ if (heady >= FIELD_RECT_HEIGHT) {
+ heady = 0;
+ }
+
+ if (heady < 0) {
+ heady = FIELD_RECT_HEIGHT - 1;
+ }
+
+ // store the new head position in the
+ // worm arrays
+ wormx[head] = headx;
+ wormy[head] = heady;
+
+ // update the worms grow state
+ if (growing > 0) growing --;
+}
+
+/**
+ * Draws the head and clears the tail of the worm in
+ * the display buffer. lcd_update() is NOT called thus
+ * the caller has to take care that the buffer is displayed.
+ */
+void drawWorm(void) {
+ // draw the new head
+ lcd_drawpixel( wormx[head] + FIELD_RECT_X, wormy[head] + FIELD_RECT_Y);
+
+ // clear the space behind the worm
+ lcd_clearpixel(wormx[tail] + FIELD_RECT_X, wormy[tail] + FIELD_RECT_Y);
+}
+
+/**
+ * Checks wether the coordinate is part of the worm.
+ * @param x int The x coordinate
+ * @param y int The y coordinate
+ * @return int The index of the worm arrays that contain x, y.
+ * Returns -1 if the coordinates are not part of the worm.
+ */
+int wormCollision(int x, int y) {
+ int retVal = -1;
+
+ // getWormLength is expensive -> buffer the value
+ int wormLength = getWormLength();
+ int i;
+
+ // test each entry that is part of the worm
+ for (i = 0; i < wormLength && retVal == -1; i++) {
+
+ // The iteration iterates the length of the worm.
+ // Here's the conversion to the true indices within
+ // the worm arrays.
+ int trueIndex = (tail + i) % MAX_WORM_LENGTH;
+
+ // The check
+ if (wormx[trueIndex] == x && wormy[trueIndex] == y) {
+ retVal = trueIndex;
+ }
+ }
+ return retVal;
+}
+
+/**
+ * Returns true if the head of the worm just has
+ * crossed the field boundaries.
+ * @return bool true if the worm just has wrapped.
+ */
+bool fieldCollision(void) {
+ bool retVal = false;
+ if ((headx == FIELD_RECT_WIDTH - 1 && dirx == -1) ||
+ (headx == 0 && dirx == 1) ||
+ (heady == FIELD_RECT_HEIGHT - 1 && diry == -1) ||
+ (heady == 0 && diry == 1)) {
+
+ retVal = true;
+ }
+ return retVal;
+}
+
+/**
+ * Checks and returns wether the head of the worm
+ * is colliding with something currently.
+ * @return int One of the values
+ * <ul>
+ * <li>COLLISION_NONE
+ * <li>COLLISION_WORM
+ * <li>COLLISION_FOOD
+ * <li>COLLISION_ARGH
+ * <li>COLLISION_FIELD
+ * </ul>
+ */
+int checkCollision(void) {
+ int retVal = COLLISION_NONE;
+
+ if (wormCollision(headx, heady) >= 0) {
+ retVal = COLLISION_WORM;
+ }
+
+ if (foodCollision(headx, heady) >= 0) {
+ retVal = COLLISION_FOOD;
+ }
+
+ if (arghCollision(headx, heady) >= 0) {
+ retVal = COLLISION_ARGH;
+ }
+
+ if (fieldCollision()) {
+ retVal = COLLISION_FIELD;
+ }
+
+ return retVal;
+}
+
+/*
+void debugOutput(void) {
+ char buf[40];
+
+ // head
+ snprintf(buf, sizeof(buf), "h:%d(%d;%d) ", head, wormx[head], wormy[head]);
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 0, buf, 0);
+
+ // tail
+ snprintf(buf, sizeof(buf), "t:%d(%d;%d) ", tail, wormx[tail], wormy[tail]);
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 8, buf, 0);
+
+ // speed
+ snprintf(buf, sizeof(buf), "div:%d ", speed);
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 16, buf, 0);
+
+ // collision
+ switch (checkCollision()) {
+ case COLLISION_NONE: snprintf(buf, sizeof(buf), "free "); break;
+ case COLLISION_WORM: snprintf(buf, sizeof(buf), "worm "); break;
+ case COLLISION_FOOD: snprintf(buf, sizeof(buf), "food "); break;
+ case COLLISION_ARGH: snprintf(buf, sizeof(buf), "argh "); break;
+ case COLLISION_FIELD: snprintf(buf, sizeof(buf), "field "); break;
+ }
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 24, buf, 0);
+}
+*/
+
+/**
+ * Prints out the score board with all the status information
+ * about the game.
+ */
+void scoreBoard(void) {
+ char buf[15];
+ char buf2[15];
+
+ // Title
+ snprintf(buf, sizeof (buf), "Wormlet");
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 0, buf, 0);
+
+ // length
+ snprintf(buf, sizeof (buf), "length:");
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 12, buf, 0);
+ snprintf(buf, sizeof (buf), "%d ", getWormLength() - growing);
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 20, buf, 0);
+
+ switch (checkCollision()) {
+ case COLLISION_NONE:
+ snprintf(buf, sizeof(buf), "I'm hungry! ");
+ if (growing > 0) {
+ snprintf(buf2, sizeof(buf2), "growing");
+ }
+ else {
+ snprintf(buf2, sizeof(buf2), " ");
+ }
+ break;
+
+ case COLLISION_WORM:
+ snprintf(buf, sizeof(buf), "Ouch! I bit");
+ snprintf(buf2, sizeof(buf2), "myself! ");
+ break;
+
+ case COLLISION_FOOD:
+ snprintf(buf, sizeof(buf), "Yummy! ");
+ snprintf(buf2, sizeof(buf2), "growing");
+ break;
+
+ case COLLISION_ARGH:
+ snprintf(buf, sizeof(buf), "Argh! I'm ");
+ snprintf(buf2, sizeof(buf2), "poisoned! ");
+ break;
+
+ case COLLISION_FIELD:
+ snprintf(buf, sizeof(buf), "Boing! ");
+ snprintf(buf2, sizeof(buf2), "Headcrash!");
+ break;
+ }
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 32, buf, 0);
+ lcd_putsxy(FIELD_RECT_WIDTH + 3, 40, buf2, 0);
+}
+
+/**
+ * Checks for collisions of the worm and its environment and
+ * takes appropriate actions like growing the worm or killing it.
+ * @return bool Returns true if the worm is dead. Returns
+ * false if the worm is healthy, up and creeping.
+ */
+bool processCollisions(void) {
+ bool wormDead = false;
+ int index = -1;
+
+ wormDead = fieldCollision();
+
+ if (!wormDead) {
+
+ // check if food was eaten
+ index = foodCollision(headx, heady);
+ if (index != -1){
+ clearFood(index);
+ makeFood(index);
+ drawFood(index);
+
+ int i = 0;
+
+ for (i = 0; i < ARGHS_PER_FOOD; i++) {
+ arghCount++;
+ if (arghCount > MAX_ARGH) {
+ arghCount = MAX_ARGH;
+ }
+ makeArgh(arghCount - 1);
+ drawArgh(arghCount - 1);
+ }
+
+ tail -= WORM_PER_FOOD;
+ growing += WORM_PER_FOOD;
+ if (tail < 0) {
+ tail += MAX_WORM_LENGTH;
+ }
+
+ drawWorm();
+ }
+
+ // check if argh was eaten
+ else {
+ index = arghCollision(headx, heady);
+ if (index != -1) {
+ wormDead = true;
+ }
+ else {
+ if (wormCollision(headx, heady) != -1) {
+ wormDead = true;
+ }
+ }
+ }
+ }
+ return wormDead;
+}
+
+/**
+ * The main loop of the game.
+ * @return bool Returns true if the game ended
+ * with a dead worm. Returns false if the user
+ * aborted the game manually.
+ */
+bool run(void) {
+ int button = 0;
+ int wormDead = false;
+
+ // initialize the board and so on
+ initWormlet();
+
+ // change the direction of the worm
+ while (button != BUTTON_OFF && ! wormDead)
+ {
+ switch (button) {
+ case BUTTON_UP:
+ diry = -1;
+ dirx = 0;
+ break;
+
+ case BUTTON_DOWN:
+ diry = 1;
+ dirx = 0;
+ break;
+
+ case BUTTON_LEFT:
+ dirx = -1;
+ diry = 0;
+ break;
+
+ case BUTTON_RIGHT:
+ dirx = 1;
+ diry = 0;
+ break;
+
+ case BUTTON_F2:
+ speed--;
+ break;
+
+ case BUTTON_F3:
+ speed ++;
+ break;
+ }
+
+ moveWorm();
+// debugOutput();
+ wormDead = processCollisions();
+ drawWorm();
+ scoreBoard();
+ lcd_update();
+ button = button_get_w_tmo(HZ/speed);
+ }
+ return wormDead;
+}
+
+/**
+ * Main entry point from the menu to start the game control.
+ */
+Menu wormlet(void)
+{
+ bool wormDead = false;
+ int button;
+ do {
+
+ // button state will be overridden if
+ // the game quits with the death of the worm.
+ // Initializing button to BUTTON_OFF ensures
+ // that the user can hit BUTTON_OFF during the
+ // game to return to the menu.
+ button = BUTTON_OFF;
+
+ // start the game
+ wormDead = run();
+
+ // if worm isn't dead the game was quit
+ // via BUTTON_OFF -> no need to wait for
+ // buttons.
+ if (wormDead) {
+ do {
+ button = button_get(true);
+ }
+ // BUTTON_ON -> start new game
+ // BUTTON_OFF -> back to game menu
+ while (button != BUTTON_OFF && button != BUTTON_ON);
+ }
+ }
+ while (button != BUTTON_OFF);
+
+ return MENU_OK;
+}