1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Philipp Pertermann
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "configfile.h"
25 /* size of the field the worm lives in */
26 #define FIELD_RECT_X 1
27 #define FIELD_RECT_Y 1
28 #define FIELD_RECT_WIDTH (LCD_WIDTH - 45)
29 #define FIELD_RECT_HEIGHT (LCD_HEIGHT - 2)
31 /* when the game starts */
32 #define INITIAL_WORM_LENGTH 10
34 /* num of pixel the worm grows per eaten food */
35 #define WORM_PER_FOOD 7
37 /* num of worms creeping in the FIELD */
40 /* minimal distance between a worm and an argh
41 when a new argh is made */
42 #define MIN_ARGH_DIST 5
44 #if (CONFIG_KEYPAD == RECORDER_PAD)
45 #define BTN_DIR_UP BUTTON_UP
46 #define BTN_DIR_DOWN BUTTON_DOWN
47 #define BTN_DIR_LEFT BUTTON_LEFT
48 #define BTN_DIR_RIGHT BUTTON_RIGHT
49 #define BTN_PLAYER2_DIR1 BUTTON_F2
50 #define BTN_PLAYER2_DIR2 BUTTON_F3
51 #define BTN_STARTPAUSE BUTTON_PLAY
52 #define BTN_QUIT BUTTON_OFF
53 #define BTN_STOPRESET BUTTON_ON
54 #define BTN_TOGGLE_KEYS BUTTON_F1
56 #if BUTTON_REMOTE != 0
57 #define BTN_RC_UP BUTTON_RC_VOL_UP
58 #define BTN_RC_DOWN BUTTON_RC_VOL_DOWN
63 #define PLAYERS_TEXT "UP/DN"
64 #define WORMS_TEXT "L/R"
65 #define KEY_CONTROL_TEXT "F1"
67 #elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
68 #define BTN_DIR_UP BUTTON_UP
69 #define BTN_DIR_DOWN BUTTON_DOWN
70 #define BTN_DIR_LEFT BUTTON_LEFT
71 #define BTN_DIR_RIGHT BUTTON_RIGHT
72 #define BTN_PLAYER2_DIR1 BUTTON_F2
73 #define BTN_PLAYER2_DIR2 BUTTON_F3
74 #define BTN_STARTPAUSE BUTTON_SELECT
75 #define BTN_QUIT BUTTON_OFF
76 #define BTN_STOPRESET BUTTON_ON
77 #define BTN_TOGGLE_KEYS BUTTON_F1
79 #define PLAYERS_TEXT "UP/DN"
80 #define WORMS_TEXT "L/R"
81 #define KEY_CONTROL_TEXT "F1"
83 #elif (CONFIG_KEYPAD == ONDIO_PAD)
84 #define BTN_DIR_UP BUTTON_UP
85 #define BTN_DIR_DOWN BUTTON_DOWN
86 #define BTN_DIR_LEFT BUTTON_LEFT
87 #define BTN_DIR_RIGHT BUTTON_RIGHT
88 #define BTN_STARTPAUSE (BUTTON_MENU|BUTTON_REL)
89 #define BTN_QUIT (BUTTON_OFF|BUTTON_REL)
90 #define BTN_STOPRESET (BUTTON_OFF|BUTTON_MENU)
92 #define PLAYERS_TEXT "UP/DN"
93 #define WORMS_TEXT "L/R"
95 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
96 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
98 #define BTN_DIR_UP BUTTON_MENU
99 #define BTN_DIR_DOWN BUTTON_PLAY
100 #define BTN_DIR_LEFT BUTTON_LEFT
101 #define BTN_DIR_RIGHT BUTTON_RIGHT
102 #define BTN_STARTPAUSE (BUTTON_SELECT|BUTTON_REL)
103 #define BTN_QUIT (BUTTON_SELECT|BUTTON_MENU)
104 #define BTN_STOPRESET (BUTTON_SELECT|BUTTON_PLAY)
106 #define PLAYERS_TEXT "Menu/Play"
107 #define WORMS_TEXT "Left/Right"
109 #elif (CONFIG_KEYPAD == IRIVER_H300_PAD) || (CONFIG_KEYPAD == IRIVER_H100_PAD)
111 #define BTN_DIR_UP BUTTON_UP
112 #define BTN_DIR_DOWN BUTTON_DOWN
113 #define BTN_DIR_LEFT BUTTON_LEFT
114 #define BTN_DIR_RIGHT BUTTON_RIGHT
115 #define BTN_STARTPAUSE (BUTTON_SELECT|BUTTON_REL)
116 #define BTN_QUIT BUTTON_OFF
117 #define BTN_STOPRESET BUTTON_ON
119 #define BTN_RC_QUIT BUTTON_RC_STOP
121 #define PLAYERS_TEXT "Up/Down"
122 #define WORMS_TEXT "Left/Right"
124 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
126 #define BTN_DIR_UP BUTTON_UP
127 #define BTN_DIR_DOWN BUTTON_DOWN
128 #define BTN_DIR_LEFT BUTTON_LEFT
129 #define BTN_DIR_RIGHT BUTTON_RIGHT
130 #define BTN_STARTPAUSE BUTTON_PLAY
131 #define BTN_QUIT BUTTON_POWER
132 #define BTN_STOPRESET BUTTON_REC
134 #define PLAYERS_TEXT "Up/Down"
135 #define WORMS_TEXT "Left/Right"
137 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
139 #define BTN_DIR_UP BUTTON_UP
140 #define BTN_DIR_DOWN BUTTON_DOWN
141 #define BTN_DIR_LEFT BUTTON_LEFT
142 #define BTN_DIR_RIGHT BUTTON_RIGHT
143 #define BTN_STARTPAUSE BUTTON_SELECT
144 #define BTN_QUIT BUTTON_POWER
145 #define BTN_STOPRESET BUTTON_A
147 #define PLAYERS_TEXT "Up/Down"
148 #define WORMS_TEXT "Left/Right"
151 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
152 (CONFIG_KEYPAD == SANSA_C200_PAD)
154 #define BTN_DIR_UP BUTTON_UP
155 #define BTN_DIR_DOWN BUTTON_DOWN
156 #define BTN_DIR_LEFT BUTTON_LEFT
157 #define BTN_DIR_RIGHT BUTTON_RIGHT
158 #define BTN_STARTPAUSE BUTTON_SELECT
159 #define BTN_QUIT BUTTON_POWER
160 #define BTN_STOPRESET BUTTON_REC
162 #define PLAYERS_TEXT "Up/Down"
163 #define WORMS_TEXT "Left/Right"
166 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
168 #define BTN_DIR_UP BUTTON_SCROLL_UP
169 #define BTN_DIR_DOWN BUTTON_SCROLL_DOWN
170 #define BTN_DIR_LEFT BUTTON_LEFT
171 #define BTN_DIR_RIGHT BUTTON_RIGHT
172 #define BTN_STARTPAUSE BUTTON_PLAY
173 #define BTN_QUIT BUTTON_POWER
174 #define BTN_STOPRESET BUTTON_REW
176 #define PLAYERS_TEXT "Up/Down"
177 #define WORMS_TEXT "Left/Right"
181 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
185 #define MAX_WORM_SEGMENTS 128
186 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
190 #define MAX_WORM_SEGMENTS 128
191 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
195 #define MAX_WORM_SEGMENTS 128
196 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
200 #define MAX_WORM_SEGMENTS 128
201 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
205 #define MAX_WORM_SEGMENTS 256
206 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
210 #define MAX_WORM_SEGMENTS 256
211 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
215 #define MAX_WORM_SEGMENTS 512
216 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
220 #define MAX_WORM_SEGMENTS 512
221 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
225 #define MAX_WORM_SEGMENTS 512
226 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
230 #define MAX_WORM_SEGMENTS 512
233 #ifdef HAVE_LCD_COLOR
234 #define COLOR_WORM LCD_RGBPACK(80, 40, 0)
235 #define COLOR_ARGH LCD_RGBPACK(175, 0, 0)
236 #define COLOR_FOOD LCD_RGBPACK(0, 150, 0)
237 #define COLOR_FG LCD_RGBPACK(0, 0, 0)
238 #define COLOR_BG LCD_RGBPACK(181, 199, 231)
242 * All the properties that a worm has.
245 /* The worm is stored in a ring of xy coordinates */
246 int x
[MAX_WORM_SEGMENTS
];
247 int y
[MAX_WORM_SEGMENTS
];
249 int head
; /* index of the head within the buffer */
250 int tail
; /* index of the tail within the buffer */
251 int growing
; /* number of cyles the worm still keeps growing */
252 bool alive
; /* the worms living state */
254 /* direction vector in which the worm moves */
255 int dirx
; /* only values -1 0 1 allowed */
256 int diry
; /* only values -1 0 1 allowed */
258 /* this method is used to fetch the direction the user
259 has selected. It can be one of the values
260 human_player1, human_player2, remote_player, virtual_player.
261 All these values are fuctions, that can change the direction
263 void (*fetch_worm_direction
)(struct worm
*w
);
266 /* stores the highscore - besides it was scored by a virtual player */
267 static int highscore
;
269 #define MAX_FOOD 5 /* maximal number of food items */
271 /* The arrays store the food coordinates */
272 static int foodx
[MAX_FOOD
];
273 static int foody
[MAX_FOOD
];
275 #define MAX_ARGH 100 /* maximal number of argh items */
276 #define ARGHS_PER_FOOD 2 /* number of arghs produced per eaten food */
278 /* The arrays store the argh coordinates */
279 static int arghx
[MAX_ARGH
];
280 static int arghy
[MAX_ARGH
];
282 /* the number of arghs that are currently in use */
283 static int argh_count
;
285 /* the number of arghs per food, settable by user */
286 static int arghs_per_food
= ARGHS_PER_FOOD
;
287 /* the size of the argh, settable by user */
288 static int argh_size
= ARGH_SIZE
;
289 /* the size of the food, settable by user */
290 static int food_size
= FOOD_SIZE
;
291 /* the speed of the worm, settable by user */
292 static int speed
= SPEED
;
293 /* the amount a worm grows by eating a food, settable by user */
294 static int worm_food
= WORM_PER_FOOD
;
296 /* End additional variables */
299 /* just a buffer used for debug output */
300 static char debugout
[15];
303 /* the number of active worms (dead or alive) */
304 static int worm_count
= MAX_WORMS
;
306 /* in multiplayer mode: en- / disables the remote worm control
307 in singleplayer mode: toggles 4 / 2 button worm control */
308 static bool use_remote
= false;
310 /* return values of check_collision */
311 #define COLLISION_NONE 0
312 #define COLLISION_WORM 1
313 #define COLLISION_FOOD 2
314 #define COLLISION_ARGH 3
315 #define COLLISION_FIELD 4
317 /* constants for use as directions.
318 Note that the values are ordered clockwise.
319 Thus increasing / decreasing the values
320 is equivalent to right / left turns. */
326 /* direction of human player 1 */
327 static int player1_dir
= EAST
;
328 /* direction of human player 2 */
329 static int player2_dir
= EAST
;
330 /* direction of human player 3 */
331 static int player3_dir
= EAST
;
333 /* the number of (human) players that currently
335 static int players
= 1;
337 /* the rockbox plugin api */
338 static struct plugin_api
* rb
;
340 #define SETTINGS_VERSION 1
341 #define SETTINGS_MIN_VERSION 1
342 #define SETTINGS_FILENAME "wormlet.cfg"
344 static struct configdata config
[] =
346 {TYPE_INT
, 0, 1024, &highscore
, "highscore", NULL
, NULL
},
347 {TYPE_INT
, 0, 15, &arghs_per_food
, "arghs per food", NULL
, NULL
},
348 {TYPE_INT
, 0, 15, &argh_size
, "argh size", NULL
, NULL
},
349 {TYPE_INT
, 0, 15, &food_size
, "food size", NULL
, NULL
},
350 {TYPE_INT
, 0, 3, &players
, "players", NULL
, NULL
},
351 {TYPE_INT
, 0, 3, &worm_count
, "worms", NULL
, NULL
},
352 {TYPE_INT
, 0, 20, &speed
, "speed", NULL
, NULL
},
353 {TYPE_INT
, 0, 15, &worm_food
, "Worm Growth Per Food", NULL
, NULL
}//,
354 //{TYPE_INT, 0, 3, &use_remote, "use remote", NULL, NULL}
358 static void set_debug_out(char *str
){
359 strcpy(debugout
, str
);
364 * Returns the direction id in which the worm
365 * currently is creeping.
366 * @param struct worm *w The worm that is to be investigated.
367 * w Must not be null.
368 * @return int A value 0 <= value < 4
369 * Note the predefined constants NORTH, SOUTH, EAST, WEST
371 static int get_worm_dir(struct worm
*w
) {
390 * Set the direction of the specified worm with a direction id.
391 * Increasing the value by 1 means to turn the worm direction
392 * to right by 90 degree.
393 * @param struct worm *w The worm that is to be altered. w Must not be null.
394 * @param int dir The new direction in which the worm is to creep.
395 * dir must be 0 <= dir < 4. Use predefined constants
396 * NORTH, SOUTH, EAST, WEST
398 static void set_worm_dir(struct worm
*w
, int dir
) {
420 * Returns the current length of the worm array. This
421 * is also a value for the number of bends that are in the worm.
422 * @return int a positive value with 0 <= value < MAX_WORM_SEGMENTS
424 static int get_worm_array_length(struct worm
*w
) {
425 /* initial simple calculation will be overwritten if wrong. */
426 int retVal
= w
->head
- w
->tail
;
428 /* if the worm 'crosses' the boundaries of the ringbuffer */
430 retVal
= w
->head
+ MAX_WORM_SEGMENTS
- w
->tail
;
437 * Returns the score the specified worm. The score is the length
439 * @param struct worm *w The worm that is to be investigated.
440 * w must not be null.
441 * @return int The length of the worm (>= 0).
443 static int get_score(struct worm
*w
) {
445 int length
= get_worm_array_length(w
);
447 for (i
= 0; i
< length
; i
++) {
449 /* The iteration iterates the length of the worm.
450 Here's the conversion to the true indices within the worm arrays. */
451 int linestart
= (w
->tail
+ i
) % MAX_WORM_SEGMENTS
;
452 int lineend
= (linestart
+ 1) % MAX_WORM_SEGMENTS
;
453 int startx
= w
->x
[linestart
];
454 int starty
= w
->y
[linestart
];
455 int endx
= w
->x
[lineend
];
456 int endy
= w
->y
[lineend
];
458 int minimum
, maximum
;
460 if (startx
== endx
) {
461 minimum
= MIN(starty
, endy
);
462 maximum
= MAX(starty
, endy
);
464 minimum
= MIN(startx
, endx
);
465 maximum
= MAX(startx
, endx
);
467 retval
+= abs(maximum
- minimum
);
473 * Determines wether the line specified by startx, starty, endx, endy intersects
474 * the rectangle specified by x, y, width, height. Note that the line must be exactly
475 * horizontal or vertical (startx == endx or starty == endy).
476 * @param int startx The x coordinate of the start point of the line.
477 * @param int starty The y coordinate of the start point of the line.
478 * @param int endx The x coordinate of the end point of the line.
479 * @param int endy The y coordinate of the end point of the line.
480 * @param int x The x coordinate of the top left corner of the rectangle.
481 * @param int y The y coordinate of the top left corner of the rectangle.
482 * @param int width The width of the rectangle.
483 * @param int height The height of the rectangle.
484 * @return bool Returns true if the specified line intersects with the recangle.
486 static bool line_in_rect(int startx
, int starty
, int endx
, int endy
, int x
, int y
, int width
, int height
) {
488 int simple
, simplemin
, simplemax
;
489 int compa
, compb
, compmin
, compmax
;
491 if (startx
== endx
) {
494 simplemax
= x
+ width
;
499 compmax
= y
+ height
;
503 simplemax
= y
+ height
;
512 compa
= MIN(compa
, compb
);
513 compb
= MAX(temp
, compb
);
515 if (simplemin
<= simple
&& simple
<= simplemax
) {
516 if ((compmin
<= compa
&& compa
<= compmax
) ||
517 (compmin
<= compb
&& compb
<= compmax
) ||
518 (compa
<= compmin
&& compb
>= compmax
)) {
526 * Tests wether the specified worm intersects with the rect.
527 * @param struct worm *w The worm to be investigated
528 * @param int x The x coordinate of the top left corner of the rect
529 * @param int y The y coordinate of the top left corner of the rect
530 * @param int widht The width of the rect
531 * @param int height The height of the rect
532 * @return bool Returns true if the worm intersects with the rect
534 static bool worm_in_rect(struct worm
*w
, int x
, int y
, int width
, int height
) {
538 /* get_worm_array_length is expensive -> buffer the value */
539 int wormLength
= get_worm_array_length(w
);
542 /* test each entry that is part of the worm */
543 for (i
= 0; i
< wormLength
&& retval
== false; i
++) {
545 /* The iteration iterates the length of the worm.
546 Here's the conversion to the true indices within the worm arrays. */
547 int linestart
= (w
->tail
+ i
) % MAX_WORM_SEGMENTS
;
548 int lineend
= (linestart
+ 1) % MAX_WORM_SEGMENTS
;
549 int startx
= w
->x
[linestart
];
550 int starty
= w
->y
[linestart
];
551 int endx
= w
->x
[lineend
];
552 int endy
= w
->y
[lineend
];
554 retval
= line_in_rect(startx
, starty
, endx
, endy
, x
, y
, width
, height
);
561 * Checks wether a specific food in the food arrays is at the
562 * specified coordinates.
563 * @param int foodIndex The index of the food in the food arrays
564 * @param int x the x coordinate.
565 * @param int y the y coordinate.
566 * @return Returns true if the coordinate hits the food specified by
569 static bool specific_food_collision(int foodIndex
, int x
, int y
) {
571 if (x
>= foodx
[foodIndex
] &&
572 x
< foodx
[foodIndex
] + food_size
&&
573 y
>= foody
[foodIndex
] &&
574 y
< foody
[foodIndex
] + food_size
) {
582 * Returns the index of the food that is at the
583 * given coordinates. If no food is at the coordinates
585 * @return int -1 <= value < MAX_FOOD
587 static int food_collision(int x
, int y
) {
590 for (i
= 0; i
< MAX_FOOD
; i
++) {
591 if (specific_food_collision(i
, x
, y
)) {
600 * Checks wether a specific argh in the argh arrays is at the
601 * specified coordinates.
602 * @param int arghIndex The index of the argh in the argh arrays
603 * @param int x the x coordinate.
604 * @param int y the y coordinate.
605 * @return Returns true if the coordinate hits the argh specified by
608 static bool specific_argh_collision(int arghIndex
, int x
, int y
) {
610 if ( x
>= arghx
[arghIndex
] &&
611 y
>= arghy
[arghIndex
] &&
612 x
< arghx
[arghIndex
] + argh_size
&&
613 y
< arghy
[arghIndex
] + argh_size
)
622 * Returns the index of the argh that is at the
623 * given coordinates. If no argh is at the coordinates
625 * @param int x The x coordinate.
626 * @param int y The y coordinate.
627 * @return int -1 <= value < argh_count <= MAX_ARGH
629 static int argh_collision(int x
, int y
) {
633 /* search for the argh that has the specified coords */
634 for (i
= 0; i
< argh_count
; i
++) {
635 if (specific_argh_collision(i
, x
, y
)) {
644 * Checks wether the worm collides with the food at the specfied food-arrays.
645 * @param int foodIndex The index of the food in the arrays. Ensure the value is
646 * 0 <= foodIndex <= MAX_FOOD
647 * @return Returns true if the worm collides with the specified food.
649 static bool worm_food_collision(struct worm
*w
, int foodIndex
)
653 retVal
= worm_in_rect(w
, foodx
[foodIndex
], foody
[foodIndex
],
654 food_size
- 1, food_size
- 1);
660 * Returns true if the worm hits the argh within the next moves (unless
661 * the worm changes it's direction).
662 * @param struct worm *w - The worm to investigate
663 * @param int argh_idx - The index of the argh
664 * @param int moves - The number of moves that are considered.
665 * @return Returns false if the specified argh is not hit within the next
668 static bool worm_argh_collision_in_moves(struct worm
*w
, int argh_idx
, int moves
){
674 x2
= w
->x
[w
->head
] + moves
* w
->dirx
;
675 y2
= w
->y
[w
->head
] + moves
* w
->diry
;
677 retVal
= line_in_rect(x1
, y1
, x2
, y2
, arghx
[argh_idx
], arghy
[argh_idx
],
678 argh_size
, argh_size
);
683 * Checks wether the worm collides with the argh at the specfied argh-arrays.
684 * @param int arghIndex The index of the argh in the arrays.
685 * Ensure the value is 0 <= arghIndex < argh_count <= MAX_ARGH
686 * @return Returns true if the worm collides with the specified argh.
688 static bool worm_argh_collision(struct worm
*w
, int arghIndex
)
692 retVal
= worm_in_rect(w
, arghx
[arghIndex
], arghy
[arghIndex
],
693 argh_size
- 1, argh_size
- 1);
699 * Find new coordinates for the food stored in foodx[index], foody[index]
700 * that don't collide with any other food or argh
702 * Ensure that 0 <= index < MAX_FOOD.
704 static void make_food(int index
) {
708 bool collisionDetected
= false;
712 /* make coordinates for a new food so that
713 the entire food lies within the FIELD */
714 x
= rb
->rand() % (FIELD_RECT_WIDTH
- food_size
);
715 y
= rb
->rand() % (FIELD_RECT_HEIGHT
- food_size
);
717 /* Ensure that the new food doesn't collide with any
718 existing foods or arghs.
719 If one or more corners of the new food hit any existing
720 argh or food a collision is detected.
723 food_collision(x
, y
) >= 0 ||
724 food_collision(x
, y
+ food_size
- 1) >= 0 ||
725 food_collision(x
+ food_size
- 1, y
) >= 0 ||
726 food_collision(x
+ food_size
- 1, y
+ food_size
- 1) >= 0 ||
727 argh_collision(x
, y
) >= 0 ||
728 argh_collision(x
, y
+ food_size
- 1) >= 0 ||
729 argh_collision(x
+ food_size
- 1, y
) >= 0 ||
730 argh_collision(x
+ food_size
- 1, y
+ food_size
- 1) >= 0;
732 /* use coordinates for further testing */
736 /* now test wether we accidently hit the worm with food ;) */
738 for (i
= 0; i
< worm_count
&& !collisionDetected
; i
++) {
739 collisionDetected
|= worm_food_collision(&worms
[i
], index
);
742 while (collisionDetected
);
747 * Clears a food from the lcd buffer.
748 * @param int index The index of the food arrays under which
749 * the coordinates of the desired food can be found. Ensure
750 * that the value is 0 <= index <= MAX_FOOD.
752 static void clear_food(int index
)
754 /* remove the old food from the screen */
755 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
756 rb
->lcd_fillrect(foodx
[index
] + FIELD_RECT_X
,
757 foody
[index
] + FIELD_RECT_Y
,
758 food_size
, food_size
);
759 rb
->lcd_set_drawmode(DRMODE_SOLID
);
763 * Draws a food in the lcd buffer.
764 * @param int index The index of the food arrays under which
765 * the coordinates of the desired food can be found. Ensure
766 * that the value is 0 <= index <= MAX_FOOD.
768 static void draw_food(int index
)
770 /* draw the food object */
771 #ifdef HAVE_LCD_COLOR
772 rb
->lcd_set_foreground(COLOR_FOOD
);
774 rb
->lcd_fillrect(foodx
[index
] + FIELD_RECT_X
,
775 foody
[index
] + FIELD_RECT_Y
,
776 food_size
, food_size
);
777 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
778 rb
->lcd_fillrect(foodx
[index
] + FIELD_RECT_X
+ 1,
779 foody
[index
] + FIELD_RECT_Y
+ 1,
780 food_size
- 2, food_size
- 2);
781 rb
->lcd_set_drawmode(DRMODE_SOLID
);
782 #ifdef HAVE_LCD_COLOR
783 rb
->lcd_set_foreground(COLOR_FG
);
788 * Find new coordinates for the argh stored in arghx[index], arghy[index]
789 * that don't collide with any other food or argh.
791 * Ensure that 0 <= index < argh_count < MAX_ARGH.
793 static void make_argh(int index
)
797 bool collisionDetected
= false;
801 /* make coordinates for a new argh so that
802 the entire food lies within the FIELD */
803 x
= rb
->rand() % (FIELD_RECT_WIDTH
- argh_size
);
804 y
= rb
->rand() % (FIELD_RECT_HEIGHT
- argh_size
);
806 /* Ensure that the new argh doesn't intersect with any
807 existing foods or arghs.
808 If one or more corners of the new argh hit any existing
809 argh or food an intersection is detected.
812 food_collision(x
, y
) >= 0 ||
813 food_collision(x
, y
+ argh_size
- 1) >= 0 ||
814 food_collision(x
+ argh_size
- 1, y
) >= 0 ||
815 food_collision(x
+ argh_size
- 1, y
+ argh_size
- 1) >= 0 ||
816 argh_collision(x
, y
) >= 0 ||
817 argh_collision(x
, y
+ argh_size
- 1) >= 0 ||
818 argh_collision(x
+ argh_size
- 1, y
) >= 0 ||
819 argh_collision(x
+ argh_size
- 1, y
+ argh_size
- 1) >= 0;
821 /* use the candidate coordinates to make a real argh */
825 /* now test wether we accidently hit the worm with argh ;) */
826 for (i
= 0; i
< worm_count
&& !collisionDetected
; i
++) {
827 collisionDetected
|= worm_argh_collision(&worms
[i
], index
);
828 collisionDetected
|= worm_argh_collision_in_moves(&worms
[i
], index
,
832 while (collisionDetected
);
837 * Draws an argh in the lcd buffer.
838 * @param int index The index of the argh arrays under which
839 * the coordinates of the desired argh can be found. Ensure
840 * that the value is 0 <= index < argh_count <= MAX_ARGH.
842 static void draw_argh(int index
)
844 /* draw the new argh */
845 #ifdef HAVE_LCD_COLOR
846 rb
->lcd_set_foreground(COLOR_ARGH
);
848 rb
->lcd_fillrect(arghx
[index
] + FIELD_RECT_X
,
849 arghy
[index
] + FIELD_RECT_Y
,
850 argh_size
, argh_size
);
851 #ifdef HAVE_LCD_COLOR
852 rb
->lcd_set_foreground(COLOR_FG
);
856 static void virtual_player(struct worm
*w
);
858 * Initialzes the specified worm with INITIAL_WORM_LENGTH
859 * and the tail at the specified position. The worm will
860 * be initialized alive and creeping EAST.
861 * @param struct worm *w The worm that is to be initialized
862 * @param int x The x coordinate at which the tail of the worm starts.
863 * x must be 0 <= x < FIELD_RECT_WIDTH.
864 * @param int y The y coordinate at which the tail of the worm starts
865 * y must be 0 <= y < FIELD_RECT_WIDTH.
867 static void init_worm(struct worm
*w
, int x
, int y
){
868 /* initialize the worm size */
872 w
->x
[w
->head
] = x
+ 1;
878 /* set the initial direction the worm creeps to */
882 w
->growing
= INITIAL_WORM_LENGTH
- 1;
884 w
->fetch_worm_direction
= virtual_player
;
888 * Writes the direction that was stored for
889 * human player 1 into the specified worm. This function
890 * may be used to be stored in worm.fetch_worm_direction.
892 * the direction is read from player1_dir.
893 * @param struct worm *w - The worm of which the direction
896 static void human_player1(struct worm
*w
) {
897 set_worm_dir(w
, player1_dir
);
901 * Writes the direction that was stored for
902 * human player 2 into the specified worm. This function
903 * may be used to be stored in worm.fetch_worm_direction.
905 * the direction is read from player2_dir.
906 * @param struct worm *w - The worm of which the direction
909 static void human_player2(struct worm
*w
) {
910 set_worm_dir(w
, player2_dir
);
914 * Writes the direction that was stored for
915 * human player using a remote control
916 * into the specified worm. This function
917 * may be used to be stored in worm.fetch_worm_direction.
919 * the direction is read from player3_dir.
920 * @param struct worm *w - The worm of which the direction
923 static void remote_player(struct worm
*w
) {
924 set_worm_dir(w
, player3_dir
);
928 * Initializes the worm-, food- and argh-arrays, draws a frame,
929 * makes some food and argh and display all that stuff.
931 static void init_wormlet(void)
935 for (i
= 0; i
< worm_count
; i
++) {
936 /* Initialize all the worm coordinates to center. */
937 int x
= (int)(FIELD_RECT_WIDTH
/ 2);
938 int y
= (int)((FIELD_RECT_HEIGHT
- 20)/ 2) + i
* 10;
940 init_worm(&worms
[i
], x
, y
);
948 worms
[0].fetch_worm_direction
= human_player1
;
953 worms
[1].fetch_worm_direction
= remote_player
;
955 worms
[1].fetch_worm_direction
= human_player2
;
960 worms
[2].fetch_worm_direction
= human_player2
;
963 /* Needed when the game is restarted using BTN_STOPRESET */
964 rb
->lcd_clear_display();
966 /* make and display some food and argh */
967 argh_count
= MAX_FOOD
;
968 for (i
= 0; i
< MAX_FOOD
; i
++) {
975 /* draw the game field */
976 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
977 rb
->lcd_fillrect(0, 0, FIELD_RECT_WIDTH
+ 2, FIELD_RECT_HEIGHT
+ 2);
978 rb
->lcd_fillrect(1, 1, FIELD_RECT_WIDTH
, FIELD_RECT_HEIGHT
);
979 rb
->lcd_set_drawmode(DRMODE_SOLID
);
981 /* make everything visible */
987 * Move the worm one step further if it is alive.
988 * The direction in which the worm moves is taken from dirx and diry.
989 * move_worm decreases growing if > 0. While the worm is growing the tail
991 * @param struct worm *w The worm to move. w must not be NULL.
993 static void move_worm(struct worm
*w
)
996 /* determine the head point and its precessor */
997 int headx
= w
->x
[w
->head
];
998 int heady
= w
->y
[w
->head
];
999 int prehead
= (w
->head
+ MAX_WORM_SEGMENTS
- 1) % MAX_WORM_SEGMENTS
;
1000 int preheadx
= w
->x
[prehead
];
1001 int preheady
= w
->y
[prehead
];
1003 /* determine the old direction */
1006 if (headx
== preheadx
) {
1008 olddiry
= (heady
> preheady
) ? 1 : -1;
1011 olddirx
= (headx
> preheadx
) ? 1 : -1;
1015 a change of direction means a new segment
1017 if (olddirx
!= w
->dirx
||
1018 olddiry
!= w
->diry
) {
1019 w
->head
= (w
->head
+ 1) % MAX_WORM_SEGMENTS
;
1022 /* new head position */
1023 w
->x
[w
->head
] = headx
+ w
->dirx
;
1024 w
->y
[w
->head
] = heady
+ w
->diry
;
1027 /* while the worm is growing no tail procession is necessary */
1028 if (w
->growing
> 0) {
1029 /* update the worms grow state */
1033 /* if the worm isn't growing the tail has to be dragged */
1035 /* index of the end of the tail segment */
1036 int tail_segment_end
= (w
->tail
+ 1) % MAX_WORM_SEGMENTS
;
1038 /* drag the end of the tail */
1039 /* only one coordinate has to be altered. Here it is
1040 determined which one */
1041 int dir
= 0; /* specifies wether the coord has to be in- or decreased */
1042 if (w
->x
[w
->tail
] == w
->x
[tail_segment_end
]) {
1043 dir
= (w
->y
[w
->tail
] - w
->y
[tail_segment_end
] < 0) ? 1 : -1;
1044 w
->y
[w
->tail
] += dir
;
1046 dir
= (w
->x
[w
->tail
] - w
->x
[tail_segment_end
] < 0) ? 1 : -1;
1047 w
->x
[w
->tail
] += dir
;
1050 /* when the tail has been dragged so far that it meets
1051 the next segment start the tail segment is obsolete and
1053 if (w
->x
[w
->tail
] == w
->x
[tail_segment_end
] &&
1054 w
->y
[w
->tail
] == w
->y
[tail_segment_end
]){
1056 /* drop the last tail point */
1057 w
->tail
= tail_segment_end
;
1064 * Draws the head and clears the tail of the worm in
1065 * the display buffer. lcd_update() is NOT called thus
1066 * the caller has to take care that the buffer is displayed.
1068 static void draw_worm(struct worm
*w
)
1070 #ifdef HAVE_LCD_COLOR
1071 rb
->lcd_set_foreground(COLOR_WORM
);
1073 /* draw the new head */
1074 int x
= w
->x
[w
->head
];
1075 int y
= w
->y
[w
->head
];
1076 if (x
>= 0 && x
< FIELD_RECT_WIDTH
&& y
>= 0 && y
< FIELD_RECT_HEIGHT
) {
1077 rb
->lcd_drawpixel(x
+ FIELD_RECT_X
, y
+ FIELD_RECT_Y
);
1080 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1082 /* clear the space behind the worm */
1085 if (x
>= 0 && x
< FIELD_RECT_WIDTH
&& y
>= 0 && y
< FIELD_RECT_HEIGHT
) {
1086 rb
->lcd_drawpixel(x
+ FIELD_RECT_X
, y
+ FIELD_RECT_Y
);
1088 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1089 #ifdef HAVE_LCD_COLOR
1090 rb
->lcd_set_foreground(COLOR_FG
);
1095 * Checks wether the coordinate is part of the worm. Returns
1096 * true if any part of the worm was hit - including the head.
1097 * @param x int The x coordinate
1098 * @param y int The y coordinate
1099 * @return int The index of the worm arrays that contain x, y.
1100 * Returns -1 if the coordinates are not part of the worm.
1102 static int specific_worm_collision(struct worm
*w
, int x
, int y
)
1106 /* get_worm_array_length is expensive -> buffer the value */
1107 int wormLength
= get_worm_array_length(w
);
1110 /* test each entry that is part of the worm */
1111 for (i
= 0; i
< wormLength
&& retVal
== -1; i
++) {
1113 /* The iteration iterates the length of the worm.
1114 Here's the conversion to the true indices within the worm arrays. */
1115 int linestart
= (w
->tail
+ i
) % MAX_WORM_SEGMENTS
;
1116 int lineend
= (linestart
+ 1) % MAX_WORM_SEGMENTS
;
1117 bool samex
= (w
->x
[linestart
] == x
) && (w
->x
[lineend
] == x
);
1118 bool samey
= (w
->y
[linestart
] == y
) && (w
->y
[lineend
] == y
);
1119 if (samex
|| samey
){
1120 int test
, min
, max
, tmp
;
1123 min
= w
->x
[linestart
];
1124 max
= w
->x
[lineend
];
1127 min
= w
->y
[linestart
];
1128 max
= w
->y
[lineend
];
1133 min
= MIN(min
, max
);
1134 max
= MAX(tmp
, max
);
1136 if (min
<= test
&& test
<= max
) {
1145 * Increases the length of the specified worm by marking
1146 * that it may grow by len pixels. Note that the worm has
1147 * to move to make the growing happen.
1148 * @param worm *w The worm that is to be altered.
1149 * @param int len A positive value specifying the amount of
1150 * pixels the worm may grow.
1152 static void add_growing(struct worm
*w
, int len
) {
1157 * Determins the worm that is at the coordinates x, y. The parameter
1158 * w is a switch parameter that changes the functionality of worm_collision.
1159 * If w is specified and x,y hits the head of w NULL is returned.
1160 * This is a useful way to determine wether the head of w hits
1161 * any worm but including itself but excluding its own head.
1162 * (It hits always its own head ;))
1163 * If w is set to NULL worm_collision returns any worm including all heads
1164 * that is at position of x,y.
1165 * @param struct worm *w The worm of which the head should be excluded in
1166 * the test. w may be set to NULL.
1167 * @param int x The x coordinate that is checked
1168 * @param int y The y coordinate that is checkec
1169 * @return struct worm* The worm that has been hit by x,y. If no worm
1170 * was at the position NULL is returned.
1172 static struct worm
* worm_collision(struct worm
*w
, int x
, int y
){
1173 struct worm
*retVal
= NULL
;
1175 for (i
= 0; (i
< worm_count
) && (retVal
== NULL
); i
++) {
1176 int collision_at
= specific_worm_collision(&worms
[i
], x
, y
);
1177 if (collision_at
!= -1) {
1178 if (!(w
== &worms
[i
] && collision_at
== w
->head
)){
1187 * Returns true if the head of the worm just has
1188 * crossed the field boundaries.
1189 * @return bool true if the worm just has wrapped.
1191 static bool field_collision(struct worm
*w
)
1193 bool retVal
= false;
1194 if ((w
->x
[w
->head
] >= FIELD_RECT_WIDTH
) ||
1195 (w
->y
[w
->head
] >= FIELD_RECT_HEIGHT
) ||
1196 (w
->x
[w
->head
] < 0) ||
1197 (w
->y
[w
->head
] < 0))
1206 * Returns true if the specified coordinates are within the
1207 * field specified by the FIELD_RECT_XXX constants.
1208 * @param int x The x coordinate of the point that is investigated
1209 * @param int y The y coordinate of the point that is investigated
1210 * @return bool Returns false if x,y specifies a point outside the
1213 static bool is_in_field_rect(int x
, int y
) {
1214 bool retVal
= false;
1215 retVal
= (x
>= 0 && x
< FIELD_RECT_WIDTH
&&
1216 y
>= 0 && y
< FIELD_RECT_HEIGHT
);
1221 * Checks and returns wether the head of the w
1222 * is colliding with something currently.
1223 * @return int One of the values:
1230 static int check_collision(struct worm
*w
)
1232 int retVal
= COLLISION_NONE
;
1234 if (worm_collision(w
, w
->x
[w
->head
], w
->y
[w
->head
]) != NULL
)
1235 retVal
= COLLISION_WORM
;
1237 if (food_collision(w
->x
[w
->head
], w
->y
[w
->head
]) >= 0)
1238 retVal
= COLLISION_FOOD
;
1240 if (argh_collision(w
->x
[w
->head
], w
->y
[w
->head
]) >= 0)
1241 retVal
= COLLISION_ARGH
;
1243 if (field_collision(w
))
1244 retVal
= COLLISION_FIELD
;
1250 * Returns the index of the food that is closest to the point
1251 * specified by x, y. This index may be used in the foodx and
1253 * @param int x The x coordinate of the point
1254 * @param int y The y coordinate of the point
1255 * @return int A value usable as index in foodx and foody.
1257 static int get_nearest_food(int x
, int y
){
1258 int nearestfood
= 0;
1259 int olddistance
= FIELD_RECT_WIDTH
+ FIELD_RECT_HEIGHT
;
1263 for (foodindex
= 0; foodindex
< MAX_FOOD
; foodindex
++) {
1265 deltax
= foodx
[foodindex
] - x
;
1266 deltay
= foody
[foodindex
] - y
;
1267 deltax
= deltax
> 0 ? deltax
: deltax
* (-1);
1268 deltay
= deltay
> 0 ? deltay
: deltay
* (-1);
1269 distance
= deltax
+ deltay
;
1271 if (distance
< olddistance
) {
1272 olddistance
= distance
;
1273 nearestfood
= foodindex
;
1280 * Returns wether the specified position is next to the worm
1281 * and in the direction the worm looks. Use this method to
1282 * test wether this position would be hit with the next move of
1283 * the worm unless the worm changes its direction.
1284 * @param struct worm *w - The worm to be investigated
1285 * @param int x - The x coordinate of the position to test.
1286 * @param int y - The y coordinate of the position to test.
1287 * @return Returns true if the worm will hit the position unless
1288 * it change its direction before the next move.
1290 static bool is_in_front_of_worm(struct worm
*w
, int x
, int y
) {
1291 bool infront
= false;
1292 int deltax
= x
- w
->x
[w
->head
];
1293 int deltay
= y
- w
->y
[w
->head
];
1296 infront
= (w
->diry
* deltay
) > 0;
1298 infront
= (w
->dirx
* deltax
) > 0;
1304 * Returns true if the worm will collide with the next move unless
1305 * it changes its direction.
1306 * @param struct worm *w - The worm to be investigated.
1307 * @return Returns true if the worm will collide with the next move
1308 * unless it changes its direction.
1310 static bool will_worm_collide(struct worm
*w
) {
1311 int x
= w
->x
[w
->head
] + w
->dirx
;
1312 int y
= w
->y
[w
->head
] + w
->diry
;
1313 bool retVal
= !is_in_field_rect(x
, y
);
1315 retVal
= (argh_collision(x
, y
) != -1);
1319 retVal
= (worm_collision(w
, x
, y
) != NULL
);
1326 * may be used to be stored in worm.fetch_worm_direction for
1327 * worms that are not controlled by humans but by artificial stupidity.
1328 * A direction is searched that doesn't lead to collision but to the nearest
1329 * food - but not very intelligent. The direction is written to the specified
1331 * @param struct worm *w - The worm of which the direction
1334 static void virtual_player(struct worm
*w
) {
1336 int plana
, planb
, planc
;
1337 /* find the next lunch */
1338 int nearestfood
= get_nearest_food(w
->x
[w
->head
], w
->y
[w
->head
]);
1340 /* determine in which direction it is */
1342 /* in front of me? */
1343 bool infront
= is_in_front_of_worm(w
, foodx
[nearestfood
], foody
[nearestfood
]);
1345 /* left right of me? */
1346 int olddir
= get_worm_dir(w
);
1347 set_worm_dir(w
, (olddir
+ 1) % 4);
1348 isright
= is_in_front_of_worm(w
, foodx
[nearestfood
], foody
[nearestfood
]);
1349 set_worm_dir(w
, olddir
);
1351 /* detect situation, set strategy */
1355 planb
= (olddir
+ 1) % 4;
1356 planc
= (olddir
+ 3) % 4;
1359 planb
= (olddir
+ 3) % 4;
1360 planc
= (olddir
+ 1) % 4;
1364 plana
= (olddir
+ 1) % 4;
1366 planc
= (olddir
+ 3) % 4;
1368 plana
= (olddir
+ 3) % 4;
1370 planc
= (olddir
+ 1) % 4;
1374 /* test for collision */
1375 set_worm_dir(w
, plana
);
1376 if (will_worm_collide(w
)){
1379 set_worm_dir(w
, planb
);
1381 /* test for collision */
1382 if (will_worm_collide(w
)) {
1385 set_worm_dir(w
, planc
);
1391 * prints out the score board with all the status information
1394 static void score_board(void)
1400 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1401 rb
->lcd_fillrect(FIELD_RECT_WIDTH
+ 2, 0, LCD_WIDTH
- FIELD_RECT_WIDTH
- 2, LCD_HEIGHT
);
1402 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1403 for (i
= 0; i
< worm_count
; i
++) {
1404 int score
= get_score(&worms
[i
]);
1407 if (worms
[i
].fetch_worm_direction
!= virtual_player
){
1408 if (highscore
< score
) {
1414 rb
->snprintf(buf
, sizeof (buf
),"Len:%d", score
);
1417 switch (check_collision(&worms
[i
])) {
1418 case COLLISION_NONE
:
1419 if (worms
[i
].growing
> 0)
1429 case COLLISION_WORM
:
1433 case COLLISION_FOOD
:
1437 case COLLISION_ARGH
:
1441 case COLLISION_FIELD
:
1445 rb
->lcd_putsxy(FIELD_RECT_WIDTH
+ 3, y
, buf
);
1446 rb
->lcd_putsxy(FIELD_RECT_WIDTH
+ 3, y
+8, buf2
);
1448 if (!worms
[i
].alive
){
1449 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1450 rb
->lcd_fillrect(FIELD_RECT_WIDTH
+ 2, y
,
1451 LCD_WIDTH
- FIELD_RECT_WIDTH
- 2, 17);
1452 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1456 rb
->snprintf(buf
, sizeof(buf
), "Hs: %d", highscore
);
1457 #ifndef DEBUG_WORMLET
1458 rb
->lcd_putsxy(FIELD_RECT_WIDTH
+ 3, LCD_HEIGHT
- 8, buf
);
1460 rb
->lcd_putsxy(FIELD_RECT_WIDTH
+ 3, LCD_HEIGHT
- 8, debugout
);
1465 * Checks for collisions of the worm and its environment and
1466 * takes appropriate actions like growing the worm or killing it.
1467 * @return bool Returns true if the worm is dead. Returns
1468 * false if the worm is healthy, up and creeping.
1470 static bool process_collisions(struct worm
*w
)
1474 w
->alive
&= !field_collision(w
);
1478 /* check if food was eaten */
1479 index
= food_collision(w
->x
[w
->head
], w
->y
[w
->head
]);
1487 for (i
= 0; i
< arghs_per_food
; i
++) {
1489 if (argh_count
> MAX_ARGH
)
1490 argh_count
= MAX_ARGH
;
1491 make_argh(argh_count
- 1);
1492 draw_argh(argh_count
- 1);
1495 add_growing(w
, worm_food
);
1500 /* check if argh was eaten */
1502 index
= argh_collision(w
->x
[w
->head
], w
->y
[w
->head
]);
1507 if (worm_collision(w
, w
->x
[w
->head
], w
->y
[w
->head
]) != NULL
) {
1517 * The main loop of the game.
1518 * @return bool Returns true if the game ended
1519 * with a dead worm. Returns false if the user
1520 * aborted the game manually.
1522 static int run(void)
1525 int wormDead
= false;
1526 bool paused
= false;
1528 /* ticks are counted to compensate speed variations */
1529 long cycle_start
= 0, cycle_end
= 0;
1530 #ifdef DEBUG_WORMLET
1531 int ticks_to_max_cycle_reset
= 20;
1536 /* initialize the board and so on */
1539 cycle_start
= *rb
->current_tick
;
1540 /* change the direction of the worm */
1544 long cycle_duration
=0;
1546 #ifdef HAS_BUTTON_HOLD
1547 if (rb
->button_hold())
1552 case BTN_STARTPAUSE
:
1557 return 1; /* restart game */
1565 return 2; /* back to menu */
1572 if (players
== 1 && !use_remote
) {
1573 player1_dir
= NORTH
;
1578 if (players
== 1 && !use_remote
) {
1579 player1_dir
= SOUTH
;
1584 if (players
!= 1 || use_remote
) {
1585 player1_dir
= (player1_dir
+ 3) % 4;
1592 if (players
!= 1 || use_remote
) {
1593 player1_dir
= (player1_dir
+ 1) % 4;
1600 case BTN_PLAYER2_DIR1
:
1601 player2_dir
= (player2_dir
+ 3) % 4;
1604 case BTN_PLAYER2_DIR2
:
1605 player2_dir
= (player2_dir
+ 1) % 4;
1611 player3_dir
= (player3_dir
+ 1) % 4;
1615 player3_dir
= (player3_dir
+ 3) % 4;
1621 for (i
= 0; i
< worm_count
; i
++) {
1622 worms
[i
].fetch_worm_direction(&worms
[i
]);
1626 for (i
= 0; i
< worm_count
; i
++){
1627 struct worm
*w
= &worms
[i
];
1629 wormDead
&= process_collisions(w
);
1634 if (button
== BTN_STOPRESET
) {
1638 /* here the wormlet game cycle ends
1639 thus the current tick is stored
1641 cycle_end
= *rb
->current_tick
;
1643 /* The duration of the game cycle */
1644 cycle_duration
= cycle_end
- cycle_start
;
1645 cycle_duration
= MAX(0, cycle_duration
);
1646 cycle_duration
= MIN(speed
-1, cycle_duration
);
1649 #ifdef DEBUG_WORMLET
1650 ticks_to_max_cycle_reset
--;
1651 if (ticks_to_max_cycle_reset
<= 0) {
1655 if (max_cycle
< cycle_duration
) {
1656 max_cycle
= cycle_duration
;
1657 ticks_to_max_cycle_reset
= 20;
1659 rb
->snprintf(buf
, sizeof buf
, "ticks %d", max_cycle
);
1663 /* adjust the number of ticks to wait for a button.
1664 This ensures that a complete game cycle including
1665 user input runs in constant time */
1666 button
= rb
->button_get_w_tmo(speed
- cycle_duration
);
1667 cycle_start
= *rb
->current_tick
;
1670 rb
->splash(HZ
*2, "Game Over!");
1672 return 2; /* back to menu */
1675 #ifdef DEBUG_WORMLET
1678 * Just a test routine that checks that worm_food_collision works
1679 * in some typical situations.
1681 static void test_worm_food_collision(void) {
1682 int collision_count
= 0;
1684 rb
->lcd_clear_display();
1685 init_worm(&worms
[0], 10, 10);
1686 add_growing(&worms
[0], 10);
1687 set_worm_dir(&worms
[0], EAST
);
1688 for (i
= 0; i
< 10; i
++) {
1689 move_worm(&worms
[0]);
1690 draw_worm(&worms
[0]);
1693 set_worm_dir(&worms
[0], SOUTH
);
1694 for (i
= 0; i
< 10; i
++) {
1695 move_worm(&worms
[0]);
1696 draw_worm(&worms
[0]);
1701 for (foody
[0] = 20; foody
[0] > 0; foody
[0] --) {
1704 draw_worm(&worms
[0]);
1706 collision
= worm_food_collision(&worms
[0], 0);
1710 rb
->snprintf(buf
, sizeof buf
, "collisions: %d", collision_count
);
1711 rb
->lcd_putsxy(0, LCD_HEIGHT
-8, buf
);
1714 if (collision_count
!= food_size
) {
1715 rb
->button_get(true);
1720 for (foodx
[0] = 30; foodx
[0] > 0; foodx
[0] --) {
1723 draw_worm(&worms
[0]);
1725 collision
= worm_food_collision(&worms
[0], 0);
1729 rb
->snprintf(buf
, sizeof buf
, "collisions: %d", collision_count
);
1730 rb
->lcd_putsxy(0, LCD_HEIGHT
-8, buf
);
1733 if (collision_count
!= food_size
* 2) {
1734 rb
->button_get(true);
1739 static bool expensive_worm_in_rect(struct worm
*w
, int rx
, int ry
, int rw
, int rh
){
1741 bool retVal
= false;
1742 for (x
= rx
; x
< rx
+ rw
; x
++){
1743 for (y
= ry
; y
< ry
+ rh
; y
++) {
1744 if (specific_worm_collision(w
, x
, y
) != -1) {
1752 static void test_worm_argh_collision(void) {
1755 int collision_count
= 0;
1756 rb
->lcd_clear_display();
1757 init_worm(&worms
[0], 10, 10);
1758 add_growing(&worms
[0], 40);
1759 for (dir
= 0; dir
< 4; dir
++) {
1760 set_worm_dir(&worms
[0], (EAST
+ dir
) % 4);
1761 for (i
= 0; i
< 10; i
++) {
1762 move_worm(&worms
[0]);
1763 draw_worm(&worms
[0]);
1768 for (arghy
[0] = 0; arghy
[0] < FIELD_RECT_HEIGHT
- argh_size
; arghy
[0]++){
1772 collision
= worm_argh_collision(&worms
[0], 0);
1776 rb
->snprintf(buf
, sizeof buf
, "collisions: %d", collision_count
);
1777 rb
->lcd_putsxy(0, LCD_HEIGHT
-8, buf
);
1780 if (collision_count
!= argh_size
* 2) {
1781 rb
->button_get(true);
1785 for (arghx
[0] = 0; arghx
[0] < FIELD_RECT_HEIGHT
- argh_size
; arghx
[0]++){
1789 collision
= worm_argh_collision(&worms
[0], 0);
1793 rb
->snprintf(buf
, sizeof buf
, "collisions: %d", collision_count
);
1794 rb
->lcd_putsxy(0, LCD_HEIGHT
-8, buf
);
1797 if (collision_count
!= argh_size
* 4) {
1798 rb
->button_get(true);
1802 static int testline_in_rect(void) {
1803 int testfailed
= -1;
1816 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1817 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1818 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1819 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1821 rb
->lcd_putsxy(0, 0, "failed 1");
1822 rb
->button_get(true);
1828 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1829 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1830 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1831 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1832 rb
->lcd_putsxy(0, 0, "failed 2");
1834 rb
->button_get(true);
1840 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1841 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1842 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1843 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1844 rb
->lcd_putsxy(0, 0, "failed 3");
1846 rb
->button_get(true);
1852 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1853 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1854 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1855 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1856 rb
->lcd_putsxy(0, 0, "failed 4");
1858 rb
->button_get(true);
1864 if (line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) ||
1865 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1866 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1867 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1868 rb
->lcd_putsxy(0, 0, "failed 5");
1870 rb
->button_get(true);
1877 if (line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) ||
1878 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1879 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1880 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1881 rb
->lcd_putsxy(0, 0, "failed 6");
1883 rb
->button_get(true);
1892 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1893 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1894 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1895 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1896 rb
->lcd_putsxy(0, 0, "failed 7");
1898 rb
->button_get(true);
1904 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1905 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1906 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1907 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1908 rb
->lcd_putsxy(0, 0, "failed 8");
1910 rb
->button_get(true);
1916 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1917 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1918 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1919 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1920 rb
->lcd_putsxy(0, 0, "failed 9");
1922 rb
->button_get(true);
1928 if (!line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1929 !line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1930 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1931 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1932 rb
->lcd_putsxy(0, 0, "failed 10");
1934 rb
->button_get(true);
1940 if (line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) ||
1941 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1942 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1943 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1944 rb
->lcd_putsxy(0, 0, "failed 11");
1946 rb
->button_get(true);
1953 if (line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) ||
1954 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
)) {
1955 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1956 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1957 rb
->lcd_putsxy(0, 0, "failed 12");
1959 rb
->button_get(true);
1973 if (!(line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1974 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
))) {
1975 rb
->lcd_drawrect(rx
, ry
, rw
, rh
);
1976 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1977 rb
->lcd_putsxy(0, 0, "failed 13");
1979 rb
->button_get(true);
1993 if (!(line_in_rect(x1
, y1
, x2
, y2
, rx
, ry
, rw
, rh
) &&
1994 line_in_rect(x2
, y2
, x1
, y1
, rx
, ry
, rw
, rh
))) {
1995 rb
->lcd_drawline(x1
, y1
, x2
, y2
);
1996 rb
->lcd_invertrect(rx
, ry
, rw
, rh
);
1997 rb
->lcd_putsxy(0, 0, "failed 14");
1999 rb
->button_get(true);
2003 rb
->lcd_clear_display();
2009 * Just a test routine to test wether specific_worm_collision might work properly
2011 static int test_specific_worm_collision(void) {
2017 rb
->lcd_clear_display();
2018 init_worm(&worms
[0], 10, 20);
2019 add_growing(&worms
[0], 20 - INITIAL_WORM_LENGTH
);
2021 for (dir
= EAST
; dir
< EAST
+ 4; dir
++) {
2023 set_worm_dir(&worms
[0], dir
% 4);
2024 for (i
= 0; i
< 5; i
++) {
2025 if (!(dir
% 4 == NORTH
&& i
== 9)) {
2026 move_worm(&worms
[0]);
2027 draw_worm(&worms
[0]);
2032 for (y
= 15; y
< 30; y
++){
2033 for (x
= 5; x
< 20; x
++) {
2034 if (specific_worm_collision(&worms
[0], x
, y
) != -1) {
2037 rb
->lcd_invertpixel(x
+ FIELD_RECT_X
, y
+ FIELD_RECT_Y
);
2038 rb
->snprintf(buf
, sizeof buf
, "collisions %d", collisions
);
2039 rb
->lcd_putsxy(0, LCD_HEIGHT
- 8, buf
);
2043 if (collisions
!= 21) {
2044 rb
->button_get(true);
2049 static void test_make_argh(void){
2054 int last_failures
= 0;
2056 rb
->lcd_clear_display();
2059 for (worm_idx
= 0; worm_idx
< worm_count
; worm_idx
++) {
2060 init_worm(&worms
[worm_idx
], 10 + worm_idx
* 20, 20);
2061 add_growing(&worms
[worm_idx
], 40 - INITIAL_WORM_LENGTH
);
2064 for (dir
= EAST
; dir
< EAST
+ 4; dir
++) {
2065 for (worm_idx
= 0; worm_idx
< worm_count
; worm_idx
++) {
2066 set_worm_dir(&worms
[worm_idx
], dir
% 4);
2067 for (i
= 0; i
< 10; i
++) {
2068 if (!(dir
% 4 == NORTH
&& i
== 9)) {
2069 move_worm(&worms
[worm_idx
]);
2070 draw_worm(&worms
[worm_idx
]);
2078 for (seed
= 0; hit
< 20; seed
+= 2) {
2082 x
= rb
->rand() % (FIELD_RECT_WIDTH
- argh_size
);
2083 y
= rb
->rand() % (FIELD_RECT_HEIGHT
- argh_size
);
2085 for (worm_idx
= 0; worm_idx
< worm_count
; worm_idx
++){
2086 if (expensive_worm_in_rect(&worms
[worm_idx
], x
, y
, argh_size
, argh_size
)) {
2090 tries
= make_argh(0);
2091 if ((x
== arghx
[0] && y
== arghy
[0]) || tries
< 2) {
2095 rb
->snprintf(buf
, sizeof buf
, "(%d;%d) fail%d try%d", x
, y
, failures
, tries
);
2096 rb
->lcd_putsxy(0, LCD_HEIGHT
- 8, buf
);
2098 rb
->lcd_invertrect(x
+ FIELD_RECT_X
, y
+ FIELD_RECT_Y
, argh_size
, argh_size
);
2102 rb
->lcd_invertrect(x
+ FIELD_RECT_X
, y
+ FIELD_RECT_Y
, argh_size
, argh_size
);
2103 rb
->lcd_clearrect(arghx
[0] + FIELD_RECT_X
, arghy
[0] + FIELD_RECT_Y
, argh_size
, argh_size
);
2105 if (failures
> last_failures
) {
2106 rb
->button_get(true);
2108 last_failures
= failures
;
2115 static void test_worm_argh_collision_in_moves(void) {
2118 rb
->lcd_clear_display();
2119 init_worm(&worms
[0], 10, 20);
2125 set_worm_dir(&worms
[0], EAST
);
2126 for (i
= 0; i
< 20; i
++) {
2128 move_worm(&worms
[0]);
2129 draw_worm(&worms
[0]);
2130 if (worm_argh_collision_in_moves(&worms
[0], 0, 5)){
2133 rb
->snprintf(buf
, sizeof buf
, "in 5 moves hits: %d", hit_count
);
2134 rb
->lcd_putsxy(0, LCD_HEIGHT
- 8, buf
);
2137 if (hit_count
!= argh_size
+ 5) {
2138 rb
->button_get(true);
2141 #endif /* DEBUG_WORMLET */
2143 extern bool use_old_rect
;
2146 * These are additional functions required to set various wormlet settings
2147 * and to enable saving of settings and high score
2151 Sets the total number of worms, both human and machine
2153 bool set_worm_num_worms(void)
2156 static const struct opt_items num_worms_option
[3] = {
2162 ret
= rb
->set_option("Number Of Worms", &worm_count
,INT
, num_worms_option
, 3, NULL
);
2163 if (worm_count
< players
) {
2170 Sets the number of human players
2172 bool set_worm_num_players(void)
2175 static const struct opt_items num_players_option
[4] = {
2182 ret
= rb
->set_option("Number of Players", &players
, INT
,num_players_option
, 4, NULL
);
2183 if (players
> worm_count
) {
2184 worm_count
= players
;
2193 Sets the size of each argh block created
2195 bool set_worm_argh_size(void)
2197 static const struct opt_items argh_size_option
[11] = {
2211 return rb
->set_option("Argh Size", &argh_size
,INT
,argh_size_option
, 11, NULL
);
2215 Sets the amount a worm grows per food
2217 bool set_worm_food(void)
2219 static const struct opt_items worm_food_option
[11] = {
2232 return rb
->set_option("Worm Growth Per Food", &worm_food
,INT
,worm_food_option
, 11, NULL
);
2236 Sets the number of arghs created per food
2238 bool set_argh_per_food(void)
2240 static const struct opt_items argh_food_option
[5] = {
2247 return rb
->set_option("Arghs Per Food", &arghs_per_food
,INT
,argh_food_option
, 5, NULL
);
2251 Sets the number of ticks per move
2253 bool set_worm_speed(void)
2256 static const struct opt_items speed_option
[19] = {
2280 ret
= rb
->set_option("Worm Speed", &speed
,INT
,speed_option
, 19, NULL
);
2286 Sets the control style, which depends on the number of players,
2287 remote control existing, etc
2288 bool set_bool_options(char* string, bool* variable,
2289 char* yes_str, char* no_str, void (*function)(bool))
2291 bool set_worm_control_style(void)
2293 static const struct opt_items key1_option
[2] = {
2294 { "Remote Control", -1 },
2295 { "No Rem. Control", -1 },
2298 static const struct opt_items key2_option
[2] = {
2299 { "2 Key Control", -1 },
2300 { "4 Key COntrol", -1 },
2303 static const struct opt_items key3_option
[1] = {
2304 { "Out of Control", -1 },
2308 rb
->set_option("Control Style",&use_remote
,INT
, key1_option
, 2, NULL
);
2311 rb
->set_option("Control Style",&use_remote
,INT
, key2_option
, 2, NULL
);
2314 rb
->set_option("Control Style",&use_remote
,INT
, key3_option
, 1, NULL
);
2320 void default_settings(void)
2322 arghs_per_food
= ARGHS_PER_FOOD
;
2323 argh_size
= ARGH_SIZE
;
2324 food_size
= FOOD_SIZE
;
2326 worm_food
= WORM_PER_FOOD
;
2328 worm_count
= MAX_WORMS
;
2334 Launches the wormlet game
2336 bool launch_wormlet(void)
2338 int game_result
= 1;
2340 rb
->lcd_clear_display();
2342 /* Turn off backlight timeout */
2343 backlight_force_on(rb
); /* backlight control in lib/helper.c */
2345 /* start the game */
2346 while (game_result
== 1)
2347 game_result
= run();
2349 switch (game_result
)
2352 /* Turn on backlight timeout (revert to settings) */
2353 backlight_use_settings(rb
); /* backlight control in lib/helper.c */
2360 /* End of settings/changes etc */
2365 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
2375 configfile_init(rb
);
2376 if (configfile_load(SETTINGS_FILENAME
, config
,
2377 sizeof(config
)/sizeof(*config
),
2378 SETTINGS_MIN_VERSION
) < 0)
2380 /* If the loading failed, save a new config file (as the disk is
2381 already spinning) */
2382 configfile_save(SETTINGS_FILENAME
, config
,
2383 sizeof(config
)/sizeof(*config
),
2387 #ifdef HAVE_LCD_COLOR
2388 rb
->lcd_set_foreground(COLOR_FG
);
2389 rb
->lcd_set_background(COLOR_BG
);
2393 rb
->lcd_set_backdrop(NULL
);
2396 #ifdef DEBUG_WORMLET
2398 test_worm_argh_collision_in_moves();
2400 test_worm_food_collision();
2401 test_worm_argh_collision();
2402 test_specific_worm_collision();
2407 static const struct opt_items noyes
[2] = {
2412 static const struct opt_items num_worms_option
[3] = {
2419 static const struct opt_items num_players_option
[4] = {
2421 static const struct opt_items num_players_option
[2] = {
2431 static const struct opt_items argh_size_option
[9] = {
2443 static const struct opt_items food_size_option
[9] = {
2455 static const struct opt_items worm_food_option
[16] = {
2474 static const struct opt_items argh_food_option
[9] = {
2486 static const struct opt_items speed_option
[21] = {
2510 static const struct opt_items remoteonly_option
[1] = {
2511 { "Remote Control", -1 }
2514 static const struct opt_items key24_option
[2] = {
2515 { "4 Key Control", -1 },
2516 { "2 Key Control", -1 }
2520 static const struct opt_items remote_option
[2] = {
2521 { "Remote Control", -1 },
2522 { "No Rem. Control", -1 }
2525 static const struct opt_items key2_option
[1] = {
2526 { "2 Key Control", -1 }
2530 static const struct opt_items nokey_option
[1] = {
2531 { "Out of Control", -1 }
2534 MENUITEM_STRINGLIST(menu
, "Wormlet Menu", NULL
, "Play Wormlet!",
2535 "Number of Worms", "Number of Players", "Control Style",
2536 "Worm Growth Per Food","Worm Speed","Arghs Per Food",
2537 "Argh Size","Food Size","Revert to Default Settings",
2540 rb
->button_clear_queue();
2542 while (!menu_quit
) {
2543 switch(rb
->do_menu(&menu
, &result
))
2546 rb
->lcd_setfont(FONT_SYSFIXED
);
2550 new_setting
= worm_count
- 1;
2551 rb
->set_option("Number of Worms", &new_setting
, INT
, num_worms_option
, 3, NULL
);
2552 if (new_setting
!= worm_count
)
2553 worm_count
= new_setting
+ 1;
2554 if (worm_count
< players
) {
2555 worm_count
= players
;
2559 new_setting
= players
;
2561 rb
->set_option("Number of Players", &new_setting
, INT
, num_players_option
, 4, NULL
);
2563 rb
->set_option("Number of Players", &new_setting
, INT
, num_players_option
, 2, NULL
);
2565 if (new_setting
!= players
)
2566 players
= new_setting
;
2567 if (players
> worm_count
) {
2568 worm_count
= players
;
2575 new_setting
= use_remote
;
2578 rb
->set_option("Control Style",&new_setting
,INT
, nokey_option
, 1, NULL
);
2581 rb
->set_option("Control Style",&new_setting
,INT
, key24_option
, 2, NULL
);
2585 rb
->set_option("Control Style",&new_setting
,INT
, remote_option
, 2, NULL
);
2587 rb
->set_option("Control Style",&new_setting
,INT
, key2_option
, 1, NULL
);
2591 rb
->set_option("Control Style",&new_setting
,INT
, remoteonly_option
, 1, NULL
);
2594 if (new_setting
!= use_remote
)
2595 use_remote
= new_setting
;
2598 new_setting
= worm_food
;
2599 rb
->set_option("Worm Growth Per Food", &new_setting
,INT
,worm_food_option
, 16, NULL
);
2600 if (new_setting
!= worm_food
)
2601 worm_food
= new_setting
;
2604 new_setting
= speed
;
2605 new_setting
= 20 - new_setting
;
2606 rb
->set_option("Worm Speed", &new_setting
,INT
,speed_option
, 21, NULL
);
2607 new_setting
= 20 - new_setting
;
2608 if (new_setting
!= speed
)
2609 speed
= new_setting
;
2612 new_setting
= arghs_per_food
;
2613 rb
->set_option("Arghs Per Food", &new_setting
,INT
,argh_food_option
, 9, NULL
);
2614 if (new_setting
!= arghs_per_food
)
2615 arghs_per_food
= new_setting
;
2618 new_setting
= argh_size
-2;
2619 rb
->set_option("Argh Size", &new_setting
,INT
,argh_size_option
, 9, NULL
);
2620 if (new_setting
!= argh_size
)
2621 argh_size
= new_setting
+2;
2624 new_setting
= food_size
-2;
2625 rb
->set_option("Food Size", &new_setting
,INT
,food_size_option
, 9, NULL
);
2626 if (new_setting
!= food_size
)
2627 food_size
= new_setting
+2;
2631 rb
->set_option("Reset Settings?", &new_setting
,INT
, noyes
, 2, NULL
);
2632 if (new_setting
== 1)
2641 configfile_save(SETTINGS_FILENAME
, config
,
2642 sizeof(config
)/sizeof(*config
),