Extract config file saving code to a function; Do not write the NUL character to...
[kugel-rb.git] / apps / plugins / brickmania.c
blob79ebfefbd47d0018093d8ca6eae215a0ef1864a4
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 #define QUIT BUTTON_POWER
144 #define LEFT BUTTON_LEFT
145 #define RIGHT BUTTON_RIGHT
146 #define ALTLEFT BUTTON_VOL_DOWN
147 #define ALTRIGHT BUTTON_VOL_UP
148 #define SELECT BUTTON_SELECT
149 #define UP BUTTON_UP
150 #define DOWN BUTTON_DOWN
152 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
153 #define QUIT BUTTON_POWER
154 #define LEFT BUTTON_LEFT
155 #define RIGHT BUTTON_RIGHT
156 #define SELECT BUTTON_PLAY
157 #define UP BUTTON_SCROLL_UP
158 #define DOWN BUTTON_SCROLL_DOWN
160 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
161 #define QUIT BUTTON_BACK
162 #define LEFT BUTTON_LEFT
163 #define RIGHT BUTTON_RIGHT
164 #define SELECT BUTTON_SELECT
165 #define UP BUTTON_UP
166 #define DOWN BUTTON_DOWN
168 #elif (CONFIG_KEYPAD == MROBE100_PAD)
169 #define QUIT BUTTON_POWER
170 #define LEFT BUTTON_LEFT
171 #define RIGHT BUTTON_RIGHT
172 #define SELECT BUTTON_SELECT
173 #define UP BUTTON_UP
174 #define DOWN BUTTON_DOWN
176 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
177 #define CONTINUE_TEXT "PLAY To Continue"
178 #define QUIT BUTTON_RC_REC
179 #define LEFT BUTTON_RC_REW
180 #define RIGHT BUTTON_RC_FF
181 #define SELECT BUTTON_RC_PLAY
182 #define UP BUTTON_RC_VOL_UP
183 #define DOWN BUTTON_RC_VOL_DOWN
184 #define RC_QUIT BUTTON_REC
186 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
187 #define QUIT BUTTON_BACK
188 #define LEFT BUTTON_LEFT
189 #define RIGHT BUTTON_RIGHT
190 #define SELECT BUTTON_SELECT
191 #define UP BUTTON_UP
192 #define DOWN BUTTON_DOWN
194 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
195 #define QUIT BUTTON_POWER
196 #define LEFT BUTTON_LEFT
197 #define RIGHT BUTTON_RIGHT
198 #define SELECT BUTTON_SELECT
199 #define UP BUTTON_UP
200 #define DOWN BUTTON_DOWN
202 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
203 #define QUIT BUTTON_POWER
204 #define LEFT BUTTON_LEFT
205 #define RIGHT BUTTON_RIGHT
206 #define SELECT BUTTON_PLAY
207 #define UP BUTTON_UP
208 #define DOWN BUTTON_DOWN
210 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
211 #define QUIT BUTTON_POWER
212 #define LEFT BUTTON_PREV
213 #define RIGHT BUTTON_NEXT
214 #define SELECT BUTTON_PLAY
215 #define UP BUTTON_UP
216 #define DOWN BUTTON_DOWN
218 #elif CONFIG_KEYPAD == COWON_D2_PAD
219 #define CONTINUE_TEXT "MENU To Continue"
220 #define QUIT BUTTON_POWER
221 #define LEFT BUTTON_MINUS
222 #define RIGHT BUTTON_PLUS
223 #define SELECT BUTTON_MENU
225 #elif CONFIG_KEYPAD == ONDAVX747_PAD
226 #define QUIT BUTTON_POWER
227 #define LEFT BUTTON_VOL_DOWN
228 #define RIGHT BUTTON_VOL_UP
229 #define SELECT BUTTON_MENU
230 #elif CONFIG_KEYPAD == ONDAVX777_PAD
231 #define QUIT BUTTON_POWER
233 #elif CONFIG_KEYPAD == MROBE500_PAD
234 #define QUIT BUTTON_POWER
236 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
237 #define QUIT BUTTON_FFWD
238 #define SELECT BUTTON_PLAY
239 #define LEFT BUTTON_LEFT
240 #define RIGHT BUTTON_RIGHT
241 #define UP BUTTON_UP
242 #define DOWN BUTTON_DOWN
244 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
245 #define QUIT BUTTON_REC
246 #define LEFT BUTTON_PREV
247 #define RIGHT BUTTON_NEXT
248 #define ALTLEFT BUTTON_MENU
249 #define ALTRIGHT BUTTON_PLAY
250 #define SELECT BUTTON_OK
251 #define UP BUTTON_UP
252 #define DOWN BUTTON_DOWN
254 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
255 #define QUIT (BUTTON_REC|BUTTON_PLAY)
256 #define LEFT BUTTON_VOL_DOWN
257 #define RIGHT BUTTON_VOL_UP
258 #define SELECT BUTTON_FUNC
259 #define UP BUTTON_REW
260 #define DOWN BUTTON_FF
262 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
263 #define QUIT (BUTTON_REC|BUTTON_REPEAT)
264 #define LEFT BUTTON_REW
265 #define RIGHT BUTTON_FF
266 #define SELECT BUTTON_ENTER
267 #define UP BUTTON_UP
268 #define DOWN BUTTON_DOWN
270 #else
271 #error No keymap defined!
272 #endif
274 #ifdef HAVE_TOUCHSCREEN
275 #ifdef LEFT
276 #define ALTLEFT BUTTON_BOTTOMLEFT
277 #else
278 #define LEFT BUTTON_BOTTOMLEFT
279 #endif
280 #ifdef RIGHT
281 #define ALTRIGHT BUTTON_BOTTOMRIGHT
282 #else
283 #define RIGHT BUTTON_BOTTOMRIGHT
284 #endif
285 #ifdef SELECT
286 #define ALTSELECT BUTTON_CENTER
287 #else
288 #define SELECT BUTTON_CENTER
289 #endif
290 #ifndef UP
291 #define UP BUTTON_TOPMIDDLE
292 #endif
293 #ifndef DOWN
294 #define DOWN BUTTON_BOTTOMMIDDLE
295 #endif
296 #endif
298 /* Continue text is used as a string later when the game is paused. This allows
299 * targets to specify their own text if needed.
301 #if !defined(CONTINUE_TEXT)
302 #define CONTINUE_TEXT "Press SELECT To Continue"
303 #endif
305 #ifndef SCROLL_FWD /* targets without scroll wheel*/
306 #define SCROLL_FWD(x) (0)
307 #define SCROLL_BACK(x) (0)
308 #endif
311 #define NUM_BRICKS_ROWS 8
312 #define NUM_BRICKS_COLS 10
316 * Geometric dimensions
320 /* If there are three fractional bits, the smallest screen size that will scale
321 * properly is 28x22. If you have a smaller screen increase the fractional
322 * precision. If you have a precision of 4 the smallest screen size would be
323 * 14x11. Note though that this will decrease the maximum resolution due to
324 * the line intersection tests. These defines are used for all of the fixed
325 * point calculations/conversions.
327 #define FIXED3(x) ((x)<<3)
328 #define FIXED3_MUL(x, y) ((long long)((x)*(y))>>3)
329 #define FIXED3_DIV(x, y) (((x)<<3)/(y))
330 #define INT3(x) ((x)>>3)
332 #define GAMESCREEN_WIDTH FIXED3(LCD_WIDTH)
333 #define GAMESCREEN_HEIGHT FIXED3(LCD_HEIGHT)
335 #define PAD_WIDTH FIXED3(BMPWIDTH_brickmania_pads)
336 #define PAD_HEIGHT FIXED3(BMPHEIGHT_brickmania_pads/3)
337 #define SHORT_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_short_pads)
338 #define LONG_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_long_pads)
339 #define BRICK_HEIGHT FIXED3(BMPHEIGHT_brickmania_bricks/7)
340 #define BRICK_WIDTH FIXED3(BMPWIDTH_brickmania_bricks)
341 #define LEFTMARGIN ((GAMESCREEN_WIDTH-NUM_BRICKS_COLS*BRICK_WIDTH)/2)
342 #define POWERUP_WIDTH FIXED3(BMPWIDTH_brickmania_powerups)
343 #define BALL FIXED3(BMPHEIGHT_brickmania_ball)
344 #define HALFBALL (BALL / 2)
345 #define PAD_POS_Y (GAMESCREEN_HEIGHT - PAD_HEIGHT - 1)
346 #define ON_PAD_POS_Y (PAD_POS_Y - HALFBALL)
348 #define GAMEOVER_WIDTH FIXED3(BMPWIDTH_brickmania_gameover)
349 #define GAMEOVER_HEIGHT FIXED3(BMPHEIGHT_brickmania_gameover)
351 #define TOPMARGIN MAX(BRICK_HEIGHT, FIXED3(8))
353 #define STRINGPOS_FINISH (GAMESCREEN_HEIGHT - (GAMESCREEN_HEIGHT / 6))
354 #define STRINGPOS_NAVI (STRINGPOS_FINISH - 10)
355 #define STRINGPOS_FLIP (STRINGPOS_FINISH - 10)
360 * Speeds
364 /* Brickmania was originally designed for the H300, other targets should scale
365 * the speed up/down as needed based on the screen height.
367 #define SPEED_SCALE_H(y) FIXED3_DIV(GAMESCREEN_HEIGHT, FIXED3(176)/(y) )
368 #define SPEED_SCALE_W(x) FIXED3_DIV(GAMESCREEN_WIDTH, FIXED3(220)/(x) )
370 /* These are all used as ball speeds depending on where the ball hit the
371 * paddle.
373 * Note that all of these speeds (including pad, power, and fire)
374 * could be made variable and could be raised to be much higher to add
375 * additional difficulty to the game. The line intersection tests allow this
376 * to be drastically increased without the collision detection failing
377 * (ideally).
379 #define SPEED_1Q_X SPEED_SCALE_W( 6)
380 #define SPEED_1Q_Y SPEED_SCALE_H(-2)
382 #define SPEED_2Q_X SPEED_SCALE_W( 4)
383 #define SPEED_2Q_Y SPEED_SCALE_H(-3)
385 #define SPEED_3Q_X SPEED_SCALE_W( 3)
386 #define SPEED_3Q_Y SPEED_SCALE_H(-4)
388 #define SPEED_4Q_X SPEED_SCALE_W( 2)
389 #define SPEED_4Q_Y SPEED_SCALE_H(-4)
391 /* This is used to determine the speed of the paddle */
392 #define SPEED_PAD SPEED_SCALE_W( 8)
394 /* This defines the speed that the powerups drop */
395 #define SPEED_POWER SPEED_SCALE_H( 2)
397 /* This defines the speed that the shot moves */
398 #define SPEED_FIRE SPEED_SCALE_H( 4)
399 #define FIRE_LENGTH SPEED_SCALE_H( 7)
404 * Timings
408 /* The time ms for one iteration through the game loop - decrease this to speed
409 * up the game - note that current_tick is (currently) only accurate to 10ms.
411 #define CYCLETIME 30 /* ms */
413 #define FLIP_SIDES_DELAY 10 /* seconds */
418 * Scores
422 #define SCORE_BALL_HIT_BRICK 2
423 #define SCORE_BALL_DEMOLISHED_BRICK 8
424 #define SCORE_FIRE_HIT_BRICK 13
425 #define SCORE_LEVEL_COMPLETED 100
426 #define SCORE_POWER_LIFE_GAIN 50
427 #define SCORE_POWER_PADDLE_STICKY 34
428 #define SCORE_POWER_PADDLE_SHOOTER 47
429 #define SCORE_POWER_PADDLE_NORMAL 23
430 #define SCORE_POWER_FLIP 23
431 #define SCORE_POWER_EXTRA_BALL 23
432 #define SCORE_POWER_LONG_PADDLE 23
437 * Limits
441 #define MAX_BALLS 10
442 #define MAX_FIRES 30
443 #define MAX_POWERS 10
448 * Files
452 #define CONFIG_FILE_NAME "brickmania.cfg"
453 #define SAVE_FILE PLUGIN_GAMES_DIR "/brickmania.save"
454 #define SCORE_FILE PLUGIN_GAMES_DIR "/brickmania.score"
455 #define NUM_SCORES 5
460 * Game levels
464 /* change to however many levels there are, i.e. how many arrays there are total */
465 #define NUM_LEVELS 40
467 /* change the first number in [ ] to however many levels there are */
468 static unsigned char levels[NUM_LEVELS][NUM_BRICKS_ROWS][NUM_BRICKS_COLS] =
469 /* You can set up new levels with the level editor
470 ( http://plugbox.rockbox-lounge.com/brickmania.htm ).
471 With 0x1, it refers to the first brick in the bitmap, 0x2 would refer to the
472 second, ect., 0x0 leaves a empty space. If you add a 2 before the 2nd number,
473 it will take two hits to break, and 3 hits if you add a 3. That is 0x24, will
474 result with the fourth brick being displayed and having take 2 hits to break.
475 You could do the same with the 3, just replace the 2 with a 3 for it to take
476 three hits to break it apart. */
478 { /* level 1 */
479 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
480 {0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2},
481 {0x0,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x0},
482 {0x0,0x0,0x2,0x1,0x0,0x0,0x1,0x2,0x0,0x0},
483 {0x0,0x0,0x0,0x2,0x1,0x1,0x2,0x0,0x0,0x0},
484 {0x7,0x0,0x0,0x7,0x2,0x2,0x7,0x0,0x0,0x7},
485 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
486 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
488 { /* level 2 */
489 {0x0,0x0,0x7,0x7,0x1,0x1,0x7,0x7,0x0,0x0},
490 {0x0,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0},
491 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
492 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
493 {0x1,0x1,0x2,0x1,0x0,0x0,0x1,0x2,0x1,0x1},
494 {0x1,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x1},
495 {0x0,0x1,0x2,0x0,0x0,0x0,0x0,0x2,0x1,0x0},
496 {0x0,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x0}
498 { /* level 3 */
499 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
500 {0x3,0x23,0x23,0x3,0x0,0x0,0x2,0x22,0x22,0x2},
501 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
502 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
503 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
504 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6},
505 {0x5,0x25,0x25,0x5,0x0,0x0,0x6,0x26,0x26,0x6},
506 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6}
508 { /* level 4 */
509 {0x0,0x0,0x0,0x27,0x27,0x27,0x27,0x0,0x0,0x0},
510 {0x0,0x0,0x0,0x27,0x7,0x7,0x27,0x0,0x0,0x0},
511 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
512 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
513 {0x26,0x6,0x0,0x2,0x2,0x2,0x2,0x0,0x6,0x26},
514 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
515 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
516 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1}
518 { /* level 5 */
519 {0x1,0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4},
520 {0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0},
521 {0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5},
522 {0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5,0x5},
523 {0x0,0x33,0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0},
524 {0x3,0x33,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x36},
525 {0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x6,0x36},
526 {0x0,0x24,0x24,0x0,0x25,0x25,0x0,0x26,0x26,0x0}
528 { /* level 6 */
529 {0x0,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x0},
530 {0x3,0x1,0x3,0x7,0x0,0x0,0x7,0x3,0x1,0x3},
531 {0x3,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x3},
532 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x0},
533 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
534 {0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5},
535 {0x0,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x0},
536 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
538 { /* level 7 */
539 {0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x0},
540 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
541 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
542 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
543 {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x6},
544 {0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0},
545 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
546 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
548 { /* level 8 */
549 {0x0,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x0},
550 {0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0},
551 {0x6,0x6,0x0,0x2,0x32,0x32,0x2,0x0,0x6,0x6},
552 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
553 {0x0,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x0},
554 {0x0,0x0,0x0,0x5,0x25,0x25,0x5,0x0,0x0,0x0},
555 {0x0,0x5,0x5,0x25,0x5,0x5,0x25,0x5,0x5,0x0},
556 {0x5,0x5,0x25,0x5,0x5,0x5,0x5,0x25,0x5,0x5}
558 { /* level 9 */
559 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
560 {0x2,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x2},
561 {0x2,0x0,0x3,0x0,0x1,0x1,0x0,0x3,0x0,0x2},
562 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
563 {0x2,0x0,0x1,0x0,0x3,0x3,0x0,0x1,0x0,0x2},
564 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
565 {0x2,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x2,0x2},
566 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
568 { /* level 10 */
569 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
570 {0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5},
571 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
572 {0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0},
573 {0x0,0x0,0x0,0x4,0x1,0x1,0x4,0x0,0x0,0x0},
574 {0x0,0x0,0x3,0x4,0x1,0x1,0x4,0x3,0x0,0x0},
575 {0x0,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x0},
576 {0x1,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x1}
578 { /* level 11 */
579 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
580 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2},
581 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
582 {0x2,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x2},
583 {0x2,0x0,0x0,0x7,0x7,0x7,0x7,0x0,0x0,0x2},
584 {0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x0},
585 {0x0,0x2,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x0},
586 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5}
588 { /* level 12 */
589 {0x2,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x2},
590 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
591 {0x1,0x1,0x1,0x0,0x1,0x1,0x0,0x1,0x1,0x1},
592 {0x0,0x1,0x0,0x1,0x6,0x6,0x1,0x0,0x1,0x0},
593 {0x0,0x0,0x1,0x1,0x6,0x6,0x1,0x1,0x0,0x0},
594 {0x1,0x1,0x1,0x7,0x0,0x0,0x7,0x1,0x1,0x1},
595 {0x1,0x1,0x7,0x1,0x0,0x0,0x1,0x7,0x1,0x1},
596 {0x2,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x2}
598 {/* levell13 */
599 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
600 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
601 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x2},
602 {0x2,0x0,0x2,0x3,0x3,0x3,0x3,0x3,0x0,0x2},
603 {0x2,0x0,0x2,0x4,0x4,0x4,0x4,0x4,0x0,0x2},
604 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
605 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
606 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
608 {/* level 14 */
609 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
610 {0x4,0x4,0x4,0x4,0x2,0x2,0x4,0x4,0x4,0x4},
611 {0x4,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x4},
612 {0x4,0x0,0x0,0x2,0x3,0x3,0x2,0x0,0x0,0x4},
613 {0x4,0x0,0x2,0x23,0x3,0x3,0x23,0x2,0x0,0x4},
614 {0x4,0x0,0x2,0x22,0x2,0x2,0x22,0x2,0x0,0x4},
615 {0x4,0x0,0x6,0x21,0x5,0x5,0x21,0x6,0x0,0x4},
616 {0x4,0x6,0x1,0x1,0x5,0x5,0x1,0x1,0x6,0x4}
618 {/* level 15 */
619 {0x4,0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,0x3},
620 {0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x5,0x0,0x0},
621 {0x2,0x2,0x1,0x1,0x1,0x0,0x1,0x6,0x0,0x0},
622 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x5,0x0,0x0},
623 {0x2,0x1,0x2,0x2,0x2,0x1,0x1,0x6,0x0,0x0},
624 {0x2,0x1,0x2,0x2,0x2,0x1,0x3,0x5,0x3,0x0},
625 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x6,0x0,0x0},
626 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
628 {/* level 16 (Rockbox) by ts-x */
629 {0x2,0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
630 {0x2,0x0,0x3,0x0,0x3,0x4,0x0,0x5,0x5,0x0},
631 {0x2,0x0,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
632 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
633 {0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
634 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0},
635 {0x7,0x0,0x7,0x1,0x0,0x1,0x0,0x2,0x0,0x0},
636 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0}
638 {/* level 17 (Alien) by ts-x */
639 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
640 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
641 {0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1},
642 {0x2,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x2},
643 {0x1,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x1},
644 {0x2,0x0,0x0,0x1,0x2,0x2,0x1,0x0,0x0,0x2},
645 {0x2,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x2},
646 {0x2,0x2,0x1,0x0,0x1,0x1,0x0,0x1,0x2,0x2}
648 {/* level 18 (Tetris) by ts-x */
649 {0x0,0x2,0x0,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
650 {0x0,0x2,0x7,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
651 {0x2,0x2,0x7,0x0,0x3,0x4,0x0,0x6,0x2,0x2},
652 {0x2,0x2,0x7,0x7,0x3,0x4,0x0,0x6,0x2,0x2},
653 {0x2,0x1,0x7,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
654 {0x2,0x1,0x0,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
655 {0x1,0x1,0x1,0x7,0x3,0x0,0x6,0x6,0x5,0x5},
656 {0x1,0x1,0x1,0x0,0x3,0x0,0x6,0x6,0x5,0x5}
658 { /* level 19 (Stalactites) by ts-x */
659 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
660 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
661 {0x5,0x0,0x6,0x3,0x4,0x7,0x5,0x0,0x1,0x2},
662 {0x5,0x2,0x6,0x3,0x4,0x0,0x5,0x3,0x1,0x2},
663 {0x5,0x0,0x6,0x0,0x4,0x7,0x5,0x0,0x1,0x0},
664 {0x5,0x0,0x0,0x3,0x4,0x0,0x0,0x0,0x1,0x2},
665 {0x0,0x0,0x6,0x0,0x0,0x0,0x5,0x0,0x0,0x0},
666 {0x5,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0}
668 { /* level 20 (Maze) by ts-x */
669 {0x1,0x1,0x21,0x1,0x1,0x1,0x1,0x1,0x1,0x21},
670 {0x1,0x0,0x0,0x3,0x0,0x0,0x3,0x1,0x31,0x1},
671 {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x1},
672 {0x21,0x0,0x21,0x3,0x0,0x3,0x0,0x3,0x0,0x2},
673 {0x1,0x0,0x1,0x21,0x0,0x12,0x0,0x0,0x0,0x0},
674 {0x31,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x3,0x0},
675 {0x1,0x0,0x1,0x0,0x1,0x1,0x31,0x1,0x1,0x2},
676 {0x22,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x21}
678 { /* level 21 (Dentist) by ts-x */
679 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
680 {0x2,0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x2,0x2},
681 {0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x2},
682 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x2},
683 {0x2,0x0,0x6,0x0,0x6,0x0,0x0,0x0,0x0,0x2},
684 {0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x2},
685 {0x2,0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x2,0x2},
686 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0}
688 { /* level 22 (Spider) by ts-x */
689 {0x31,0x3,0x1,0x1,0x0,0x0,0x1,0x1,0x3,0x31},
690 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
691 {0x33,0x1,0x1,0x36,0x1,0x1,0x36,0x1,0x1,0x33},
692 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
693 {0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0},
694 {0x21,0x3,0x1,0x21,0x2,0x2,0x21,0x1,0x3,0x21},
695 {0x0,0x0,0x0,0x1,0x21,0x1,0x1,0x0,0x0,0x0},
696 {0x3,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x3}
698 { /* level 23 (Pool) by ts-x */
699 {0x0,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x7,0x0},
700 {0x0,0x0,0x5,0x0,0x2,0x0,0x0,0x0,0x2,0x0},
701 {0x7,0x3,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x7},
702 {0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0x7},
703 {0x7,0x0,0x4,0x0,0x0,0x3,0x0,0x0,0x0,0x7},
704 {0x7,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x4,0x7},
705 {0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
706 {0x0,0x7,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x0}
708 { /* level 24 (Vorbis Fish) by ts-x */
709 {0x0,0x0,0x4,0x4,0x5,0x5,0x5,0x0,0x0,0x5},
710 {0x0,0x4,0x6,0x4,0x4,0x5,0x5,0x5,0x0,0x5},
711 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x5,0x5,0x5},
712 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x4,0x5,0x5},
713 {0x0,0x5,0x6,0x4,0x4,0x5,0x5,0x4,0x5,0x0},
714 {0x5,0x5,0x4,0x4,0x5,0x5,0x5,0x4,0x5,0x5},
715 {0x5,0x4,0x4,0x4,0x5,0x5,0x4,0x4,0x5,0x5},
716 {0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x5,0x0,0x5}
718 {/* level 25 (Rainbow) by ts-x */
719 {0x0,0x4,0x1,0x0,0x0,0x0,0x0,0x1,0x4,0x0},
720 {0x24,0x1,0x3,0x1,0x0,0x0,0x21,0x3,0x1,0x24},
721 {0x1,0x23,0x5,0x3,0x1,0x21,0x3,0x5,0x3,0x21},
722 {0x3,0x5,0x6,0x5,0x3,0x3,0x5,0x6,0x5,0x3},
723 {0x5,0x6,0x7,0x6,0x5,0x5,0x6,0x7,0x6,0x5},
724 {0x6,0x7,0x2,0x27,0x6,0x6,0x27,0x2,0x7,0x6},
725 {0x7,0x2,0x0,0x2,0x27,0x27,0x2,0x0,0x2,0x7},
726 {0x32,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x32}
728 { /* level 26 (Bowtie) by ts-x */
729 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5},
730 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
731 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
732 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
733 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
734 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
735 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
736 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5}
738 { /* level 27 (Frog) by ts-x */
739 {0x0,0x5,0x25,0x0,0x0,0x0,0x0,0x25,0x5,0x0},
740 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
741 {0x25,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x25},
742 {0x5,0x0,0x3,0x0,0x6,0x6,0x0,0x3,0x0,0x5},
743 {0x5,0x0,0x31,0x0,0x6,0x6,0x0,0x31,0x0,0x5},
744 {0x5,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x5},
745 {0x5,0x5,0x5,0x35,0x0,0x0,0x35,0x5,0x5,0x5},
746 {0x0,0x25,0x5,0x0,0x4,0x4,0x0,0x5,0x25,0x0}
748 { /* level 28 (DigDug) by ts-x */
749 {0x35,0x5,0x5,0x25,0x0,0x25,0x25,0x5,0x5,0x35},
750 {0x6,0x0,0x0,0x6,0x0,0x6,0x6,0x0,0x0,0x6},
751 {0x7,0x0,0x37,0x37,0x0,0x37,0x37,0x7,0x0,0x7},
752 {0x7,0x0,0x7,0x0,0x0,0x0,0x7,0x7,0x7,0x7},
753 {0x4,0x4,0x4,0x24,0x0,0x24,0x4,0x0,0x0,0x4},
754 {0x4,0x4,0x0,0x0,0x0,0x4,0x4,0x0,0x4,0x4},
755 {0x24,0x24,0x4,0x4,0x4,0x4,0x0,0x0,0x24,0x4},
756 {0x1,0x1,0x1,0x1,0x1,0x1,0x21,0x21,0x1,0x1}
758 { /* level 29 UK Flag by Seth Opgenorth */
759 {0x32,0x0,0x3,0x3,0x2,0x2,0x3,0x3,0x0,0x32},
760 {0x0,0x2,0x0,0x3,0x32,0x22,0x33,0x0,0x32,0x0},
761 {0x33,0x0,0x22,0x0,0x2,0x2,0x0,0x2,0x0,0x33},
762 {0x22,0x32,0x2,0x2,0x2,0x2,0x2,0x2,0x22,0x2},
763 {0x3,0x0,0x0,0x32,0x22,0x2,0x2,0x0,0x0,0x3},
764 {0x23,0x0,0x32,0x0,0x32,0x2,0x0,0x2,0x0,0x3},
765 {0x0,0x2,0x0,0x3,0x2,0x2,0x3,0x0,0x22,0x0},
766 {0x32,0x0,0x3,0x23,0x2,0x2,0x23,0x33,0x0,0x32}
768 { /* level 30 Win-Logo by Seth Opgenorth */
769 {0x0,0x0,0x0,0x22,0x0,0x0,0x0,0x0,0x0,0x0},
770 {0x0,0x0,0x32,0x2,0x2,0x25,0x0,0x5,0x0,0x0},
771 {0x0,0x0,0x2,0x22,0x2,0x5,0x5,0x35,0x0,0x0},
772 {0x0,0x0,0x2,0x1,0x2,0x5,0x5,0x25,0x0,0x0},
773 {0x0,0x0,0x21,0x1,0x1,0x36,0x7,0x26,0x0,0x0},
774 {0x0,0x0,0x1,0x1,0x1,0x6,0x6,0x6,0x0,0x0},
775 {0x0,0x0,0x21,0x0,0x21,0x6,0x6,0x26,0x0,0x0},
776 {0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0}
778 { /* level 31 Color wave/V by Seth Opgenorth */
779 {0x25,0x34,0x2,0x31,0x33,0x23,0x1,0x2,0x34,0x5},
780 {0x3,0x5,0x24,0x2,0x1,0x1,0x2,0x4,0x5,0x3},
781 {0x1,0x3,0x5,0x4,0x2,0x2,0x4,0x5,0x3,0x1},
782 {0x2,0x1,0x33,0x35,0x4,0x4,0x5,0x33,0x1,0x22},
783 {0x31,0x22,0x1,0x3,0x5,0x25,0x3,0x1,0x2,0x31},
784 {0x3,0x1,0x2,0x1,0x3,0x3,0x1,0x2,0x21,0x3},
785 {0x5,0x23,0x1,0x32,0x1,0x1,0x2,0x1,0x3,0x5},
786 {0x4,0x35,0x3,0x1,0x2,0x22,0x31,0x3,0x5,0x4}
788 { /* level 32 Sweedish Flag by Seth Opgenorth */
789 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
790 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
791 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
792 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
793 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
794 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
795 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
796 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3}
798 { /* level 33 Color Pyramid by Seth Opgenorth */
799 {0x0,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x0},
800 {0x0,0x0,0x0,0x4,0x24,0x4,0x24,0x0,0x0,0x0},
801 {0x0,0x0,0x23,0x3,0x3,0x3,0x23,0x3,0x0,0x0},
802 {0x0,0x0,0x25,0x5,0x25,0x35,0x5,0x35,0x0,0x0},
803 {0x0,0x36,0x6,0x6,0x6,0x6,0x26,0x6,0x6,0x0},
804 {0x0,0x7,0x7,0x7,0x7,0x25,0x27,0x7,0x27,0x0},
805 {0x2,0x2,0x22,0x2,0x2,0x2,0x22,0x2,0x2,0x2},
806 {0x21,0x1,0x1,0x31,0x1,0x21,0x1,0x1,0x31,0x1}
808 { /* level 34 Rhombus by Seth Opgenorth */
809 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0},
810 {0x0,0x0,0x0,0x3,0x32,0x22,0x23,0x0,0x0,0x0},
811 {0x0,0x0,0x3,0x2,0x24,0x4,0x2,0x23,0x0,0x0},
812 {0x26,0x3,0x2,0x4,0x5,0x5,0x4,0x22,0x3,0x6},
813 {0x36,0x3,0x2,0x34,0x5,0x5,0x4,0x2,0x3,0x36},
814 {0x0,0x0,0x3,0x2,0x4,0x34,0x2,0x23,0x0,0x0},
815 {0x0,0x0,0x0,0x23,0x2,0x2,0x3,0x0,0x0,0x0},
816 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0}
818 { /* level 35 PacMan Ghost by Seth Opgenorth */
819 {0x0,0x0,0x0,0x0,0x2,0x32,0x2,0x0,0x0,0x0},
820 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
821 {0x0,0x0,0x2,0x24,0x4,0x2,0x4,0x4,0x32,0x0},
822 {0x0,0x0,0x2,0x24,0x0,0x22,0x24,0x0,0x22,0x0},
823 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
824 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
825 {0x0,0x0,0x2,0x32,0x2,0x2,0x22,0x2,0x32,0x0},
826 {0x0,0x0,0x0,0x22,0x0,0x32,0x0,0x22,0x0,0x0}
828 { /* level 36 Star by Seth Opgenorth */
829 {0x3,0x4,0x3,0x4,0x6,0x24,0x3,0x24,0x3,0x0},
830 {0x24,0x0,0x0,0x6,0x6,0x6,0x0,0x0,0x4,0x0},
831 {0x3,0x26,0x6,0x2,0x6,0x2,0x6,0x26,0x23,0x0},
832 {0x4,0x0,0x6,0x6,0x36,0x6,0x6,0x0,0x4,0x0},
833 {0x3,0x0,0x0,0x26,0x6,0x26,0x0,0x0,0x33,0x0},
834 {0x34,0x0,0x6,0x6,0x0,0x6,0x6,0x0,0x4,0x0},
835 {0x3,0x26,0x6,0x0,0x0,0x0,0x6,0x6,0x3,0x0},
836 {0x4,0x3,0x4,0x23,0x24,0x3,0x4,0x33,0x4,0x0}
838 { /* level 37 It's 8-Bit by Seth Opgenorth */
839 {0x26,0x26,0x6,0x6,0x5,0x6,0x26,0x6,0x26,0x6},
840 {0x2,0x2,0x22,0x3,0x3,0x0,0x0,0x0,0x4,0x0},
841 {0x2,0x0,0x2,0x33,0x3,0x3,0x5,0x0,0x24,0x0},
842 {0x32,0x2,0x2,0x33,0x0,0x23,0x0,0x4,0x4,0x4},
843 {0x2,0x22,0x2,0x3,0x3,0x0,0x5,0x4,0x4,0x24},
844 {0x2,0x0,0x2,0x23,0x0,0x3,0x25,0x0,0x4,0x0},
845 {0x22,0x2,0x2,0x3,0x23,0x0,0x5,0x0,0x4,0x0},
846 {0x6,0x26,0x6,0x36,0x6,0x36,0x6,0x6,0x6,0x6}
848 { /* level 38 Linux by Seth Opgenorth */
849 {0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
850 {0x7,0x0,0x0,0x0,0x33,0x0,0x23,0x0,0x0,0x0},
851 {0x7,0x32,0x0,0x0,0x3,0x0,0x23,0x6,0x0,0x6},
852 {0x37,0x0,0x0,0x0,0x23,0x0,0x3,0x6,0x0,0x26},
853 {0x7,0x22,0x24,0x0,0x3,0x33,0x3,0x0,0x26,0x0},
854 {0x37,0x22,0x24,0x24,0x4,0x0,0x0,0x0,0x26,0x0},
855 {0x7,0x2,0x4,0x0,0x4,0x0,0x0,0x6,0x0,0x26},
856 {0x7,0x27,0x4,0x0,0x34,0x0,0x0,0x6,0x0,0x26}
858 { /* level 39 Colorful Squares by Seth Opgenorth*/
859 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0},
860 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
861 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
862 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
863 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
864 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
865 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
866 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0}
868 { /* TheEnd */
869 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
870 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
871 {0x32,0x0,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
872 {0x32,0x32,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
873 {0x32,0x32,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
874 {0x32,0x0,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
875 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
876 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
883 * Enums and structs
887 enum power_types
889 POWER_TYPE_LIFE_GAIN = 0,
890 POWER_TYPE_LIFE_LOSS,
891 POWER_TYPE_PADDLE_STICKY,
892 POWER_TYPE_PADDLE_SHOOTER,
893 POWER_TYPE_PADDLE_NORMAL,
894 POWER_TYPE_PADDLE_FLIP,
895 POWER_TYPE_EXTRA_BALL,
896 POWER_TYPE_PADDLE_LONG,
897 POWER_TYPE_PADDLE_SHORT,
898 NUMBER_OF_POWERUPS,
901 #define POWERUP_HEIGHT FIXED3(BMPHEIGHT_brickmania_powerups/NUMBER_OF_POWERUPS)
902 /* Increasing this value makes the game with less powerups */
903 #define POWER_RAND (NUMBER_OF_POWERUPS + 15)
905 enum difficulty_options
907 EASY,
908 NORMAL
911 enum game_state
913 ST_READY,
914 ST_START,
915 ST_PAUSE
918 enum paddle_type
920 PADDLE_TYPE_NORMAL = 0,
921 PADDLE_TYPE_STICKY,
922 PADDLE_TYPE_SHOOTER,
925 enum intersection
927 INTERSECTION_TOP,
928 INTERSECTION_BOTTOM,
929 INTERSECTION_LEFT,
930 INTERSECTION_RIGHT,
931 INTERSECTION_ALL,
934 struct brick
936 bool used; /* Is the brick still in play? */
937 int color;
938 int hits; /* How many hits can this brick take? */
939 int hiteffect;
942 struct ball
944 /* pos_x and y store the current center position of the ball */
945 int pos_x;
946 int pos_y;
947 /* tempx and tempy store an absolute position the ball should be in. If
948 * they are equal to 0, they are not used when positioning the ball.
950 int tempx;
951 int tempy;
952 /* speedx and speedy store the current speed of the ball */
953 int speedx;
954 int speedy;
955 bool glue; /* Is the ball stuck to the paddle? */
958 struct fire
960 int top; /* This stores the fire y position, it is a fixed point num */
961 int x_pos; /* This stores the fire x position, it is a whole number */
964 struct power
966 int top; /* This stores the powerup y position, it is a fixed point num */
967 int x_pos; /* This stores the (middle of) powerup x position, it is a whole number */
968 enum power_types type; /* This stores the powerup type */
971 struct point
973 int x;
974 int y;
977 struct line
979 struct point p1;
980 struct point p2;
983 struct rect
985 struct point top_left;
986 struct point bottom_right;
991 * Globals
995 static enum game_state game_state;
996 static int pad_pos_x;
997 static int life;
998 static int score,vscore;
999 static bool flip_sides;
1000 static int level;
1001 static int brick_on_board;
1002 static int used_balls;
1003 static int used_fires;
1004 static int used_powers;
1005 static int difficulty = NORMAL;
1006 static int pad_width;
1007 static int flip_sides_delay;
1008 static bool resume = false;
1009 static bool resume_file = false;
1010 static struct brick brick[NUM_BRICKS_ROWS][NUM_BRICKS_COLS];
1011 static struct ball ball[MAX_BALLS];
1012 static struct fire fire[MAX_FIRES];
1013 static struct power power[MAX_POWERS];
1014 static enum paddle_type paddle_type;
1016 static struct configdata config[] =
1018 {TYPE_INT, 0, 1, { .int_p = &difficulty }, "difficulty", NULL},
1021 static struct highscore highscores[NUM_SCORES];
1026 * Functions
1031 * check_lines:
1032 * This is based off an explanation and expanded math presented by Paul Bourke:
1033 * http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
1035 * It takes two lines as inputs and returns 1 if they intersect, 0 if they do
1036 * not. hitp returns the point where the two lines intersected.
1038 * This function expects fixed point inputs with a precision of 3. When a
1039 * collision occurs hitp is updated with a fixed point location (precision 3)
1040 * where the collision happened. The internal calculations are fixed
1041 * point with a 7 bit fractional precision.
1043 * If you choose 10 bits of precision a screen size of about 640x480 is the
1044 * largest this can go. 7 bits allows for an accurate intersection calculation
1045 * with a line length of about 64 and a rougher line lenght of 128 which is
1046 * larger than any target currently needs (the pad is the longest line and it
1047 * only needs an accuracy of 2^4 at most to figure out which section of the pad
1048 * the ball hit). A precision of 7 gives breathing room for larger screens.
1049 * Longer line sizes that need accurate intersection points will need more
1050 * precision, but will decrease the maximum screen resolution.
1053 #define LINE_PREC 7
1054 static int check_lines(struct line *line1, struct line *line2,
1055 struct point *hitp)
1057 /* Introduction:
1058 * This code is based on the solution of these two input equations:
1059 * Pa = P1 + ua (P2-P1)
1060 * Pb = P3 + ub (P4-P3)
1062 * Where line one is composed of points P1 and P2 and line two is composed
1063 * of points P3 and P4.
1065 * ua/b is the fractional value you can multiply the x and y legs of the
1066 * triangle formed by each line to find a point on the line.
1068 * The two equations can be expanded to their x/y components:
1069 * Pa.x = p1.x + ua(p2.x - p1.x)
1070 * Pa.y = p1.y + ua(p2.y - p1.y)
1072 * Pb.x = p3.x + ub(p4.x - p3.x)
1073 * Pb.y = p3.y + ub(p4.y - p3.y)
1075 * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
1076 * up with two equations (one for x and one for y):
1078 * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
1079 * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
1081 * ua and ub can then be individually solved for. This results in the
1082 * equations used in the following code.
1085 /* Denominator for ua and ub are the same so store this calculation */
1086 int d = FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p2.x-line1->p1.x))
1087 -FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p2.y-line1->p1.y));
1089 /* n_a and n_b are calculated as seperate values for readability */
1090 int n_a = FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p1.y-line2->p1.y))
1091 -FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p1.x-line2->p1.x));
1093 int n_b = FIXED3_MUL((line1->p2.x - line1->p1.x),(line1->p1.y-line2->p1.y))
1094 -FIXED3_MUL((line1->p2.y - line1->p1.y),(line1->p1.x-line2->p1.x));
1096 /* Make sure there is not a division by zero - this also indicates that
1097 * the lines are parallel.
1099 * If n_a and n_b were both equal to zero the lines would be on top of each
1100 * other (coincidental). This check is not done because it is not
1101 * necessary for this implementation (the parallel check accounts for this).
1103 if(d == 0)
1104 return 0;
1106 /* Calculate the intermediate fractional point that the lines potentially
1107 * intersect.
1109 int ua = (n_a << LINE_PREC)/d;
1110 int ub = (n_b << LINE_PREC)/d;
1112 /* The fractional point will be between 0 and 1 inclusive if the lines
1113 * intersect. If the fractional calculation is larger than 1 or smaller
1114 * than 0 the lines would need to be longer to intersect.
1116 if(ua >=0 && ua <= (1<<LINE_PREC) && ub >= 0 && ub <= (1<<LINE_PREC))
1118 hitp->x = line1->p1.x + ((ua * (line1->p2.x - line1->p1.x))>>LINE_PREC);
1119 hitp->y = line1->p1.y + ((ua * (line1->p2.y - line1->p1.y))>>LINE_PREC);
1120 return 1;
1122 return 0;
1126 static int check_rect(struct line *line, struct rect *rect,
1127 enum intersection intersection, struct point *hitp)
1129 struct line edge;
1131 switch (intersection)
1133 case INTERSECTION_TOP:
1135 edge.p1.x = rect->top_left.x;
1136 edge.p1.y = rect->top_left.y;
1138 edge.p2.x = rect->bottom_right.x;
1139 edge.p2.y = rect->top_left.y;
1141 break;
1143 case INTERSECTION_BOTTOM:
1145 edge.p1.x = rect->top_left.x;
1146 edge.p1.y = rect->bottom_right.y;
1148 edge.p2.x = rect->bottom_right.x;
1149 edge.p2.y = rect->bottom_right.y;
1151 break;
1153 case INTERSECTION_LEFT:
1155 edge.p1.x = rect->top_left.x;
1156 edge.p1.y = rect->top_left.y;
1158 edge.p2.x = rect->top_left.x;
1159 edge.p2.y = rect->bottom_right.y;
1161 break;
1163 case INTERSECTION_RIGHT:
1165 edge.p1.x = rect->bottom_right.x;
1166 edge.p1.y = rect->top_left.y;
1168 edge.p2.x = rect->bottom_right.x;
1169 edge.p2.y = rect->bottom_right.y;
1171 break;
1173 case INTERSECTION_ALL: /* Test hit on all edges */
1175 return (check_rect(line, rect, INTERSECTION_TOP, hitp) ||
1176 check_rect(line, rect, INTERSECTION_BOTTOM, hitp) ||
1177 check_rect(line, rect, INTERSECTION_LEFT, hitp) ||
1178 check_rect(line, rect, INTERSECTION_RIGHT, hitp));
1182 return check_lines(line, &edge, hitp);
1185 static void brickmania_init_game(bool new_game)
1187 int i,j;
1189 pad_pos_x = GAMESCREEN_WIDTH/2 - PAD_WIDTH/2;
1191 for(i=0;i<MAX_BALLS;i++)
1193 ball[i].speedx = 0;
1194 ball[i].speedy = 0;
1195 ball[i].tempy = 0;
1196 ball[i].tempx = 0;
1197 ball[i].pos_y = ON_PAD_POS_Y;
1198 ball[i].pos_x = GAMESCREEN_WIDTH/2;
1199 ball[i].glue = false;
1202 used_balls = 1;
1203 used_fires = 0;
1204 used_powers = 0;
1205 game_state = ST_READY;
1206 paddle_type = PADDLE_TYPE_NORMAL;
1207 pad_width = PAD_WIDTH;
1208 flip_sides = false;
1209 flip_sides_delay = FLIP_SIDES_DELAY;
1211 if (new_game) {
1212 brick_on_board=0;
1213 /* add one life per achieved level */
1214 if (difficulty==EASY && life<2) {
1215 score+=SCORE_LEVEL_COMPLETED;
1216 life++;
1220 for(i=0;i<NUM_BRICKS_ROWS;i++) {
1221 for(j=0;j<NUM_BRICKS_COLS;j++) {
1222 if (new_game) {
1223 brick[i][j].hits=levels[level][i][j]>=10?
1224 levels[level][i][j]/16-1:0;
1225 brick[i][j].hiteffect=0;
1226 brick[i][j].used=!(levels[level][i][j]==0);
1227 brick[i][j].color=(levels[level][i][j]>=10?
1228 levels[level][i][j]%16:
1229 levels[level][i][j])-1;
1230 if (levels[level][i][j]!=0)
1231 brick_on_board++;
1237 static void brickmania_loadgame(void)
1239 int fd;
1241 resume = false;
1243 /* open game file */
1244 fd = rb->open(SAVE_FILE, O_RDONLY);
1245 if(fd < 0) return;
1247 /* read in saved game */
1248 if((rb->read(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1249 (rb->read(fd, &life, sizeof(life)) <= 0) ||
1250 (rb->read(fd, &game_state, sizeof(game_state)) <= 0) ||
1251 (rb->read(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1252 (rb->read(fd, &score, sizeof(score)) <= 0) ||
1253 (rb->read(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1254 (rb->read(fd, &level, sizeof(level)) <= 0) ||
1255 (rb->read(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1256 (rb->read(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1257 (rb->read(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1258 (rb->read(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1259 (rb->read(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1260 (rb->read(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1261 (rb->read(fd, &brick, sizeof(brick)) <= 0) ||
1262 (rb->read(fd, &ball, sizeof(ball)) <= 0) ||
1263 (rb->read(fd, &fire, sizeof(fire)) <= 0) ||
1264 (rb->read(fd, &power, sizeof(power)) <= 0))
1266 rb->splash(HZ/2, "Failed to load game");
1268 else
1270 vscore = score;
1271 resume = true;
1274 rb->close(fd);
1276 return;
1279 static void brickmania_savegame(void)
1281 int fd;
1283 /* write out the game state to the save file */
1284 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
1285 if(fd < 0) return;
1287 if ((rb->write(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1288 (rb->write(fd, &life, sizeof(life)) <= 0) ||
1289 (rb->write(fd, &game_state, sizeof(game_state)) <= 0) ||
1290 (rb->write(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1291 (rb->write(fd, &score, sizeof(score)) <= 0) ||
1292 (rb->write(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1293 (rb->write(fd, &level, sizeof(level)) <= 0) ||
1294 (rb->write(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1295 (rb->write(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1296 (rb->write(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1297 (rb->write(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1298 (rb->write(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1299 (rb->write(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1300 (rb->write(fd, &brick, sizeof(brick)) <= 0) ||
1301 (rb->write(fd, &ball, sizeof(ball)) <= 0) ||
1302 (rb->write(fd, &fire, sizeof(fire)) <= 0) ||
1303 (rb->write(fd, &power, sizeof(power)) <= 0))
1305 rb->close(fd);
1306 rb->remove(SAVE_FILE);
1307 rb->splash(HZ/2, "Failed to save game");
1308 return;
1311 rb->close(fd);
1314 /* brickmania_sleep timer counting the score */
1315 static void brickmania_sleep(int secs)
1317 bool done=false;
1318 char s[20];
1319 int count=0;
1320 int sw, w;
1322 while (!done)
1324 if (count == 0)
1325 count = *rb->current_tick + HZ*secs;
1326 if ( (TIME_AFTER(*rb->current_tick, count)) && (vscore == score) )
1327 done = true;
1329 if(vscore != score)
1331 if (vscore<score)
1332 vscore++;
1333 if (vscore>score)
1334 vscore--;
1335 rb->snprintf(s, sizeof(s), "%d", vscore);
1336 rb->lcd_getstringsize(s, &sw, &w);
1337 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1338 rb->lcd_update_rect(0,0,LCD_WIDTH,w+2);
1340 rb->yield();
1344 static int brickmania_help(void)
1346 static char *help_text[] = {
1347 "Brickmania", "", "Aim", "",
1348 "Destroy", "all", "the", "bricks", "by", "bouncing",
1349 "the", "ball", "of", "them", "using", "the", "paddle.", "", "",
1350 "Controls", "",
1351 #if CONFIG_KEYPAD == COWON_D2_PAD
1352 "- & +:",
1353 #else
1354 "< & >:",
1355 #endif
1356 "Moves", "the", "paddle", "",
1357 #if CONFIG_KEYPAD == ONDIO_PAD
1358 "MENU:",
1359 #elif (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
1360 "PLAY:",
1361 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
1362 "NAVI:",
1363 #elif CONFIG_KEYPAD == COWON_D2_PAD
1364 "MENU:",
1365 #else
1366 "SELECT:",
1367 #endif
1368 "Releases", "the", "ball/Fire!", "",
1369 #if CONFIG_KEYPAD == IAUDIO_M3_PAD
1370 "REC:",
1371 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
1372 (CONFIG_KEYPAD == CREATIVEZVM_PAD)
1373 "BACK:",
1374 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1375 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1376 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1377 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1378 "MENU:",
1379 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
1380 (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
1381 (CONFIG_KEYPAD == ONDIO_PAD) || \
1382 (CONFIG_KEYPAD == RECORDER_PAD) || \
1383 (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
1384 "STOP:",
1385 #else
1386 "POWER:",
1387 #endif
1388 "Returns", "to", "menu", "", "",
1389 "Specials", "",
1390 "N", "Normal:", "returns", "paddle", "to", "normal", "",
1391 "D", "DIE!:", "loses", "a", "life", "",
1392 "L", "Life:", "gains", "a", "life/power", "up", "",
1393 "F", "Fire:", "allows", "you", "to", "shoot", "bricks", "",
1394 "G", "Glue:", "ball", "sticks", "to", "paddle", "",
1395 "B", "Ball:", "generates", "another", "ball", "",
1396 "FL", "Flip:", "flips", "left / right", "movement", "",
1397 "<->", "or", "<E>:", "enlarges", "the", "paddle", "",
1398 ">-<", "or", ">S<:", "shrinks", "the", "paddle", "",
1400 static struct style_text formation[]={
1401 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1402 { 2, C_RED },
1403 { 19, C_RED },
1404 { 37, C_RED },
1405 { 39, C_BLUE },
1406 { 46, C_RED },
1407 { 52, C_GREEN },
1408 { 59, C_ORANGE },
1409 { 67, C_GREEN },
1410 { 74, C_YELLOW },
1411 { 80, C_RED },
1412 LAST_STYLE_ITEM
1415 rb->lcd_setfont(FONT_UI);
1416 #ifdef HAVE_LCD_COLOR
1417 rb->lcd_set_background(LCD_BLACK);
1418 rb->lcd_set_foreground(LCD_WHITE);
1419 #endif
1420 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1421 return 1;
1422 rb->lcd_setfont(FONT_SYSFIXED);
1424 return 0;
1427 static int brickmania_menu_cb(int action, const struct menu_item_ex *this_item)
1429 int i = ((intptr_t)this_item);
1430 if(action == ACTION_REQUEST_MENUITEM
1431 && !resume && (i==0 || i==6))
1432 return ACTION_EXIT_MENUITEM;
1433 return action;
1436 static int brickmania_menu(void)
1438 int selected = 0;
1440 static struct opt_items options[] = {
1441 { "Easy", -1 },
1442 { "Normal", -1 },
1445 #ifdef HAVE_TOUCHSCREEN
1446 /* Entering Menu, set the touchscreen to the global setting */
1447 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
1448 #endif
1450 MENUITEM_STRINGLIST(main_menu, "Brickmania Menu", brickmania_menu_cb,
1451 "Resume Game", "Start New Game",
1452 "Difficulty", "Help", "High Scores",
1453 "Playback Control",
1454 "Quit without Saving", "Quit");
1456 rb->button_clear_queue();
1457 while (true) {
1458 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1459 case 0:
1460 if(game_state!=ST_READY)
1461 game_state = ST_PAUSE;
1462 if(resume_file)
1463 rb->remove(SAVE_FILE);
1464 return 0;
1465 case 1:
1466 score=0;
1467 vscore=0;
1468 life=2;
1469 level=0;
1470 brickmania_init_game(true);
1471 return 0;
1472 case 2:
1473 rb->set_option("Difficulty", &difficulty, INT,
1474 options, 2, NULL);
1475 break;
1476 case 3:
1477 if (brickmania_help())
1478 return 1;
1479 break;
1480 case 4:
1481 highscore_show(-1, highscores, NUM_SCORES, true);
1482 break;
1483 case 5:
1484 if (playback_control(NULL))
1485 return 1;
1486 break;
1487 case 6:
1488 return 1;
1489 case 7:
1490 if (resume) {
1491 rb->splash(HZ*1, "Saving game ...");
1492 brickmania_savegame();
1494 return 1;
1495 case MENU_ATTACHED_USB:
1496 return 1;
1497 default:
1498 break;
1501 #ifdef HAVE_TOUCHSCREEN
1502 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
1503 #endif
1506 static void brick_hit(int i, int j)
1508 if(!brick[i][j].used)
1509 return;
1511 /* if this is a crackable brick hits starts as
1512 * greater than 0.
1514 if (brick[i][j].hits > 0) {
1515 brick[i][j].hits--;
1516 brick[i][j].hiteffect++;
1517 score+=SCORE_BALL_HIT_BRICK;
1519 else {
1520 brick[i][j].used=false;
1521 if (used_powers<MAX_POWERS)
1523 int ran = rb->rand()%POWER_RAND;
1525 if (ran<NUMBER_OF_POWERUPS)
1527 power[used_powers].top = TOPMARGIN + i*BRICK_HEIGHT;
1528 power[used_powers].x_pos = LEFTMARGIN + j*BRICK_WIDTH +
1529 (BRICK_WIDTH >> 1);
1530 power[used_powers].type = ran;
1531 used_powers++;
1534 brick_on_board--;
1535 score+=SCORE_BALL_DEMOLISHED_BRICK;
1539 static int brickmania_game_loop(void)
1541 int j,i,k;
1542 int sw, sh;
1543 char s[30];
1544 int sec_count=0;
1545 int end;
1547 /* pad_rect used for powerup/ball checks */
1548 struct rect pad_rect;
1549 /* This is used for various lines that are checked (ball and powerup) */
1550 struct line misc_line;
1552 /* This stores the point that the two lines intersected in a test */
1553 struct point pt_hit;
1555 if (brickmania_menu()) {
1556 return 1;
1558 resume = false;
1559 resume_file = false;
1561 #ifdef HAVE_LCD_COLOR
1562 rb->lcd_set_background(LCD_BLACK);
1563 rb->lcd_set_foreground(LCD_WHITE);
1564 rb->lcd_set_drawmode(DRMODE_SOLID);
1565 rb->lcd_clear_display();
1566 #endif
1568 while(true) {
1569 /* Convert CYCLETIME (in ms) to HZ */
1570 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1572 if (life >= 0) {
1573 rb->lcd_clear_display();
1575 if (flip_sides)
1577 if (TIME_AFTER(*rb->current_tick, sec_count))
1579 sec_count=*rb->current_tick+HZ;
1580 if (flip_sides_delay > 1)
1581 flip_sides_delay--;
1582 else
1583 flip_sides=false;
1585 rb->snprintf(s, sizeof(s), "%d", flip_sides_delay);
1586 rb->lcd_getstringsize(s, &sw, NULL);
1587 rb->lcd_putsxy(LCD_WIDTH/2-2, INT3(STRINGPOS_FLIP), s);
1590 /* write life num */
1591 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1592 #define LIFE_STR "L:%d"
1593 #else
1594 #define LIFE_STR "Life: %d"
1595 #endif
1596 rb->lcd_putsxyf(0, 0, LIFE_STR, life);
1598 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1599 rb->snprintf(s, sizeof(s), "L%d", level+1);
1600 #else
1601 rb->snprintf(s, sizeof(s), "Level %d", level+1);
1602 #endif
1604 rb->lcd_getstringsize(s, &sw, NULL);
1605 rb->lcd_putsxy(LCD_WIDTH-sw, 0, s);
1607 if (vscore<score) vscore++;
1608 rb->snprintf(s, sizeof(s), "%d", vscore);
1609 rb->lcd_getstringsize(s, &sw, NULL);
1610 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1612 /* continue game */
1613 if (game_state == ST_PAUSE)
1615 rb->snprintf(s, sizeof(s), CONTINUE_TEXT);
1616 rb->lcd_getstringsize(s, &sw, NULL);
1617 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_NAVI), s);
1619 sec_count=*rb->current_tick+HZ;
1622 /* draw the ball */
1623 for(i=0;i<used_balls;i++)
1624 rb->lcd_bitmap(brickmania_ball,
1625 INT3(ball[i].pos_x - HALFBALL),
1626 INT3(ball[i].pos_y - HALFBALL),
1627 INT3(BALL), INT3(BALL));
1629 if (brick_on_board==0)
1630 brick_on_board--;
1632 /* Setup the pad line-later used in intersection test */
1633 pad_rect.top_left.x = pad_pos_x;
1634 pad_rect.top_left.y = PAD_POS_Y;
1636 pad_rect.bottom_right.x = pad_pos_x + pad_width;
1637 pad_rect.bottom_right.y = PAD_POS_Y + PAD_HEIGHT;
1639 if (game_state!=ST_PAUSE)
1641 /* move the fires */
1642 for(k=0;k<used_fires;k++)
1644 fire[k].top -= SPEED_FIRE;
1645 if (fire[k].top < 0)
1647 used_fires--;
1648 fire[k].top = fire[used_fires].top;
1649 fire[k].x_pos = fire[used_fires].x_pos;
1650 k--;
1652 else if (fire[k].x_pos >= LEFTMARGIN &&
1653 fire[k].x_pos < LEFTMARGIN + NUM_BRICKS_COLS * BRICK_WIDTH)
1655 j = (fire[k].x_pos - LEFTMARGIN) / BRICK_WIDTH;
1656 for (i=NUM_BRICKS_ROWS-1;i>=0;i--)
1658 if (TOPMARGIN + i*BRICK_HEIGHT<=fire[k].top)
1659 break;
1660 if (brick[i][j].used)
1662 score += SCORE_FIRE_HIT_BRICK;
1663 brick_hit(i, j);
1664 used_fires--;
1665 fire[k].top = fire[used_fires].top;
1666 fire[k].x_pos = fire[used_fires].x_pos;
1667 k--;
1668 break;
1674 /* move and handle the powerups */
1675 for (k=0;k<used_powers;k++)
1677 int remove_power = 0;
1679 power[k].top += SPEED_POWER;
1681 if (power[k].top > PAD_POS_Y)
1683 /* power hit bottom */
1684 remove_power = 1;
1686 else
1688 /* Use misc_line to check if the center of the powerup
1689 * hit the paddle.
1691 misc_line.p1.x = power[k].x_pos;
1692 misc_line.p1.y = power[k].top;
1694 misc_line.p2 = misc_line.p1;
1695 misc_line.p2.y += SPEED_POWER;
1697 /* Check if the powerup will hit the paddle */
1698 if (check_rect(&misc_line, &pad_rect, INTERSECTION_ALL,
1699 &pt_hit))
1702 /* power hit paddle */
1703 remove_power = 1;
1704 switch(power[k].type)
1706 case POWER_TYPE_LIFE_GAIN:
1707 life++;
1708 score += SCORE_POWER_LIFE_GAIN;
1709 break;
1710 case POWER_TYPE_LIFE_LOSS:
1711 life--;
1712 if (life>=0)
1714 brickmania_init_game(false);
1715 brickmania_sleep(2);
1717 break;
1718 case POWER_TYPE_PADDLE_STICKY:
1719 score += SCORE_POWER_PADDLE_STICKY;
1720 paddle_type = PADDLE_TYPE_STICKY;
1721 break;
1722 case POWER_TYPE_PADDLE_SHOOTER:
1723 score += SCORE_POWER_PADDLE_SHOOTER;
1724 paddle_type = PADDLE_TYPE_SHOOTER;
1725 for(i=0;i<used_balls;i++)
1726 ball[i].glue=false;
1727 break;
1728 case POWER_TYPE_PADDLE_NORMAL:
1729 score += SCORE_POWER_PADDLE_NORMAL;
1730 paddle_type = PADDLE_TYPE_NORMAL;
1731 for(i=0;i<used_balls;i++)
1732 ball[i].glue=false;
1733 flip_sides=false;
1734 pad_pos_x += (pad_width-PAD_WIDTH)/2;
1735 pad_width = PAD_WIDTH;
1736 break;
1737 case POWER_TYPE_PADDLE_FLIP:
1738 score += SCORE_POWER_FLIP;
1739 sec_count = *rb->current_tick+HZ;
1740 flip_sides_delay = FLIP_SIDES_DELAY;
1741 flip_sides = true;
1742 break;
1743 case POWER_TYPE_EXTRA_BALL:
1744 score += SCORE_POWER_EXTRA_BALL;
1745 if(used_balls<MAX_BALLS)
1747 /* Set the speed */
1748 if(rb->rand()%2 == 0)
1749 ball[used_balls].speedx=-SPEED_4Q_X;
1750 else
1751 ball[used_balls].speedx= SPEED_4Q_X;
1752 ball[used_balls].speedy= SPEED_4Q_Y;
1753 /* Ball is not glued */
1754 ball[used_balls].glue= false;
1755 used_balls++;
1757 break;
1758 case POWER_TYPE_PADDLE_LONG:
1759 score+=SCORE_POWER_LONG_PADDLE;
1760 if (pad_width==PAD_WIDTH)
1762 pad_width = LONG_PAD_WIDTH;
1763 pad_pos_x -= (LONG_PAD_WIDTH -
1764 PAD_WIDTH)/2;
1766 else if (pad_width==SHORT_PAD_WIDTH)
1768 pad_width = PAD_WIDTH;
1769 pad_pos_x-=(PAD_WIDTH-
1770 SHORT_PAD_WIDTH)/2;
1772 if (pad_pos_x < 0)
1773 pad_pos_x = 0;
1774 else if(pad_pos_x + pad_width >
1775 GAMESCREEN_WIDTH)
1776 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
1777 break;
1778 case POWER_TYPE_PADDLE_SHORT:
1779 if (pad_width==PAD_WIDTH)
1781 pad_width=SHORT_PAD_WIDTH;
1782 pad_pos_x+=(PAD_WIDTH-
1783 SHORT_PAD_WIDTH)/2;
1785 else if (pad_width==LONG_PAD_WIDTH)
1787 pad_width=PAD_WIDTH;
1788 pad_pos_x+=(LONG_PAD_WIDTH-PAD_WIDTH)/2;
1790 break;
1791 default:
1792 break;
1796 if (remove_power)
1798 used_powers--;
1799 if (k != used_powers)
1801 power[k].top = power[used_powers].top;
1802 power[k].x_pos = power[used_powers].x_pos;
1803 power[k].type = power[used_powers].type;
1805 k--;
1811 /* draw the fires */
1812 for(k=0;k<used_fires;k++)
1814 rb->lcd_vline(INT3(fire[k].x_pos), INT3(fire[k].top),
1815 INT3(fire[k].top + FIRE_LENGTH));
1818 /* draw the powerups */
1819 for(k=0;k<used_powers;k++)
1821 rb->lcd_bitmap_part(brickmania_powerups,0,
1822 INT3(POWERUP_HEIGHT)*power[k].type,
1823 STRIDE(SCREEN_MAIN, BMPWIDTH_brickmania_powerups,
1824 BMPHEIGHT_brickmania_powerups),
1825 INT3(power[k].x_pos - (POWERUP_WIDTH >> 1)),
1826 INT3(power[k].top), INT3(POWERUP_WIDTH),
1827 INT3(POWERUP_HEIGHT));
1830 /* handle all of the bricks */
1831 for (i=0; i<NUM_BRICKS_ROWS; i++)
1833 for (j=0; j<NUM_BRICKS_COLS ;j++)
1835 int brickx,bricky;
1837 /* The brick is a brick, but it may or may not be in use */
1838 if(brick[i][j].used)
1840 struct rect brick_rect;
1842 brickx = LEFTMARGIN + j*BRICK_WIDTH;
1843 bricky = TOPMARGIN + i*BRICK_HEIGHT;
1845 brick_rect.top_left.x = brickx;
1846 brick_rect.top_left.y = bricky;
1848 brick_rect.bottom_right.x = brickx + BRICK_WIDTH;
1849 brick_rect.bottom_right.y = bricky + BRICK_HEIGHT;
1851 /* Draw the brick */
1852 rb->lcd_bitmap_part(brickmania_bricks,0,
1853 INT3(BRICK_HEIGHT)*brick[i][j].color,
1854 STRIDE( SCREEN_MAIN,
1855 BMPWIDTH_brickmania_bricks,
1856 BMPHEIGHT_brickmania_bricks),
1857 INT3(brickx),
1858 INT3(bricky),
1859 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1861 #ifdef HAVE_LCD_COLOR /* No transparent effect for greyscale lcds for now */
1862 if (brick[i][j].hiteffect > 0)
1863 rb->lcd_bitmap_transparent_part(brickmania_break,0,
1864 INT3(BRICK_HEIGHT)*brick[i][j].hiteffect,
1865 STRIDE( SCREEN_MAIN,
1866 BMPWIDTH_brickmania_break,
1867 BMPHEIGHT_brickmania_break),
1868 INT3(brickx),
1869 INT3(bricky),
1870 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1871 #endif
1873 /* Check if any balls collided with the brick */
1874 for(k=0; k<used_balls; k++)
1876 int hit = 0;
1878 /* Setup the ball path to describe the current ball
1879 * position and the line it makes to its next
1880 * position.
1882 misc_line.p1.x = ball[k].pos_x;
1883 misc_line.p1.y = ball[k].pos_y;
1885 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1886 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1888 /* Check to see if the ball and the bottom hit. If
1889 * the ball is moving down we don't want to
1890 * include the bottom line intersection.
1892 * The order that the sides are checked matters.
1894 * Note that tempx/tempy store the next position
1895 * that the ball should be drawn.
1897 if (ball[k].speedy <= 0 && check_rect(&misc_line,
1898 &brick_rect, INTERSECTION_BOTTOM, &pt_hit))
1900 ball[k].speedy = -ball[k].speedy;
1901 hit = 1;
1903 /* Check the top, if the ball is moving up dont
1904 * count it as a hit.
1906 else if (ball[k].speedy > 0 && check_rect(&misc_line,
1907 &brick_rect, INTERSECTION_TOP, &pt_hit))
1909 ball[k].speedy = -ball[k].speedy;
1910 hit = 1;
1912 /* Check the left side of the brick */
1913 else if (check_rect(&misc_line, &brick_rect,
1914 INTERSECTION_LEFT, &pt_hit))
1916 ball[k].speedx = -ball[k].speedx;
1917 hit = 1;
1919 /* Check the right side of the brick */
1920 else if (check_rect(&misc_line, &brick_rect,
1921 INTERSECTION_RIGHT, &pt_hit))
1923 ball[k].speedx = -ball[k].speedx;
1924 hit = 1;
1927 if (hit)
1929 ball[k].tempy = pt_hit.y;
1930 ball[k].tempx = pt_hit.x;
1931 brick_hit(i, j);
1932 break;
1934 } /* for k */
1935 } /* if(used) */
1937 } /* for j */
1938 } /* for i */
1940 /* draw the paddle according to the PAD_WIDTH */
1941 if( pad_width == PAD_WIDTH ) /* Normal width */
1943 rb->lcd_bitmap_part(
1944 brickmania_pads,
1945 0, paddle_type*INT3(PAD_HEIGHT),
1946 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_pads,
1947 BMPHEIGHT_brickmania_pads),
1948 INT3(pad_pos_x), INT3(PAD_POS_Y),
1949 INT3(pad_width), INT3(PAD_HEIGHT) );
1951 else if( pad_width == LONG_PAD_WIDTH ) /* Long Pad */
1953 rb->lcd_bitmap_part(
1954 brickmania_long_pads,
1955 0,paddle_type*INT3(PAD_HEIGHT),
1956 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_long_pads,
1957 BMPHEIGHT_brickmania_long_pads),
1958 INT3(pad_pos_x), INT3(PAD_POS_Y),
1959 INT3(pad_width), INT3(PAD_HEIGHT) );
1961 else /* Short pad */
1963 rb->lcd_bitmap_part(
1964 brickmania_short_pads,
1965 0,paddle_type*INT3(PAD_HEIGHT),
1966 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_short_pads,
1967 BMPHEIGHT_brickmania_short_pads),
1968 INT3(pad_pos_x), INT3(PAD_POS_Y),
1969 INT3(pad_width), INT3(PAD_HEIGHT) );
1972 /* If the game is not paused continue */
1973 if (game_state!=ST_PAUSE)
1975 /* Loop through all of the balls in play */
1976 for(k=0;k<used_balls;k++)
1978 struct line screen_edge;
1980 /* Describe the ball movement for the edge collision detection */
1981 misc_line.p1.x = ball[k].pos_x;
1982 misc_line.p1.y = ball[k].pos_y;
1984 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1985 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1987 /* Did the Ball hit the top of the screen? */
1988 screen_edge.p1.x = 0;
1989 screen_edge.p1.y = 0;
1991 screen_edge.p2.x = GAMESCREEN_WIDTH;
1992 screen_edge.p2.y = 0;
1993 /* the test for pos_y prevents the ball from bouncing back
1994 * from _over_ the top to infinity on some rare cases */
1995 if (ball[k].pos_y > 0 &&
1996 check_lines(&misc_line, &screen_edge, &pt_hit))
1998 ball[k].tempy = pt_hit.y + 1;
1999 ball[k].tempx = pt_hit.x;
2000 /* Reverse the direction */
2001 ball[k].speedy = -ball[k].speedy;
2004 /* Player missed the ball and hit bottom of screen */
2005 if (ball[k].pos_y >= GAMESCREEN_HEIGHT)
2007 /* Player had balls to spare, so handle the removal */
2008 if (used_balls>1)
2010 /* decrease number of balls in play */
2011 used_balls--;
2012 /* Replace removed ball with the last ball */
2013 ball[k].pos_x = ball[used_balls].pos_x;
2014 ball[k].pos_y = ball[used_balls].pos_y;
2015 ball[k].speedy = ball[used_balls].speedy;
2016 ball[k].tempy = ball[used_balls].tempy;
2017 ball[k].speedx = ball[used_balls].speedx;
2018 ball[k].tempx = ball[used_balls].tempx;
2019 ball[k].glue = ball[used_balls].glue;
2021 /* Reset the last ball that was removed */
2022 ball[used_balls].speedx=0;
2023 ball[used_balls].speedy=0;
2024 ball[used_balls].tempy=0;
2025 ball[used_balls].tempx=0;
2026 ball[used_balls].pos_y=ON_PAD_POS_Y;
2027 ball[used_balls].pos_x=pad_pos_x+(pad_width/2)-HALFBALL;
2029 k--;
2030 continue;
2032 else
2034 /* Player lost a life */
2035 life--;
2036 if (life>=0)
2038 /* No lives left reset game */
2039 brickmania_init_game(false);
2040 brickmania_sleep(2);
2041 rb->button_clear_queue();
2046 if (game_state != ST_READY && !ball[k].glue)
2048 /* Check if the ball hit the left side */
2049 screen_edge.p1.x = 0;
2050 screen_edge.p1.y = 0;
2052 screen_edge.p2.x = 0;
2053 screen_edge.p2.y = GAMESCREEN_HEIGHT;
2054 if (check_lines(&misc_line, &screen_edge, &pt_hit))
2056 /* Reverse direction */
2057 ball[k].speedx = abs(ball[k].speedx);
2059 /* Re-position ball in gameboard */
2060 ball[k].tempy = pt_hit.y;
2061 ball[k].tempx = 0;
2064 /* Check if the ball hit the right side */
2065 screen_edge.p1.x = GAMESCREEN_WIDTH;
2066 screen_edge.p1.y = 0;
2068 screen_edge.p2.x = GAMESCREEN_WIDTH;
2069 screen_edge.p2.y = GAMESCREEN_HEIGHT;
2070 if (check_lines(&misc_line, &screen_edge, &pt_hit))
2072 /* Reverse direction */
2073 ball[k].speedx = -abs(ball[k].speedx);
2075 /* Re-position ball in gameboard */
2076 ball[k].tempy = pt_hit.y;
2077 ball[k].tempx = GAMESCREEN_WIDTH - FIXED3(1);
2080 /* Did the ball hit the paddle? Depending on where the ball
2081 * Hit set the x/y speed appropriately.
2083 if(check_rect(&misc_line, &pad_rect, INTERSECTION_TOP,
2084 &pt_hit) )
2086 /* Re-position ball based on collision */
2087 ball[k].tempy = ON_PAD_POS_Y;
2088 ball[k].tempx = pt_hit.x;
2090 /* Calculate the ball position relative to the paddle width */
2091 int ball_repos = pt_hit.x - pad_pos_x;
2092 /* If the ball hits the right half of paddle, x speed
2093 * should be positive, if it hits the left half it
2094 * should be negative.
2096 int x_direction = -1;
2098 /* Comparisons are done with respect to 1/2 pad_width */
2099 if(ball_repos > pad_width/2)
2101 /* flip the relative position */
2102 ball_repos -= ((ball_repos - pad_width/2) << 1);
2103 /* Ball hit the right half so X speed calculations
2104 * should be positive.
2106 x_direction = 1;
2109 /* Figure out where the ball hit relative to 1/2 pad
2110 * and in divisions of 4.
2112 ball_repos = ball_repos / (pad_width/2/4);
2114 switch(ball_repos)
2116 /* Ball hit the outer edge of the paddle */
2117 case 0:
2118 ball[k].speedy = SPEED_1Q_Y;
2119 ball[k].speedx = SPEED_1Q_X * x_direction;
2120 break;
2121 /* Ball hit the next fourth of the paddle */
2122 case 1:
2123 ball[k].speedy = SPEED_2Q_Y;
2124 ball[k].speedx = SPEED_2Q_X * x_direction;
2125 break;
2126 /* Ball hit the third fourth of the paddle */
2127 case 2:
2128 ball[k].speedy = SPEED_3Q_Y;
2129 ball[k].speedx = SPEED_3Q_X * x_direction;
2130 break;
2131 /* Ball hit the fourth fourth of the paddle or dead
2132 * center.
2134 case 3:
2135 case 4:
2136 ball[k].speedy = SPEED_4Q_Y;
2137 /* Since this is the middle we don't want to
2138 * force the ball in a different direction.
2139 * Just keep it going in the same direction
2140 * with a specific speed.
2142 if(ball[k].speedx > 0)
2144 ball[k].speedx = SPEED_4Q_X;
2146 else
2148 ball[k].speedx = -SPEED_4Q_X;
2150 break;
2152 default:
2153 ball[k].speedy = SPEED_4Q_Y;
2154 break;
2157 if(paddle_type == PADDLE_TYPE_STICKY)
2159 ball[k].speedy = -ball[k].speedy;
2160 ball[k].glue=true;
2162 /* X location should not be forced since that is moved with the paddle. The Y
2163 * position should be forced to keep the ball at the paddle.
2165 ball[k].tempx = 0;
2166 ball[k].tempy = ON_PAD_POS_Y;
2171 /* Update the ball position */
2172 if (!ball[k].glue)
2174 if(ball[k].tempx)
2175 ball[k].pos_x = ball[k].tempx;
2176 else
2177 ball[k].pos_x += ball[k].speedx;
2179 if(ball[k].tempy)
2180 ball[k].pos_y = ball[k].tempy;
2181 else
2182 ball[k].pos_y += ball[k].speedy;
2184 ball[k].tempy=0;
2185 ball[k].tempx=0;
2187 } /* for k */
2190 rb->lcd_update();
2192 if (brick_on_board < 0)
2194 if (level+1<NUM_LEVELS)
2196 level++;
2197 if (difficulty==NORMAL)
2198 score+=SCORE_LEVEL_COMPLETED;
2199 brickmania_init_game(true);
2200 brickmania_sleep(2);
2201 rb->button_clear_queue();
2203 else
2205 rb->lcd_getstringsize("Congratulations!", &sw, &sh);
2206 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH) - 2 * sh,
2207 "Congratulations!");
2208 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
2209 rb->lcd_getstringsize("No more levels", &sw, NULL);
2210 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2211 "No more levels");
2212 #else
2213 rb->lcd_getstringsize("You have finished the game!",
2214 &sw, NULL);
2215 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2216 "You have finished the game!");
2217 #endif
2218 vscore=score;
2219 rb->lcd_update();
2220 brickmania_sleep(2);
2221 return 0;
2225 int button=rb->button_get(false);
2226 int move_button = rb->button_status();
2228 #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
2229 /* FIXME: Should probably check remote hold here */
2230 if (rb->button_hold())
2231 button = QUIT;
2232 #endif
2234 #ifdef HAVE_TOUCHSCREEN
2235 if( move_button & BUTTON_TOUCHSCREEN)
2237 int data;
2238 short touch_x, touch_y;
2239 rb->button_status_wdata(&data);
2240 touch_x = FIXED3(data >> 16);
2241 touch_y = FIXED3(data & 0xffff);
2243 if(flip_sides)
2245 pad_pos_x = GAMESCREEN_WIDTH - (touch_x + pad_width/2);
2247 else
2249 pad_pos_x = (touch_x - pad_width/2);
2252 if(pad_pos_x < 0)
2253 pad_pos_x = 0;
2254 else if(pad_pos_x + pad_width > GAMESCREEN_WIDTH)
2255 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
2256 for(k=0; k<used_balls; k++)
2257 if (game_state==ST_READY || ball[k].glue)
2258 ball[k].pos_x = pad_pos_x + pad_width/2;
2260 else
2261 #endif
2263 int button_right, button_left;
2264 #ifdef ALTRIGHT
2265 button_right = move_button & (RIGHT | ALTRIGHT);
2266 button_left = move_button & (LEFT | ALTLEFT);
2267 #else
2268 button_right =((move_button & RIGHT)|| SCROLL_FWD(button));
2269 button_left =((move_button & LEFT) ||SCROLL_BACK(button));
2270 #endif
2271 if ((game_state==ST_PAUSE) && (button_right || button_left))
2272 continue;
2274 if (button_left || button_right)
2276 int dx = 0;
2278 if ((button_right && !flip_sides) ||
2279 (button_left && flip_sides))
2281 if (pad_pos_x+SPEED_PAD+pad_width > GAMESCREEN_WIDTH)
2282 dx = GAMESCREEN_WIDTH - pad_pos_x - pad_width;
2283 else
2284 dx = SPEED_PAD;
2286 else if ((button_left && !flip_sides) ||
2287 (button_right && flip_sides))
2289 if (pad_pos_x-SPEED_PAD < 0)
2290 dx = -pad_pos_x;
2291 else
2292 dx = -SPEED_PAD;
2295 pad_pos_x+=dx;
2296 for(k=0;k<used_balls;k++)
2298 if (game_state==ST_READY || ball[k].glue)
2300 ball[k].pos_x+=dx;
2302 if (ball[k].pos_x < HALFBALL)
2303 ball[k].pos_x = HALFBALL;
2304 else if (ball[k].pos_x > GAMESCREEN_WIDTH - HALFBALL)
2305 ball[k].pos_x = GAMESCREEN_WIDTH - HALFBALL;
2311 switch(button)
2313 #if defined(HAVE_TOUCHSCREEN)
2314 case (BUTTON_REL | BUTTON_TOUCHSCREEN):
2315 #endif
2316 case UP:
2317 case SELECT:
2318 #ifdef ALTSELECT
2319 case ALTSELECT:
2320 #endif
2321 if (game_state==ST_READY)
2323 /* Initialize used balls starting speed */
2324 for(k=0 ; k < used_balls ; k++)
2326 ball[k].speedy = SPEED_4Q_Y;
2327 if(pad_pos_x + (pad_width/2) >= GAMESCREEN_WIDTH/2)
2329 ball[k].speedx = SPEED_4Q_X;
2331 else
2333 ball[k].speedx = -SPEED_4Q_X;
2336 game_state=ST_START;
2338 else if (game_state==ST_PAUSE)
2340 game_state=ST_START;
2342 else if (paddle_type == PADDLE_TYPE_STICKY)
2344 for(k=0;k<used_balls;k++)
2346 if (ball[k].glue)
2348 ball[k].glue=false;
2349 ball[k].speedy = -ball[k].speedy;
2353 else if (paddle_type == PADDLE_TYPE_SHOOTER)
2355 if (used_fires < MAX_FIRES)
2357 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2358 fire[used_fires].x_pos = pad_pos_x + 1; /* Add 1 for edge */
2359 used_fires++;
2361 if (used_fires < MAX_FIRES)
2363 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2364 fire[used_fires].x_pos = pad_pos_x + pad_width - 1; /* Sub1 edge*/
2365 used_fires++;
2368 break;
2369 #ifdef RC_QUIT
2370 case RC_QUIT:
2371 #endif
2372 case QUIT:
2373 resume = true;
2374 return 0;
2375 break;
2377 default:
2378 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
2379 return 1;
2380 break;
2383 else
2385 #ifdef HAVE_LCD_COLOR
2386 rb->lcd_bitmap_transparent(brickmania_gameover,
2387 (LCD_WIDTH - INT3(GAMEOVER_WIDTH))/2,
2388 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2389 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT));
2390 #else /* greyscale and mono */
2391 rb->lcd_bitmap(brickmania_gameover,(LCD_WIDTH -
2392 INT3(GAMEOVER_WIDTH))/2,
2393 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2394 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT) );
2395 #endif
2396 rb->lcd_update();
2397 brickmania_sleep(2);
2398 return 0;
2401 /* Game always needs to yield for other threads */
2402 rb->yield();
2404 /* Sleep for a bit if there is time to spare */
2405 if (TIME_BEFORE(*rb->current_tick, end))
2406 rb->sleep(end-*rb->current_tick);
2408 return 0;
2411 /* this is the plugin entry point */
2412 enum plugin_status plugin_start(const void* parameter)
2414 (void)parameter;
2415 int last_difficulty;
2417 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
2418 configfile_load(CONFIG_FILE_NAME,config,1,0);
2419 last_difficulty = difficulty;
2421 #ifdef HAVE_TOUCHSCREEN
2422 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
2423 #endif
2425 rb->lcd_setfont(FONT_SYSFIXED);
2426 #if LCD_DEPTH > 1
2427 rb->lcd_set_backdrop(NULL);
2428 #endif
2429 /* Turn off backlight timeout */
2430 backlight_force_on(); /* backlight control in lib/helper.c */
2432 /* now go ahead and have fun! */
2433 rb->srand( *rb->current_tick );
2434 brickmania_loadgame();
2435 resume_file = resume;
2436 while(!brickmania_game_loop())
2438 if(!resume)
2440 int position = highscore_update(score, level+1, "",
2441 highscores, NUM_SCORES);
2442 if (position != -1)
2444 if (position == 0)
2445 rb->splash(HZ*2, "New High Score");
2446 highscore_show(position, highscores, NUM_SCORES, true);
2448 else
2450 brickmania_sleep(3);
2455 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2456 if(last_difficulty != difficulty)
2457 configfile_save(CONFIG_FILE_NAME,config,1,0);
2458 /* Restore user's original backlight setting */
2459 rb->lcd_setfont(FONT_UI);
2460 /* Turn on backlight timeout (revert to settings) */
2461 backlight_use_settings(); /* backlight control in lib/helper.c */
2463 return PLUGIN_OK;