diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/recorder/wormlet.c | 779 | ||||
-rw-r--r-- | apps/recorder/wormlet.h | 28 |
2 files changed, 807 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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Philipp Pertermann | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <sprintf.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include "lcd.h" | ||
24 | #include "button.h" | ||
25 | #include "kernel.h" | ||
26 | #include "menu.h" | ||
27 | |||
28 | #define MAX_WORM_LENGTH 500 // size of the ring of the worm | ||
29 | #define INITIAL_WORM_LENGTH 10 // when the game starts | ||
30 | #define WORM_PER_FOOD 7 // num of pixel the worm grows by eating a food | ||
31 | |||
32 | // The worm is stored in a ring of xy coordinates | ||
33 | short wormx[MAX_WORM_LENGTH]; | ||
34 | short wormy[MAX_WORM_LENGTH]; | ||
35 | |||
36 | int head; // index of the head within the buffer | ||
37 | short headx; | ||
38 | short heady; | ||
39 | |||
40 | int tail; // index of the tail within the buffer | ||
41 | int growing; // number of cyles the worm still keeps growing | ||
42 | |||
43 | |||
44 | #define MAX_FOOD 5 // maximal number of food items | ||
45 | #define FOOD_SIZE 3 // the width and height of a food | ||
46 | short foodx[MAX_FOOD]; | ||
47 | short foody[MAX_FOOD]; | ||
48 | |||
49 | #define MAX_ARGH 100 // maximal number of argh items | ||
50 | #define ARGH_SIZE 4 // the width and height of a argh | ||
51 | #define ARGHS_PER_FOOD 2 // number of arghs produced each time a food was eaten | ||
52 | short arghx[MAX_ARGH]; | ||
53 | short arghy[MAX_ARGH]; | ||
54 | int arghCount; | ||
55 | |||
56 | // direction vector in which the worm moves | ||
57 | short dirx; // only values -1 0 1 allowed | ||
58 | short diry; // only values -1 0 1 allowed | ||
59 | |||
60 | int speed = 10; | ||
61 | |||
62 | // return values of checkCollision | ||
63 | #define COLLISION_NONE 0 | ||
64 | #define COLLISION_WORM 1 | ||
65 | #define COLLISION_FOOD 2 | ||
66 | #define COLLISION_ARGH 3 | ||
67 | #define COLLISION_FIELD 4 | ||
68 | |||
69 | // size of the field the worm lives in | ||
70 | #define FIELD_RECT_X 1 | ||
71 | #define FIELD_RECT_Y 1 | ||
72 | #define FIELD_RECT_WIDTH LCD_HEIGHT - 2 | ||
73 | #define FIELD_RECT_HEIGHT LCD_HEIGHT - 2 | ||
74 | |||
75 | /** | ||
76 | * Returns the current length of the worm. | ||
77 | * @return int a positive value | ||
78 | */ | ||
79 | int getWormLength(void) { | ||
80 | // initial simple calculation will be overwritten | ||
81 | // if wrong. | ||
82 | int retVal = head - tail; | ||
83 | |||
84 | // if the worm 'crosses' the boundaries of the ringbuffer | ||
85 | if (retVal < 0) { | ||
86 | retVal = head + MAX_WORM_LENGTH - tail; | ||
87 | } | ||
88 | |||
89 | return retVal; | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Checks wether a specific food in the food arrays is at the | ||
94 | * specified coordinates. | ||
95 | * @param int foodIndex The index of the food in the food arrays | ||
96 | * @param int x the x coordinate. | ||
97 | * @param int y the y coordinate. | ||
98 | * @return Returns true if the coordinate hits the food specified by | ||
99 | * foodIndex. | ||
100 | */ | ||
101 | bool specificFoodCollision(int foodIndex, int x, int y) { | ||
102 | bool retVal = false; | ||
103 | if (x >= foodx[foodIndex] && | ||
104 | x < foodx[foodIndex] + FOOD_SIZE && | ||
105 | y >= foody[foodIndex] && | ||
106 | y < foody[foodIndex] + FOOD_SIZE) { | ||
107 | |||
108 | retVal = true; | ||
109 | } | ||
110 | return retVal; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * Returns the index of the food that is at the | ||
115 | * given coordinates. If no food is at the coordinates | ||
116 | * -1 is returned. | ||
117 | * @return int -1 <= value < MAX_FOOD | ||
118 | */ | ||
119 | int foodCollision(int x, int y) { | ||
120 | int i = 0; | ||
121 | int retVal = -1; | ||
122 | bool collisionDetected = false; | ||
123 | for (i = 0; i < MAX_FOOD && !collisionDetected; i++) { | ||
124 | if (specificFoodCollision(i, x, y)) { | ||
125 | |||
126 | collisionDetected = true; | ||
127 | retVal = i; | ||
128 | } | ||
129 | } | ||
130 | return retVal; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * Checks wether a specific argh in the argh arrays is at the | ||
135 | * specified coordinates. | ||
136 | * @param int arghIndex The index of the argh in the argh arrays | ||
137 | * @param int x the x coordinate. | ||
138 | * @param int y the y coordinate. | ||
139 | * @return Returns true if the coordinate hits the argh specified by | ||
140 | * arghIndex. | ||
141 | */ | ||
142 | bool specificArghCollision(int arghIndex, int x, int y) { | ||
143 | bool retVal = false; | ||
144 | if (x >= arghx[arghIndex] && | ||
145 | x < arghx[arghIndex] + ARGH_SIZE && | ||
146 | y >= arghy[arghIndex] && | ||
147 | y < arghy[arghIndex] + ARGH_SIZE) { | ||
148 | |||
149 | retVal = true; | ||
150 | } | ||
151 | return retVal; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * Returns the index of the argh that is at the | ||
156 | * given coordinates. If no argh is at the coordinates | ||
157 | * -1 is returned. | ||
158 | * @param int x The x coordinate. | ||
159 | * @param int y The y coordinate. | ||
160 | * @return int -1 <= value < arghCount <= MAX_ARGH | ||
161 | */ | ||
162 | int arghCollision(int x, int y) { | ||
163 | int i = 0; | ||
164 | int retVal = -1; | ||
165 | bool collisionDetected = false; | ||
166 | |||
167 | // search for the argh that has the specified coords | ||
168 | for (i = 0; i < arghCount && !collisionDetected; i++) { | ||
169 | if (specificArghCollision(i, x, y)) { | ||
170 | |||
171 | collisionDetected = true; | ||
172 | retVal = i; | ||
173 | } | ||
174 | } | ||
175 | return retVal; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Checks wether the worm collides with the food at the specfied food-arrays. | ||
180 | * @param int foodIndex The index of the food in the arrays. Ensure the value is | ||
181 | * 0 <= foodIndex <= MAX_FOOD | ||
182 | * @return Returns true if the worm collides with the specified food. | ||
183 | */ | ||
184 | bool wormFoodCollision(int foodIndex) { | ||
185 | bool retVal = false; | ||
186 | |||
187 | // buffer wormLength because getWormLength is expensive | ||
188 | int wormLength = getWormLength(); | ||
189 | int i; | ||
190 | |||
191 | // although all the worm gets iterated i is NOT the index | ||
192 | // of the worm arrays | ||
193 | for (i = 0; i < wormLength && !retVal; i++) { | ||
194 | |||
195 | // convert i to the true worm indices | ||
196 | int wormIndex = (tail + i) % MAX_WORM_LENGTH; | ||
197 | |||
198 | // The check | ||
199 | if (specificFoodCollision(foodIndex, wormx[wormIndex], wormy[wormIndex])) { | ||
200 | retVal = true; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | return retVal; | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * Checks wether the worm collides with the argh at the specfied argh-arrays. | ||
209 | * @param int arghIndex The index of the argh in the arrays. Ensure the value is | ||
210 | * 0 <= arghIndex < arghCount <= MAX_ARGH | ||
211 | * @return Returns true if the worm collides with the specified argh. | ||
212 | */ | ||
213 | bool wormArghCollision(int arghIndex) { | ||
214 | bool retVal = false; | ||
215 | |||
216 | // buffer wormLength because getWormLength is expensive | ||
217 | int wormLength = getWormLength(); | ||
218 | int i; | ||
219 | |||
220 | // although all the worm gets iterated i is NOT the index | ||
221 | // of the worm arrays | ||
222 | for (i = 0; i < wormLength && !retVal; i++) { | ||
223 | |||
224 | // convert i to the true worm indices | ||
225 | int wormIndex = (tail + i) % MAX_WORM_LENGTH; | ||
226 | |||
227 | // The check | ||
228 | if (specificArghCollision(arghIndex, wormx[wormIndex], wormy[wormIndex])) { | ||
229 | retVal = true; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | return retVal; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * Find new coordinates for the food stored in foodx[index], foody[index] | ||
238 | * that don't collide with any other food or argh | ||
239 | * @param int index | ||
240 | * Ensure that 0 <= index < MAX_FOOD. | ||
241 | */ | ||
242 | void makeFood(int index) { | ||
243 | |||
244 | int x = 0; | ||
245 | int y = 0; | ||
246 | bool collisionDetected = false; | ||
247 | |||
248 | do { | ||
249 | // make coordinates for a new food so that | ||
250 | // the entire food lies within the FIELD | ||
251 | x = rand() % (FIELD_RECT_WIDTH - FOOD_SIZE); | ||
252 | y = rand() % (FIELD_RECT_HEIGHT - FOOD_SIZE); | ||
253 | |||
254 | // Ensure that the new food doesn't collide with any | ||
255 | // existing foods or arghs. | ||
256 | // If one or more corners of the new food hit any existing | ||
257 | // argh or food a collision is detected. | ||
258 | collisionDetected = | ||
259 | foodCollision(x , y ) >= 0 || | ||
260 | foodCollision(x + FOOD_SIZE - 1, y ) >= 0 || | ||
261 | foodCollision(x , y + FOOD_SIZE - 1) >= 0 || | ||
262 | foodCollision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0 || | ||
263 | arghCollision(x , y ) >= 0 || | ||
264 | arghCollision(x + FOOD_SIZE - 1, y ) >= 0 || | ||
265 | arghCollision(x , y + FOOD_SIZE - 1) >= 0 || | ||
266 | arghCollision(x + FOOD_SIZE - 1, y + FOOD_SIZE - 1) >= 0; | ||
267 | |||
268 | // use coordinates for further testing | ||
269 | foodx[index] = x; | ||
270 | foody[index] = y; | ||
271 | |||
272 | // now test wether we accidently hit the worm with food ;) | ||
273 | collisionDetected |= wormFoodCollision(index); | ||
274 | } | ||
275 | while (collisionDetected); | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * Clears a food from the lcd buffer. | ||
280 | * @param int index The index of the food arrays under which | ||
281 | * the coordinates of the desired food can be found. Ensure | ||
282 | * that the value is 0 <= index <= MAX_FOOD. | ||
283 | */ | ||
284 | void clearFood(int index) { | ||
285 | // remove the old food from the screen | ||
286 | lcd_clearrect (foodx[index] + FIELD_RECT_X, | ||
287 | foody[index] + FIELD_RECT_Y, | ||
288 | FOOD_SIZE, FOOD_SIZE); | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * Draws a food in the lcd buffer. | ||
293 | * @param int index The index of the food arrays under which | ||
294 | * the coordinates of the desired food can be found. Ensure | ||
295 | * that the value is 0 <= index <= MAX_FOOD. | ||
296 | */ | ||
297 | void drawFood(int index) { | ||
298 | // draw the food object | ||
299 | lcd_fillrect (foodx[index] + FIELD_RECT_X, | ||
300 | foody[index] + FIELD_RECT_Y, | ||
301 | FOOD_SIZE, FOOD_SIZE); | ||
302 | lcd_clearrect(foodx[index] + FIELD_RECT_X + 1, | ||
303 | foody[index] + FIELD_RECT_Y + 1, | ||
304 | FOOD_SIZE - 2, FOOD_SIZE - 2); | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * Find new coordinates for the argh stored in arghx[index], arghy[index] | ||
309 | * that don't collide with any other food or argh. | ||
310 | * @param int index | ||
311 | * Ensure that 0 <= index < arghCount < MAX_ARGH. | ||
312 | */ | ||
313 | void makeArgh(int index) { | ||
314 | int x; | ||
315 | int y; | ||
316 | bool collisionDetected = false; | ||
317 | |||
318 | do { | ||
319 | // make coordinates for a new argh so that | ||
320 | // the entire food lies within the FIELD | ||
321 | x = rand() % (FIELD_RECT_WIDTH - ARGH_SIZE); | ||
322 | y = rand() % (FIELD_RECT_HEIGHT - ARGH_SIZE); | ||
323 | // Ensure that the new argh doesn't intersect with any | ||
324 | // existing foods or arghs. | ||
325 | // If one or more corners of the new argh hit any existing | ||
326 | // argh or food an intersection is detected. | ||
327 | collisionDetected = | ||
328 | foodCollision(x , y ) >= 0 || | ||
329 | foodCollision(x + ARGH_SIZE - 1, y ) >= 0 || | ||
330 | foodCollision(x , y + ARGH_SIZE - 1) >= 0 || | ||
331 | foodCollision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0 || | ||
332 | arghCollision(x , y ) >= 0 || | ||
333 | arghCollision(x + ARGH_SIZE - 1, y ) >= 0 || | ||
334 | arghCollision(x , y + ARGH_SIZE - 1) >= 0 || | ||
335 | arghCollision(x + ARGH_SIZE - 1, y + ARGH_SIZE - 1) >= 0; | ||
336 | |||
337 | // use the candidate coordinates to make a real argh | ||
338 | arghx[index] = x; | ||
339 | arghy[index] = y; | ||
340 | |||
341 | // now test wether we accidently hit the worm with argh ;) | ||
342 | collisionDetected |= wormArghCollision(index); | ||
343 | } | ||
344 | while (collisionDetected); | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * Draws an argh in the lcd buffer. | ||
349 | * @param int index The index of the argh arrays under which | ||
350 | * the coordinates of the desired argh can be found. Ensure | ||
351 | * that the value is 0 <= index < arghCount <= MAX_ARGH. | ||
352 | */ | ||
353 | void drawArgh(int index) { | ||
354 | // draw the new argh | ||
355 | lcd_fillrect (arghx[index] + FIELD_RECT_X, | ||
356 | arghy[index] + FIELD_RECT_Y, | ||
357 | ARGH_SIZE, ARGH_SIZE); | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * Initializes the worm-, food- and argh-arrays, draws a frame, | ||
362 | * makes some food and argh and display all that stuff. | ||
363 | */ | ||
364 | void initWormlet(void) { | ||
365 | |||
366 | // Needed when the game is restarted using BUTTON_ON | ||
367 | lcd_clear_display(); | ||
368 | |||
369 | // Initialize all the worm coordinates to 0,0. | ||
370 | int i; | ||
371 | for (i = 0; i < MAX_WORM_LENGTH; i++){ | ||
372 | wormx[i] = 0; | ||
373 | wormy[i] = 0; | ||
374 | } | ||
375 | |||
376 | // initialize the worm size | ||
377 | head = INITIAL_WORM_LENGTH; | ||
378 | tail = 0; | ||
379 | |||
380 | // initialize the worm start point | ||
381 | headx = 0; | ||
382 | heady = 0; | ||
383 | |||
384 | // set the initial direction the worm creeps to | ||
385 | dirx = 1; | ||
386 | diry = 0; | ||
387 | |||
388 | // make and display some food and argh | ||
389 | arghCount = MAX_FOOD; | ||
390 | for (i = 0; i < MAX_FOOD; i++) { | ||
391 | makeFood(i); | ||
392 | drawFood(i); | ||
393 | makeArgh(i); | ||
394 | drawArgh(i); | ||
395 | } | ||
396 | |||
397 | // draw the game field | ||
398 | lcd_invertrect (0 , 0 , FIELD_RECT_WIDTH + 2, FIELD_RECT_HEIGHT + 2); | ||
399 | lcd_invertrect(0 + 1, 0 + 1, FIELD_RECT_WIDTH , FIELD_RECT_HEIGHT); | ||
400 | |||
401 | // make everything visible | ||
402 | lcd_update(); | ||
403 | } | ||
404 | |||
405 | /** | ||
406 | * Move the worm one step further. | ||
407 | * The direction in which the worm moves is taken | ||
408 | * from dirx and diry. If the | ||
409 | * worm crosses the boundaries of the field the | ||
410 | * worm is wrapped (it enters the field from the | ||
411 | * opposite side). moveWorm decreases growing if > 0. | ||
412 | */ | ||
413 | void moveWorm(void) { | ||
414 | // find the next array index for the head | ||
415 | head++; | ||
416 | if (head >= MAX_WORM_LENGTH){ | ||
417 | head = 0; | ||
418 | } | ||
419 | |||
420 | // find the next array index for the tail | ||
421 | tail++; | ||
422 | if (tail >= MAX_WORM_LENGTH){ | ||
423 | tail = 0; | ||
424 | } | ||
425 | |||
426 | // determine the new head position | ||
427 | headx += dirx; | ||
428 | heady += diry; | ||
429 | |||
430 | // Wrap the new head position if necessary | ||
431 | if (headx >= FIELD_RECT_WIDTH) { | ||
432 | headx = 0; | ||
433 | } | ||
434 | |||
435 | if (headx < 0){ | ||
436 | headx = FIELD_RECT_WIDTH - 1; | ||
437 | } | ||
438 | |||
439 | if (heady >= FIELD_RECT_HEIGHT) { | ||
440 | heady = 0; | ||
441 | } | ||
442 | |||
443 | if (heady < 0) { | ||
444 | heady = FIELD_RECT_HEIGHT - 1; | ||
445 | } | ||
446 | |||
447 | // store the new head position in the | ||
448 | // worm arrays | ||
449 | wormx[head] = headx; | ||
450 | wormy[head] = heady; | ||
451 | |||
452 | // update the worms grow state | ||
453 | if (growing > 0) growing --; | ||
454 | } | ||
455 | |||
456 | /** | ||
457 | * Draws the head and clears the tail of the worm in | ||
458 | * the display buffer. lcd_update() is NOT called thus | ||
459 | * the caller has to take care that the buffer is displayed. | ||
460 | */ | ||
461 | void drawWorm(void) { | ||
462 | // draw the new head | ||
463 | lcd_drawpixel( wormx[head] + FIELD_RECT_X, wormy[head] + FIELD_RECT_Y); | ||
464 | |||
465 | // clear the space behind the worm | ||
466 | lcd_clearpixel(wormx[tail] + FIELD_RECT_X, wormy[tail] + FIELD_RECT_Y); | ||
467 | } | ||
468 | |||
469 | /** | ||
470 | * Checks wether the coordinate is part of the worm. | ||
471 | * @param x int The x coordinate | ||
472 | * @param y int The y coordinate | ||
473 | * @return int The index of the worm arrays that contain x, y. | ||
474 | * Returns -1 if the coordinates are not part of the worm. | ||
475 | */ | ||
476 | int wormCollision(int x, int y) { | ||
477 | int retVal = -1; | ||
478 | |||
479 | // getWormLength is expensive -> buffer the value | ||
480 | int wormLength = getWormLength(); | ||
481 | int i; | ||
482 | |||
483 | // test each entry that is part of the worm | ||
484 | for (i = 0; i < wormLength && retVal == -1; i++) { | ||
485 | |||
486 | // The iteration iterates the length of the worm. | ||
487 | // Here's the conversion to the true indices within | ||
488 | // the worm arrays. | ||
489 | int trueIndex = (tail + i) % MAX_WORM_LENGTH; | ||
490 | |||
491 | // The check | ||
492 | if (wormx[trueIndex] == x && wormy[trueIndex] == y) { | ||
493 | retVal = trueIndex; | ||
494 | } | ||
495 | } | ||
496 | return retVal; | ||
497 | } | ||
498 | |||
499 | /** | ||
500 | * Returns true if the head of the worm just has | ||
501 | * crossed the field boundaries. | ||
502 | * @return bool true if the worm just has wrapped. | ||
503 | */ | ||
504 | bool fieldCollision(void) { | ||
505 | bool retVal = false; | ||
506 | if ((headx == FIELD_RECT_WIDTH - 1 && dirx == -1) || | ||
507 | (headx == 0 && dirx == 1) || | ||
508 | (heady == FIELD_RECT_HEIGHT - 1 && diry == -1) || | ||
509 | (heady == 0 && diry == 1)) { | ||
510 | |||
511 | retVal = true; | ||
512 | } | ||
513 | return retVal; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * Checks and returns wether the head of the worm | ||
518 | * is colliding with something currently. | ||
519 | * @return int One of the values | ||
520 | * <ul> | ||
521 | * <li>COLLISION_NONE | ||
522 | * <li>COLLISION_WORM | ||
523 | * <li>COLLISION_FOOD | ||
524 | * <li>COLLISION_ARGH | ||
525 | * <li>COLLISION_FIELD | ||
526 | * </ul> | ||
527 | */ | ||
528 | int checkCollision(void) { | ||
529 | int retVal = COLLISION_NONE; | ||
530 | |||
531 | if (wormCollision(headx, heady) >= 0) { | ||
532 | retVal = COLLISION_WORM; | ||
533 | } | ||
534 | |||
535 | if (foodCollision(headx, heady) >= 0) { | ||
536 | retVal = COLLISION_FOOD; | ||
537 | } | ||
538 | |||
539 | if (arghCollision(headx, heady) >= 0) { | ||
540 | retVal = COLLISION_ARGH; | ||
541 | } | ||
542 | |||
543 | if (fieldCollision()) { | ||
544 | retVal = COLLISION_FIELD; | ||
545 | } | ||
546 | |||
547 | return retVal; | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | void debugOutput(void) { | ||
552 | char buf[40]; | ||
553 | |||
554 | // head | ||
555 | snprintf(buf, sizeof(buf), "h:%d(%d;%d) ", head, wormx[head], wormy[head]); | ||
556 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 0, buf, 0); | ||
557 | |||
558 | // tail | ||
559 | snprintf(buf, sizeof(buf), "t:%d(%d;%d) ", tail, wormx[tail], wormy[tail]); | ||
560 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 8, buf, 0); | ||
561 | |||
562 | // speed | ||
563 | snprintf(buf, sizeof(buf), "div:%d ", speed); | ||
564 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 16, buf, 0); | ||
565 | |||
566 | // collision | ||
567 | switch (checkCollision()) { | ||
568 | case COLLISION_NONE: snprintf(buf, sizeof(buf), "free "); break; | ||
569 | case COLLISION_WORM: snprintf(buf, sizeof(buf), "worm "); break; | ||
570 | case COLLISION_FOOD: snprintf(buf, sizeof(buf), "food "); break; | ||
571 | case COLLISION_ARGH: snprintf(buf, sizeof(buf), "argh "); break; | ||
572 | case COLLISION_FIELD: snprintf(buf, sizeof(buf), "field "); break; | ||
573 | } | ||
574 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 24, buf, 0); | ||
575 | } | ||
576 | */ | ||
577 | |||
578 | /** | ||
579 | * Prints out the score board with all the status information | ||
580 | * about the game. | ||
581 | */ | ||
582 | void scoreBoard(void) { | ||
583 | char buf[15]; | ||
584 | char buf2[15]; | ||
585 | |||
586 | // Title | ||
587 | snprintf(buf, sizeof (buf), "Wormlet"); | ||
588 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 0, buf, 0); | ||
589 | |||
590 | // length | ||
591 | snprintf(buf, sizeof (buf), "length:"); | ||
592 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 12, buf, 0); | ||
593 | snprintf(buf, sizeof (buf), "%d ", getWormLength() - growing); | ||
594 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 20, buf, 0); | ||
595 | |||
596 | switch (checkCollision()) { | ||
597 | case COLLISION_NONE: | ||
598 | snprintf(buf, sizeof(buf), "I'm hungry! "); | ||
599 | if (growing > 0) { | ||
600 | snprintf(buf2, sizeof(buf2), "growing"); | ||
601 | } | ||
602 | else { | ||
603 | snprintf(buf2, sizeof(buf2), " "); | ||
604 | } | ||
605 | break; | ||
606 | |||
607 | case COLLISION_WORM: | ||
608 | snprintf(buf, sizeof(buf), "Ouch! I bit"); | ||
609 | snprintf(buf2, sizeof(buf2), "myself! "); | ||
610 | break; | ||
611 | |||
612 | case COLLISION_FOOD: | ||
613 | snprintf(buf, sizeof(buf), "Yummy! "); | ||
614 | snprintf(buf2, sizeof(buf2), "growing"); | ||
615 | break; | ||
616 | |||
617 | case COLLISION_ARGH: | ||
618 | snprintf(buf, sizeof(buf), "Argh! I'm "); | ||
619 | snprintf(buf2, sizeof(buf2), "poisoned! "); | ||
620 | break; | ||
621 | |||
622 | case COLLISION_FIELD: | ||
623 | snprintf(buf, sizeof(buf), "Boing! "); | ||
624 | snprintf(buf2, sizeof(buf2), "Headcrash!"); | ||
625 | break; | ||
626 | } | ||
627 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 32, buf, 0); | ||
628 | lcd_putsxy(FIELD_RECT_WIDTH + 3, 40, buf2, 0); | ||
629 | } | ||
630 | |||
631 | /** | ||
632 | * Checks for collisions of the worm and its environment and | ||
633 | * takes appropriate actions like growing the worm or killing it. | ||
634 | * @return bool Returns true if the worm is dead. Returns | ||
635 | * false if the worm is healthy, up and creeping. | ||
636 | */ | ||
637 | bool processCollisions(void) { | ||
638 | bool wormDead = false; | ||
639 | int index = -1; | ||
640 | |||
641 | wormDead = fieldCollision(); | ||
642 | |||
643 | if (!wormDead) { | ||
644 | |||
645 | // check if food was eaten | ||
646 | index = foodCollision(headx, heady); | ||
647 | if (index != -1){ | ||
648 | clearFood(index); | ||
649 | makeFood(index); | ||
650 | drawFood(index); | ||
651 | |||
652 | int i = 0; | ||
653 | |||
654 | for (i = 0; i < ARGHS_PER_FOOD; i++) { | ||
655 | arghCount++; | ||
656 | if (arghCount > MAX_ARGH) { | ||
657 | arghCount = MAX_ARGH; | ||
658 | } | ||
659 | makeArgh(arghCount - 1); | ||
660 | drawArgh(arghCount - 1); | ||
661 | } | ||
662 | |||
663 | tail -= WORM_PER_FOOD; | ||
664 | growing += WORM_PER_FOOD; | ||
665 | if (tail < 0) { | ||
666 | tail += MAX_WORM_LENGTH; | ||
667 | } | ||
668 | |||
669 | drawWorm(); | ||
670 | } | ||
671 | |||
672 | // check if argh was eaten | ||
673 | else { | ||
674 | index = arghCollision(headx, heady); | ||
675 | if (index != -1) { | ||
676 | wormDead = true; | ||
677 | } | ||
678 | else { | ||
679 | if (wormCollision(headx, heady) != -1) { | ||
680 | wormDead = true; | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | return wormDead; | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * The main loop of the game. | ||
690 | * @return bool Returns true if the game ended | ||
691 | * with a dead worm. Returns false if the user | ||
692 | * aborted the game manually. | ||
693 | */ | ||
694 | bool run(void) { | ||
695 | int button = 0; | ||
696 | int wormDead = false; | ||
697 | |||
698 | // initialize the board and so on | ||
699 | initWormlet(); | ||
700 | |||
701 | // change the direction of the worm | ||
702 | while (button != BUTTON_OFF && ! wormDead) | ||
703 | { | ||
704 | switch (button) { | ||
705 | case BUTTON_UP: | ||
706 | diry = -1; | ||
707 | dirx = 0; | ||
708 | break; | ||
709 | |||
710 | case BUTTON_DOWN: | ||
711 | diry = 1; | ||
712 | dirx = 0; | ||
713 | break; | ||
714 | |||
715 | case BUTTON_LEFT: | ||
716 | dirx = -1; | ||
717 | diry = 0; | ||
718 | break; | ||
719 | |||
720 | case BUTTON_RIGHT: | ||
721 | dirx = 1; | ||
722 | diry = 0; | ||
723 | break; | ||
724 | |||
725 | case BUTTON_F2: | ||
726 | speed--; | ||
727 | break; | ||
728 | |||
729 | case BUTTON_F3: | ||
730 | speed ++; | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | moveWorm(); | ||
735 | // debugOutput(); | ||
736 | wormDead = processCollisions(); | ||
737 | drawWorm(); | ||
738 | scoreBoard(); | ||
739 | lcd_update(); | ||
740 | button = button_get_w_tmo(HZ/speed); | ||
741 | } | ||
742 | return wormDead; | ||
743 | } | ||
744 | |||
745 | /** | ||
746 | * Main entry point from the menu to start the game control. | ||
747 | */ | ||
748 | Menu wormlet(void) | ||
749 | { | ||
750 | bool wormDead = false; | ||
751 | int button; | ||
752 | do { | ||
753 | |||
754 | // button state will be overridden if | ||
755 | // the game quits with the death of the worm. | ||
756 | // Initializing button to BUTTON_OFF ensures | ||
757 | // that the user can hit BUTTON_OFF during the | ||
758 | // game to return to the menu. | ||
759 | button = BUTTON_OFF; | ||
760 | |||
761 | // start the game | ||
762 | wormDead = run(); | ||
763 | |||
764 | // if worm isn't dead the game was quit | ||
765 | // via BUTTON_OFF -> no need to wait for | ||
766 | // buttons. | ||
767 | if (wormDead) { | ||
768 | do { | ||
769 | button = button_get(true); | ||
770 | } | ||
771 | // BUTTON_ON -> start new game | ||
772 | // BUTTON_OFF -> back to game menu | ||
773 | while (button != BUTTON_OFF && button != BUTTON_ON); | ||
774 | } | ||
775 | } | ||
776 | while (button != BUTTON_OFF); | ||
777 | |||
778 | return MENU_OK; | ||
779 | } | ||
diff --git a/apps/recorder/wormlet.h b/apps/recorder/wormlet.h new file mode 100644 index 0000000000..347c6be737 --- /dev/null +++ b/apps/recorder/wormlet.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Philipp Pertermann | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef __WORMLET__ | ||
21 | #define __WORMLET__ | ||
22 | |||
23 | #include "menu.h" | ||
24 | |||
25 | Menu wormlet(void); | ||
26 | |||
27 | #endif /*__WORMLET__ */ | ||
28 | |||