1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Eli Sherer
11 * 2007 Antoine Cellerier
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #include "lib/helper.h"
25 #include "lib/playback_control.h"
29 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
31 #define QUIT BUTTON_OFF
32 #define LEFT BUTTON_LEFT
33 #define RIGHT BUTTON_RIGHT
34 #define PAUSE BUTTON_MODE
36 #define DOWN BUTTON_DOWN
38 #define RC_QUIT BUTTON_RC_STOP
40 #elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
42 #define QUIT BUTTON_OFF
43 #define LEFT BUTTON_LEFT
44 #define RIGHT BUTTON_RIGHT
45 #define PAUSE BUTTON_ON
47 #define DOWN BUTTON_DOWN
49 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
50 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
53 #define QUIT (BUTTON_SELECT | BUTTON_MENU)
54 #define LEFT BUTTON_LEFT
55 #define RIGHT BUTTON_RIGHT
56 #define PAUSE BUTTON_SELECT
57 #define MENU_UP BUTTON_SCROLL_FWD
58 #define MENU_DOWN BUTTON_SCROLL_BACK
59 #define UP BUTTON_MENU
60 #define DOWN BUTTON_PLAY
62 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
64 #define QUIT BUTTON_POWER
65 #define LEFT BUTTON_LEFT
66 #define RIGHT BUTTON_RIGHT
68 #define DOWN BUTTON_DOWN
69 #define PAUSE BUTTON_PLAY
71 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
73 #define QUIT BUTTON_POWER
74 #define LEFT BUTTON_LEFT
75 #define RIGHT BUTTON_RIGHT
77 #define DOWN BUTTON_DOWN
78 #define PAUSE BUTTON_A
80 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
81 (CONFIG_KEYPAD == SANSA_C200_PAD)
83 #define QUIT BUTTON_POWER
84 #define LEFT BUTTON_LEFT
85 #define RIGHT BUTTON_RIGHT
87 #define DOWN BUTTON_DOWN
88 #define PAUSE BUTTON_REC
90 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
92 #define QUIT BUTTON_POWER
93 #define LEFT BUTTON_LEFT
94 #define RIGHT BUTTON_RIGHT
96 #define DOWN BUTTON_DOWN
97 #define PAUSE BUTTON_HOME
99 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
101 #define QUIT (BUTTON_HOME|BUTTON_REPEAT)
102 #define LEFT BUTTON_LEFT
103 #define RIGHT BUTTON_RIGHT
105 #define DOWN BUTTON_DOWN
106 #define PAUSE BUTTON_SELECT
108 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
110 #define QUIT BUTTON_POWER
111 #define LEFT BUTTON_LEFT
112 #define RIGHT BUTTON_RIGHT
114 #define DOWN BUTTON_DOWN
115 #define PAUSE BUTTON_SELECT
117 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
119 #define QUIT BUTTON_POWER
120 #define LEFT BUTTON_LEFT
121 #define RIGHT BUTTON_RIGHT
122 #define UP BUTTON_SCROLL_UP
123 #define DOWN BUTTON_SCROLL_DOWN
124 #define PAUSE BUTTON_PLAY
126 #elif CONFIG_KEYPAD == RECORDER_PAD
128 #define QUIT BUTTON_OFF
129 #define LEFT BUTTON_LEFT
130 #define RIGHT BUTTON_RIGHT
131 #define DOWN BUTTON_DOWN
133 #define PAUSE BUTTON_PLAY
135 #elif CONFIG_KEYPAD == ONDIO_PAD
137 #define QUIT BUTTON_OFF
138 #define LEFT BUTTON_LEFT
139 #define RIGHT BUTTON_RIGHT
140 #define DOWN BUTTON_DOWN
142 #define PAUSE BUTTON_MENU
144 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
146 #define QUIT BUTTON_BACK
147 #define LEFT BUTTON_LEFT
148 #define RIGHT BUTTON_RIGHT
150 #define DOWN BUTTON_DOWN
151 #define PAUSE BUTTON_PLAY
153 #elif (CONFIG_KEYPAD == MROBE100_PAD)
155 #define QUIT BUTTON_POWER
156 #define LEFT BUTTON_LEFT
157 #define RIGHT BUTTON_RIGHT
159 #define DOWN BUTTON_DOWN
160 #define PAUSE BUTTON_DISPLAY
162 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
164 #define QUIT BUTTON_RC_REC
165 #define LEFT BUTTON_RC_REW
166 #define RIGHT BUTTON_RC_FF
167 #define UP BUTTON_RC_VOL_UP
168 #define DOWN BUTTON_RC_VOL_DOWN
169 #define PAUSE BUTTON_RC_PLAY
171 #elif CONFIG_KEYPAD == COWON_D2_PAD
173 #define QUIT BUTTON_POWER
175 #elif CONFIG_KEYPAD == IAUDIO67_PAD
177 #define QUIT BUTTON_POWER
178 #define LEFT BUTTON_LEFT
179 #define RIGHT BUTTON_RIGHT
180 #define UP BUTTON_STOP
181 #define DOWN BUTTON_PLAY
182 #define PAUSE BUTTON_MENU
184 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
186 #define QUIT BUTTON_BACK
187 #define LEFT BUTTON_LEFT
188 #define RIGHT BUTTON_RIGHT
190 #define DOWN BUTTON_DOWN
191 #define PAUSE BUTTON_PLAY
193 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
195 #define QUIT BUTTON_POWER
196 #define LEFT BUTTON_LEFT
197 #define RIGHT BUTTON_RIGHT
199 #define DOWN BUTTON_DOWN
200 #define PAUSE BUTTON_VIEW
202 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
204 #define QUIT BUTTON_POWER
205 #define LEFT BUTTON_PREV
206 #define RIGHT BUTTON_NEXT
208 #define DOWN BUTTON_DOWN
209 #define PAUSE BUTTON_MENU
211 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
213 #define QUIT BUTTON_POWER
214 #define LEFT BUTTON_PREV
215 #define RIGHT BUTTON_NEXT
217 #define DOWN BUTTON_DOWN
218 #define PAUSE BUTTON_MENU
220 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
221 CONFIG_KEYPAD == ONDAVX777_PAD || \
222 CONFIG_KEYPAD == MROBE500_PAD
224 #define QUIT BUTTON_POWER
226 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
228 #define QUIT BUTTON_PLAY
229 #define LEFT BUTTON_LEFT
230 #define RIGHT BUTTON_RIGHT
232 #define DOWN BUTTON_DOWN
233 #define PAUSE BUTTON_FFWD
235 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
237 #define QUIT BUTTON_REC
238 #define LEFT BUTTON_PREV
239 #define RIGHT BUTTON_NEXT
241 #define DOWN BUTTON_DOWN
242 #define PAUSE BUTTON_PLAY
244 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
246 #define QUIT (BUTTON_REC|BUTTON_PLAY)
247 #define LEFT BUTTON_VOL_DOWN
248 #define RIGHT BUTTON_VOL_UP
249 #define UP BUTTON_REW
250 #define DOWN BUTTON_FF
251 #define PAUSE BUTTON_PLAY
253 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
255 #define QUIT (BUTTON_MENU | BUTTON_REPEAT)
256 #define LEFT BUTTON_REW
257 #define RIGHT BUTTON_FF
259 #define DOWN BUTTON_DOWN
260 #define PAUSE BUTTON_PLAY
262 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
264 #define QUIT BUTTON_POWER
265 #define LEFT BUTTON_LEFT
266 #define RIGHT BUTTON_RIGHT
268 #define DOWN BUTTON_DOWN
269 #define PAUSE BUTTON_PLAYPAUSE
271 #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
273 #define QUIT BUTTON_POWER
274 #define LEFT BUTTON_LEFT
275 #define RIGHT BUTTON_RIGHT
277 #define DOWN BUTTON_DOWN
278 #define PAUSE BUTTON_SELECT
280 #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
282 #define QUIT BUTTON_BACK
283 #define LEFT BUTTON_LEFT
284 #define RIGHT BUTTON_RIGHT
286 #define DOWN BUTTON_DOWN
287 #define PAUSE BUTTON_SELECT
289 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
290 (CONFIG_KEYPAD == HM801_PAD)
292 #define QUIT BUTTON_POWER
293 #define LEFT BUTTON_LEFT
294 #define RIGHT BUTTON_RIGHT
296 #define DOWN BUTTON_DOWN
297 #define PAUSE BUTTON_SELECT
300 #error No keymap defined!
303 #ifdef HAVE_TOUCHSCREEN
305 #define QUIT BUTTON_TOPLEFT
308 #define LEFT BUTTON_MIDLEFT
311 #define RIGHT BUTTON_MIDRIGHT
314 #define UP BUTTON_TOPMIDDLE
317 #define DOWN BUTTON_BOTTOMMIDDLE
320 #define PAUSE BUTTON_CENTER
324 #define MOVE_NO 0 /* player movement */
325 #define MOVE_UP 1 /* 1 */
326 #define MOVE_DN 2 /* 3 0 4 */
327 #define MOVE_LT 3 /* 2 */
330 /* ball movement (12 ways) */
338 #define DIR_UU (1<<7)
340 #define DIR_RR (1<<5)
342 #define DIR_DD (1<<3)
344 #define DIR_LL (1<<1)
347 #define MOVE_UUR ( DIR_UU | DIR_R )
348 #define MOVE_UR ( DIR_U | DIR_R )
349 #define MOVE_URR ( DIR_U | DIR_RR )
350 #define MOVE_DRR ( DIR_D | DIR_RR )
351 #define MOVE_DR ( DIR_D | DIR_R )
352 #define MOVE_DDR ( DIR_DD | DIR_R )
353 #define MOVE_DDL ( DIR_DD | DIR_L )
354 #define MOVE_DL ( DIR_D | DIR_L )
355 #define MOVE_DLL ( DIR_D | DIR_LL )
356 #define MOVE_ULL ( DIR_U | DIR_LL )
357 #define MOVE_UL ( DIR_U | DIR_L )
358 #define MOVE_UUL ( DIR_UU | DIR_L )
360 #if (LCD_WIDTH>112) && (LCD_HEIGHT>64)
361 # define CUBE_SIZE 8 /* 8x22=176 */
362 # define pos(a) ((a)>>3)
365 # define pos(a) ((a)>>2)
368 #define STARTING_QIXES 2
370 #define MAX_QIXES MAX_LEVEL+STARTING_QIXES
371 #define BOARD_W ((int)(LCD_WIDTH/CUBE_SIZE))
372 #define BOARD_H ((int)(LCD_HEIGHT/CUBE_SIZE))
373 #define BOARD_X (LCD_WIDTH-BOARD_W*CUBE_SIZE)/2
374 #define BOARD_Y (LCD_HEIGHT-BOARD_H*CUBE_SIZE)/2
376 #ifdef HAVE_LCD_COLOR
377 #define CLR_RED LCD_RGBPACK(255,0,0) /* used to imply danger */
378 #define CLR_LTBLUE LCD_RGBPACK(125, 145, 180) /* used for frame and filling */
379 #define PLR_COL LCD_WHITE /* color used for the player */
381 #define CLR_RED LCD_DARKGRAY /* used to imply danger */
382 #define CLR_LTBLUE LCD_LIGHTGRAY /* used for frame and filling */
383 #define PLR_COL LCD_BLACK /* color used for the player */
387 #define EMPTIED LCD_BLACK /* empty spot */
388 #define FILLED CLR_LTBLUE /* filled spot */
389 #define TRAIL CLR_RED /* the red trail of the player */
390 #define QIX LCD_WHITE
403 /* The time (in ms) for one iteration through the game loop - decrease this
404 to speed up the game - note that current_tick is (currently) only accurate
407 static int speed
= 6; /* CYCLETIME = (11-speed)*10 ms */
408 static int difficulty
= 75; /* Percentage of screen that needs to be filled
409 * in order to win the game */
411 static bool quit
= false;
413 static unsigned int board
[BOARD_H
][BOARD_W
];
414 static int testboard
[BOARD_H
][BOARD_W
];
418 00011000 0x18 - 11100111 0xe7
419 00111100 0x3c - 11100111 0xe7
420 01111110 0x7e - 11000011 0xc3
421 11111111 0xff - 00000000 0x00
422 11111111 0xff - 00000000 0x00
423 01111110 0x7e - 11000011 0xc3
424 00111100 0x3c - 11100111 0xe7
425 00011000 0x18 - 11100111 0xe7
427 const unsigned char pics
[2][8] = {
428 {0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18}, /* Alien (QIX) */
429 {0xe7, 0xe7, 0xc3, 0x00, 0x00, 0xc3, 0xe7, 0xe7} /* Player (XONIX) */
438 const unsigned char pics
[2][4] = {
439 {0x6, 0xf, 0xf, 0x6}, /* Alien (QIX) */
440 {0x9, 0x6, 0x6, 0x9} /* Player (XONIX) */
443 #error Incorrect CUBE_SIZE value.
448 int velocity
; /* velocity */
449 int x
, y
; /* position on screen */
450 int angle
; /* angle */
451 } qixes
[MAX_QIXES
]; /* black_qix */
453 static struct splayer
455 int i
, j
; /* position on board */
456 int move
, score
, level
, lives
;
461 static int percentage_cache
;
463 /*************************** STACK STUFF **********************/
466 #define STACK_SIZE (2*BOARD_W*BOARD_H)
469 int x
, y
; /* position on board */
471 static int stackPointer
;
473 static inline bool pop (struct pos
*p
)
475 if (stackPointer
> 0) {
476 p
->x
= stack
[stackPointer
].x
;
477 p
->y
= stack
[stackPointer
].y
;
481 return false; /* SE */
484 static inline bool push (struct pos
*p
)
486 if (stackPointer
< STACK_SIZE
- 1) {
488 stack
[stackPointer
].x
= p
->x
;
489 stack
[stackPointer
].y
= p
->y
;
492 return false; /* SOF */
495 static inline void emptyStack (void)
500 /*********************** END OF STACK STUFF *********************/
502 /* calculate the new x coordinate of the ball according to angle and speed */
503 static inline int get_newx (int x
, int len
, int deg
)
507 else if (deg
& DIR_L
)
509 else if (deg
& DIR_RR
)
511 else /* (def & DIR_LL) */
515 /* calculate the new y coordinate of the ball according to angle and speed */
516 static inline int get_newy (int y
, int len
, int deg
)
520 else if (deg
& DIR_U
)
522 else if (deg
& DIR_DD
)
524 else /* (deg & DIR_UU) */
528 /* make random function get it's value from the device ticker */
529 static inline void randomize (void)
531 rb
->srand (*rb
->current_tick
);
534 /* get a random number between 0 and range-1 */
535 static int t_rand (int range
)
537 return rb
->rand () % range
;
540 /* initializes the test help board */
541 static void init_testboard (void)
543 int j
; /* testboard */
544 for (j
= 0; j
< BOARD_H
; j
++)
545 /* UNCHEKED == (int)0 */
546 rb
->memset( testboard
[j
], 0, BOARD_W
* sizeof( int ) );
549 /* initializes the game board on with the player,qix's and black qix */
550 static void init_board (void)
553 for (j
= 0; j
< BOARD_H
; j
++)
554 for (i
= 0; i
< BOARD_W
; i
++) { /* make a nice cyan frame */
555 if ((i
== 0) || (j
<= 1) || (i
== BOARD_W
- 1)
556 || (j
>= BOARD_H
- 2))
557 board
[j
][i
] = FILLED
;
559 board
[j
][i
] = EMPTIED
;
562 /* (level+2) is the number of qixes */
563 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++) {
564 qixes
[j
].velocity
= t_rand (2) + 1; /* 1 or 2 pix-per-sec */
567 qixes
[j
].x
= CUBE_SIZE
*2 + 2*t_rand (((BOARD_W
-4)*CUBE_SIZE
)/2);
568 qixes
[j
].y
= CUBE_SIZE
*2 + 2*t_rand (((BOARD_H
-4)*CUBE_SIZE
)/2);
570 const int angle_table
[] = {
571 MOVE_UUR
, MOVE_UR
, MOVE_URR
, MOVE_DRR
, MOVE_DR
, MOVE_DDR
,
572 MOVE_UUL
, MOVE_UL
, MOVE_ULL
, MOVE_DLL
, MOVE_DL
, MOVE_DDL
};
573 qixes
[j
].angle
= angle_table
[t_rand (12)];
575 /* Work arround a nasty bug. FIXME */
576 if( qixes
[j
].angle
& (DIR_LL
|DIR_RR
|DIR_UU
|DIR_DD
) )
577 qixes
[j
].velocity
= 1;
580 /*black_qix.velocity=1;
581 black_qix.x=BOARD_X+(BOARD_W*CUBE_SIZE)/2-CUBE_SIZE/2;
582 black_qix.y=BOARD_Y+(BOARD_H*CUBE_SIZE)-CUBE_SIZE-CUBE_SIZE/2;
583 black_qix.angle=MOVE_UR; */
584 player
.move
= MOVE_NO
;
585 player
.drawing
= false;
586 player
.i
= BOARD_W
/ 2;
589 percentage_cache
= 0;
592 /* calculates the percentage of the screen filling */
593 static int percentage (void)
595 int i
, j
, filled
= 0;
596 for (j
= 2; j
< BOARD_H
- 2; j
++)
597 for (i
= 1; i
< BOARD_W
- 1; i
++)
598 if (board
[j
][i
] == FILLED
)
600 return (filled
* 100) / ((BOARD_W
- 2) * (BOARD_H
- 4));
603 /* draw the board on with all the game figures */
604 static void refresh_board (void)
610 rb
->lcd_set_background (LCD_BLACK
);
612 rb
->lcd_clear_display ();
613 for (j
= 0; j
< BOARD_H
; j
++)
615 unsigned last_color
= board
[j
][0];
617 for (i
= 1; i
< BOARD_W
; i
++) {
618 if( last_color
!= board
[j
][i
] )
621 rb
->lcd_set_foreground (last_color
);
623 if (last_color
!= EMPTIED
)
625 rb
->lcd_fillrect (BOARD_X
+ CUBE_SIZE
* (last_i
),
626 BOARD_Y
+ CUBE_SIZE
* j
,
627 CUBE_SIZE
* (i
- last_i
), CUBE_SIZE
);
628 last_color
= board
[j
][i
];
633 rb
->lcd_set_foreground (last_color
);
635 if (last_color
!= EMPTIED
)
637 rb
->lcd_fillrect (BOARD_X
+ CUBE_SIZE
* (last_i
),
638 BOARD_Y
+ CUBE_SIZE
* j
,
639 CUBE_SIZE
* (i
- last_i
), CUBE_SIZE
);
643 rb
->lcd_set_foreground (LCD_BLACK
);
644 rb
->lcd_set_background (CLR_LTBLUE
);
646 rb
->lcd_set_drawmode (DRMODE_COMPLEMENT
);
648 rb
->lcd_putsxyf (BOARD_X
, BOARD_Y
, "Level %d", player
.level
+ 1);
649 rb
->lcd_putsxyf (BOARD_X
+ CUBE_SIZE
* BOARD_W
- 24, BOARD_Y
, "%d%%",
651 rb
->lcd_putsxyf (BOARD_X
, BOARD_Y
+ CUBE_SIZE
* BOARD_H
- 8, "Score: %d",
654 x
= BOARD_X
+ CUBE_SIZE
* BOARD_W
- 60;
656 x
= BOARD_X
+ CUBE_SIZE
* BOARD_W
- 40;
658 rb
->lcd_putsxyf (x
, BOARD_Y
+ CUBE_SIZE
* BOARD_H
- 8,
659 (player
.lives
!= 1) ? "%d Lives" : "%d Life", player
.lives
);
662 rb
->lcd_set_foreground (PLR_COL
);
663 rb
->lcd_set_background (board
[player
.j
][player
.i
]);
665 rb
->lcd_mono_bitmap (pics
[PIC_PLAYER
], player
.i
* CUBE_SIZE
+ BOARD_X
,
666 player
.j
* CUBE_SIZE
+ BOARD_Y
, CUBE_SIZE
, CUBE_SIZE
);
669 rb
->lcd_set_background (EMPTIED
);
670 rb
->lcd_set_foreground (LCD_WHITE
);
671 rb
->lcd_set_drawmode (DRMODE_FG
);
673 rb
->lcd_set_drawmode (DRMODE_FG
);
675 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++)
676 rb
->lcd_mono_bitmap (pics
[PIC_QIX
], qixes
[j
].x
+ BOARD_X
,
677 qixes
[j
].y
+ BOARD_Y
, CUBE_SIZE
, CUBE_SIZE
);
679 rb
->lcd_set_foreground (LCD_BLACK
);
681 rb
->lcd_set_drawmode (DRMODE_SOLID
);
686 static inline int infested_area (int i
, int j
, int v
)
695 if (testboard
[p
.y
][p
.x
] == v
) continue;
696 if (testboard
[p
.y
][p
.x
] > UNCHECKED
)
697 return 1; /* This area was previously flagged as infested */
698 testboard
[p
.y
][p
.x
] = v
;
699 if (board
[p
.y
][p
.x
] == QIX
)
700 return 1; /* Infested area */
702 struct pos p1
= { p
.x
+1, p
.y
};
704 && (board
[p1
.y
][p1
.x
] != FILLED
)
709 struct pos p1
= { p
.x
-1, p
.y
};
711 && (board
[p1
.y
][p1
.x
] != FILLED
)
716 struct pos p1
= { p
.x
, p
.y
+1 };
718 && (board
[p1
.y
][p1
.x
] != FILLED
)
723 struct pos p1
= { p
.x
, p
.y
-1 };
725 && (board
[p1
.y
][p1
.x
] != FILLED
)
733 static inline int fill_area (int i
, int j
)
738 int v
= testboard
[p
.y
][p
.x
];
743 board
[p
.y
][p
.x
] = FILLED
;
744 testboard
[p
.y
][p
.x
] = PAINTED
;
746 struct pos p1
= { p
.x
+1, p
.y
};
748 && (testboard
[p1
.y
][p1
.x
] == v
)
753 struct pos p1
= { p
.x
-1, p
.y
};
755 && (testboard
[p1
.y
][p1
.x
] == v
)
760 struct pos p1
= { p
.x
, p
.y
+1 };
762 && (testboard
[p1
.y
][p1
.x
] == v
)
767 struct pos p1
= { p
.x
, p
.y
-1 };
769 && (testboard
[p1
.y
][p1
.x
] == v
)
778 /* take care of stuff after xonix has landed on a filled spot */
779 static void complete_trail (int fill
)
782 for (j
= 0; j
< BOARD_H
; j
++) {
783 for (i
= 0; i
< BOARD_W
; i
++) {
784 if (board
[j
][i
] == TRAIL
) {
786 board
[j
][i
] = FILLED
;
788 board
[j
][i
] = EMPTIED
;
795 for (i
= 0; i
< player
.level
+ STARTING_QIXES
; i
++) /* add qixes to board */
796 board
[pos(qixes
[i
].y
- BOARD_Y
)]
797 [pos(qixes
[i
].x
- BOARD_X
)] = QIX
;
800 for (j
= 1; j
< BOARD_H
- 1; j
++) {
801 for (i
= 0; i
< BOARD_W
- 0; i
++) {
802 if (board
[j
][i
] != FILLED
) {
803 ret
= infested_area (i
, j
, v
);
804 if (ret
< 0 || ( ret
== 0 && fill_area (i
, j
) ) )
811 for (i
= 0; i
< player
.level
+ STARTING_QIXES
; i
++) /* add qixes to board */
812 board
[pos(qixes
[i
].y
- BOARD_Y
)]
813 [pos(qixes
[i
].x
- BOARD_X
)] = EMPTIED
;
814 percentage_cache
= percentage();
817 rb
->button_clear_queue();
820 /* returns the color the real pixel(x,y) on the lcd is pointing at */
821 static inline unsigned int getpixel (int x
, int y
)
823 const int a
= pos (x
- BOARD_X
), b
= pos (y
- BOARD_Y
);
824 if ((a
> 0) && (a
< BOARD_W
) && (b
> 0) && (b
< BOARD_H
)) /* if inside board */
830 /* returns the color the ball on (newx,newy) is heading at *----*
831 checks the four edge points of the square if 1st of all | |
832 are a trail (cause it's a lose life situation) and 2nd | |
833 if it's filled so it needs to bounce. *____*
835 static inline unsigned int next_hit (int newx
, int newy
)
837 if ((getpixel (newx
, newy
) == TRAIL
)
838 || (getpixel (newx
, newy
+ CUBE_SIZE
- 1) == TRAIL
)
839 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
) == TRAIL
)
840 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
+ CUBE_SIZE
- 1) == TRAIL
))
842 else if ((getpixel (newx
, newy
) == FILLED
)
843 || (getpixel (newx
, newy
+ CUBE_SIZE
- 1) == FILLED
)
844 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
) == FILLED
)
845 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
+ CUBE_SIZE
- 1) ==
852 static void die (void)
855 if (player
.lives
== 0)
856 player
.gameover
= true;
859 rb
->splash (HZ
, "Crash!");
860 complete_trail (false);
861 player
.move
= MOVE_NO
;
862 player
.drawing
= false;
863 player
.i
= BOARD_W
/ 2;
868 /* returns true if the (side) of the block -***-
869 starting from (newx,newy) has any filled pixels * *
872 static inline bool line_check_lt (int newx
, int newy
)
874 return getpixel (newx
, newy
+ CUBE_SIZE
/2-1) == FILLED
875 && getpixel (newx
, newy
+ CUBE_SIZE
/2 ) == FILLED
;
877 static inline bool line_check_rt (int newx
, int newy
)
879 return getpixel (newx
+ CUBE_SIZE
-1, newy
+ CUBE_SIZE
/2-1) == FILLED
880 && getpixel (newx
+ CUBE_SIZE
-1, newy
+ CUBE_SIZE
/2 ) == FILLED
;
882 static inline bool line_check_up (int newx
, int newy
)
884 return getpixel (newx
+ CUBE_SIZE
/2-1, newy
) == FILLED
885 && getpixel (newx
+ CUBE_SIZE
/2 , newy
) == FILLED
;
887 static inline bool line_check_dn (int newx
, int newy
)
889 return getpixel (newx
+ CUBE_SIZE
/2-1, newy
+ CUBE_SIZE
-1) == FILLED
890 && getpixel (newx
+ CUBE_SIZE
/2 , newy
+ CUBE_SIZE
-1) == FILLED
;
893 static inline void move_qix (struct qix
*q
)
896 newx
= get_newx (q
->x
, q
->velocity
, q
->angle
);
897 newy
= get_newy (q
->y
, q
->velocity
, q
->angle
);
898 switch (next_hit (newx
, newy
))
906 const int a
= q
->angle
;
909 ? (line_check_up (newx
, newy
) ? ((a
&(DIR_UU
|DIR_U
))>>4)
910 : (a
&(DIR_UU
|DIR_U
)))
914 ? (line_check_rt (newx
, newy
) ? ((a
&(DIR_RR
|DIR_R
))>>4)
915 : (a
&(DIR_RR
|DIR_R
)))
919 ? (line_check_dn (newx
, newy
) ? ((a
&(DIR_DD
|DIR_D
))<<4)
920 : (a
&(DIR_DD
|DIR_D
)))
924 ? (line_check_lt (newx
, newy
) ? ((a
&(DIR_LL
|DIR_L
))<<4)
925 : (a
&(DIR_LL
|DIR_L
)))
927 q
->x
= get_newx (q
->x
, q
->velocity
, q
->angle
);
928 q
->y
= get_newy (q
->y
, q
->velocity
, q
->angle
);
937 /* move the board forward timewise */
938 static inline void move_board (void)
942 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++)
943 move_qix (&qixes
[j
]);
944 /* move_qix(&black_qix,true); */
948 switch (player
.move
) {
954 if (player
.j
< BOARD_H
- 2)
962 if (player
.i
< BOARD_W
- 1)
969 if ((player
.drawing
) && (board
[newj
][newi
] == EMPTIED
)) /* continue drawing */
970 board
[newj
][newi
] = TRAIL
;
971 else if ((player
.drawing
) && (board
[newj
][newi
] == FILLED
)) { /* finish drawing */
972 player
.move
= MOVE_NO
; /* stop moving */
973 player
.drawing
= false;
974 complete_trail (true);
975 } else if ((board
[player
.j
][player
.i
] == FILLED
)
976 && (board
[newj
][newi
] == EMPTIED
)) {
978 player
.drawing
= true;
979 board
[newj
][newi
] = TRAIL
;
980 /* if the block after next is empty and we're moving onto filled, stop */
981 } else if ((board
[newj
][newi
] == FILLED
)
982 && (board
[newj
+ newj
-player
.j
][newi
+ newi
-player
.i
] == EMPTIED
)) {
983 player
.move
= MOVE_NO
;
988 if (percentage_cache
>= difficulty
) { /* finished level */
990 rb
->splashf (HZ
* 2, "Level %d finished", player
.level
+1);
991 player
.score
+= percentage_cache
;
992 if (player
.level
< MAX_LEVEL
)
996 rb
->button_clear_queue();
997 rb
->splash (HZ
* 2, "Ready?");
1001 /* init game's variables */
1002 static void init_game (void)
1007 player
.gameover
= false;
1008 player
.drawing
= false;
1011 rb
->splash (HZ
* 2, "Ready?");
1015 static bool _ingame
;
1016 static int xobox_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1018 if(action
== ACTION_REQUEST_MENUITEM
1019 && !_ingame
&& ((intptr_t)this_item
)==0)
1020 return ACTION_EXIT_MENUITEM
;
1024 static int xobox_menu(bool ingame
)
1026 rb
->button_clear_queue();
1029 MENUITEM_STRINGLIST(main_menu
, "Xobox Menu", xobox_menu_cb
,
1030 "Resume Game", "Start New Game",
1031 "Speed", "Difficulty",
1032 "Playback Control", "Quit");
1036 switch (rb
->do_menu(&main_menu
, &selection
, NULL
, false)) {
1043 rb
->set_int ("Speed", "", UNIT_INT
, &speed
, NULL
, 1, 1, 10, NULL
);
1046 rb
->set_int ("Difficulty", "", UNIT_INT
, &difficulty
, NULL
,
1050 playback_control(NULL
);
1054 case MENU_ATTACHED_USB
:
1062 /* general keypad handler loop */
1063 static int xobox_loop (void)
1069 if (xobox_menu(false)) {
1074 end
= *rb
->current_tick
+ ((11-speed
)*HZ
)/100;
1076 #ifdef HAS_BUTTON_HOLD
1077 if (rb
->button_hold()) {
1079 rb
->splash (HZ
, "Paused");
1083 button
= rb
->button_get_w_tmo (1);
1086 case UP
|BUTTON_REPEAT
:
1087 player
.move
= MOVE_UP
;
1090 case DOWN
|BUTTON_REPEAT
:
1091 player
.move
= MOVE_DN
;
1094 case LEFT
|BUTTON_REPEAT
:
1095 player
.move
= MOVE_LT
;
1098 case RIGHT
|BUTTON_REPEAT
:
1099 player
.move
= MOVE_RT
;
1104 rb
->splash (HZ
, "Paused");
1108 if (xobox_menu(true)) {
1114 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1115 return PLUGIN_USB_CONNECTED
;
1122 if (player
.gameover
) {
1123 rb
->splash (HZ
, "Game Over!");
1124 if (xobox_menu(false)) {
1129 if (TIME_BEFORE(*rb
->current_tick
, end
))
1130 rb
->sleep (end
- *rb
->current_tick
);
1135 return PLUGIN_OK
; /* for no warnings on compiling */
1138 /* plugin main procedure */
1139 enum plugin_status
plugin_start (const void *parameter
)
1141 int ret
= PLUGIN_OK
;
1145 rb
->lcd_setfont (FONT_SYSFIXED
);
1147 rb
->lcd_set_backdrop(NULL
);
1150 /* Turn off backlight timeout */
1151 backlight_ignore_timeout();
1154 ret
= xobox_loop ();
1156 /* Turn on backlight timeout (revert to settings) */
1157 backlight_use_settings();
1158 rb
->lcd_setfont (FONT_UI
);