Prepare new maemo release
[maemo-rb.git] / apps / plugins / brickmania.c
blob466b194895cd54e31c86eb5b2fafc94dedf3ff6c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005, 2006 Ben Basha (Paprica)
11 * Copyright (C) 2009 Karl Kurbjun
12 * check_lines is based off an explanation and expanded math presented by Paul
13 * Bourke: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
25 #include "plugin.h"
26 #include "lib/configfile.h"
27 #include "lib/display_text.h"
28 #include "lib/helper.h"
29 #include "lib/highscore.h"
30 #include "lib/playback_control.h"
32 #include "pluginbitmaps/brickmania_pads.h"
33 #include "pluginbitmaps/brickmania_short_pads.h"
34 #include "pluginbitmaps/brickmania_long_pads.h"
35 #include "pluginbitmaps/brickmania_bricks.h"
36 #include "pluginbitmaps/brickmania_powerups.h"
37 #include "pluginbitmaps/brickmania_ball.h"
38 #include "pluginbitmaps/brickmania_gameover.h"
40 #ifdef HAVE_LCD_COLOR /* currently no transparency for non-colour */
41 #include "pluginbitmaps/brickmania_break.h"
42 #endif
49 * Keymaps
53 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
54 (CONFIG_KEYPAD == IRIVER_H300_PAD)
55 #define CONTINUE_TEXT "Press NAVI To Continue"
56 #define QUIT BUTTON_OFF
57 #define LEFT BUTTON_LEFT
58 #define RIGHT BUTTON_RIGHT
59 #define SELECT BUTTON_SELECT
60 #define UP BUTTON_UP
61 #define DOWN BUTTON_DOWN
62 #define RC_QUIT BUTTON_RC_STOP
64 #elif CONFIG_KEYPAD == ONDIO_PAD
65 #define CONTINUE_TEXT "MENU To Continue"
66 #define QUIT BUTTON_OFF
67 #define LEFT BUTTON_LEFT
68 #define RIGHT BUTTON_RIGHT
69 #define SELECT BUTTON_MENU
70 #define UP BUTTON_UP
71 #define DOWN BUTTON_DOWN
73 #elif CONFIG_KEYPAD == RECORDER_PAD
74 #define QUIT BUTTON_OFF
75 #define LEFT BUTTON_LEFT
76 #define RIGHT BUTTON_RIGHT
77 #define SELECT BUTTON_PLAY
78 #define UP BUTTON_UP
79 #define DOWN BUTTON_DOWN
81 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
82 #define QUIT BUTTON_OFF
83 #define LEFT BUTTON_LEFT
84 #define RIGHT BUTTON_RIGHT
85 #define SELECT BUTTON_SELECT
86 #define UP BUTTON_UP
87 #define DOWN BUTTON_DOWN
89 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
90 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
91 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
92 #define QUIT BUTTON_MENU
93 #define LEFT BUTTON_LEFT
94 #define RIGHT BUTTON_RIGHT
95 #define SELECT BUTTON_SELECT
96 #define UP BUTTON_SCROLL_BACK
97 #define DOWN BUTTON_SCROLL_FWD
98 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
99 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
101 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
102 #define QUIT BUTTON_POWER
103 #define LEFT BUTTON_LEFT
104 #define RIGHT BUTTON_RIGHT
105 #define SELECT BUTTON_SELECT
106 #define UP BUTTON_UP
107 #define DOWN BUTTON_DOWN
109 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
110 #define QUIT BUTTON_POWER
111 #define LEFT BUTTON_LEFT
112 #define RIGHT BUTTON_RIGHT
113 #define SELECT BUTTON_PLAY
114 #define UP BUTTON_UP
115 #define DOWN BUTTON_DOWN
117 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
118 #define QUIT BUTTON_POWER
119 #define LEFT BUTTON_LEFT
120 #define RIGHT BUTTON_RIGHT
121 #define SELECT BUTTON_SELECT
122 #define UP BUTTON_UP
123 #define DOWN BUTTON_DOWN
124 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
125 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
128 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
129 #define QUIT (BUTTON_HOME|BUTTON_REPEAT)
130 #define LEFT BUTTON_LEFT
131 #define RIGHT BUTTON_RIGHT
132 #define SELECT BUTTON_SELECT
133 #define UP BUTTON_UP
134 #define DOWN BUTTON_DOWN
136 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
137 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
140 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
141 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
142 CONFIG_KEYPAD == SANSA_M200_PAD || \
143 CONFIG_KEYPAD == SANSA_CONNECT_PAD
144 #define QUIT BUTTON_POWER
145 #define LEFT BUTTON_LEFT
146 #define RIGHT BUTTON_RIGHT
147 #define ALTLEFT BUTTON_VOL_DOWN
148 #define ALTRIGHT BUTTON_VOL_UP
149 #define SELECT BUTTON_SELECT
150 #define UP BUTTON_UP
151 #define DOWN BUTTON_DOWN
153 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
154 #define QUIT BUTTON_POWER
155 #define LEFT BUTTON_LEFT
156 #define RIGHT BUTTON_RIGHT
157 #define SELECT BUTTON_PLAY
158 #define UP BUTTON_SCROLL_UP
159 #define DOWN BUTTON_SCROLL_DOWN
161 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD \
162 || CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
163 #define QUIT BUTTON_BACK
164 #define LEFT BUTTON_LEFT
165 #define RIGHT BUTTON_RIGHT
166 #define SELECT BUTTON_SELECT
167 #define UP BUTTON_UP
168 #define DOWN BUTTON_DOWN
170 #elif (CONFIG_KEYPAD == MROBE100_PAD)
171 #define QUIT BUTTON_POWER
172 #define LEFT BUTTON_LEFT
173 #define RIGHT BUTTON_RIGHT
174 #define SELECT BUTTON_SELECT
175 #define UP BUTTON_UP
176 #define DOWN BUTTON_DOWN
178 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
179 #define CONTINUE_TEXT "PLAY To Continue"
180 #define QUIT BUTTON_RC_REC
181 #define LEFT BUTTON_RC_REW
182 #define RIGHT BUTTON_RC_FF
183 #define SELECT BUTTON_RC_PLAY
184 #define UP BUTTON_RC_VOL_UP
185 #define DOWN BUTTON_RC_VOL_DOWN
186 #define RC_QUIT BUTTON_REC
188 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
189 #define QUIT BUTTON_BACK
190 #define LEFT BUTTON_LEFT
191 #define RIGHT BUTTON_RIGHT
192 #define SELECT BUTTON_SELECT
193 #define UP BUTTON_UP
194 #define DOWN BUTTON_DOWN
196 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
197 #define QUIT BUTTON_POWER
198 #define LEFT BUTTON_LEFT
199 #define RIGHT BUTTON_RIGHT
200 #define SELECT BUTTON_SELECT
201 #define UP BUTTON_UP
202 #define DOWN BUTTON_DOWN
204 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
205 #define QUIT BUTTON_POWER
206 #define LEFT BUTTON_LEFT
207 #define RIGHT BUTTON_RIGHT
208 #define SELECT BUTTON_PLAY
209 #define UP BUTTON_UP
210 #define DOWN BUTTON_DOWN
212 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
213 #define QUIT BUTTON_POWER
214 #define LEFT BUTTON_PREV
215 #define RIGHT BUTTON_NEXT
216 #define SELECT BUTTON_PLAY
217 #define UP BUTTON_UP
218 #define DOWN BUTTON_DOWN
220 #elif CONFIG_KEYPAD == COWON_D2_PAD
221 #define CONTINUE_TEXT "MENU To Continue"
222 #define QUIT BUTTON_POWER
223 #define LEFT BUTTON_MINUS
224 #define RIGHT BUTTON_PLUS
225 #define SELECT BUTTON_MENU
227 #elif CONFIG_KEYPAD == ONDAVX747_PAD
228 #define QUIT BUTTON_POWER
229 #define LEFT BUTTON_VOL_DOWN
230 #define RIGHT BUTTON_VOL_UP
231 #define SELECT BUTTON_MENU
232 #elif CONFIG_KEYPAD == ONDAVX777_PAD
233 #define QUIT BUTTON_POWER
235 #elif CONFIG_KEYPAD == MROBE500_PAD
236 #define QUIT BUTTON_POWER
238 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
239 #define QUIT BUTTON_FFWD
240 #define SELECT BUTTON_PLAY
241 #define LEFT BUTTON_LEFT
242 #define RIGHT BUTTON_RIGHT
243 #define UP BUTTON_UP
244 #define DOWN BUTTON_DOWN
246 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
247 #define QUIT BUTTON_REC
248 #define LEFT BUTTON_PREV
249 #define RIGHT BUTTON_NEXT
250 #define ALTLEFT BUTTON_MENU
251 #define ALTRIGHT BUTTON_PLAY
252 #define SELECT BUTTON_OK
253 #define UP BUTTON_UP
254 #define DOWN BUTTON_DOWN
256 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
257 #define QUIT (BUTTON_REC|BUTTON_PLAY)
258 #define LEFT BUTTON_VOL_DOWN
259 #define RIGHT BUTTON_VOL_UP
260 #define SELECT BUTTON_FUNC
261 #define UP BUTTON_REW
262 #define DOWN BUTTON_FF
264 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
265 #define QUIT (BUTTON_MENU|BUTTON_REPEAT)
266 #define LEFT BUTTON_REW
267 #define RIGHT BUTTON_FF
268 #define SELECT BUTTON_ENTER
269 #define UP BUTTON_UP
270 #define DOWN BUTTON_DOWN
272 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
273 #define QUIT BUTTON_POWER
274 #define LEFT BUTTON_LEFT
275 #define RIGHT BUTTON_RIGHT
276 #define SELECT BUTTON_SELECT
277 #define UP BUTTON_UP
278 #define DOWN BUTTON_DOWN
280 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
281 (CONFIG_KEYPAD == HM801_PAD)
282 #define QUIT BUTTON_POWER
283 #define LEFT BUTTON_LEFT
284 #define RIGHT BUTTON_RIGHT
285 #define SELECT BUTTON_SELECT
286 #define UP BUTTON_UP
287 #define DOWN BUTTON_DOWN
289 #else
290 #error No keymap defined!
291 #endif
293 #ifdef HAVE_TOUCHSCREEN
294 #ifdef LEFT
295 #define ALTLEFT BUTTON_BOTTOMLEFT
296 #else
297 #define LEFT BUTTON_BOTTOMLEFT
298 #endif
299 #ifdef RIGHT
300 #define ALTRIGHT BUTTON_BOTTOMRIGHT
301 #else
302 #define RIGHT BUTTON_BOTTOMRIGHT
303 #endif
304 #ifdef SELECT
305 #define ALTSELECT BUTTON_CENTER
306 #else
307 #define SELECT BUTTON_CENTER
308 #endif
309 #ifndef UP
310 #define UP BUTTON_TOPMIDDLE
311 #endif
312 #ifndef DOWN
313 #define DOWN BUTTON_BOTTOMMIDDLE
314 #endif
315 #endif
317 /* Continue text is used as a string later when the game is paused. This allows
318 * targets to specify their own text if needed.
320 #if !defined(CONTINUE_TEXT)
321 #define CONTINUE_TEXT "Press SELECT To Continue"
322 #endif
324 #ifndef SCROLL_FWD /* targets without scroll wheel*/
325 #define SCROLL_FWD(x) (0)
326 #define SCROLL_BACK(x) (0)
327 #endif
330 #define NUM_BRICKS_ROWS 8
331 #define NUM_BRICKS_COLS 10
335 * Geometric dimensions
339 /* If there are three fractional bits, the smallest screen size that will scale
340 * properly is 28x22. If you have a smaller screen increase the fractional
341 * precision. If you have a precision of 4 the smallest screen size would be
342 * 14x11. Note though that this will decrease the maximum resolution due to
343 * the line intersection tests. These defines are used for all of the fixed
344 * point calculations/conversions.
346 #define FIXED3(x) ((x)<<3)
347 #define FIXED3_MUL(x, y) ((long long)((x)*(y))>>3)
348 #define FIXED3_DIV(x, y) (((x)<<3)/(y))
349 #define INT3(x) ((x)>>3)
351 #define GAMESCREEN_WIDTH FIXED3(LCD_WIDTH)
352 #define GAMESCREEN_HEIGHT FIXED3(LCD_HEIGHT)
354 #define PAD_WIDTH FIXED3(BMPWIDTH_brickmania_pads)
355 #define PAD_HEIGHT FIXED3(BMPHEIGHT_brickmania_pads/3)
356 #define SHORT_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_short_pads)
357 #define LONG_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_long_pads)
358 #define BRICK_HEIGHT FIXED3(BMPHEIGHT_brickmania_bricks/7)
359 #define BRICK_WIDTH FIXED3(BMPWIDTH_brickmania_bricks)
360 #define LEFTMARGIN ((GAMESCREEN_WIDTH-NUM_BRICKS_COLS*BRICK_WIDTH)/2)
361 #define POWERUP_WIDTH FIXED3(BMPWIDTH_brickmania_powerups)
362 #define BALL FIXED3(BMPHEIGHT_brickmania_ball)
363 #define HALFBALL (BALL / 2)
364 #define PAD_POS_Y (GAMESCREEN_HEIGHT - PAD_HEIGHT - 1)
365 #define ON_PAD_POS_Y (PAD_POS_Y - HALFBALL)
367 #define GAMEOVER_WIDTH FIXED3(BMPWIDTH_brickmania_gameover)
368 #define GAMEOVER_HEIGHT FIXED3(BMPHEIGHT_brickmania_gameover)
370 #define TOPMARGIN MAX(BRICK_HEIGHT, FIXED3(8))
372 #define STRINGPOS_FINISH (GAMESCREEN_HEIGHT - (GAMESCREEN_HEIGHT / 6))
373 #define STRINGPOS_NAVI (STRINGPOS_FINISH - 10)
374 #define STRINGPOS_FLIP (STRINGPOS_FINISH - 10)
379 * Speeds
383 /* Brickmania was originally designed for the H300, other targets should scale
384 * the speed up/down as needed based on the screen height.
386 #define SPEED_SCALE_H(y) FIXED3_DIV(GAMESCREEN_HEIGHT, FIXED3(176)/(y) )
387 #define SPEED_SCALE_W(x) FIXED3_DIV(GAMESCREEN_WIDTH, FIXED3(220)/(x) )
389 /* These are all used as ball speeds depending on where the ball hit the
390 * paddle.
392 * Note that all of these speeds (including pad, power, and fire)
393 * could be made variable and could be raised to be much higher to add
394 * additional difficulty to the game. The line intersection tests allow this
395 * to be drastically increased without the collision detection failing
396 * (ideally).
398 #define SPEED_1Q_X SPEED_SCALE_W( 6)
399 #define SPEED_1Q_Y SPEED_SCALE_H(-2)
401 #define SPEED_2Q_X SPEED_SCALE_W( 4)
402 #define SPEED_2Q_Y SPEED_SCALE_H(-3)
404 #define SPEED_3Q_X SPEED_SCALE_W( 3)
405 #define SPEED_3Q_Y SPEED_SCALE_H(-4)
407 #define SPEED_4Q_X SPEED_SCALE_W( 2)
408 #define SPEED_4Q_Y SPEED_SCALE_H(-4)
410 /* This is used to determine the speed of the paddle */
411 #define SPEED_PAD SPEED_SCALE_W( 8)
413 /* This defines the speed that the powerups drop */
414 #define SPEED_POWER SPEED_SCALE_H( 2)
416 /* This defines the speed that the shot moves */
417 #define SPEED_FIRE SPEED_SCALE_H( 4)
418 #define FIRE_LENGTH SPEED_SCALE_H( 7)
423 * Timings
427 /* The time ms for one iteration through the game loop - decrease this to speed
428 * up the game - note that current_tick is (currently) only accurate to 10ms.
430 #define CYCLETIME 30 /* ms */
432 #define FLIP_SIDES_DELAY 10 /* seconds */
437 * Scores
441 #define SCORE_BALL_HIT_BRICK 2
442 #define SCORE_BALL_DEMOLISHED_BRICK 8
443 #define SCORE_FIRE_HIT_BRICK 13
444 #define SCORE_LEVEL_COMPLETED 100
445 #define SCORE_POWER_LIFE_GAIN 50
446 #define SCORE_POWER_PADDLE_STICKY 34
447 #define SCORE_POWER_PADDLE_SHOOTER 47
448 #define SCORE_POWER_PADDLE_NORMAL 23
449 #define SCORE_POWER_FLIP 23
450 #define SCORE_POWER_EXTRA_BALL 23
451 #define SCORE_POWER_LONG_PADDLE 23
456 * Limits
460 #define MAX_BALLS 10
461 #define MAX_FIRES 30
462 #define MAX_POWERS 10
467 * Files
471 #define CONFIG_FILE_NAME "brickmania.cfg"
472 #define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/brickmania.save"
473 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/brickmania.score"
474 #define NUM_SCORES 5
479 * Game levels
483 /* change to however many levels there are, i.e. how many arrays there are total */
484 #define NUM_LEVELS 40
486 /* change the first number in [ ] to however many levels there are */
487 static unsigned char levels[NUM_LEVELS][NUM_BRICKS_ROWS][NUM_BRICKS_COLS] =
488 /* You can set up new levels with the level editor
489 ( http://plugbox.rockbox-lounge.com/brickmania.htm ).
490 With 0x1, it refers to the first brick in the bitmap, 0x2 would refer to the
491 second, ect., 0x0 leaves a empty space. If you add a 2 before the 2nd number,
492 it will take two hits to break, and 3 hits if you add a 3. That is 0x24, will
493 result with the fourth brick being displayed and having take 2 hits to break.
494 You could do the same with the 3, just replace the 2 with a 3 for it to take
495 three hits to break it apart. */
497 { /* level 1 */
498 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
499 {0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2},
500 {0x0,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x0},
501 {0x0,0x0,0x2,0x1,0x0,0x0,0x1,0x2,0x0,0x0},
502 {0x0,0x0,0x0,0x2,0x1,0x1,0x2,0x0,0x0,0x0},
503 {0x7,0x0,0x0,0x7,0x2,0x2,0x7,0x0,0x0,0x7},
504 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
505 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
507 { /* level 2 */
508 {0x0,0x0,0x7,0x7,0x1,0x1,0x7,0x7,0x0,0x0},
509 {0x0,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0},
510 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
511 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
512 {0x1,0x1,0x2,0x1,0x0,0x0,0x1,0x2,0x1,0x1},
513 {0x1,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x1},
514 {0x0,0x1,0x2,0x0,0x0,0x0,0x0,0x2,0x1,0x0},
515 {0x0,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x0}
517 { /* level 3 */
518 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
519 {0x3,0x23,0x23,0x3,0x0,0x0,0x2,0x22,0x22,0x2},
520 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
521 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
522 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
523 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6},
524 {0x5,0x25,0x25,0x5,0x0,0x0,0x6,0x26,0x26,0x6},
525 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6}
527 { /* level 4 */
528 {0x0,0x0,0x0,0x27,0x27,0x27,0x27,0x0,0x0,0x0},
529 {0x0,0x0,0x0,0x27,0x7,0x7,0x27,0x0,0x0,0x0},
530 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
531 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
532 {0x26,0x6,0x0,0x2,0x2,0x2,0x2,0x0,0x6,0x26},
533 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
534 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
535 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1}
537 { /* level 5 */
538 {0x1,0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4},
539 {0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0},
540 {0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5},
541 {0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5,0x5},
542 {0x0,0x33,0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0},
543 {0x3,0x33,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x36},
544 {0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x6,0x36},
545 {0x0,0x24,0x24,0x0,0x25,0x25,0x0,0x26,0x26,0x0}
547 { /* level 6 */
548 {0x0,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x0},
549 {0x3,0x1,0x3,0x7,0x0,0x0,0x7,0x3,0x1,0x3},
550 {0x3,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x3},
551 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x0},
552 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
553 {0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5},
554 {0x0,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x0},
555 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
557 { /* level 7 */
558 {0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x0},
559 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
560 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
561 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
562 {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x6},
563 {0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0},
564 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
565 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
567 { /* level 8 */
568 {0x0,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x0},
569 {0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0},
570 {0x6,0x6,0x0,0x2,0x32,0x32,0x2,0x0,0x6,0x6},
571 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
572 {0x0,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x0},
573 {0x0,0x0,0x0,0x5,0x25,0x25,0x5,0x0,0x0,0x0},
574 {0x0,0x5,0x5,0x25,0x5,0x5,0x25,0x5,0x5,0x0},
575 {0x5,0x5,0x25,0x5,0x5,0x5,0x5,0x25,0x5,0x5}
577 { /* level 9 */
578 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
579 {0x2,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x2},
580 {0x2,0x0,0x3,0x0,0x1,0x1,0x0,0x3,0x0,0x2},
581 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
582 {0x2,0x0,0x1,0x0,0x3,0x3,0x0,0x1,0x0,0x2},
583 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
584 {0x2,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x2,0x2},
585 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
587 { /* level 10 */
588 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
589 {0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5},
590 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
591 {0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0},
592 {0x0,0x0,0x0,0x4,0x1,0x1,0x4,0x0,0x0,0x0},
593 {0x0,0x0,0x3,0x4,0x1,0x1,0x4,0x3,0x0,0x0},
594 {0x0,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x0},
595 {0x1,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x1}
597 { /* level 11 */
598 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
599 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2},
600 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
601 {0x2,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x2},
602 {0x2,0x0,0x0,0x7,0x7,0x7,0x7,0x0,0x0,0x2},
603 {0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x0},
604 {0x0,0x2,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x0},
605 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5}
607 { /* level 12 */
608 {0x2,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x2},
609 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
610 {0x1,0x1,0x1,0x0,0x1,0x1,0x0,0x1,0x1,0x1},
611 {0x0,0x1,0x0,0x1,0x6,0x6,0x1,0x0,0x1,0x0},
612 {0x0,0x0,0x1,0x1,0x6,0x6,0x1,0x1,0x0,0x0},
613 {0x1,0x1,0x1,0x7,0x0,0x0,0x7,0x1,0x1,0x1},
614 {0x1,0x1,0x7,0x1,0x0,0x0,0x1,0x7,0x1,0x1},
615 {0x2,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x2}
617 {/* levell13 */
618 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
619 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
620 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x2},
621 {0x2,0x0,0x2,0x3,0x3,0x3,0x3,0x3,0x0,0x2},
622 {0x2,0x0,0x2,0x4,0x4,0x4,0x4,0x4,0x0,0x2},
623 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
624 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
625 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
627 {/* level 14 */
628 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
629 {0x4,0x4,0x4,0x4,0x2,0x2,0x4,0x4,0x4,0x4},
630 {0x4,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x4},
631 {0x4,0x0,0x0,0x2,0x3,0x3,0x2,0x0,0x0,0x4},
632 {0x4,0x0,0x2,0x23,0x3,0x3,0x23,0x2,0x0,0x4},
633 {0x4,0x0,0x2,0x22,0x2,0x2,0x22,0x2,0x0,0x4},
634 {0x4,0x0,0x6,0x21,0x5,0x5,0x21,0x6,0x0,0x4},
635 {0x4,0x6,0x1,0x1,0x5,0x5,0x1,0x1,0x6,0x4}
637 {/* level 15 */
638 {0x4,0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,0x3},
639 {0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x5,0x0,0x0},
640 {0x2,0x2,0x1,0x1,0x1,0x0,0x1,0x6,0x0,0x0},
641 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x5,0x0,0x0},
642 {0x2,0x1,0x2,0x2,0x2,0x1,0x1,0x6,0x0,0x0},
643 {0x2,0x1,0x2,0x2,0x2,0x1,0x3,0x5,0x3,0x0},
644 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x6,0x0,0x0},
645 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
647 {/* level 16 (Rockbox) by ts-x */
648 {0x2,0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
649 {0x2,0x0,0x3,0x0,0x3,0x4,0x0,0x5,0x5,0x0},
650 {0x2,0x0,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
651 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
652 {0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
653 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0},
654 {0x7,0x0,0x7,0x1,0x0,0x1,0x0,0x2,0x0,0x0},
655 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0}
657 {/* level 17 (Alien) by ts-x */
658 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
659 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
660 {0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1},
661 {0x2,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x2},
662 {0x1,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x1},
663 {0x2,0x0,0x0,0x1,0x2,0x2,0x1,0x0,0x0,0x2},
664 {0x2,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x2},
665 {0x2,0x2,0x1,0x0,0x1,0x1,0x0,0x1,0x2,0x2}
667 {/* level 18 (Tetris) by ts-x */
668 {0x0,0x2,0x0,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
669 {0x0,0x2,0x7,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
670 {0x2,0x2,0x7,0x0,0x3,0x4,0x0,0x6,0x2,0x2},
671 {0x2,0x2,0x7,0x7,0x3,0x4,0x0,0x6,0x2,0x2},
672 {0x2,0x1,0x7,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
673 {0x2,0x1,0x0,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
674 {0x1,0x1,0x1,0x7,0x3,0x0,0x6,0x6,0x5,0x5},
675 {0x1,0x1,0x1,0x0,0x3,0x0,0x6,0x6,0x5,0x5}
677 { /* level 19 (Stalactites) by ts-x */
678 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
679 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
680 {0x5,0x0,0x6,0x3,0x4,0x7,0x5,0x0,0x1,0x2},
681 {0x5,0x2,0x6,0x3,0x4,0x0,0x5,0x3,0x1,0x2},
682 {0x5,0x0,0x6,0x0,0x4,0x7,0x5,0x0,0x1,0x0},
683 {0x5,0x0,0x0,0x3,0x4,0x0,0x0,0x0,0x1,0x2},
684 {0x0,0x0,0x6,0x0,0x0,0x0,0x5,0x0,0x0,0x0},
685 {0x5,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0}
687 { /* level 20 (Maze) by ts-x */
688 {0x1,0x1,0x21,0x1,0x1,0x1,0x1,0x1,0x1,0x21},
689 {0x1,0x0,0x0,0x3,0x0,0x0,0x3,0x1,0x31,0x1},
690 {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x1},
691 {0x21,0x0,0x21,0x3,0x0,0x3,0x0,0x3,0x0,0x2},
692 {0x1,0x0,0x1,0x21,0x0,0x12,0x0,0x0,0x0,0x0},
693 {0x31,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x3,0x0},
694 {0x1,0x0,0x1,0x0,0x1,0x1,0x31,0x1,0x1,0x2},
695 {0x22,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x21}
697 { /* level 21 (Dentist) by ts-x */
698 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
699 {0x2,0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x2,0x2},
700 {0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x2},
701 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x2},
702 {0x2,0x0,0x6,0x0,0x6,0x0,0x0,0x0,0x0,0x2},
703 {0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x2},
704 {0x2,0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x2,0x2},
705 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0}
707 { /* level 22 (Spider) by ts-x */
708 {0x31,0x3,0x1,0x1,0x0,0x0,0x1,0x1,0x3,0x31},
709 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
710 {0x33,0x1,0x1,0x36,0x1,0x1,0x36,0x1,0x1,0x33},
711 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
712 {0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0},
713 {0x21,0x3,0x1,0x21,0x2,0x2,0x21,0x1,0x3,0x21},
714 {0x0,0x0,0x0,0x1,0x21,0x1,0x1,0x0,0x0,0x0},
715 {0x3,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x3}
717 { /* level 23 (Pool) by ts-x */
718 {0x0,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x7,0x0},
719 {0x0,0x0,0x5,0x0,0x2,0x0,0x0,0x0,0x2,0x0},
720 {0x7,0x3,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x7},
721 {0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0x7},
722 {0x7,0x0,0x4,0x0,0x0,0x3,0x0,0x0,0x0,0x7},
723 {0x7,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x4,0x7},
724 {0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
725 {0x0,0x7,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x0}
727 { /* level 24 (Vorbis Fish) by ts-x */
728 {0x0,0x0,0x4,0x4,0x5,0x5,0x5,0x0,0x0,0x5},
729 {0x0,0x4,0x6,0x4,0x4,0x5,0x5,0x5,0x0,0x5},
730 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x5,0x5,0x5},
731 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x4,0x5,0x5},
732 {0x0,0x5,0x6,0x4,0x4,0x5,0x5,0x4,0x5,0x0},
733 {0x5,0x5,0x4,0x4,0x5,0x5,0x5,0x4,0x5,0x5},
734 {0x5,0x4,0x4,0x4,0x5,0x5,0x4,0x4,0x5,0x5},
735 {0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x5,0x0,0x5}
737 {/* level 25 (Rainbow) by ts-x */
738 {0x0,0x4,0x1,0x0,0x0,0x0,0x0,0x1,0x4,0x0},
739 {0x24,0x1,0x3,0x1,0x0,0x0,0x21,0x3,0x1,0x24},
740 {0x1,0x23,0x5,0x3,0x1,0x21,0x3,0x5,0x3,0x21},
741 {0x3,0x5,0x6,0x5,0x3,0x3,0x5,0x6,0x5,0x3},
742 {0x5,0x6,0x7,0x6,0x5,0x5,0x6,0x7,0x6,0x5},
743 {0x6,0x7,0x2,0x27,0x6,0x6,0x27,0x2,0x7,0x6},
744 {0x7,0x2,0x0,0x2,0x27,0x27,0x2,0x0,0x2,0x7},
745 {0x32,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x32}
747 { /* level 26 (Bowtie) by ts-x */
748 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5},
749 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
750 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
751 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
752 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
753 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
754 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
755 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5}
757 { /* level 27 (Frog) by ts-x */
758 {0x0,0x5,0x25,0x0,0x0,0x0,0x0,0x25,0x5,0x0},
759 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
760 {0x25,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x25},
761 {0x5,0x0,0x3,0x0,0x6,0x6,0x0,0x3,0x0,0x5},
762 {0x5,0x0,0x31,0x0,0x6,0x6,0x0,0x31,0x0,0x5},
763 {0x5,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x5},
764 {0x5,0x5,0x5,0x35,0x0,0x0,0x35,0x5,0x5,0x5},
765 {0x0,0x25,0x5,0x0,0x4,0x4,0x0,0x5,0x25,0x0}
767 { /* level 28 (DigDug) by ts-x */
768 {0x35,0x5,0x5,0x25,0x0,0x25,0x25,0x5,0x5,0x35},
769 {0x6,0x0,0x0,0x6,0x0,0x6,0x6,0x0,0x0,0x6},
770 {0x7,0x0,0x37,0x37,0x0,0x37,0x37,0x7,0x0,0x7},
771 {0x7,0x0,0x7,0x0,0x0,0x0,0x7,0x7,0x7,0x7},
772 {0x4,0x4,0x4,0x24,0x0,0x24,0x4,0x0,0x0,0x4},
773 {0x4,0x4,0x0,0x0,0x0,0x4,0x4,0x0,0x4,0x4},
774 {0x24,0x24,0x4,0x4,0x4,0x4,0x0,0x0,0x24,0x4},
775 {0x1,0x1,0x1,0x1,0x1,0x1,0x21,0x21,0x1,0x1}
777 { /* level 29 UK Flag by Seth Opgenorth */
778 {0x32,0x0,0x3,0x3,0x2,0x2,0x3,0x3,0x0,0x32},
779 {0x0,0x2,0x0,0x3,0x32,0x22,0x33,0x0,0x32,0x0},
780 {0x33,0x0,0x22,0x0,0x2,0x2,0x0,0x2,0x0,0x33},
781 {0x22,0x32,0x2,0x2,0x2,0x2,0x2,0x2,0x22,0x2},
782 {0x3,0x0,0x0,0x32,0x22,0x2,0x2,0x0,0x0,0x3},
783 {0x23,0x0,0x32,0x0,0x32,0x2,0x0,0x2,0x0,0x3},
784 {0x0,0x2,0x0,0x3,0x2,0x2,0x3,0x0,0x22,0x0},
785 {0x32,0x0,0x3,0x23,0x2,0x2,0x23,0x33,0x0,0x32}
787 { /* level 30 Win-Logo by Seth Opgenorth */
788 {0x0,0x0,0x0,0x22,0x0,0x0,0x0,0x0,0x0,0x0},
789 {0x0,0x0,0x32,0x2,0x2,0x25,0x0,0x5,0x0,0x0},
790 {0x0,0x0,0x2,0x22,0x2,0x5,0x5,0x35,0x0,0x0},
791 {0x0,0x0,0x2,0x1,0x2,0x5,0x5,0x25,0x0,0x0},
792 {0x0,0x0,0x21,0x1,0x1,0x36,0x7,0x26,0x0,0x0},
793 {0x0,0x0,0x1,0x1,0x1,0x6,0x6,0x6,0x0,0x0},
794 {0x0,0x0,0x21,0x0,0x21,0x6,0x6,0x26,0x0,0x0},
795 {0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0}
797 { /* level 31 Color wave/V by Seth Opgenorth */
798 {0x25,0x34,0x2,0x31,0x33,0x23,0x1,0x2,0x34,0x5},
799 {0x3,0x5,0x24,0x2,0x1,0x1,0x2,0x4,0x5,0x3},
800 {0x1,0x3,0x5,0x4,0x2,0x2,0x4,0x5,0x3,0x1},
801 {0x2,0x1,0x33,0x35,0x4,0x4,0x5,0x33,0x1,0x22},
802 {0x31,0x22,0x1,0x3,0x5,0x25,0x3,0x1,0x2,0x31},
803 {0x3,0x1,0x2,0x1,0x3,0x3,0x1,0x2,0x21,0x3},
804 {0x5,0x23,0x1,0x32,0x1,0x1,0x2,0x1,0x3,0x5},
805 {0x4,0x35,0x3,0x1,0x2,0x22,0x31,0x3,0x5,0x4}
807 { /* level 32 Sweedish Flag by Seth Opgenorth */
808 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
809 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
810 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
811 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
812 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
813 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
814 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
815 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3}
817 { /* level 33 Color Pyramid by Seth Opgenorth */
818 {0x0,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x0},
819 {0x0,0x0,0x0,0x4,0x24,0x4,0x24,0x0,0x0,0x0},
820 {0x0,0x0,0x23,0x3,0x3,0x3,0x23,0x3,0x0,0x0},
821 {0x0,0x0,0x25,0x5,0x25,0x35,0x5,0x35,0x0,0x0},
822 {0x0,0x36,0x6,0x6,0x6,0x6,0x26,0x6,0x6,0x0},
823 {0x0,0x7,0x7,0x7,0x7,0x25,0x27,0x7,0x27,0x0},
824 {0x2,0x2,0x22,0x2,0x2,0x2,0x22,0x2,0x2,0x2},
825 {0x21,0x1,0x1,0x31,0x1,0x21,0x1,0x1,0x31,0x1}
827 { /* level 34 Rhombus by Seth Opgenorth */
828 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0},
829 {0x0,0x0,0x0,0x3,0x32,0x22,0x23,0x0,0x0,0x0},
830 {0x0,0x0,0x3,0x2,0x24,0x4,0x2,0x23,0x0,0x0},
831 {0x26,0x3,0x2,0x4,0x5,0x5,0x4,0x22,0x3,0x6},
832 {0x36,0x3,0x2,0x34,0x5,0x5,0x4,0x2,0x3,0x36},
833 {0x0,0x0,0x3,0x2,0x4,0x34,0x2,0x23,0x0,0x0},
834 {0x0,0x0,0x0,0x23,0x2,0x2,0x3,0x0,0x0,0x0},
835 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0}
837 { /* level 35 PacMan Ghost by Seth Opgenorth */
838 {0x0,0x0,0x0,0x0,0x2,0x32,0x2,0x0,0x0,0x0},
839 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
840 {0x0,0x0,0x2,0x24,0x4,0x2,0x4,0x4,0x32,0x0},
841 {0x0,0x0,0x2,0x24,0x0,0x22,0x24,0x0,0x22,0x0},
842 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
843 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
844 {0x0,0x0,0x2,0x32,0x2,0x2,0x22,0x2,0x32,0x0},
845 {0x0,0x0,0x0,0x22,0x0,0x32,0x0,0x22,0x0,0x0}
847 { /* level 36 Star by Seth Opgenorth */
848 {0x3,0x4,0x3,0x4,0x6,0x24,0x3,0x24,0x3,0x0},
849 {0x24,0x0,0x0,0x6,0x6,0x6,0x0,0x0,0x4,0x0},
850 {0x3,0x26,0x6,0x2,0x6,0x2,0x6,0x26,0x23,0x0},
851 {0x4,0x0,0x6,0x6,0x36,0x6,0x6,0x0,0x4,0x0},
852 {0x3,0x0,0x0,0x26,0x6,0x26,0x0,0x0,0x33,0x0},
853 {0x34,0x0,0x6,0x6,0x0,0x6,0x6,0x0,0x4,0x0},
854 {0x3,0x26,0x6,0x0,0x0,0x0,0x6,0x6,0x3,0x0},
855 {0x4,0x3,0x4,0x23,0x24,0x3,0x4,0x33,0x4,0x0}
857 { /* level 37 It's 8-Bit by Seth Opgenorth */
858 {0x26,0x26,0x6,0x6,0x5,0x6,0x26,0x6,0x26,0x6},
859 {0x2,0x2,0x22,0x3,0x3,0x0,0x0,0x0,0x4,0x0},
860 {0x2,0x0,0x2,0x33,0x3,0x3,0x5,0x0,0x24,0x0},
861 {0x32,0x2,0x2,0x33,0x0,0x23,0x0,0x4,0x4,0x4},
862 {0x2,0x22,0x2,0x3,0x3,0x0,0x5,0x4,0x4,0x24},
863 {0x2,0x0,0x2,0x23,0x0,0x3,0x25,0x0,0x4,0x0},
864 {0x22,0x2,0x2,0x3,0x23,0x0,0x5,0x0,0x4,0x0},
865 {0x6,0x26,0x6,0x36,0x6,0x36,0x6,0x6,0x6,0x6}
867 { /* level 38 Linux by Seth Opgenorth */
868 {0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
869 {0x7,0x0,0x0,0x0,0x33,0x0,0x23,0x0,0x0,0x0},
870 {0x7,0x32,0x0,0x0,0x3,0x0,0x23,0x6,0x0,0x6},
871 {0x37,0x0,0x0,0x0,0x23,0x0,0x3,0x6,0x0,0x26},
872 {0x7,0x22,0x24,0x0,0x3,0x33,0x3,0x0,0x26,0x0},
873 {0x37,0x22,0x24,0x24,0x4,0x0,0x0,0x0,0x26,0x0},
874 {0x7,0x2,0x4,0x0,0x4,0x0,0x0,0x6,0x0,0x26},
875 {0x7,0x27,0x4,0x0,0x34,0x0,0x0,0x6,0x0,0x26}
877 { /* level 39 Colorful Squares by Seth Opgenorth*/
878 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0},
879 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
880 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
881 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
882 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
883 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
884 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
885 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0}
887 { /* TheEnd */
888 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
889 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
890 {0x32,0x0,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
891 {0x32,0x32,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
892 {0x32,0x32,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
893 {0x32,0x0,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
894 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
895 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
902 * Enums and structs
906 enum power_types
908 POWER_TYPE_LIFE_GAIN = 0,
909 POWER_TYPE_LIFE_LOSS,
910 POWER_TYPE_PADDLE_STICKY,
911 POWER_TYPE_PADDLE_SHOOTER,
912 POWER_TYPE_PADDLE_NORMAL,
913 POWER_TYPE_PADDLE_FLIP,
914 POWER_TYPE_EXTRA_BALL,
915 POWER_TYPE_PADDLE_LONG,
916 POWER_TYPE_PADDLE_SHORT,
917 NUMBER_OF_POWERUPS,
920 #define POWERUP_HEIGHT FIXED3(BMPHEIGHT_brickmania_powerups/NUMBER_OF_POWERUPS)
921 /* Increasing this value makes the game with less powerups */
922 #define POWER_RAND (NUMBER_OF_POWERUPS + 15)
924 enum difficulty_options
926 EASY,
927 NORMAL
930 enum game_state
932 ST_READY,
933 ST_START,
934 ST_PAUSE
937 enum paddle_type
939 PADDLE_TYPE_NORMAL = 0,
940 PADDLE_TYPE_STICKY,
941 PADDLE_TYPE_SHOOTER,
944 enum intersection
946 INTERSECTION_TOP,
947 INTERSECTION_BOTTOM,
948 INTERSECTION_LEFT,
949 INTERSECTION_RIGHT,
950 INTERSECTION_ALL,
953 struct brick
955 bool used; /* Is the brick still in play? */
956 int color;
957 int hits; /* How many hits can this brick take? */
958 int hiteffect;
961 struct ball
963 /* pos_x and y store the current center position of the ball */
964 int pos_x;
965 int pos_y;
966 /* tempx and tempy store an absolute position the ball should be in. If
967 * they are equal to 0, they are not used when positioning the ball.
969 int tempx;
970 int tempy;
971 /* speedx and speedy store the current speed of the ball */
972 int speedx;
973 int speedy;
974 bool glue; /* Is the ball stuck to the paddle? */
977 struct fire
979 int top; /* This stores the fire y position, it is a fixed point num */
980 int x_pos; /* This stores the fire x position, it is a whole number */
983 struct power
985 int top; /* This stores the powerup y position, it is a fixed point num */
986 int x_pos; /* This stores the (middle of) powerup x position, it is a whole number */
987 enum power_types type; /* This stores the powerup type */
990 struct point
992 int x;
993 int y;
996 struct line
998 struct point p1;
999 struct point p2;
1002 struct rect
1004 struct point top_left;
1005 struct point bottom_right;
1010 * Globals
1014 static enum game_state game_state;
1015 static int pad_pos_x;
1016 static int life;
1017 static int score,vscore;
1018 static bool flip_sides;
1019 static int level;
1020 static int brick_on_board;
1021 static int used_balls;
1022 static int used_fires;
1023 static int used_powers;
1024 static int difficulty = NORMAL;
1025 static int pad_width;
1026 static int flip_sides_delay;
1027 static bool resume = false;
1028 static bool resume_file = false;
1029 static struct brick brick[NUM_BRICKS_ROWS][NUM_BRICKS_COLS];
1030 static struct ball ball[MAX_BALLS];
1031 static struct fire fire[MAX_FIRES];
1032 static struct power power[MAX_POWERS];
1033 static enum paddle_type paddle_type;
1035 static struct configdata config[] =
1037 {TYPE_INT, 0, 1, { .int_p = &difficulty }, "difficulty", NULL},
1040 static struct highscore highscores[NUM_SCORES];
1045 * Functions
1050 * check_lines:
1051 * This is based off an explanation and expanded math presented by Paul Bourke:
1052 * http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
1054 * It takes two lines as inputs and returns 1 if they intersect, 0 if they do
1055 * not. hitp returns the point where the two lines intersected.
1057 * This function expects fixed point inputs with a precision of 3. When a
1058 * collision occurs hitp is updated with a fixed point location (precision 3)
1059 * where the collision happened. The internal calculations are fixed
1060 * point with a 7 bit fractional precision.
1062 * If you choose 10 bits of precision a screen size of about 640x480 is the
1063 * largest this can go. 7 bits allows for an accurate intersection calculation
1064 * with a line length of about 64 and a rougher line lenght of 128 which is
1065 * larger than any target currently needs (the pad is the longest line and it
1066 * only needs an accuracy of 2^4 at most to figure out which section of the pad
1067 * the ball hit). A precision of 7 gives breathing room for larger screens.
1068 * Longer line sizes that need accurate intersection points will need more
1069 * precision, but will decrease the maximum screen resolution.
1072 #define LINE_PREC 7
1073 static int check_lines(struct line *line1, struct line *line2,
1074 struct point *hitp)
1076 /* Introduction:
1077 * This code is based on the solution of these two input equations:
1078 * Pa = P1 + ua (P2-P1)
1079 * Pb = P3 + ub (P4-P3)
1081 * Where line one is composed of points P1 and P2 and line two is composed
1082 * of points P3 and P4.
1084 * ua/b is the fractional value you can multiply the x and y legs of the
1085 * triangle formed by each line to find a point on the line.
1087 * The two equations can be expanded to their x/y components:
1088 * Pa.x = p1.x + ua(p2.x - p1.x)
1089 * Pa.y = p1.y + ua(p2.y - p1.y)
1091 * Pb.x = p3.x + ub(p4.x - p3.x)
1092 * Pb.y = p3.y + ub(p4.y - p3.y)
1094 * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
1095 * up with two equations (one for x and one for y):
1097 * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
1098 * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
1100 * ua and ub can then be individually solved for. This results in the
1101 * equations used in the following code.
1104 /* Denominator for ua and ub are the same so store this calculation */
1105 int d = FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p2.x-line1->p1.x))
1106 -FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p2.y-line1->p1.y));
1108 /* n_a and n_b are calculated as seperate values for readability */
1109 int n_a = FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p1.y-line2->p1.y))
1110 -FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p1.x-line2->p1.x));
1112 int n_b = FIXED3_MUL((line1->p2.x - line1->p1.x),(line1->p1.y-line2->p1.y))
1113 -FIXED3_MUL((line1->p2.y - line1->p1.y),(line1->p1.x-line2->p1.x));
1115 /* Make sure there is not a division by zero - this also indicates that
1116 * the lines are parallel.
1118 * If n_a and n_b were both equal to zero the lines would be on top of each
1119 * other (coincidental). This check is not done because it is not
1120 * necessary for this implementation (the parallel check accounts for this).
1122 if(d == 0)
1123 return 0;
1125 /* Calculate the intermediate fractional point that the lines potentially
1126 * intersect.
1128 int ua = (n_a << LINE_PREC)/d;
1129 int ub = (n_b << LINE_PREC)/d;
1131 /* The fractional point will be between 0 and 1 inclusive if the lines
1132 * intersect. If the fractional calculation is larger than 1 or smaller
1133 * than 0 the lines would need to be longer to intersect.
1135 if(ua >=0 && ua <= (1<<LINE_PREC) && ub >= 0 && ub <= (1<<LINE_PREC))
1137 hitp->x = line1->p1.x + ((ua * (line1->p2.x - line1->p1.x))>>LINE_PREC);
1138 hitp->y = line1->p1.y + ((ua * (line1->p2.y - line1->p1.y))>>LINE_PREC);
1139 return 1;
1141 return 0;
1145 static int check_rect(struct line *line, struct rect *rect,
1146 enum intersection intersection, struct point *hitp)
1148 struct line edge;
1150 switch (intersection)
1152 case INTERSECTION_TOP:
1154 edge.p1.x = rect->top_left.x;
1155 edge.p1.y = rect->top_left.y;
1157 edge.p2.x = rect->bottom_right.x;
1158 edge.p2.y = rect->top_left.y;
1160 break;
1162 case INTERSECTION_BOTTOM:
1164 edge.p1.x = rect->top_left.x;
1165 edge.p1.y = rect->bottom_right.y;
1167 edge.p2.x = rect->bottom_right.x;
1168 edge.p2.y = rect->bottom_right.y;
1170 break;
1172 case INTERSECTION_LEFT:
1174 edge.p1.x = rect->top_left.x;
1175 edge.p1.y = rect->top_left.y;
1177 edge.p2.x = rect->top_left.x;
1178 edge.p2.y = rect->bottom_right.y;
1180 break;
1182 case INTERSECTION_RIGHT:
1184 edge.p1.x = rect->bottom_right.x;
1185 edge.p1.y = rect->top_left.y;
1187 edge.p2.x = rect->bottom_right.x;
1188 edge.p2.y = rect->bottom_right.y;
1190 break;
1192 case INTERSECTION_ALL: /* Test hit on all edges */
1194 return (check_rect(line, rect, INTERSECTION_TOP, hitp) ||
1195 check_rect(line, rect, INTERSECTION_BOTTOM, hitp) ||
1196 check_rect(line, rect, INTERSECTION_LEFT, hitp) ||
1197 check_rect(line, rect, INTERSECTION_RIGHT, hitp));
1201 return check_lines(line, &edge, hitp);
1204 static void brickmania_init_game(bool new_game)
1206 int i,j;
1208 pad_pos_x = GAMESCREEN_WIDTH/2 - PAD_WIDTH/2;
1210 for(i=0;i<MAX_BALLS;i++)
1212 ball[i].speedx = 0;
1213 ball[i].speedy = 0;
1214 ball[i].tempy = 0;
1215 ball[i].tempx = 0;
1216 ball[i].pos_y = ON_PAD_POS_Y;
1217 ball[i].pos_x = GAMESCREEN_WIDTH/2;
1218 ball[i].glue = false;
1221 used_balls = 1;
1222 used_fires = 0;
1223 used_powers = 0;
1224 game_state = ST_READY;
1225 paddle_type = PADDLE_TYPE_NORMAL;
1226 pad_width = PAD_WIDTH;
1227 flip_sides = false;
1228 flip_sides_delay = FLIP_SIDES_DELAY;
1230 if (new_game) {
1231 brick_on_board=0;
1232 /* add one life per achieved level */
1233 if (difficulty==EASY && life<2) {
1234 score+=SCORE_LEVEL_COMPLETED;
1235 life++;
1239 for(i=0;i<NUM_BRICKS_ROWS;i++) {
1240 for(j=0;j<NUM_BRICKS_COLS;j++) {
1241 if (new_game) {
1242 brick[i][j].hits=levels[level][i][j]>=10?
1243 levels[level][i][j]/16-1:0;
1244 brick[i][j].hiteffect=0;
1245 brick[i][j].used=!(levels[level][i][j]==0);
1246 brick[i][j].color=(levels[level][i][j]>=10?
1247 levels[level][i][j]%16:
1248 levels[level][i][j])-1;
1249 if (levels[level][i][j]!=0)
1250 brick_on_board++;
1256 static void brickmania_loadgame(void)
1258 int fd;
1260 resume = false;
1262 /* open game file */
1263 fd = rb->open(SAVE_FILE, O_RDONLY);
1264 if(fd < 0) return;
1266 /* read in saved game */
1267 if((rb->read(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1268 (rb->read(fd, &life, sizeof(life)) <= 0) ||
1269 (rb->read(fd, &game_state, sizeof(game_state)) <= 0) ||
1270 (rb->read(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1271 (rb->read(fd, &score, sizeof(score)) <= 0) ||
1272 (rb->read(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1273 (rb->read(fd, &level, sizeof(level)) <= 0) ||
1274 (rb->read(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1275 (rb->read(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1276 (rb->read(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1277 (rb->read(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1278 (rb->read(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1279 (rb->read(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1280 (rb->read(fd, &brick, sizeof(brick)) <= 0) ||
1281 (rb->read(fd, &ball, sizeof(ball)) <= 0) ||
1282 (rb->read(fd, &fire, sizeof(fire)) <= 0) ||
1283 (rb->read(fd, &power, sizeof(power)) <= 0))
1285 rb->splash(HZ/2, "Failed to load game");
1287 else
1289 vscore = score;
1290 resume = true;
1293 rb->close(fd);
1295 return;
1298 static void brickmania_savegame(void)
1300 int fd;
1302 /* write out the game state to the save file */
1303 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
1304 if(fd < 0) return;
1306 if ((rb->write(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1307 (rb->write(fd, &life, sizeof(life)) <= 0) ||
1308 (rb->write(fd, &game_state, sizeof(game_state)) <= 0) ||
1309 (rb->write(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1310 (rb->write(fd, &score, sizeof(score)) <= 0) ||
1311 (rb->write(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1312 (rb->write(fd, &level, sizeof(level)) <= 0) ||
1313 (rb->write(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1314 (rb->write(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1315 (rb->write(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1316 (rb->write(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1317 (rb->write(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1318 (rb->write(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1319 (rb->write(fd, &brick, sizeof(brick)) <= 0) ||
1320 (rb->write(fd, &ball, sizeof(ball)) <= 0) ||
1321 (rb->write(fd, &fire, sizeof(fire)) <= 0) ||
1322 (rb->write(fd, &power, sizeof(power)) <= 0))
1324 rb->close(fd);
1325 rb->remove(SAVE_FILE);
1326 rb->splash(HZ/2, "Failed to save game");
1327 return;
1330 rb->close(fd);
1333 /* brickmania_sleep timer counting the score */
1334 static void brickmania_sleep(int secs)
1336 bool done=false;
1337 char s[20];
1338 int count=0;
1339 int sw, w;
1341 while (!done)
1343 if (count == 0)
1344 count = *rb->current_tick + HZ*secs;
1345 if ( (TIME_AFTER(*rb->current_tick, count)) && (vscore == score) )
1346 done = true;
1348 if(vscore != score)
1350 if (vscore<score)
1351 vscore++;
1352 if (vscore>score)
1353 vscore--;
1354 rb->snprintf(s, sizeof(s), "%d", vscore);
1355 rb->lcd_getstringsize(s, &sw, &w);
1356 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1357 rb->lcd_update_rect(0,0,LCD_WIDTH,w+2);
1359 rb->yield();
1363 static int brickmania_help(void)
1365 static char *help_text[] = {
1366 "Brickmania", "", "Aim", "",
1367 "Destroy", "all", "the", "bricks", "by", "bouncing",
1368 "the", "ball", "of", "them", "using", "the", "paddle.", "", "",
1369 "Controls", "",
1370 #if CONFIG_KEYPAD == COWON_D2_PAD
1371 "- & +:",
1372 #else
1373 "< & >:",
1374 #endif
1375 "Moves", "the", "paddle", "",
1376 #if CONFIG_KEYPAD == ONDIO_PAD
1377 "MENU:",
1378 #elif (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
1379 "PLAY:",
1380 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
1381 "NAVI:",
1382 #elif CONFIG_KEYPAD == COWON_D2_PAD
1383 "MENU:",
1384 #else
1385 "SELECT:",
1386 #endif
1387 "Releases", "the", "ball/Fire!", "",
1388 #if CONFIG_KEYPAD == IAUDIO_M3_PAD
1389 "REC:",
1390 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
1391 (CONFIG_KEYPAD == CREATIVEZVM_PAD)
1392 "BACK:",
1393 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1394 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1395 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1396 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1397 "MENU:",
1398 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
1399 (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
1400 (CONFIG_KEYPAD == ONDIO_PAD) || \
1401 (CONFIG_KEYPAD == RECORDER_PAD) || \
1402 (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
1403 "STOP:",
1404 #else
1405 "POWER:",
1406 #endif
1407 "Returns", "to", "menu", "", "",
1408 "Specials", "",
1409 "N", "Normal:", "returns", "paddle", "to", "normal", "",
1410 "D", "DIE!:", "loses", "a", "life", "",
1411 "L", "Life:", "gains", "a", "life/power", "up", "",
1412 "F", "Fire:", "allows", "you", "to", "shoot", "bricks", "",
1413 "G", "Glue:", "ball", "sticks", "to", "paddle", "",
1414 "B", "Ball:", "generates", "another", "ball", "",
1415 "FL", "Flip:", "flips", "left / right", "movement", "",
1416 "<->", "or", "<E>:", "enlarges", "the", "paddle", "",
1417 ">-<", "or", ">S<:", "shrinks", "the", "paddle", "",
1419 static struct style_text formation[]={
1420 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1421 { 2, C_RED },
1422 { 19, C_RED },
1423 { 37, C_RED },
1424 { 39, C_BLUE },
1425 { 46, C_RED },
1426 { 52, C_GREEN },
1427 { 59, C_ORANGE },
1428 { 67, C_GREEN },
1429 { 74, C_YELLOW },
1430 { 80, C_RED },
1431 LAST_STYLE_ITEM
1434 rb->lcd_setfont(FONT_UI);
1435 #ifdef HAVE_LCD_COLOR
1436 rb->lcd_set_background(LCD_BLACK);
1437 rb->lcd_set_foreground(LCD_WHITE);
1438 #endif
1439 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1440 return 1;
1441 rb->lcd_setfont(FONT_SYSFIXED);
1443 return 0;
1446 static int brickmania_menu_cb(int action, const struct menu_item_ex *this_item)
1448 int i = ((intptr_t)this_item);
1449 if(action == ACTION_REQUEST_MENUITEM
1450 && !resume && (i==0 || i==6))
1451 return ACTION_EXIT_MENUITEM;
1452 return action;
1455 static int brickmania_menu(void)
1457 int selected = 0;
1459 static struct opt_items options[] = {
1460 { "Easy", -1 },
1461 { "Normal", -1 },
1464 #ifdef HAVE_TOUCHSCREEN
1465 /* Entering Menu, set the touchscreen to the global setting */
1466 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
1467 #endif
1469 MENUITEM_STRINGLIST(main_menu, "Brickmania Menu", brickmania_menu_cb,
1470 "Resume Game", "Start New Game",
1471 "Difficulty", "Help", "High Scores",
1472 "Playback Control",
1473 "Quit without Saving", "Quit");
1475 rb->button_clear_queue();
1476 while (true) {
1477 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1478 case 0:
1479 if(game_state!=ST_READY)
1480 game_state = ST_PAUSE;
1481 if(resume_file)
1482 rb->remove(SAVE_FILE);
1483 return 0;
1484 case 1:
1485 score=0;
1486 vscore=0;
1487 life=2;
1488 level=0;
1489 brickmania_init_game(true);
1490 return 0;
1491 case 2:
1492 rb->set_option("Difficulty", &difficulty, INT,
1493 options, 2, NULL);
1494 break;
1495 case 3:
1496 if (brickmania_help())
1497 return 1;
1498 break;
1499 case 4:
1500 highscore_show(-1, highscores, NUM_SCORES, true);
1501 break;
1502 case 5:
1503 if (playback_control(NULL))
1504 return 1;
1505 break;
1506 case 6:
1507 return 1;
1508 case 7:
1509 if (resume) {
1510 rb->splash(HZ*1, "Saving game ...");
1511 brickmania_savegame();
1513 return 1;
1514 case MENU_ATTACHED_USB:
1515 return 1;
1516 default:
1517 break;
1520 #ifdef HAVE_TOUCHSCREEN
1521 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
1522 #endif
1525 static void brick_hit(int i, int j)
1527 if(!brick[i][j].used)
1528 return;
1530 /* if this is a crackable brick hits starts as
1531 * greater than 0.
1533 if (brick[i][j].hits > 0) {
1534 brick[i][j].hits--;
1535 brick[i][j].hiteffect++;
1536 score+=SCORE_BALL_HIT_BRICK;
1538 else {
1539 brick[i][j].used=false;
1540 if (used_powers<MAX_POWERS)
1542 int ran = rb->rand()%POWER_RAND;
1544 if (ran<NUMBER_OF_POWERUPS)
1546 power[used_powers].top = TOPMARGIN + i*BRICK_HEIGHT;
1547 power[used_powers].x_pos = LEFTMARGIN + j*BRICK_WIDTH +
1548 (BRICK_WIDTH >> 1);
1549 power[used_powers].type = ran;
1550 used_powers++;
1553 brick_on_board--;
1554 score+=SCORE_BALL_DEMOLISHED_BRICK;
1558 static int brickmania_game_loop(void)
1560 int j,i,k;
1561 int sw, sh;
1562 char s[30];
1563 int sec_count=0;
1564 int end;
1566 /* pad_rect used for powerup/ball checks */
1567 struct rect pad_rect;
1568 /* This is used for various lines that are checked (ball and powerup) */
1569 struct line misc_line;
1571 /* This stores the point that the two lines intersected in a test */
1572 struct point pt_hit;
1574 if (brickmania_menu()) {
1575 return 1;
1577 resume = false;
1578 resume_file = false;
1580 #ifdef HAVE_LCD_COLOR
1581 rb->lcd_set_background(LCD_BLACK);
1582 rb->lcd_set_foreground(LCD_WHITE);
1583 rb->lcd_set_drawmode(DRMODE_SOLID);
1584 rb->lcd_clear_display();
1585 #endif
1587 while(true) {
1588 /* Convert CYCLETIME (in ms) to HZ */
1589 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1591 if (life >= 0) {
1592 rb->lcd_clear_display();
1594 if (flip_sides)
1596 if (TIME_AFTER(*rb->current_tick, sec_count))
1598 sec_count=*rb->current_tick+HZ;
1599 if (flip_sides_delay > 1)
1600 flip_sides_delay--;
1601 else
1602 flip_sides=false;
1604 rb->snprintf(s, sizeof(s), "%d", flip_sides_delay);
1605 rb->lcd_getstringsize(s, &sw, NULL);
1606 rb->lcd_putsxy(LCD_WIDTH/2-2, INT3(STRINGPOS_FLIP), s);
1610 if (vscore<score) vscore++;
1611 rb->snprintf(s, sizeof(s), "%d", vscore);
1612 rb->lcd_getstringsize(s, &sw, NULL);
1613 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1615 /* write life num */
1616 rb->snprintf(s, sizeof(s), "Life: %d", life);
1618 /* hijack i */
1619 i = sw;
1620 rb->lcd_getstringsize(s, &sw, NULL);
1621 if (sw >= (LCD_WIDTH/2-i/2))
1622 rb->snprintf(s, sizeof(s), "L: %d", life);
1623 rb->lcd_putsxy(0, 0, s);
1625 /* write level */
1626 rb->snprintf(s, sizeof(s), "Level %d", level+1);
1627 rb->lcd_getstringsize(s, &sw, NULL);
1629 if (LCD_WIDTH-sw <= (LCD_WIDTH/2+i/2)+1)
1631 rb->snprintf(s, sizeof(s), "Lvl %d", level+1);
1632 rb->lcd_getstringsize(s, &sw, NULL);
1635 rb->lcd_putsxy(LCD_WIDTH-sw, 0, s);
1636 i = 0;
1638 /* continue game */
1639 if (game_state == ST_PAUSE)
1641 rb->snprintf(s, sizeof(s), CONTINUE_TEXT);
1642 rb->lcd_getstringsize(s, &sw, NULL);
1643 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_NAVI), s);
1645 sec_count=*rb->current_tick+HZ;
1648 /* draw the ball */
1649 for(i=0;i<used_balls;i++)
1650 rb->lcd_bitmap(brickmania_ball,
1651 INT3(ball[i].pos_x - HALFBALL),
1652 INT3(ball[i].pos_y - HALFBALL),
1653 INT3(BALL), INT3(BALL));
1655 if (brick_on_board==0)
1656 brick_on_board--;
1658 /* Setup the pad line-later used in intersection test */
1659 pad_rect.top_left.x = pad_pos_x;
1660 pad_rect.top_left.y = PAD_POS_Y;
1662 pad_rect.bottom_right.x = pad_pos_x + pad_width;
1663 pad_rect.bottom_right.y = PAD_POS_Y + PAD_HEIGHT;
1665 if (game_state!=ST_PAUSE)
1667 /* move the fires */
1668 for(k=0;k<used_fires;k++)
1670 fire[k].top -= SPEED_FIRE;
1671 if (fire[k].top < 0)
1673 used_fires--;
1674 fire[k].top = fire[used_fires].top;
1675 fire[k].x_pos = fire[used_fires].x_pos;
1676 k--;
1678 else if (fire[k].x_pos >= LEFTMARGIN &&
1679 fire[k].x_pos < LEFTMARGIN + NUM_BRICKS_COLS * BRICK_WIDTH)
1681 j = (fire[k].x_pos - LEFTMARGIN) / BRICK_WIDTH;
1682 for (i=NUM_BRICKS_ROWS-1;i>=0;i--)
1684 if (TOPMARGIN + i*BRICK_HEIGHT<=fire[k].top)
1685 break;
1686 if (brick[i][j].used)
1688 score += SCORE_FIRE_HIT_BRICK;
1689 brick_hit(i, j);
1690 used_fires--;
1691 fire[k].top = fire[used_fires].top;
1692 fire[k].x_pos = fire[used_fires].x_pos;
1693 k--;
1694 break;
1700 /* move and handle the powerups */
1701 for (k=0;k<used_powers;k++)
1703 int remove_power = 0;
1705 power[k].top += SPEED_POWER;
1707 if (power[k].top > PAD_POS_Y)
1709 /* power hit bottom */
1710 remove_power = 1;
1712 else
1714 /* Use misc_line to check if the center of the powerup
1715 * hit the paddle.
1717 misc_line.p1.x = power[k].x_pos;
1718 misc_line.p1.y = power[k].top;
1720 misc_line.p2 = misc_line.p1;
1721 misc_line.p2.y += SPEED_POWER;
1723 /* Check if the powerup will hit the paddle */
1724 if (check_rect(&misc_line, &pad_rect, INTERSECTION_ALL,
1725 &pt_hit))
1728 /* power hit paddle */
1729 remove_power = 1;
1730 switch(power[k].type)
1732 case POWER_TYPE_LIFE_GAIN:
1733 life++;
1734 score += SCORE_POWER_LIFE_GAIN;
1735 break;
1736 case POWER_TYPE_LIFE_LOSS:
1737 life--;
1738 if (life>=0)
1740 brickmania_init_game(false);
1741 brickmania_sleep(2);
1743 break;
1744 case POWER_TYPE_PADDLE_STICKY:
1745 score += SCORE_POWER_PADDLE_STICKY;
1746 paddle_type = PADDLE_TYPE_STICKY;
1747 break;
1748 case POWER_TYPE_PADDLE_SHOOTER:
1749 score += SCORE_POWER_PADDLE_SHOOTER;
1750 paddle_type = PADDLE_TYPE_SHOOTER;
1751 for(i=0;i<used_balls;i++)
1752 ball[i].glue=false;
1753 break;
1754 case POWER_TYPE_PADDLE_NORMAL:
1755 score += SCORE_POWER_PADDLE_NORMAL;
1756 paddle_type = PADDLE_TYPE_NORMAL;
1757 for(i=0;i<used_balls;i++)
1758 ball[i].glue=false;
1759 flip_sides=false;
1760 pad_pos_x += (pad_width-PAD_WIDTH)/2;
1761 pad_width = PAD_WIDTH;
1762 break;
1763 case POWER_TYPE_PADDLE_FLIP:
1764 score += SCORE_POWER_FLIP;
1765 sec_count = *rb->current_tick+HZ;
1766 flip_sides_delay = FLIP_SIDES_DELAY;
1767 flip_sides = true;
1768 break;
1769 case POWER_TYPE_EXTRA_BALL:
1770 score += SCORE_POWER_EXTRA_BALL;
1771 if(used_balls<MAX_BALLS)
1773 /* Set the speed */
1774 if(rb->rand()%2 == 0)
1775 ball[used_balls].speedx=-SPEED_4Q_X;
1776 else
1777 ball[used_balls].speedx= SPEED_4Q_X;
1778 ball[used_balls].speedy= SPEED_4Q_Y;
1779 /* Ball is not glued */
1780 ball[used_balls].glue= false;
1781 used_balls++;
1783 break;
1784 case POWER_TYPE_PADDLE_LONG:
1785 score+=SCORE_POWER_LONG_PADDLE;
1786 if (pad_width==PAD_WIDTH)
1788 pad_width = LONG_PAD_WIDTH;
1789 pad_pos_x -= (LONG_PAD_WIDTH -
1790 PAD_WIDTH)/2;
1792 else if (pad_width==SHORT_PAD_WIDTH)
1794 pad_width = PAD_WIDTH;
1795 pad_pos_x-=(PAD_WIDTH-
1796 SHORT_PAD_WIDTH)/2;
1798 if (pad_pos_x < 0)
1799 pad_pos_x = 0;
1800 else if(pad_pos_x + pad_width >
1801 GAMESCREEN_WIDTH)
1802 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
1803 break;
1804 case POWER_TYPE_PADDLE_SHORT:
1805 if (pad_width==PAD_WIDTH)
1807 pad_width=SHORT_PAD_WIDTH;
1808 pad_pos_x+=(PAD_WIDTH-
1809 SHORT_PAD_WIDTH)/2;
1811 else if (pad_width==LONG_PAD_WIDTH)
1813 pad_width=PAD_WIDTH;
1814 pad_pos_x+=(LONG_PAD_WIDTH-PAD_WIDTH)/2;
1816 break;
1817 default:
1818 break;
1822 if (remove_power)
1824 used_powers--;
1825 if (k != used_powers)
1827 power[k].top = power[used_powers].top;
1828 power[k].x_pos = power[used_powers].x_pos;
1829 power[k].type = power[used_powers].type;
1831 k--;
1837 /* draw the fires */
1838 for(k=0;k<used_fires;k++)
1840 rb->lcd_vline(INT3(fire[k].x_pos), INT3(fire[k].top),
1841 INT3(fire[k].top + FIRE_LENGTH));
1844 /* draw the powerups */
1845 for(k=0;k<used_powers;k++)
1847 rb->lcd_bitmap_part(brickmania_powerups,0,
1848 INT3(POWERUP_HEIGHT)*power[k].type,
1849 STRIDE(SCREEN_MAIN, BMPWIDTH_brickmania_powerups,
1850 BMPHEIGHT_brickmania_powerups),
1851 INT3(power[k].x_pos - (POWERUP_WIDTH >> 1)),
1852 INT3(power[k].top), INT3(POWERUP_WIDTH),
1853 INT3(POWERUP_HEIGHT));
1856 /* handle all of the bricks */
1857 for (i=0; i<NUM_BRICKS_ROWS; i++)
1859 for (j=0; j<NUM_BRICKS_COLS ;j++)
1861 int brickx,bricky;
1863 /* The brick is a brick, but it may or may not be in use */
1864 if(brick[i][j].used)
1866 struct rect brick_rect;
1868 brickx = LEFTMARGIN + j*BRICK_WIDTH;
1869 bricky = TOPMARGIN + i*BRICK_HEIGHT;
1871 brick_rect.top_left.x = brickx;
1872 brick_rect.top_left.y = bricky;
1874 brick_rect.bottom_right.x = brickx + BRICK_WIDTH;
1875 brick_rect.bottom_right.y = bricky + BRICK_HEIGHT;
1877 /* Draw the brick */
1878 rb->lcd_bitmap_part(brickmania_bricks,0,
1879 INT3(BRICK_HEIGHT)*brick[i][j].color,
1880 STRIDE( SCREEN_MAIN,
1881 BMPWIDTH_brickmania_bricks,
1882 BMPHEIGHT_brickmania_bricks),
1883 INT3(brickx),
1884 INT3(bricky),
1885 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1887 #ifdef HAVE_LCD_COLOR /* No transparent effect for greyscale lcds for now */
1888 if (brick[i][j].hiteffect > 0)
1889 rb->lcd_bitmap_transparent_part(brickmania_break,0,
1890 INT3(BRICK_HEIGHT)*brick[i][j].hiteffect,
1891 STRIDE( SCREEN_MAIN,
1892 BMPWIDTH_brickmania_break,
1893 BMPHEIGHT_brickmania_break),
1894 INT3(brickx),
1895 INT3(bricky),
1896 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1897 #endif
1899 /* Check if any balls collided with the brick */
1900 for(k=0; k<used_balls; k++)
1902 int hit = 0;
1904 /* Setup the ball path to describe the current ball
1905 * position and the line it makes to its next
1906 * position.
1908 misc_line.p1.x = ball[k].pos_x;
1909 misc_line.p1.y = ball[k].pos_y;
1911 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1912 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1914 /* Check to see if the ball and the bottom hit. If
1915 * the ball is moving down we don't want to
1916 * include the bottom line intersection.
1918 * The order that the sides are checked matters.
1920 * Note that tempx/tempy store the next position
1921 * that the ball should be drawn.
1923 if (ball[k].speedy <= 0 && check_rect(&misc_line,
1924 &brick_rect, INTERSECTION_BOTTOM, &pt_hit))
1926 ball[k].speedy = -ball[k].speedy;
1927 hit = 1;
1929 /* Check the top, if the ball is moving up dont
1930 * count it as a hit.
1932 else if (ball[k].speedy > 0 && check_rect(&misc_line,
1933 &brick_rect, INTERSECTION_TOP, &pt_hit))
1935 ball[k].speedy = -ball[k].speedy;
1936 hit = 1;
1938 /* Check the left side of the brick */
1939 else if (check_rect(&misc_line, &brick_rect,
1940 INTERSECTION_LEFT, &pt_hit))
1942 ball[k].speedx = -ball[k].speedx;
1943 hit = 1;
1945 /* Check the right side of the brick */
1946 else if (check_rect(&misc_line, &brick_rect,
1947 INTERSECTION_RIGHT, &pt_hit))
1949 ball[k].speedx = -ball[k].speedx;
1950 hit = 1;
1953 if (hit)
1955 ball[k].tempy = pt_hit.y;
1956 ball[k].tempx = pt_hit.x;
1957 brick_hit(i, j);
1958 break;
1960 } /* for k */
1961 } /* if(used) */
1963 } /* for j */
1964 } /* for i */
1966 /* draw the paddle according to the PAD_WIDTH */
1967 if( pad_width == PAD_WIDTH ) /* Normal width */
1969 rb->lcd_bitmap_part(
1970 brickmania_pads,
1971 0, paddle_type*INT3(PAD_HEIGHT),
1972 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_pads,
1973 BMPHEIGHT_brickmania_pads),
1974 INT3(pad_pos_x), INT3(PAD_POS_Y),
1975 INT3(pad_width), INT3(PAD_HEIGHT) );
1977 else if( pad_width == LONG_PAD_WIDTH ) /* Long Pad */
1979 rb->lcd_bitmap_part(
1980 brickmania_long_pads,
1981 0,paddle_type*INT3(PAD_HEIGHT),
1982 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_long_pads,
1983 BMPHEIGHT_brickmania_long_pads),
1984 INT3(pad_pos_x), INT3(PAD_POS_Y),
1985 INT3(pad_width), INT3(PAD_HEIGHT) );
1987 else /* Short pad */
1989 rb->lcd_bitmap_part(
1990 brickmania_short_pads,
1991 0,paddle_type*INT3(PAD_HEIGHT),
1992 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_short_pads,
1993 BMPHEIGHT_brickmania_short_pads),
1994 INT3(pad_pos_x), INT3(PAD_POS_Y),
1995 INT3(pad_width), INT3(PAD_HEIGHT) );
1998 /* If the game is not paused continue */
1999 if (game_state!=ST_PAUSE)
2001 /* Loop through all of the balls in play */
2002 for(k=0;k<used_balls;k++)
2004 struct line screen_edge;
2006 /* Describe the ball movement for the edge collision detection */
2007 misc_line.p1.x = ball[k].pos_x;
2008 misc_line.p1.y = ball[k].pos_y;
2010 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
2011 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
2013 /* Did the Ball hit the top of the screen? */
2014 screen_edge.p1.x = 0;
2015 screen_edge.p1.y = 0;
2017 screen_edge.p2.x = GAMESCREEN_WIDTH;
2018 screen_edge.p2.y = 0;
2019 /* the test for pos_y prevents the ball from bouncing back
2020 * from _over_ the top to infinity on some rare cases */
2021 if (ball[k].pos_y > 0 &&
2022 check_lines(&misc_line, &screen_edge, &pt_hit))
2024 ball[k].tempy = pt_hit.y + 1;
2025 ball[k].tempx = pt_hit.x;
2026 /* Reverse the direction */
2027 ball[k].speedy = -ball[k].speedy;
2030 /* Player missed the ball and hit bottom of screen */
2031 if (ball[k].pos_y >= GAMESCREEN_HEIGHT)
2033 /* Player had balls to spare, so handle the removal */
2034 if (used_balls>1)
2036 /* decrease number of balls in play */
2037 used_balls--;
2038 /* Replace removed ball with the last ball */
2039 ball[k].pos_x = ball[used_balls].pos_x;
2040 ball[k].pos_y = ball[used_balls].pos_y;
2041 ball[k].speedy = ball[used_balls].speedy;
2042 ball[k].tempy = ball[used_balls].tempy;
2043 ball[k].speedx = ball[used_balls].speedx;
2044 ball[k].tempx = ball[used_balls].tempx;
2045 ball[k].glue = ball[used_balls].glue;
2047 /* Reset the last ball that was removed */
2048 ball[used_balls].speedx=0;
2049 ball[used_balls].speedy=0;
2050 ball[used_balls].tempy=0;
2051 ball[used_balls].tempx=0;
2052 ball[used_balls].pos_y=ON_PAD_POS_Y;
2053 ball[used_balls].pos_x=pad_pos_x+(pad_width/2)-HALFBALL;
2055 k--;
2056 continue;
2058 else
2060 /* Player lost a life */
2061 life--;
2062 if (life>=0)
2064 /* No lives left reset game */
2065 brickmania_init_game(false);
2066 brickmania_sleep(2);
2067 rb->button_clear_queue();
2072 if (game_state != ST_READY && !ball[k].glue)
2074 /* Check if the ball hit the left side */
2075 screen_edge.p1.x = 0;
2076 screen_edge.p1.y = 0;
2078 screen_edge.p2.x = 0;
2079 screen_edge.p2.y = GAMESCREEN_HEIGHT;
2080 if (check_lines(&misc_line, &screen_edge, &pt_hit))
2082 /* Reverse direction */
2083 ball[k].speedx = abs(ball[k].speedx);
2085 /* Re-position ball in gameboard */
2086 ball[k].tempy = pt_hit.y;
2087 ball[k].tempx = 0;
2090 /* Check if the ball hit the right side */
2091 screen_edge.p1.x = GAMESCREEN_WIDTH;
2092 screen_edge.p1.y = 0;
2094 screen_edge.p2.x = GAMESCREEN_WIDTH;
2095 screen_edge.p2.y = GAMESCREEN_HEIGHT;
2096 if (check_lines(&misc_line, &screen_edge, &pt_hit))
2098 /* Reverse direction */
2099 ball[k].speedx = -abs(ball[k].speedx);
2101 /* Re-position ball in gameboard */
2102 ball[k].tempy = pt_hit.y;
2103 ball[k].tempx = GAMESCREEN_WIDTH - FIXED3(1);
2106 /* Did the ball hit the paddle? Depending on where the ball
2107 * Hit set the x/y speed appropriately.
2109 if(check_rect(&misc_line, &pad_rect, INTERSECTION_TOP,
2110 &pt_hit) )
2112 /* Re-position ball based on collision */
2113 ball[k].tempy = ON_PAD_POS_Y;
2114 ball[k].tempx = pt_hit.x;
2116 /* Calculate the ball position relative to the paddle width */
2117 int ball_repos = pt_hit.x - pad_pos_x;
2118 /* If the ball hits the right half of paddle, x speed
2119 * should be positive, if it hits the left half it
2120 * should be negative.
2122 int x_direction = -1;
2124 /* Comparisons are done with respect to 1/2 pad_width */
2125 if(ball_repos > pad_width/2)
2127 /* flip the relative position */
2128 ball_repos -= ((ball_repos - pad_width/2) << 1);
2129 /* Ball hit the right half so X speed calculations
2130 * should be positive.
2132 x_direction = 1;
2135 /* Figure out where the ball hit relative to 1/2 pad
2136 * and in divisions of 4.
2138 ball_repos = ball_repos / (pad_width/2/4);
2140 switch(ball_repos)
2142 /* Ball hit the outer edge of the paddle */
2143 case 0:
2144 ball[k].speedy = SPEED_1Q_Y;
2145 ball[k].speedx = SPEED_1Q_X * x_direction;
2146 break;
2147 /* Ball hit the next fourth of the paddle */
2148 case 1:
2149 ball[k].speedy = SPEED_2Q_Y;
2150 ball[k].speedx = SPEED_2Q_X * x_direction;
2151 break;
2152 /* Ball hit the third fourth of the paddle */
2153 case 2:
2154 ball[k].speedy = SPEED_3Q_Y;
2155 ball[k].speedx = SPEED_3Q_X * x_direction;
2156 break;
2157 /* Ball hit the fourth fourth of the paddle or dead
2158 * center.
2160 case 3:
2161 case 4:
2162 ball[k].speedy = SPEED_4Q_Y;
2163 /* Since this is the middle we don't want to
2164 * force the ball in a different direction.
2165 * Just keep it going in the same direction
2166 * with a specific speed.
2168 if(ball[k].speedx > 0)
2170 ball[k].speedx = SPEED_4Q_X;
2172 else
2174 ball[k].speedx = -SPEED_4Q_X;
2176 break;
2178 default:
2179 ball[k].speedy = SPEED_4Q_Y;
2180 break;
2183 if(paddle_type == PADDLE_TYPE_STICKY)
2185 ball[k].speedy = -ball[k].speedy;
2186 ball[k].glue=true;
2188 /* X location should not be forced since that is moved with the paddle. The Y
2189 * position should be forced to keep the ball at the paddle.
2191 ball[k].tempx = 0;
2192 ball[k].tempy = ON_PAD_POS_Y;
2197 /* Update the ball position */
2198 if (!ball[k].glue)
2200 if(ball[k].tempx)
2201 ball[k].pos_x = ball[k].tempx;
2202 else
2203 ball[k].pos_x += ball[k].speedx;
2205 if(ball[k].tempy)
2206 ball[k].pos_y = ball[k].tempy;
2207 else
2208 ball[k].pos_y += ball[k].speedy;
2210 ball[k].tempy=0;
2211 ball[k].tempx=0;
2213 } /* for k */
2216 rb->lcd_update();
2218 if (brick_on_board < 0)
2220 if (level+1<NUM_LEVELS)
2222 level++;
2223 if (difficulty==NORMAL)
2224 score+=SCORE_LEVEL_COMPLETED;
2225 brickmania_init_game(true);
2226 brickmania_sleep(2);
2227 rb->button_clear_queue();
2229 else
2231 rb->lcd_getstringsize("Congratulations!", &sw, &sh);
2232 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH) - 2 * sh,
2233 "Congratulations!");
2234 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
2235 rb->lcd_getstringsize("No more levels", &sw, NULL);
2236 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2237 "No more levels");
2238 #else
2239 rb->lcd_getstringsize("You have finished the game!",
2240 &sw, NULL);
2241 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2242 "You have finished the game!");
2243 #endif
2244 vscore=score;
2245 rb->lcd_update();
2246 brickmania_sleep(2);
2247 return 0;
2251 int button=rb->button_get(false);
2252 int move_button = rb->button_status();
2254 #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
2255 /* FIXME: Should probably check remote hold here */
2256 if (rb->button_hold())
2257 button = QUIT;
2258 #endif
2260 #ifdef HAVE_TOUCHSCREEN
2261 if( move_button & BUTTON_TOUCHSCREEN)
2263 int data;
2264 short touch_x;
2265 rb->button_status_wdata(&data);
2266 touch_x = FIXED3(data >> 16);
2268 if(flip_sides)
2270 pad_pos_x = GAMESCREEN_WIDTH - (touch_x + pad_width/2);
2272 else
2274 pad_pos_x = (touch_x - pad_width/2);
2277 if(pad_pos_x < 0)
2278 pad_pos_x = 0;
2279 else if(pad_pos_x + pad_width > GAMESCREEN_WIDTH)
2280 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
2281 for(k=0; k<used_balls; k++)
2282 if (game_state==ST_READY || ball[k].glue)
2283 ball[k].pos_x = pad_pos_x + pad_width/2;
2285 else
2286 #endif
2288 int button_right, button_left;
2289 #ifdef ALTRIGHT
2290 button_right = move_button & (RIGHT | ALTRIGHT);
2291 button_left = move_button & (LEFT | ALTLEFT);
2292 #else
2293 button_right =((move_button & RIGHT)|| SCROLL_FWD(button));
2294 button_left =((move_button & LEFT) ||SCROLL_BACK(button));
2295 #endif
2296 if ((game_state==ST_PAUSE) && (button_right || button_left))
2297 continue;
2299 if (button_left || button_right)
2301 int dx = 0;
2303 if ((button_right && !flip_sides) ||
2304 (button_left && flip_sides))
2306 if (pad_pos_x+SPEED_PAD+pad_width > GAMESCREEN_WIDTH)
2307 dx = GAMESCREEN_WIDTH - pad_pos_x - pad_width;
2308 else
2309 dx = SPEED_PAD;
2311 else if ((button_left && !flip_sides) ||
2312 (button_right && flip_sides))
2314 if (pad_pos_x-SPEED_PAD < 0)
2315 dx = -pad_pos_x;
2316 else
2317 dx = -SPEED_PAD;
2320 pad_pos_x+=dx;
2321 for(k=0;k<used_balls;k++)
2323 if (game_state==ST_READY || ball[k].glue)
2325 ball[k].pos_x+=dx;
2327 if (ball[k].pos_x < HALFBALL)
2328 ball[k].pos_x = HALFBALL;
2329 else if (ball[k].pos_x > GAMESCREEN_WIDTH - HALFBALL)
2330 ball[k].pos_x = GAMESCREEN_WIDTH - HALFBALL;
2336 switch(button)
2338 #if defined(HAVE_TOUCHSCREEN)
2339 case (BUTTON_REL | BUTTON_TOUCHSCREEN):
2340 #endif
2341 case UP:
2342 case SELECT:
2343 #ifdef ALTSELECT
2344 case ALTSELECT:
2345 #endif
2346 if (game_state==ST_READY)
2348 /* Initialize used balls starting speed */
2349 for(k=0 ; k < used_balls ; k++)
2351 ball[k].speedy = SPEED_4Q_Y;
2352 if(pad_pos_x + (pad_width/2) >= GAMESCREEN_WIDTH/2)
2354 ball[k].speedx = SPEED_4Q_X;
2356 else
2358 ball[k].speedx = -SPEED_4Q_X;
2361 game_state=ST_START;
2363 else if (game_state==ST_PAUSE)
2365 game_state=ST_START;
2367 else if (paddle_type == PADDLE_TYPE_STICKY)
2369 for(k=0;k<used_balls;k++)
2371 if (ball[k].glue)
2373 ball[k].glue=false;
2374 ball[k].speedy = -ball[k].speedy;
2378 else if (paddle_type == PADDLE_TYPE_SHOOTER)
2380 if (used_fires < MAX_FIRES)
2382 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2383 fire[used_fires].x_pos = pad_pos_x + 1; /* Add 1 for edge */
2384 used_fires++;
2386 if (used_fires < MAX_FIRES)
2388 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2389 fire[used_fires].x_pos = pad_pos_x + pad_width - 1; /* Sub1 edge*/
2390 used_fires++;
2393 break;
2394 #ifdef RC_QUIT
2395 case RC_QUIT:
2396 #endif
2397 case QUIT:
2398 resume = true;
2399 return 0;
2400 break;
2402 default:
2403 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
2404 return 1;
2405 break;
2408 else
2410 resume = false;
2411 if(resume_file)
2413 rb->remove(SAVE_FILE);
2414 resume_file = false;
2416 #ifdef HAVE_LCD_COLOR
2417 rb->lcd_bitmap_transparent(brickmania_gameover,
2418 (LCD_WIDTH - INT3(GAMEOVER_WIDTH))/2,
2419 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2420 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT));
2421 #else /* greyscale and mono */
2422 rb->lcd_bitmap(brickmania_gameover,(LCD_WIDTH -
2423 INT3(GAMEOVER_WIDTH))/2,
2424 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2425 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT) );
2426 #endif
2427 rb->lcd_update();
2428 brickmania_sleep(2);
2429 return 0;
2432 /* Game always needs to yield for other threads */
2433 rb->yield();
2435 /* Sleep for a bit if there is time to spare */
2436 if (TIME_BEFORE(*rb->current_tick, end))
2437 rb->sleep(end-*rb->current_tick);
2439 return 0;
2442 /* this is the plugin entry point */
2443 enum plugin_status plugin_start(const void* parameter)
2445 (void)parameter;
2446 int last_difficulty;
2448 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
2449 configfile_load(CONFIG_FILE_NAME,config,1,0);
2450 last_difficulty = difficulty;
2452 #ifdef HAVE_TOUCHSCREEN
2453 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
2454 #endif
2456 rb->lcd_setfont(FONT_SYSFIXED);
2457 #if LCD_DEPTH > 1
2458 rb->lcd_set_backdrop(NULL);
2459 #endif
2460 /* Turn off backlight timeout */
2461 backlight_ignore_timeout();
2463 /* now go ahead and have fun! */
2464 rb->srand( *rb->current_tick );
2465 brickmania_loadgame();
2466 resume_file = resume;
2467 while(!brickmania_game_loop())
2469 if(!resume)
2471 int position = highscore_update(score, level+1, "",
2472 highscores, NUM_SCORES);
2473 if (position != -1)
2475 if (position == 0)
2476 rb->splash(HZ*2, "New High Score");
2477 highscore_show(position, highscores, NUM_SCORES, true);
2479 else
2481 brickmania_sleep(3);
2486 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2487 if(last_difficulty != difficulty)
2488 configfile_save(CONFIG_FILE_NAME,config,1,0);
2489 /* Restore user's original backlight setting */
2490 rb->lcd_setfont(FONT_UI);
2491 /* Turn on backlight timeout (revert to settings) */
2492 backlight_use_settings();
2494 return PLUGIN_OK;