1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Eli Sherer
11 * 2007 Antoine Cellerier
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
26 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
28 #define QUIT BUTTON_OFF
29 #define LEFT BUTTON_LEFT
30 #define RIGHT BUTTON_RIGHT
31 #define PAUSE BUTTON_MODE
33 #define DOWN BUTTON_DOWN
35 #define RC_QUIT BUTTON_RC_STOP
37 #elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
39 #define QUIT BUTTON_OFF
40 #define LEFT BUTTON_LEFT
41 #define RIGHT BUTTON_RIGHT
42 #define PAUSE BUTTON_ON
44 #define DOWN BUTTON_DOWN
46 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
47 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
48 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
50 #define QUIT (BUTTON_SELECT | BUTTON_MENU)
51 #define LEFT BUTTON_LEFT
52 #define RIGHT BUTTON_RIGHT
53 #define PAUSE BUTTON_SELECT
54 #define MENU_UP BUTTON_SCROLL_FWD
55 #define MENU_DOWN BUTTON_SCROLL_BACK
56 #define UP BUTTON_MENU
57 #define DOWN BUTTON_PLAY
59 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
61 #define QUIT BUTTON_POWER
62 #define LEFT BUTTON_LEFT
63 #define RIGHT BUTTON_RIGHT
65 #define DOWN BUTTON_DOWN
66 #define PAUSE BUTTON_PLAY
68 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
70 #define QUIT BUTTON_POWER
71 #define LEFT BUTTON_LEFT
72 #define RIGHT BUTTON_RIGHT
74 #define DOWN BUTTON_DOWN
75 #define PAUSE BUTTON_A
77 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
78 (CONFIG_KEYPAD == SANSA_C200_PAD)
80 #define QUIT BUTTON_POWER
81 #define LEFT BUTTON_LEFT
82 #define RIGHT BUTTON_RIGHT
84 #define DOWN BUTTON_DOWN
85 #define PAUSE BUTTON_REC
88 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
90 #define QUIT BUTTON_POWER
91 #define LEFT BUTTON_LEFT
92 #define RIGHT BUTTON_RIGHT
93 #define UP BUTTON_SCROLL_UP
94 #define DOWN BUTTON_SCROLL_DOWN
95 #define PAUSE BUTTON_PLAY
97 #elif CONFIG_KEYPAD == RECORDER_PAD
99 #define QUIT BUTTON_OFF
100 #define LEFT BUTTON_LEFT
101 #define RIGHT BUTTON_RIGHT
102 #define DOWN BUTTON_DOWN
104 #define PAUSE BUTTON_PLAY
106 #elif CONFIG_KEYPAD == ONDIO_PAD
108 #define QUIT BUTTON_OFF
109 #define LEFT BUTTON_LEFT
110 #define RIGHT BUTTON_RIGHT
111 #define DOWN BUTTON_DOWN
113 #define PAUSE BUTTON_MENU
115 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
117 #define QUIT BUTTON_BACK
118 #define LEFT BUTTON_LEFT
119 #define RIGHT BUTTON_RIGHT
121 #define DOWN BUTTON_DOWN
122 #define PAUSE BUTTON_PLAY
124 #elif (CONFIG_KEYPAD == MROBE100_PAD)
126 #define QUIT BUTTON_POWER
127 #define LEFT BUTTON_LEFT
128 #define RIGHT BUTTON_RIGHT
130 #define DOWN BUTTON_DOWN
131 #define PAUSE BUTTON_DISPLAY
133 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
135 #define QUIT BUTTON_RC_REC
136 #define LEFT BUTTON_RC_REW
137 #define RIGHT BUTTON_RC_FF
138 #define UP BUTTON_RC_VOL_UP
139 #define DOWN BUTTON_RC_VOL_DOWN
140 #define PAUSE BUTTON_RC_PLAY
142 #elif CONFIG_KEYPAD == COWOND2_PAD
144 #define QUIT BUTTON_POWER
147 #error No keymap defined!
152 #define QUIT BUTTON_TOPLEFT
155 #define LEFT BUTTON_MIDLEFT
158 #define RIGHT BUTTON_MIDRIGHT
161 #define UP BUTTON_TOPMIDDLE
164 #define DOWN BUTTON_BOTTOMMIDDLE
167 #define PAUSE BUTTON_CENTER
171 #define MOVE_NO 0 /* player movement */
172 #define MOVE_UP 1 /* 1 */
173 #define MOVE_DN 2 /* 3 0 4 */
174 #define MOVE_LT 3 /* 2 */
177 /* ball movement (12 ways) */
185 #define DIR_UU (1<<7)
187 #define DIR_RR (1<<5)
189 #define DIR_DD (1<<3)
191 #define DIR_LL (1<<1)
194 #define MOVE_UUR ( DIR_UU | DIR_R )
195 #define MOVE_UR ( DIR_U | DIR_R )
196 #define MOVE_URR ( DIR_U | DIR_RR )
197 #define MOVE_DRR ( DIR_D | DIR_RR )
198 #define MOVE_DR ( DIR_D | DIR_R )
199 #define MOVE_DDR ( DIR_DD | DIR_R )
200 #define MOVE_DDL ( DIR_DD | DIR_L )
201 #define MOVE_DL ( DIR_D | DIR_L )
202 #define MOVE_DLL ( DIR_D | DIR_LL )
203 #define MOVE_ULL ( DIR_U | DIR_LL )
204 #define MOVE_UL ( DIR_U | DIR_L )
205 #define MOVE_UUL ( DIR_UU | DIR_L )
207 #if (LCD_WIDTH>112) && (LCD_HEIGHT>64)
208 # define CUBE_SIZE 8 /* 8x22=176 */
209 # define pos(a) ((a)>>3)
212 # define pos(a) ((a)>>2)
215 #define STARTING_QIXES 2
217 #define MAX_QIXES MAX_LEVEL+STARTING_QIXES
218 #define BOARD_W ((int)(LCD_WIDTH/CUBE_SIZE))
219 #define BOARD_H ((int)(LCD_HEIGHT/CUBE_SIZE))
220 #define BOARD_X (LCD_WIDTH-BOARD_W*CUBE_SIZE)/2
221 #define BOARD_Y (LCD_HEIGHT-BOARD_H*CUBE_SIZE)/2
223 #ifdef HAVE_LCD_COLOR
224 #define CLR_RED LCD_RGBPACK(255,0,0) /* used to imply danger */
225 #define CLR_LTBLUE LCD_RGBPACK(125, 145, 180) /* used for frame and filling */
226 #define PLR_COL LCD_WHITE /* color used for the player */
228 #define CLR_RED LCD_DARKGRAY /* used to imply danger */
229 #define CLR_LTBLUE LCD_LIGHTGRAY /* used for frame and filling */
230 #define PLR_COL LCD_BLACK /* color used for the player */
234 #define EMPTIED LCD_BLACK /* empty spot */
235 #define FILLED CLR_LTBLUE /* filled spot */
236 #define TRAIL CLR_RED /* the red trail of the player */
237 #define QIX LCD_WHITE
253 /* The time (in ms) for one iteration through the game loop - decrease this
254 to speed up the game - note that current_tick is (currently) only accurate
257 static int speed
= 6; /* CYCLETIME = (11-speed)*10 ms */
258 static int difficulty
= 75; /* Percentage of screen that needs to be filled
259 * in order to win the game */
261 static struct plugin_api
*rb
;
263 MEM_FUNCTION_WRAPPERS(rb
);
265 static bool quit
= false;
267 static unsigned int board
[BOARD_H
][BOARD_W
];
268 static int testboard
[BOARD_H
][BOARD_W
];
272 00011000 0x18 - 11100111 0xe7
273 00111100 0x3c - 11100111 0xe7
274 01111110 0x7e - 11000011 0xc3
275 11111111 0xff - 00000000 0x00
276 11111111 0xff - 00000000 0x00
277 01111110 0x7e - 11000011 0xc3
278 00111100 0x3c - 11100111 0xe7
279 00011000 0x18 - 11100111 0xe7
281 const unsigned char pics
[2][8] = {
282 {0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18}, /* Alien (QIX) */
283 {0xe7, 0xe7, 0xc3, 0x00, 0x00, 0xc3, 0xe7, 0xe7} /* Player (XONIX) */
292 const unsigned char pics
[2][4] = {
293 {0x6, 0xf, 0xf, 0x6}, /* Alien (QIX) */
294 {0x9, 0x6, 0x6, 0x9} /* Player (XONIX) */
297 #error Incorrect CUBE_SIZE value.
302 int velocity
; /* velocity */
303 int x
, y
; /* position on screen */
304 int angle
; /* angle */
305 } qixes
[MAX_QIXES
]; /* black_qix */
307 static struct splayer
309 int i
, j
; /* position on board */
310 int move
, score
, level
, lives
;
315 static int percentage_cache
;
317 /*************************** STACK STUFF **********************/
320 #define STACK_SIZE (2*BOARD_W*BOARD_H)
323 int x
, y
; /* position on board */
325 static int stackPointer
;
327 static inline bool pop (struct pos
*p
)
329 if (stackPointer
> 0) {
330 p
->x
= stack
[stackPointer
].x
;
331 p
->y
= stack
[stackPointer
].y
;
335 return false; /* SE */
338 static inline bool push (struct pos
*p
)
340 if (stackPointer
< STACK_SIZE
- 1) {
342 stack
[stackPointer
].x
= p
->x
;
343 stack
[stackPointer
].y
= p
->y
;
346 return false; /* SOF */
349 static inline void emptyStack (void)
354 /*********************** END OF STACK STUFF *********************/
356 /* calculate the new x coordinate of the ball according to angle and speed */
357 static inline int get_newx (int x
, int len
, int deg
)
361 else if (deg
& DIR_L
)
363 else if (deg
& DIR_RR
)
365 else /* (def & DIR_LL) */
369 /* calculate the new y coordinate of the ball according to angle and speed */
370 static inline int get_newy (int y
, int len
, int deg
)
374 else if (deg
& DIR_U
)
376 else if (deg
& DIR_DD
)
378 else /* (deg & DIR_UU) */
382 /* make random function get it's value from the device ticker */
383 static inline void randomize (void)
385 rb
->srand (*rb
->current_tick
);
388 /* get a random number between 0 and range-1 */
389 static int t_rand (int range
)
391 return rb
->rand () % range
;
394 /* initializes the test help board */
395 static void init_testboard (void)
397 int j
; /* testboard */
398 for (j
= 0; j
< BOARD_H
; j
++)
399 /* UNCHEKED == (int)0 */
400 rb
->memset( testboard
[j
], 0, BOARD_W
* sizeof( int ) );
403 /* initializes the game board on with the player,qix's and black qix */
404 static void init_board (void)
407 for (j
= 0; j
< BOARD_H
; j
++)
408 for (i
= 0; i
< BOARD_W
; i
++) { /* make a nice cyan frame */
409 if ((i
== 0) || (j
<= 1) || (i
== BOARD_W
- 1)
410 || (j
>= BOARD_H
- 2))
411 board
[j
][i
] = FILLED
;
413 board
[j
][i
] = EMPTIED
;
416 /* (level+2) is the number of qixes */
417 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++) {
418 qixes
[j
].velocity
= t_rand (2) + 1; /* 1 or 2 pix-per-sec */
421 qixes
[j
].x
= CUBE_SIZE
*2 + 2*t_rand (((BOARD_W
-4)*CUBE_SIZE
)/2);
422 qixes
[j
].y
= CUBE_SIZE
*2 + 2*t_rand (((BOARD_H
-4)*CUBE_SIZE
)/2);
424 const int angle_table
[] = {
425 MOVE_UUR
, MOVE_UR
, MOVE_URR
, MOVE_DRR
, MOVE_DR
, MOVE_DDR
,
426 MOVE_UUL
, MOVE_UL
, MOVE_ULL
, MOVE_DLL
, MOVE_DL
, MOVE_DDL
};
427 qixes
[j
].angle
= angle_table
[t_rand (12)];
429 /* Work arround a nasty bug. FIXME */
430 if( qixes
[j
].angle
& (DIR_LL
|DIR_RR
|DIR_UU
|DIR_DD
) )
431 qixes
[j
].velocity
= 1;
434 /*black_qix.velocity=1;
435 black_qix.x=BOARD_X+(BOARD_W*CUBE_SIZE)/2-CUBE_SIZE/2;
436 black_qix.y=BOARD_Y+(BOARD_H*CUBE_SIZE)-CUBE_SIZE-CUBE_SIZE/2;
437 black_qix.angle=MOVE_UR; */
438 player
.move
= MOVE_NO
;
439 player
.drawing
= false;
440 player
.i
= BOARD_W
/ 2;
443 percentage_cache
= 0;
446 /* calculates the percentage of the screen filling */
447 static int percentage (void)
449 int i
, j
, filled
= 0;
450 for (j
= 2; j
< BOARD_H
- 2; j
++)
451 for (i
= 1; i
< BOARD_W
- 1; i
++)
452 if (board
[j
][i
] == FILLED
)
454 return (filled
* 100) / ((BOARD_W
- 2) * (BOARD_H
- 4));
457 /* draw the board on with all the game figures */
458 static void refresh_board (void)
464 rb
->lcd_set_background (LCD_BLACK
);
466 rb
->lcd_clear_display ();
468 for (j
= 0; j
< BOARD_H
; j
++)
470 unsigned last_color
= board
[j
][0];
472 for (i
= 1; i
< BOARD_W
; i
++) {
473 if( last_color
!= board
[j
][i
] )
476 rb
->lcd_set_foreground (last_color
);
478 if (last_color
!= EMPTIED
)
480 rb
->lcd_fillrect (BOARD_X
+ CUBE_SIZE
* (last_i
),
481 BOARD_Y
+ CUBE_SIZE
* j
,
482 CUBE_SIZE
* (i
- last_i
), CUBE_SIZE
);
483 last_color
= board
[j
][i
];
488 rb
->lcd_set_foreground (last_color
);
490 if (last_color
!= EMPTIED
)
492 rb
->lcd_fillrect (BOARD_X
+ CUBE_SIZE
* (last_i
),
493 BOARD_Y
+ CUBE_SIZE
* j
,
494 CUBE_SIZE
* (i
- last_i
), CUBE_SIZE
);
498 rb
->lcd_set_foreground (LCD_BLACK
);
499 rb
->lcd_set_background (CLR_LTBLUE
);
501 rb
->lcd_set_drawmode (DRMODE_COMPLEMENT
);
503 rb
->snprintf (str
, sizeof (str
), "Level %d", player
.level
+ 1);
504 rb
->lcd_putsxy (BOARD_X
, BOARD_Y
, str
);
505 rb
->snprintf (str
, sizeof (str
), "%d%%", percentage_cache
);
506 rb
->lcd_putsxy (BOARD_X
+ CUBE_SIZE
* BOARD_W
- 24, BOARD_Y
, str
);
507 rb
->snprintf (str
, sizeof (str
), "Score: %d", player
.score
);
508 rb
->lcd_putsxy (BOARD_X
, BOARD_Y
+ CUBE_SIZE
* BOARD_H
- 8, str
);
509 rb
->snprintf (str
, sizeof (str
), "%d Lives", player
.lives
);
511 rb
->lcd_putsxy (BOARD_X
+ CUBE_SIZE
* BOARD_W
- 60,
512 BOARD_Y
+ CUBE_SIZE
* BOARD_H
- 8, str
);
514 rb
->lcd_putsxy (BOARD_X
+ CUBE_SIZE
* BOARD_W
- 40,
515 BOARD_Y
+ CUBE_SIZE
* BOARD_H
- 8, str
);
519 rb
->lcd_set_foreground (PLR_COL
);
520 rb
->lcd_set_background (board
[player
.j
][player
.i
]);
522 rb
->lcd_mono_bitmap (pics
[PIC_PLAYER
], player
.i
* CUBE_SIZE
+ BOARD_X
,
523 player
.j
* CUBE_SIZE
+ BOARD_Y
, CUBE_SIZE
, CUBE_SIZE
);
526 rb
->lcd_set_background (EMPTIED
);
527 rb
->lcd_set_foreground (LCD_WHITE
);
528 rb
->lcd_set_drawmode (DRMODE_FG
);
530 rb
->lcd_set_drawmode (DRMODE_FG
);
532 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++)
533 rb
->lcd_mono_bitmap (pics
[PIC_QIX
], qixes
[j
].x
+ BOARD_X
,
534 qixes
[j
].y
+ BOARD_Y
, CUBE_SIZE
, CUBE_SIZE
);
536 rb
->lcd_set_foreground (LCD_BLACK
);
538 rb
->lcd_set_drawmode (DRMODE_SOLID
);
543 static inline int infested_area (int i
, int j
, int v
)
552 if (testboard
[p
.y
][p
.x
] == v
) continue;
553 if (testboard
[p
.y
][p
.x
] > UNCHECKED
)
554 return 1; /* This area was previously flagged as infested */
555 testboard
[p
.y
][p
.x
] = v
;
556 if (board
[p
.y
][p
.x
] == QIX
)
557 return 1; /* Infested area */
559 struct pos p1
= { p
.x
+1, p
.y
};
561 && (board
[p1
.y
][p1
.x
] != FILLED
)
566 struct pos p1
= { p
.x
-1, p
.y
};
568 && (board
[p1
.y
][p1
.x
] != FILLED
)
573 struct pos p1
= { p
.x
, p
.y
+1 };
575 && (board
[p1
.y
][p1
.x
] != FILLED
)
580 struct pos p1
= { p
.x
, p
.y
-1 };
582 && (board
[p1
.y
][p1
.x
] != FILLED
)
590 static inline int fill_area (int i
, int j
)
595 int v
= testboard
[p
.y
][p
.x
];
600 board
[p
.y
][p
.x
] = FILLED
;
601 testboard
[p
.y
][p
.x
] = PAINTED
;
603 struct pos p1
= { p
.x
+1, p
.y
};
605 && (testboard
[p1
.y
][p1
.x
] == v
)
610 struct pos p1
= { p
.x
-1, p
.y
};
612 && (testboard
[p1
.y
][p1
.x
] == v
)
617 struct pos p1
= { p
.x
, p
.y
+1 };
619 && (testboard
[p1
.y
][p1
.x
] == v
)
624 struct pos p1
= { p
.x
, p
.y
-1 };
626 && (testboard
[p1
.y
][p1
.x
] == v
)
635 /* take care of stuff after xonix has landed on a filled spot */
636 static void complete_trail (int fill
)
639 for (j
= 0; j
< BOARD_H
; j
++) {
640 for (i
= 0; i
< BOARD_W
; i
++) {
641 if (board
[j
][i
] == TRAIL
) {
643 board
[j
][i
] = FILLED
;
645 board
[j
][i
] = EMPTIED
;
652 for (i
= 0; i
< player
.level
+ STARTING_QIXES
; i
++) /* add qixes to board */
653 board
[pos(qixes
[i
].y
- BOARD_Y
)]
654 [pos(qixes
[i
].x
- BOARD_X
)] = QIX
;
657 for (j
= 1; j
< BOARD_H
- 1; j
++) {
658 for (i
= 0; i
< BOARD_W
- 0; i
++) {
659 if (board
[j
][i
] != FILLED
) {
660 ret
= infested_area (i
, j
, v
);
661 if (ret
< 0 || ( ret
== 0 && fill_area (i
, j
) ) )
668 for (i
= 0; i
< player
.level
+ STARTING_QIXES
; i
++) /* add qixes to board */
669 board
[pos(qixes
[i
].y
- BOARD_Y
)]
670 [pos(qixes
[i
].x
- BOARD_X
)] = EMPTIED
;
671 percentage_cache
= percentage();
674 rb
->button_clear_queue();
677 /* returns the color the real pixel(x,y) on the lcd is pointing at */
678 static inline unsigned int getpixel (int x
, int y
)
680 const int a
= pos (x
- BOARD_X
), b
= pos (y
- BOARD_Y
);
681 if ((a
> 0) && (a
< BOARD_W
) && (b
> 0) && (b
< BOARD_H
)) /* if inside board */
687 /* returns the color the ball on (newx,newy) is heading at *----*
688 checks the four edge points of the square if 1st of all | |
689 are a trail (cause it's a lose life situation) and 2nd | |
690 if it's filled so it needs to bounce. *____*
692 static inline unsigned int next_hit (int newx
, int newy
)
694 if ((getpixel (newx
, newy
) == TRAIL
)
695 || (getpixel (newx
, newy
+ CUBE_SIZE
- 1) == TRAIL
)
696 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
) == TRAIL
)
697 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
+ CUBE_SIZE
- 1) == TRAIL
))
699 else if ((getpixel (newx
, newy
) == FILLED
)
700 || (getpixel (newx
, newy
+ CUBE_SIZE
- 1) == FILLED
)
701 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
) == FILLED
)
702 || (getpixel (newx
+ CUBE_SIZE
- 1, newy
+ CUBE_SIZE
- 1) ==
709 static void die (void)
712 if (player
.lives
== 0)
713 player
.gameover
= true;
716 rb
->splash (HZ
, "Crash!");
717 complete_trail (false);
718 player
.move
= MOVE_NO
;
719 player
.drawing
= false;
720 player
.i
= BOARD_W
/ 2;
725 /* returns true if the (side) of the block -***-
726 starting from (newx,newy) has any filled pixels * *
729 static inline bool line_check_lt (int newx
, int newy
)
731 return getpixel (newx
, newy
+ CUBE_SIZE
/2-1) == FILLED
732 && getpixel (newx
, newy
+ CUBE_SIZE
/2 ) == FILLED
;
734 static inline bool line_check_rt (int newx
, int newy
)
736 return getpixel (newx
+ CUBE_SIZE
-1, newy
+ CUBE_SIZE
/2-1) == FILLED
737 && getpixel (newx
+ CUBE_SIZE
-1, newy
+ CUBE_SIZE
/2 ) == FILLED
;
739 static inline bool line_check_up (int newx
, int newy
)
741 return getpixel (newx
+ CUBE_SIZE
/2-1, newy
) == FILLED
742 && getpixel (newx
+ CUBE_SIZE
/2 , newy
) == FILLED
;
744 static inline bool line_check_dn (int newx
, int newy
)
746 return getpixel (newx
+ CUBE_SIZE
/2-1, newy
+ CUBE_SIZE
-1) == FILLED
747 && getpixel (newx
+ CUBE_SIZE
/2 , newy
+ CUBE_SIZE
-1) == FILLED
;
750 static inline void move_qix (struct qix
*q
)
753 newx
= get_newx (q
->x
, q
->velocity
, q
->angle
);
754 newy
= get_newy (q
->y
, q
->velocity
, q
->angle
);
755 switch (next_hit (newx
, newy
))
763 const int a
= q
->angle
;
766 ? (line_check_up (newx
, newy
) ? ((a
&(DIR_UU
|DIR_U
))>>4)
767 : (a
&(DIR_UU
|DIR_U
)))
771 ? (line_check_rt (newx
, newy
) ? ((a
&(DIR_RR
|DIR_R
))>>4)
772 : (a
&(DIR_RR
|DIR_R
)))
776 ? (line_check_dn (newx
, newy
) ? ((a
&(DIR_DD
|DIR_D
))<<4)
777 : (a
&(DIR_DD
|DIR_D
)))
781 ? (line_check_lt (newx
, newy
) ? ((a
&(DIR_LL
|DIR_L
))<<4)
782 : (a
&(DIR_LL
|DIR_L
)))
784 q
->x
= get_newx (q
->x
, q
->velocity
, q
->angle
);
785 q
->y
= get_newy (q
->y
, q
->velocity
, q
->angle
);
794 /* move the board forward timewise */
795 static inline void move_board (void)
799 for (j
= 0; j
< player
.level
+ STARTING_QIXES
; j
++)
800 move_qix (&qixes
[j
]);
801 /* move_qix(&black_qix,true); */
805 switch (player
.move
) {
811 if (player
.j
< BOARD_H
- 2)
819 if (player
.i
< BOARD_W
- 1)
826 if ((player
.drawing
) && (board
[newj
][newi
] == EMPTIED
)) /* continue drawing */
827 board
[newj
][newi
] = TRAIL
;
828 else if ((player
.drawing
) && (board
[newj
][newi
] == FILLED
)) { /* finish drawing */
829 player
.move
= MOVE_NO
; /* stop moving */
830 player
.drawing
= false;
831 complete_trail (true);
832 } else if ((board
[player
.j
][player
.i
] == FILLED
)
833 && (board
[newj
][newi
] == EMPTIED
)) {
835 player
.drawing
= true;
836 board
[newj
][newi
] = TRAIL
;
837 /* if the block after next is empty and we're moving onto filled, stop */
838 } else if ((board
[newj
][newi
] == FILLED
)
839 && (board
[newj
+ newj
-player
.j
][newi
+ newi
-player
.i
] == EMPTIED
)) {
840 player
.move
= MOVE_NO
;
845 if (percentage_cache
>= difficulty
) { /* finished level */
846 rb
->splash (HZ
* 2, "Level %d finished", player
.level
+1);
847 player
.score
+= percentage_cache
;
848 if (player
.level
< MAX_LEVEL
)
852 rb
->splash (HZ
* 2, "Ready?");
857 static int game_menu (void)
859 MENUITEM_STRINGLIST(menu
, "XOBOX Menu", NULL
, "Start New Game",
860 "Speed","Difficulty","Quit");
862 #ifdef HAVE_LCD_COLOR
863 rb
->lcd_set_foreground (rb
->global_settings
->fg_color
);
864 rb
->lcd_set_background (rb
->global_settings
->bg_color
);
866 rb
->lcd_set_foreground(LCD_BLACK
);
867 rb
->lcd_set_background(LCD_WHITE
);
870 rb
->do_menu(&menu
,&selection
, NULL
, false);
872 rb
->set_int ("Speed", "", UNIT_INT
, &speed
, NULL
, 1, 1, 10, NULL
);
873 else if (selection
==2)
874 rb
->set_int ("Difficulty", "", UNIT_INT
, &difficulty
, NULL
,
879 if (selection
!= MENU_START
) {
880 selection
= MENU_QUIT
;
885 /* init game's variables */
886 static void init_game (void)
891 player
.gameover
= false;
892 player
.drawing
= false;
893 rb
->lcd_setfont(FONT_SYSFIXED
);
896 rb
->splash (HZ
* 2, "Ready?");
899 /* general keypad handler loop */
900 static int xobox_loop (void)
907 end
= *rb
->current_tick
+ ((11-speed
)*HZ
)/100;
909 #ifdef HAS_BUTTON_HOLD
910 if (rb
->button_hold()) {
912 rb
->splash (HZ
, "PAUSED");
916 button
= rb
->button_get_w_tmo (true);
919 case UP
|BUTTON_REPEAT
:
920 player
.move
= MOVE_UP
;
923 case DOWN
|BUTTON_REPEAT
:
924 player
.move
= MOVE_DN
;
927 case LEFT
|BUTTON_REPEAT
:
928 player
.move
= MOVE_LT
;
931 case RIGHT
|BUTTON_REPEAT
:
932 player
.move
= MOVE_RT
;
937 rb
->splash (HZ
, "Paused");
941 if (ret
== MENU_START
)
950 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
951 return PLUGIN_USB_CONNECTED
;
958 if (player
.gameover
) {
959 rb
->splash (HZ
, "Game Over!");
961 if (ret
== MENU_START
)
967 if (end
> *rb
->current_tick
)
968 rb
->sleep (end
- *rb
->current_tick
);
973 return PLUGIN_OK
; /* for no warnings on compiling */
976 /* plugin main procedure */
977 enum plugin_status
plugin_start (struct plugin_api
*api
, void *parameter
)
984 rb
->lcd_setfont (FONT_SYSFIXED
);
986 rb
->lcd_set_backdrop(NULL
);
989 /* Turn off backlight timeout */
990 backlight_force_on(rb
); /* backlight control in lib/helper.c */
995 if (game_menu () == MENU_START
) {
1000 /* Turn on backlight timeout (revert to settings) */
1001 backlight_use_settings(rb
); /* backlight control in lib/helper.c */
1002 rb
->lcd_setfont (FONT_UI
);