summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Basha <benbasha@rockbox.org>2006-03-12 09:35:53 +0000
committerBen Basha <benbasha@rockbox.org>2006-03-12 09:35:53 +0000
commitb7a96707bc462c493ff04cce08b2c971eb92f7dc (patch)
tree4b5ab2a3ace539dc8641f9ee76209c416a487233
parenta3cfdef7c8464c15c2c26fb7a80c77b82632645e (diff)
downloadrockbox-b7a96707bc462c493ff04cce08b2c971eb92f7dc.tar.gz
rockbox-b7a96707bc462c493ff04cce08b2c971eb92f7dc.zip
New plugin - Xobox - xonix clone by Eli Sherer with changes by me and Mikael Magnusson
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9011 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/SOURCES5
-rw-r--r--apps/plugins/xobox.c813
-rw-r--r--docs/CREDITS1
3 files changed, 819 insertions, 0 deletions
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index ce6bb33081..7cd2882ab6 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -77,6 +77,11 @@ rockboy.c
77#endif 77#endif
78#endif 78#endif
79 79
80/* not support recorder models for now */
81#if (LCD_WIDTH > 112) && (LCD_HEIGHT > 64)
82xobox.c
83#endif
84
80#endif /* HAVE_LCD_BITMAP */ 85#endif /* HAVE_LCD_BITMAP */
81 86
82#ifdef HAVE_LCD_CHARCELLS /* Player model only */ 87#ifdef HAVE_LCD_CHARCELLS /* Player model only */
diff --git a/apps/plugins/xobox.c b/apps/plugins/xobox.c
new file mode 100644
index 0000000000..b578ccbf53
--- /dev/null
+++ b/apps/plugins/xobox.c
@@ -0,0 +1,813 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Eli Sherer
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 "plugin.h"
21
22PLUGIN_HEADER
23
24#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
25
26#define QUIT BUTTON_OFF
27#define LEFT BUTTON_LEFT
28#define RIGHT BUTTON_RIGHT
29#define PAUSE BUTTON_MODE
30#define UP BUTTON_UP
31#define DOWN BUTTON_DOWN
32#define SELECT BUTTON_SELECT
33
34#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \
35 (CONFIG_KEYPAD == IPOD_4G_PAD)
36
37#define QUIT (BUTTON_SELECT | BUTTON_MENU)
38#define LEFT BUTTON_LEFT
39#define RIGHT BUTTON_RIGHT
40#define PAUSE BUTTON_SELECT
41#define SELECT BUTTON_SELECT
42#define UP BUTTON_MENU
43#define DOWN BUTTON_PLAY
44
45#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
46
47#define QUIT BUTTON_POWER
48#define LEFT BUTTON_LEFT
49#define RIGHT BUTTON_RIGHT
50#define SELECT BUTTON_SELECT
51#define UP BUTTON_UP
52#define DOWN BUTTON_DOWN
53#define PAUSE BUTTON_PLAY
54
55#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
56
57#define QUIT BUTTON_A
58#define LEFT BUTTON_LEFT
59#define RIGHT BUTTON_RIGHT
60#define SELECT BUTTON_SELECT
61#define UP BUTTON_UP
62#define DOWN BUTTON_DOWN
63#define PAUSE BUTTON_MENU
64
65#else
66#error Unsupported keypad
67#endif
68
69#define MOVE_NO 0 /* player movement */
70#define MOVE_UP 1 /* 1 */
71#define MOVE_DN 2 /* 3 0 4 */
72#define MOVE_LT 3 /* 2 */
73#define MOVE_RT 4
74
75#define MOVE_UUR 0 /* ball movement (12 ways) */
76#define MOVE_UR 1
77#define MOVE_URR 2
78#define MOVE_DRR 3 /* UUL110UUR */
79#define MOVE_DR 4 /* UL10 1UR */
80#define MOVE_DDR 5 /* ULL9 . 2URR */
81#define MOVE_DDL 6 /* DLL8 3DRR */
82#define MOVE_DL 7 /* DL7 4DR */
83#define MOVE_DLL 8 /* DDL6 5DDR */
84#define MOVE_ULL 9
85#define MOVE_UL 10
86#define MOVE_UUL 11
87
88#define CUBE_SIZE 8 /* 8x22=176 */
89#define STARTING_QIXES 2
90#define MAX_LEVEL 10
91#define MAX_QIXES MAX_LEVEL+STARTING_QIXES
92#define BOARD_W ((int)LCD_WIDTH/CUBE_SIZE)
93#define BOARD_H ((int)LCD_HEIGHT/CUBE_SIZE)
94#define BOARD_X (LCD_WIDTH-BOARD_W*CUBE_SIZE)/2
95#define BOARD_Y (LCD_HEIGHT-BOARD_H*CUBE_SIZE)/2
96
97#ifdef HAVE_LCD_COLOR
98#define CLR_RED LCD_RGBPACK(255,0,0) /* used to imply danger */
99#define CLR_BLUE LCD_RGBPACK(0,0,128) /* used for menu selection */
100#define CLR_CYAN LCD_RGBPACK(0,128,128) /* used for frame and filling */
101#else
102#define CLR_RED LCD_DARKGRAY /* used to imply danger */
103#define CLR_BLUE LCD_LIGHTGRAY /* used for menu selection */
104#define CLR_CYAN LCD_LIGHTGRAY /* used for frame and filling */
105#endif
106
107#define EMPTIED LCD_BLACK /* empty spot */
108#define FILLED CLR_CYAN /* filled spot */
109#define TRAIL CLR_RED /* the red trail of the player */
110#define QIX LCD_WHITE
111#define UNCHECKED 0
112#define CHECKED 1
113#define PIC_QIX 0
114#define PIC_PLAYER 1
115
116/* The time (in ms) for one iteration through the game loop - decrease this
117 to speed up the game - note that current_tick is (currently) only accurate
118 to 10ms.
119*/
120#define CYCLETIME 50
121
122static struct plugin_api *rb;
123static bool quit = false;
124
125static unsigned short board[BOARD_H][BOARD_W],
126 testboard[BOARD_H][BOARD_W], boardcopy[BOARD_H][BOARD_W];
127
128/*
129 00001000 0x08 - 01110111 0x77
130 00011100 0x1c - 01110111 0x77
131 00111110 0x3e - 01100011 0x63
132 01111111 0x7f - 00000000 0x00
133 00111110 0x3e - 01100011 0x63
134 00011100 0x1c - 01110111 0x77
135 00001000 0x08 - 01110111 0x77
136 00000000 0x00 - 00000000 0x00
137 */
138const unsigned char pics[2][8] = {
139 {0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00}, /* Alien (QIX) */
140 {0x77, 0x77, 0x63, 0x00, 0x63, 0x77, 0x77, 0x00} /* Player (XONIX) */
141};
142
143static struct qix
144{
145 short velocity; /* velocity */
146 short x, y; /* position on screen */
147 short angle; /* angle */
148} qixes[MAX_QIXES]; /* black_qix */
149
150static struct splayer
151{
152 short i, j; /* position on board */
153 short move, score, level, lives;
154 bool drawing;
155 bool gameover;
156} player;
157
158/*************************** STACK STUFF **********************/
159
160/* the stack */
161#define STACK_SIZE BOARD_W*BOARD_H
162static struct pos
163{
164 int x, y; /* position on board */
165} stack[STACK_SIZE];
166static int stackPointer;
167
168/* div function (divide two numbers and truncate the answer) */
169static inline int div (int a, int b)
170{
171 return (a/b);
172}
173
174static bool pop (struct pos *p)
175{
176 if (stackPointer > 0) {
177 p->x = stack[stackPointer].x;
178 p->y = stack[stackPointer].y;
179 stackPointer--;
180 return true;
181 } else
182 return false; /* SE */
183}
184
185static bool push (struct pos *p)
186{
187 if (stackPointer < STACK_SIZE - 1) {
188 stackPointer++;
189 stack[stackPointer].x = p->x;
190 stack[stackPointer].y = p->y;
191 return true;
192 } else
193 return false; /* SOF */
194}
195
196static void emptyStack (void)
197{
198 stackPointer = 0;
199 /* int x, y;
200 while(pop(&x, &y)); */
201}
202
203/*********************** END OF STACK STUFF *********************/
204
205
206/* calculate the new x coordinate of the ball according to angle and speed */
207static int get_newx (int x, int len, int deg)
208{
209 int dx;
210 if ((deg == MOVE_DRR) || (deg == MOVE_URR))
211 dx = 2;
212 else if ((deg == MOVE_DDR) || (deg == MOVE_UUR) || (deg == MOVE_DR)
213 || (deg == MOVE_UR))
214 dx = 1;
215 else if ((deg == MOVE_DDL) || (deg == MOVE_UUL) || (deg == MOVE_DL)
216 || (deg == MOVE_UL))
217 dx = -1;
218 else
219 dx = -2;
220 return x + dx * len;
221}
222
223/* calculate the new y coordinate of the ball according to angle and speed */
224static int get_newy (int y, int len, int deg)
225{
226 int dy;
227 if ((deg == MOVE_DRR) || (deg == MOVE_DLL) || (deg == MOVE_DR)
228 || (deg == MOVE_DL))
229 dy = 1;
230 else if ((deg == MOVE_DDR) || (deg == MOVE_DDL))
231 dy = 2;
232 else if ((deg == MOVE_UUR) || (deg == MOVE_UUL))
233 dy = -2;
234 else
235 dy = -1;
236 return y + dy * len;
237}
238
239/* make random function get it's value from the device ticker */
240static inline void randomize (void)
241{
242 rb->srand (*rb->current_tick);
243}
244
245/* get a random number between 0 and range-1 */
246static int t_rand (int range)
247{
248 return rb->rand () % range;
249}
250
251/* initializes the test help board */
252static void init_testboard (void)
253{
254 int i, j; /* testboard */
255 for (j = 0; j < BOARD_H; j++)
256 for (i = 0; i < BOARD_W; i++)
257 testboard[j][i] = UNCHECKED;
258}
259
260/* initializes the game board on with the player,qix's and black qix */
261static void init_board (void)
262{
263 int i, j;
264 for (j = 0; j < BOARD_H; j++)
265 for (i = 0; i < BOARD_W; i++) { /* make a nice cyan frame */
266 if ((i == 0) || (j == 1) || (j == 0) || (i == BOARD_W - 1)
267 || (j == BOARD_H - 1) || (j == BOARD_H - 2))
268 board[j][i] = FILLED;
269 else
270 board[j][i] = EMPTIED;
271 }
272 /* (level+2) is the number of qixes */
273 for (j = 0; j < player.level + STARTING_QIXES; j++) {
274 qixes[j].velocity = t_rand (2) + 1; /* 1 or 2 pix-per-sec */
275
276 /* not on frame */
277 qixes[j].x =
278 BOARD_X + t_rand (((BOARD_W - 4) * CUBE_SIZE) - 2 * CUBE_SIZE) +
279 2 * CUBE_SIZE;
280 qixes[j].y =
281 BOARD_Y + t_rand (((BOARD_H - 6) * CUBE_SIZE) - 2 * CUBE_SIZE) +
282 3 * CUBE_SIZE;
283
284 qixes[j].angle = t_rand (12);
285 }
286 /*black_qix.velocity=1;
287 black_qix.x=BOARD_X+(BOARD_W*CUBE_SIZE)/2-CUBE_SIZE/2;
288 black_qix.y=BOARD_Y+(BOARD_H*CUBE_SIZE)-CUBE_SIZE-CUBE_SIZE/2;
289 black_qix.angle=MOVE_UR; */
290 player.move = MOVE_NO;
291 player.drawing = false;
292 player.i = BOARD_W / 2;
293 player.j = 1;
294}
295
296/* calculates the percentage of the screen filling */
297static int percentage (void)
298{
299 int i, j, filled = 0;
300 for (j = 2; j < BOARD_H - 2; j++)
301 for (i = 1; i < BOARD_W - 1; i++)
302 if (board[j][i] == FILLED)
303 filled++;
304 return filled * 100 / ((BOARD_W - 2) * (BOARD_H - 4));
305}
306
307/* draw the board on with all the game figures */
308static void refresh_board (void)
309{
310 int i, j;
311 char str[25];
312
313 rb->lcd_set_background (LCD_BLACK);
314 rb->lcd_clear_display ();
315 for (j = 0; j < BOARD_H; j++)
316 for (i = 0; i < BOARD_W; i++) {
317 rb->lcd_set_foreground (board[j][i]);
318 rb->lcd_fillrect (BOARD_X + CUBE_SIZE * i, BOARD_Y + CUBE_SIZE * j,
319 CUBE_SIZE, CUBE_SIZE);
320 }
321 rb->lcd_set_foreground (LCD_BLACK);
322 rb->lcd_set_background (CLR_CYAN);
323 rb->snprintf (str, sizeof (str), "Level %d", player.level + 1);
324 rb->lcd_putsxy (BOARD_X, BOARD_Y, str);
325 rb->snprintf (str, sizeof (str), "%d%%", percentage ());
326 rb->lcd_putsxy (BOARD_X + CUBE_SIZE * BOARD_W - 24, BOARD_Y, str);
327 rb->snprintf (str, sizeof (str), "Score: %d", player.score);
328 rb->lcd_putsxy (BOARD_X, BOARD_Y + CUBE_SIZE * BOARD_H - 8, str);
329 rb->snprintf (str, sizeof (str), "%d Lives", player.lives);
330 rb->lcd_putsxy (BOARD_X + CUBE_SIZE * BOARD_W - 60,
331 BOARD_Y + CUBE_SIZE * BOARD_H - 8, str);
332
333 rb->lcd_set_foreground (LCD_WHITE);
334 rb->lcd_set_background (board[player.j][player.i]);
335 rb->lcd_mono_bitmap (pics[PIC_PLAYER], player.i * CUBE_SIZE + BOARD_X,
336 player.j * CUBE_SIZE + BOARD_Y, CUBE_SIZE, CUBE_SIZE);
337 rb->lcd_set_background (EMPTIED);
338 for (j = 0; j < player.level + STARTING_QIXES; j++)
339 rb->lcd_mono_bitmap (pics[PIC_QIX], qixes[j].x + BOARD_X,
340 qixes[j].y + BOARD_Y, CUBE_SIZE, CUBE_SIZE);
341 rb->lcd_set_foreground (LCD_BLACK);
342
343 rb->lcd_update ();
344}
345
346static inline int infested_area (int i, int j)
347{
348 struct pos p, p1, p2, p3, p4;
349 bool hit = false;
350 p.x = i;
351 p.y = j;
352 emptyStack ();
353 init_testboard ();
354 if (!push (&p))
355 return -1;
356 while ((pop (&p)) && (!hit)) {
357 hit = (boardcopy[p.y][p.x] == QIX);
358 testboard[p.y][p.x] = CHECKED;
359 if (hit)
360 return true; /*save some time and space */
361 p1.x = p.x + 1;
362 p1.y = p.y;
363 p2.x = p.x - 1;
364 p2.y = p.y;
365 p3.x = p.x;
366 p3.y = p.y + 1;
367 p4.x = p.x;
368 p4.y = p.y - 1;
369 if ((p1.x < BOARD_W) && (p1.x >= 0) && (p1.y < BOARD_H) && (p1.y >= 0)
370 && (testboard[p1.y][p1.x] == UNCHECKED))
371 if (board[p1.y][p1.x] != FILLED)
372 if (!push (&p1))
373 return -1;
374 if ((p2.x < BOARD_W) && (p2.x >= 0) && (p2.y < BOARD_H) && (p2.y >= 0)
375 && (testboard[p2.y][p2.x] == UNCHECKED))
376 if (board[p2.y][p2.x] != FILLED)
377 if (!push (&p2))
378 return -1;
379 if ((p3.x < BOARD_W) && (p3.x >= 0) && (p3.y < BOARD_H) && (p3.y >= 0)
380 && (testboard[p3.y][p3.x] == UNCHECKED))
381 if (board[p3.y][p3.x] != FILLED)
382 if (!push (&p3))
383 return -1;
384 if ((p4.x < BOARD_W) && (p4.x >= 0) && (p4.y < BOARD_H) && (p4.y >= 0)
385 && (testboard[p4.y][p4.x] == UNCHECKED))
386 if (board[p4.y][p4.x] != FILLED)
387 if (!push (&p4))
388 return -1;
389 }
390 return (hit ? 1 : 0);
391}
392
393static inline int fill_area (int i, int j)
394{
395 struct pos p, p1, p2, p3, p4;
396 p.x = i;
397 p.y = j;
398 emptyStack ();
399 init_testboard ();
400 if (!push (&p))
401 return -1;
402 while (pop (&p)) {
403 board[p.y][p.x] = FILLED;
404 testboard[p.y][p.x] = CHECKED;
405 p1.x = p.x + 1;
406 p1.y = p.y;
407 p2.x = p.x - 1;
408 p2.y = p.y;
409 p3.x = p.x;
410 p3.y = p.y + 1;
411 p4.x = p.x;
412 p4.y = p.y - 1;
413 if ((p1.x < BOARD_W) && (p1.x >= 0) && (p1.y < BOARD_H) && (p1.y >= 0)
414 && (testboard[p1.y][p1.x] == UNCHECKED))
415 if (board[p1.y][p1.x] == EMPTIED)
416 if (!push (&p1))
417 return -1;
418 if ((p2.x < BOARD_W) && (p2.x >= 0) && (p2.y < BOARD_H) && (p2.y >= 0)
419 && (testboard[p2.y][p2.x] == UNCHECKED))
420 if (board[p2.y][p2.x] == EMPTIED)
421 if (!push (&p2))
422 return -1;
423 if ((p3.x < BOARD_W) && (p3.x >= 0) && (p3.y < BOARD_H) && (p3.y >= 0)
424 && (testboard[p3.y][p3.x] == UNCHECKED))
425 if (board[p3.y][p3.x] == EMPTIED)
426 if (!push (&p3))
427 return -1;
428 if ((p4.x < BOARD_W) && (p4.x >= 0) && (p4.y < BOARD_H) && (p4.y >= 0)
429 && (testboard[p4.y][p4.x] == UNCHECKED))
430 if (board[p4.y][p4.x] == EMPTIED)
431 if (!push (&p4))
432 return -1;
433 }
434 return 1;
435}
436
437
438/* take care of stuff after xonix has landed on a filled spot */
439static void complete_trail (void)
440{
441 int i, j, ret;
442 for (j = 0; j < BOARD_H; j++)
443 for (i = 0; i < BOARD_W; i++)
444 if (board[j][i] == TRAIL)
445 board[j][i] = FILLED;
446
447 for (j = 0; j < BOARD_H; j++)
448 for (i = 0; i < BOARD_W; i++)
449 boardcopy[j][i] = board[j][i];
450 for (i = 0; i < player.level + STARTING_QIXES; i++) /* add qixes to board */
451 boardcopy[div (qixes[i].y - BOARD_Y, CUBE_SIZE)][div
452 (qixes[i].x - BOARD_X,
453 CUBE_SIZE)] = QIX;
454
455 for (j = 1; j < BOARD_H - 1; j++)
456 for (i = 0; i < BOARD_W - 0; i++)
457 if (board[j][i] != FILLED) {
458 ret = infested_area (i, j);
459 if (ret < 0)
460 quit = true;
461 else if (ret == 0) {
462 ret = fill_area (i, j);
463 if (ret < 0)
464 quit = true;
465 }
466 }
467}
468
469/* returns the color the real pixel(x,y) on the lcd is pointing at */
470static unsigned short getpixel (int x, int y)
471{
472 int a = div (x - BOARD_X, CUBE_SIZE), b = div (y - BOARD_Y, CUBE_SIZE);
473 if ((a > 0) && (a < BOARD_W) && (b > 0) && (b < BOARD_H)) /* if inside board */
474 return board[b][a];
475 else
476 return FILLED;
477}
478
479/* returns the color the ball on (newx,newy) is heading at *----*
480 checks the four edge points of the square if 1st of all | |
481 are a trail (cause it's a lose life situation) and 2nd | |
482 if it's filled so it needs to bounce. *____*
483 */
484static inline unsigned short next_hit (int newx, int newy)
485{
486 if ((getpixel (newx, newy) == TRAIL)
487 || (getpixel (newx, newy + CUBE_SIZE - 1) == TRAIL)
488 || (getpixel (newx + CUBE_SIZE - 1, newy) == TRAIL)
489 || (getpixel (newx + CUBE_SIZE - 1, newy + CUBE_SIZE - 1) == TRAIL))
490 return TRAIL;
491 else if ((getpixel (newx, newy) == FILLED)
492 || (getpixel (newx, newy + CUBE_SIZE - 1) == FILLED)
493 || (getpixel (newx + CUBE_SIZE - 1, newy) == FILLED)
494 || (getpixel (newx + CUBE_SIZE - 1, newy + CUBE_SIZE - 1) ==
495 FILLED))
496 return FILLED;
497 else
498 return EMPTIED;
499}
500
501/* returns true if the (side) of the block -***-
502 starting from (newx,newy) has any filled pixels * *
503 -***-
504 */
505static bool line_check (int newx, int newy, int side)
506{
507 int i = 0;
508 bool filled = false;
509 for (i = 3; ((i < CUBE_SIZE - 3) && (!filled)); i++) {
510 switch (side) {
511 case MOVE_LT:
512 filled = getpixel (newx, newy + i) == FILLED;
513 break;
514 case MOVE_RT:
515 filled = getpixel (newx + CUBE_SIZE - 1, newy + i) == FILLED;
516 break;
517 case MOVE_UP:
518 filled = getpixel (newx + i, newy) == FILLED;
519 break;
520 case MOVE_DN:
521 filled = getpixel (newx + i, newy + CUBE_SIZE - 1) == FILLED;
522 break;
523 }
524 }
525 return filled;
526}
527
528static void move_qix (struct qix *q)
529{
530 int newx, newy, dir;
531 unsigned short nexthit;
532 newx = get_newx (q->x, q->velocity, q->angle);
533 newy = get_newy (q->y, q->velocity, q->angle);
534 nexthit = next_hit (newx, newy);
535 if (nexthit == EMPTIED) {
536 q->x = newx;
537 q->y = newy;
538 } else if (nexthit == FILLED) {
539 dir = q->angle;
540 switch (dir) {
541 case MOVE_URR:
542 case MOVE_UUR:
543 case MOVE_UR: /* up-right (can hit ceiling or right wall) */
544 if (line_check (newx, newy, MOVE_UP)
545 && line_check (newx, newy, MOVE_RT))
546 q->angle = q->angle + 6;
547 else if (line_check (newx, newy, MOVE_UP))
548 q->angle = 5 - q->angle; /* 5=180/(360/12)-1 */
549 else
550 q->angle = 11 - q->angle; /* 11=360/(360/12)-1 */
551 break;
552 case MOVE_ULL:
553 case MOVE_UUL:
554 case MOVE_UL: /* up-left (can hit ceiling or left wall) */
555 if (line_check (newx, newy, MOVE_UP)
556 && line_check (newx, newy, MOVE_LT))
557 q->angle = q->angle - 6;
558 else if (line_check (newx, newy, MOVE_UP))
559 q->angle = 17 - q->angle; /* 17=540/(360/12)-1 */
560 else
561 q->angle = 11 - q->angle; /* 11=360/(360/12)-1 */
562 break;
563 case MOVE_DLL:
564 case MOVE_DDL:
565 case MOVE_DL: /* down-left (can hit floor or left wall) */
566 if (line_check (newx, newy, MOVE_DN)
567 && line_check (newx, newy, MOVE_LT))
568 q->angle = q->angle - 6;
569 else if (line_check (newx, newy, MOVE_DN))
570 q->angle = 17 - q->angle; /* 17=540/(360/12)-1 */
571 else
572 q->angle = 11 - q->angle; /* 11=360/(360/12)-1 */
573 break;
574 case MOVE_DRR:
575 case MOVE_DDR:
576 case MOVE_DR: /* down-right (can hit floor or right wall) */
577 if (line_check (newx, newy, MOVE_DN)
578 && line_check (newx, newy, MOVE_RT))
579 q->angle = q->angle + 6;
580 else if (line_check (newx, newy, MOVE_DN))
581 q->angle = 5 - q->angle; /* 5=180/(360/12)-1 */
582 else
583 q->angle = 11 - q->angle; /* 11=360/(360/12)-1 */
584 break;
585 }
586 q->x = newx;
587 q->y = newy;
588 refresh_board ();
589 newx = get_newx (newx, q->velocity, q->angle);
590 newy = get_newy (newy, q->velocity, q->angle);
591 q->x = newx;
592 q->y = newy;
593 } else if (nexthit == TRAIL) {
594 player.lives--;
595 if (player.lives == 0)
596 player.gameover = true;
597 refresh_board ();
598 rb->splash (HZ, true, "Crash!");
599 init_board ();
600 }
601}
602
603/* move the board forward timewise */
604static inline void move_board (void)
605{
606 int j, newi, newj;
607
608 for (j = 0; j < player.level + STARTING_QIXES; j++)
609 move_qix (&qixes[j]);
610 /* move_qix(&black_qix,true); */
611 if (player.move) {
612 newi = player.i;
613 newj = player.j;
614 switch (player.move) {
615 case MOVE_UP:
616 if (player.j > 1)
617 newj--;
618 break;
619 case MOVE_DN:
620 if (player.j < BOARD_H - 2)
621 newj++;
622 break;
623 case MOVE_LT:
624 if (player.i > 0)
625 newi--;
626 break;
627 case MOVE_RT:
628 if (player.i < BOARD_W - 1)
629 newi++;
630 break;
631 default:
632 break;
633 }
634
635 if ((player.drawing) && (board[newj][newi] == EMPTIED)) /* continue drawing */
636 board[newj][newi] = TRAIL;
637 else if ((player.drawing) && (board[newj][newi] == FILLED)) { /* finish drawing */
638 player.move = MOVE_NO; /* stop moving */
639 player.drawing = false;
640 complete_trail ();
641 } else if ((board[player.j][player.i] == FILLED)
642 && (board[newj][newi] == EMPTIED)) {
643 /* start drawing */
644 player.drawing = true;
645 board[newj][newi] = TRAIL;
646 }
647 player.i = newi;
648 player.j = newj;
649 }
650 j = percentage ();
651 if (j > 75) { /* finished level */
652 rb->splash (HZ * 2, true, "Level %d finished", player.level+1);
653 player.score += j;
654 if (player.level < MAX_LEVEL)
655 player.level++;
656 init_board ();
657 refresh_board ();
658 rb->splash (HZ * 2, true, "READY?");
659 rb->lcd_update ();
660 refresh_board ();
661 }
662}
663
664/* the main menu */
665#define MAIN_MENU_SIZE 2
666#define MENU_START 0
667#define MENU_QUIT 1
668static int game_menu (void)
669{
670 static char menu[MAIN_MENU_SIZE][15] = {
671 "Start New Game",
672 "Quit"
673 };
674
675 int button, selection = 0, sw, sh, i;
676 bool quit = false;
677 rb->lcd_getstringsize ("A", NULL, &sh);
678 rb->lcd_getstringsize ("XOBOX", &sw, NULL);
679 sh++;
680 rb->lcd_set_background (LCD_WHITE);
681 rb->lcd_clear_display ();
682 rb->lcd_putsxy (LCD_WIDTH / 2 - sw / 2, 2, "XOBOX");
683 while (!quit) {
684 for (i = 0; i < MAIN_MENU_SIZE; i++) {
685 rb->lcd_set_foreground ((i == selection ? LCD_WHITE : LCD_BLACK));
686 rb->lcd_set_background ((i == selection ? CLR_BLUE : LCD_WHITE));
687 rb->lcd_putsxy (9, sh + 4 + i * sh, menu[i]);
688 }
689 rb->lcd_update ();
690 button = rb->button_get (true);
691 switch (button) {
692 case UP:
693 selection = (selection + MAIN_MENU_SIZE - 1) % MAIN_MENU_SIZE;
694 break;
695 case DOWN:
696 selection = (selection + 1) % MAIN_MENU_SIZE;
697 break;
698 case SELECT:
699 case RIGHT:
700 quit = true;
701 break;
702 case QUIT:
703 selection = MENU_QUIT;
704 quit = true;
705 break;
706 }
707 }
708 return selection;
709}
710
711/* init game's variables */
712static void init_game (void)
713{
714 player.level = 0;
715 player.score = 0;
716 player.lives = 3;
717 player.gameover = false;
718 player.drawing = false;
719 init_board ();
720 refresh_board ();
721 rb->splash (HZ * 2, true, "READY?");
722 rb->lcd_update ();
723 refresh_board ();
724}
725
726/* general keypad handler loop */
727static int xobox_loop (void)
728{
729 int button = 0, ret;
730 bool pause = false;
731 int end;
732
733 while (!quit) {
734 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
735 button = rb->button_get_w_tmo (true);
736 switch (button) {
737 case UP:
738 player.move = MOVE_UP;
739 break;
740 case DOWN:
741 player.move = MOVE_DN;
742 break;
743 case LEFT:
744 player.move = MOVE_LT;
745 break;
746 case RIGHT:
747 player.move = MOVE_RT;
748 break;
749 case PAUSE:
750 pause = !pause;
751 if (pause)
752 rb->splash (HZ, true, "PAUSED");
753 break;
754 case QUIT:
755 quit = true;
756 return PLUGIN_OK;
757 break;
758 default:
759 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
760 return PLUGIN_USB_CONNECTED;
761 break;
762 }
763 if (!pause) {
764 move_board ();
765 refresh_board ();
766 }
767 if (player.gameover) {
768 rb->splash (HZ, true, "GAME OVER");
769 ret = game_menu ();
770 if (ret == MENU_START)
771 init_game ();
772 else
773 quit = true;
774 }
775
776 if (end > *rb->current_tick)
777 rb->sleep (end - *rb->current_tick);
778 else
779 rb->yield ();
780
781 } /* end while */
782 return PLUGIN_OK; /* for no warnings on compiling */
783}
784
785/* plugin main procedure */
786enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
787{
788 int ret;
789
790
791 (void) parameter;
792 rb = api;
793
794 rb->lcd_setfont (FONT_SYSFIXED);
795
796 /* Permanently enable the backlight (unless the user has turned it off) */
797 if (rb->global_settings->backlight_timeout > 0)
798 rb->backlight_set_timeout (1);
799
800 randomize ();
801 ret = game_menu ();
802 if (ret == MENU_START) {
803 init_game ();
804 ret = xobox_loop ();
805 return ret;
806 }
807
808 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
809 rb->lcd_setfont (FONT_UI);
810
811
812 return PLUGIN_OK;
813}
diff --git a/docs/CREDITS b/docs/CREDITS
index e6fcf916e6..85550b20c6 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -182,3 +182,4 @@ Naoaki Okazaki
182Will Dyson 182Will Dyson
183Matthias Mohr 183Matthias Mohr
184Christian Marg 184Christian Marg
185Eli Sherer