1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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"
34 /* If there are three fractional bits, the smallest screen size that will scale
35 * properly is 28x22. If you have a smaller screen increase the fractional
36 * precision. If you have a precision of 4 the smallest screen size would be
37 * 14x11. Note though that this will decrease the maximum resolution due to
38 * the line intersection tests. These defines are used for all of the fixed
39 * point calculations/conversions.
41 #define FIXED3(x) ((x)<<3)
42 #define FIXED3_MUL(x, y) ((long long)((x)*(y))>>3)
43 #define FIXED3_DIV(x, y) (((x)<<3)/(y))
44 #define INT3(x) ((x)>>3)
46 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
47 (CONFIG_KEYPAD == IRIVER_H300_PAD)
48 #define CONTINUE_TEXT "Press NAVI To Continue"
49 #define QUIT BUTTON_OFF
50 #define LEFT BUTTON_LEFT
51 #define RIGHT BUTTON_RIGHT
52 #define SELECT BUTTON_SELECT
54 #define DOWN BUTTON_DOWN
55 #define RC_QUIT BUTTON_RC_STOP
57 #elif CONFIG_KEYPAD == ONDIO_PAD
58 #define CONTINUE_TEXT "MENU To Continue"
59 #define QUIT BUTTON_OFF
60 #define LEFT BUTTON_LEFT
61 #define RIGHT BUTTON_RIGHT
62 #define SELECT BUTTON_MENU
64 #define DOWN BUTTON_DOWN
66 #elif CONFIG_KEYPAD == RECORDER_PAD
67 #define QUIT BUTTON_OFF
68 #define LEFT BUTTON_LEFT
69 #define RIGHT BUTTON_RIGHT
70 #define SELECT BUTTON_PLAY
72 #define DOWN BUTTON_DOWN
74 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
75 #define QUIT BUTTON_OFF
76 #define LEFT BUTTON_LEFT
77 #define RIGHT BUTTON_RIGHT
78 #define SELECT BUTTON_SELECT
80 #define DOWN BUTTON_DOWN
82 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
83 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
84 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
85 #define QUIT BUTTON_MENU
86 #define LEFT BUTTON_LEFT
87 #define RIGHT BUTTON_RIGHT
88 #define SELECT BUTTON_SELECT
89 #define UP BUTTON_SCROLL_BACK
90 #define DOWN BUTTON_SCROLL_FWD
91 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
92 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
94 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
95 #define QUIT BUTTON_POWER
96 #define LEFT BUTTON_LEFT
97 #define RIGHT BUTTON_RIGHT
98 #define SELECT BUTTON_SELECT
100 #define DOWN BUTTON_DOWN
102 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
103 #define QUIT BUTTON_POWER
104 #define LEFT BUTTON_LEFT
105 #define RIGHT BUTTON_RIGHT
106 #define SELECT BUTTON_PLAY
108 #define DOWN BUTTON_DOWN
110 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
111 #define QUIT BUTTON_POWER
112 #define LEFT BUTTON_LEFT
113 #define RIGHT BUTTON_RIGHT
114 #define SELECT BUTTON_SELECT
116 #define DOWN BUTTON_DOWN
117 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
118 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
121 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
122 #define QUIT (BUTTON_HOME|BUTTON_REPEAT)
123 #define LEFT BUTTON_LEFT
124 #define RIGHT BUTTON_RIGHT
125 #define SELECT BUTTON_SELECT
127 #define DOWN BUTTON_DOWN
129 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
130 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
133 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
134 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
135 CONFIG_KEYPAD == SANSA_M200_PAD
136 #define QUIT BUTTON_POWER
137 #define LEFT BUTTON_LEFT
138 #define RIGHT BUTTON_RIGHT
139 #define ALTLEFT BUTTON_VOL_DOWN
140 #define ALTRIGHT BUTTON_VOL_UP
141 #define SELECT BUTTON_SELECT
143 #define DOWN BUTTON_DOWN
145 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
146 #define QUIT BUTTON_POWER
147 #define LEFT BUTTON_LEFT
148 #define RIGHT BUTTON_RIGHT
149 #define SELECT BUTTON_PLAY
150 #define UP BUTTON_SCROLL_UP
151 #define DOWN BUTTON_SCROLL_DOWN
153 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
154 #define QUIT BUTTON_BACK
155 #define LEFT BUTTON_LEFT
156 #define RIGHT BUTTON_RIGHT
157 #define SELECT BUTTON_SELECT
159 #define DOWN BUTTON_DOWN
161 #elif (CONFIG_KEYPAD == MROBE100_PAD)
162 #define QUIT BUTTON_POWER
163 #define LEFT BUTTON_LEFT
164 #define RIGHT BUTTON_RIGHT
165 #define SELECT BUTTON_SELECT
167 #define DOWN BUTTON_DOWN
169 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
170 #define CONTINUE_TEXT "PLAY To Continue"
171 #define QUIT BUTTON_RC_REC
172 #define LEFT BUTTON_RC_REW
173 #define RIGHT BUTTON_RC_FF
174 #define SELECT BUTTON_RC_PLAY
175 #define UP BUTTON_RC_VOL_UP
176 #define DOWN BUTTON_RC_VOL_DOWN
177 #define RC_QUIT BUTTON_REC
179 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
180 #define QUIT BUTTON_BACK
181 #define LEFT BUTTON_LEFT
182 #define RIGHT BUTTON_RIGHT
183 #define SELECT BUTTON_SELECT
185 #define DOWN BUTTON_DOWN
187 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
188 #define QUIT BUTTON_POWER
189 #define LEFT BUTTON_LEFT
190 #define RIGHT BUTTON_RIGHT
191 #define SELECT BUTTON_SELECT
193 #define DOWN BUTTON_DOWN
195 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
196 #define QUIT BUTTON_POWER
197 #define LEFT BUTTON_PREV
198 #define RIGHT BUTTON_NEXT
199 #define SELECT BUTTON_PLAY
201 #define DOWN BUTTON_DOWN
203 #elif CONFIG_KEYPAD == COWON_D2_PAD
204 #define QUIT BUTTON_POWER
205 #define LEFT BUTTON_MINUS
206 #define RIGHT BUTTON_PLUS
207 #define SELECT BUTTON_MENU
209 #elif CONFIG_KEYPAD == ONDAVX747_PAD
210 #define QUIT BUTTON_POWER
211 #define LEFT BUTTON_VOL_DOWN
212 #define RIGHT BUTTON_VOL_UP
213 #define SELECT BUTTON_MENU
214 #elif CONFIG_KEYPAD == ONDAVX777_PAD
215 #define QUIT BUTTON_POWER
217 #elif CONFIG_KEYPAD == MROBE500_PAD
218 #define QUIT BUTTON_POWER
220 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
221 #define QUIT BUTTON_FFWD
222 #define SELECT BUTTON_PLAY
223 #define LEFT BUTTON_LEFT
224 #define RIGHT BUTTON_RIGHT
226 #define DOWN BUTTON_DOWN
230 #error No keymap defined!
233 #ifdef HAVE_TOUCHSCREEN
235 #define ALTLEFT BUTTON_BOTTOMLEFT
237 #define LEFT BUTTON_BOTTOMLEFT
240 #define ALTRIGHT BUTTON_BOTTOMRIGHT
242 #define RIGHT BUTTON_BOTTOMRIGHT
245 #define ALTSELECT BUTTON_CENTER
247 #define SELECT BUTTON_CENTER
250 #define UP BUTTON_TOPMIDDLE
253 #define DOWN BUTTON_BOTTOMMIDDLE
257 /* Continue text is used as a string later when the game is paused. This allows
258 * targets to specify their own text if needed.
260 #if !defined(CONTINUE_TEXT)
261 #define CONTINUE_TEXT "Press SELECT To Continue"
264 #ifndef SCROLL_FWD /* targets without scroll wheel*/
265 #define SCROLL_FWD(x) (0)
266 #define SCROLL_BACK(x) (0)
269 #include "pluginbitmaps/brickmania_pads.h"
270 #include "pluginbitmaps/brickmania_short_pads.h"
271 #include "pluginbitmaps/brickmania_long_pads.h"
272 #include "pluginbitmaps/brickmania_bricks.h"
273 #include "pluginbitmaps/brickmania_powerups.h"
274 #include "pluginbitmaps/brickmania_ball.h"
275 #include "pluginbitmaps/brickmania_gameover.h"
277 #define GAMESCREEN_WIDTH FIXED3(LCD_WIDTH)
278 #define GAMESCREEN_HEIGHT FIXED3(LCD_HEIGHT)
280 #define PAD_WIDTH FIXED3(BMPWIDTH_brickmania_pads)
281 #define PAD_HEIGHT FIXED3(BMPHEIGHT_brickmania_pads/3)
282 #define SHORT_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_short_pads)
283 #define LONG_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_long_pads)
284 #define BRICK_HEIGHT FIXED3(BMPHEIGHT_brickmania_bricks/7)
285 #define BRICK_WIDTH FIXED3(BMPWIDTH_brickmania_bricks)
286 #define LEFTMARGIN ((GAMESCREEN_WIDTH-10*BRICK_WIDTH)/2)
287 #define NUMBER_OF_POWERUPS 9
288 #define POWERUP_HEIGHT FIXED3(BMPHEIGHT_brickmania_powerups/NUMBER_OF_POWERUPS)
289 #define POWERUP_WIDTH FIXED3(BMPWIDTH_brickmania_powerups)
290 #define BALL FIXED3(BMPHEIGHT_brickmania_ball)
291 #define HALFBALL (BALL / 2)
293 #define GAMEOVER_WIDTH FIXED3(BMPWIDTH_brickmania_gameover)
294 #define GAMEOVER_HEIGHT FIXED3(BMPHEIGHT_brickmania_gameover)
296 #ifdef HAVE_LCD_COLOR /* currently no transparency for non-colour */
297 #include "pluginbitmaps/brickmania_break.h"
300 /* The time (in ms) for one iteration through the game loop - decrease this
301 * to speed up the game - note that current_tick is (currently) only accurate
306 #define TOPMARGIN MAX(BRICK_HEIGHT, FIXED3(8))
308 #define STRINGPOS_FINISH (GAMESCREEN_HEIGHT - (GAMESCREEN_HEIGHT / 6))
309 #define STRINGPOS_CONGRATS (STRINGPOS_FINISH - 20)
310 #define STRINGPOS_NAVI (STRINGPOS_FINISH - 10)
311 #define STRINGPOS_FLIP (STRINGPOS_FINISH - 10)
313 /* Brickmania was originally designed for the H300, other targets should scale
314 * the speed up/down as needed based on the screen height.
316 #define SPEED_SCALE_H(y) FIXED3_DIV(GAMESCREEN_HEIGHT, FIXED3(176)/(y) )
317 #define SPEED_SCALE_W(x) FIXED3_DIV(GAMESCREEN_WIDTH, FIXED3(220)/(x) )
319 /* These are all used as ball speeds depending on where the ball hit the
322 * Note that all of these speeds (including pad, power, and fire)
323 * could be made variable and could be raised to be much higher to add
324 * additional difficulty to the game. The line intersection tests allow this
325 * to be drastically increased without the collision detection failing
328 #define SPEED_1Q_X SPEED_SCALE_W( 6)
329 #define SPEED_1Q_Y SPEED_SCALE_H(-2)
331 #define SPEED_2Q_X SPEED_SCALE_W( 4)
332 #define SPEED_2Q_Y SPEED_SCALE_H(-3)
334 #define SPEED_3Q_X SPEED_SCALE_W( 3)
335 #define SPEED_3Q_Y SPEED_SCALE_H(-4)
337 #define SPEED_4Q_X SPEED_SCALE_W( 2)
338 #define SPEED_4Q_Y SPEED_SCALE_H(-4)
340 /* This is used to determine the speed of the paddle */
341 #define SPEED_PAD SPEED_SCALE_W( 8)
343 /* This defines the speed that the powerups drop */
344 #define SPEED_POWER SPEED_SCALE_H( 2)
346 /* This defines the speed that the shot moves */
347 #define SPEED_FIRE SPEED_SCALE_H( 4)
348 #define FIRE_LENGTH SPEED_SCALE_H( 7)
350 /*calculate paddle y-position */
351 #define PAD_POS_Y (GAMESCREEN_HEIGHT - PAD_HEIGHT - 1)
353 /* change to however many levels there are, i.e. how many arrays there are total */
356 /* change the first number in [ ] to however many levels there are (levels_num) */
357 static unsigned char levels
[40][8][10] =
358 /* You can set up new levels with the level editor
359 ( http://plugbox.rockbox-lounge.com/brickmania.htm ).
360 With 0x1, it refers to the first brick in the bitmap, 0x2 would refer to the
361 second, ect., 0x0 leaves a empty space. If you add a 2 before the 2nd number,
362 it will take two hits to break, and 3 hits if you add a 3. That is 0x24, will
363 result with the fourth brick being displayed and having take 2 hits to break.
364 You could do the same with the 3, just replace the 2 with a 3 for it to take
365 three hits to break it apart. */
368 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
369 {0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2},
370 {0x0,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x0},
371 {0x0,0x0,0x2,0x1,0x0,0x0,0x1,0x2,0x0,0x0},
372 {0x0,0x0,0x0,0x2,0x1,0x1,0x2,0x0,0x0,0x0},
373 {0x7,0x0,0x0,0x7,0x2,0x2,0x7,0x0,0x0,0x7},
374 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
375 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
378 {0x0,0x0,0x7,0x7,0x1,0x1,0x7,0x7,0x0,0x0},
379 {0x0,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0},
380 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
381 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
382 {0x1,0x1,0x2,0x1,0x0,0x0,0x1,0x2,0x1,0x1},
383 {0x1,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x1},
384 {0x0,0x1,0x2,0x0,0x0,0x0,0x0,0x2,0x1,0x0},
385 {0x0,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x0}
388 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
389 {0x3,0x23,0x23,0x3,0x0,0x0,0x2,0x22,0x22,0x2},
390 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
391 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
392 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
393 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6},
394 {0x5,0x25,0x25,0x5,0x0,0x0,0x6,0x26,0x26,0x6},
395 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6}
398 {0x0,0x0,0x0,0x27,0x27,0x27,0x27,0x0,0x0,0x0},
399 {0x0,0x0,0x0,0x27,0x7,0x7,0x27,0x0,0x0,0x0},
400 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
401 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
402 {0x26,0x6,0x0,0x2,0x2,0x2,0x2,0x0,0x6,0x26},
403 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
404 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
405 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1}
408 {0x1,0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4},
409 {0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0},
410 {0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5},
411 {0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5,0x5},
412 {0x0,0x33,0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0},
413 {0x3,0x33,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x36},
414 {0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x6,0x36},
415 {0x0,0x24,0x24,0x0,0x25,0x25,0x0,0x26,0x26,0x0}
418 {0x0,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x0},
419 {0x3,0x1,0x3,0x7,0x0,0x0,0x7,0x3,0x1,0x3},
420 {0x3,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x3},
421 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x0},
422 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
423 {0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5},
424 {0x0,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x0},
425 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
428 {0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x0},
429 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
430 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
431 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
432 {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x6},
433 {0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0},
434 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
435 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
438 {0x0,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x0},
439 {0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0},
440 {0x6,0x6,0x0,0x2,0x32,0x32,0x2,0x0,0x6,0x6},
441 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
442 {0x0,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x0},
443 {0x0,0x0,0x0,0x5,0x25,0x25,0x5,0x0,0x0,0x0},
444 {0x0,0x5,0x5,0x25,0x5,0x5,0x25,0x5,0x5,0x0},
445 {0x5,0x5,0x25,0x5,0x5,0x5,0x5,0x25,0x5,0x5}
448 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
449 {0x2,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x2},
450 {0x2,0x0,0x3,0x0,0x1,0x1,0x0,0x3,0x0,0x2},
451 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
452 {0x2,0x0,0x1,0x0,0x3,0x3,0x0,0x1,0x0,0x2},
453 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
454 {0x2,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x2,0x2},
455 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
458 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
459 {0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5},
460 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
461 {0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0},
462 {0x0,0x0,0x0,0x4,0x1,0x1,0x4,0x0,0x0,0x0},
463 {0x0,0x0,0x3,0x4,0x1,0x1,0x4,0x3,0x0,0x0},
464 {0x0,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x0},
465 {0x1,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x1}
468 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
469 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2},
470 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
471 {0x2,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x2},
472 {0x2,0x0,0x0,0x7,0x7,0x7,0x7,0x0,0x0,0x2},
473 {0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x0},
474 {0x0,0x2,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x0},
475 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5}
478 {0x2,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x2},
479 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
480 {0x1,0x1,0x1,0x0,0x1,0x1,0x0,0x1,0x1,0x1},
481 {0x0,0x1,0x0,0x1,0x6,0x6,0x1,0x0,0x1,0x0},
482 {0x0,0x0,0x1,0x1,0x6,0x6,0x1,0x1,0x0,0x0},
483 {0x1,0x1,0x1,0x7,0x0,0x0,0x7,0x1,0x1,0x1},
484 {0x1,0x1,0x7,0x1,0x0,0x0,0x1,0x7,0x1,0x1},
485 {0x2,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x2}
488 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
489 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
490 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x2},
491 {0x2,0x0,0x2,0x3,0x3,0x3,0x3,0x3,0x0,0x2},
492 {0x2,0x0,0x2,0x4,0x4,0x4,0x4,0x4,0x0,0x2},
493 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
494 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
495 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
498 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
499 {0x4,0x4,0x4,0x4,0x2,0x2,0x4,0x4,0x4,0x4},
500 {0x4,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x4},
501 {0x4,0x0,0x0,0x2,0x3,0x3,0x2,0x0,0x0,0x4},
502 {0x4,0x0,0x2,0x23,0x3,0x3,0x23,0x2,0x0,0x4},
503 {0x4,0x0,0x2,0x22,0x2,0x2,0x22,0x2,0x0,0x4},
504 {0x4,0x0,0x6,0x21,0x5,0x5,0x21,0x6,0x0,0x4},
505 {0x4,0x6,0x1,0x1,0x5,0x5,0x1,0x1,0x6,0x4}
508 {0x4,0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,0x3},
509 {0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x5,0x0,0x0},
510 {0x2,0x2,0x1,0x1,0x1,0x0,0x1,0x6,0x0,0x0},
511 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x5,0x0,0x0},
512 {0x2,0x1,0x2,0x2,0x2,0x1,0x1,0x6,0x0,0x0},
513 {0x2,0x1,0x2,0x2,0x2,0x1,0x3,0x5,0x3,0x0},
514 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x6,0x0,0x0},
515 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
517 {/* level 16 (Rockbox) by ts-x */
518 {0x2,0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
519 {0x2,0x0,0x3,0x0,0x3,0x4,0x0,0x5,0x5,0x0},
520 {0x2,0x0,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
521 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
522 {0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
523 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0},
524 {0x7,0x0,0x7,0x1,0x0,0x1,0x0,0x2,0x0,0x0},
525 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0}
527 {/* level 17 (Alien) by ts-x */
528 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
529 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
530 {0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1},
531 {0x2,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x2},
532 {0x1,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x1},
533 {0x2,0x0,0x0,0x1,0x2,0x2,0x1,0x0,0x0,0x2},
534 {0x2,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x2},
535 {0x2,0x2,0x1,0x0,0x1,0x1,0x0,0x1,0x2,0x2}
537 {/* level 18 (Tetris) by ts-x */
538 {0x0,0x2,0x0,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
539 {0x0,0x2,0x7,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
540 {0x2,0x2,0x7,0x0,0x3,0x4,0x0,0x6,0x2,0x2},
541 {0x2,0x2,0x7,0x7,0x3,0x4,0x0,0x6,0x2,0x2},
542 {0x2,0x1,0x7,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
543 {0x2,0x1,0x0,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
544 {0x1,0x1,0x1,0x7,0x3,0x0,0x6,0x6,0x5,0x5},
545 {0x1,0x1,0x1,0x0,0x3,0x0,0x6,0x6,0x5,0x5}
547 { /* level 19 (Stalactites) by ts-x */
548 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
549 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
550 {0x5,0x0,0x6,0x3,0x4,0x7,0x5,0x0,0x1,0x2},
551 {0x5,0x2,0x6,0x3,0x4,0x0,0x5,0x3,0x1,0x2},
552 {0x5,0x0,0x6,0x0,0x4,0x7,0x5,0x0,0x1,0x0},
553 {0x5,0x0,0x0,0x3,0x4,0x0,0x0,0x0,0x1,0x2},
554 {0x0,0x0,0x6,0x0,0x0,0x0,0x5,0x0,0x0,0x0},
555 {0x5,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0}
557 { /* level 20 (Maze) by ts-x */
558 {0x1,0x1,0x21,0x1,0x1,0x1,0x1,0x1,0x1,0x21},
559 {0x1,0x0,0x0,0x3,0x0,0x0,0x3,0x1,0x31,0x1},
560 {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x1},
561 {0x21,0x0,0x21,0x3,0x0,0x3,0x0,0x3,0x0,0x2},
562 {0x1,0x0,0x1,0x21,0x0,0x12,0x0,0x0,0x0,0x0},
563 {0x31,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x3,0x0},
564 {0x1,0x0,0x1,0x0,0x1,0x1,0x31,0x1,0x1,0x2},
565 {0x22,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x21}
567 { /* level 21 (Dentist) by ts-x */
568 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
569 {0x2,0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x2,0x2},
570 {0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x2},
571 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x2},
572 {0x2,0x0,0x6,0x0,0x6,0x0,0x0,0x0,0x0,0x2},
573 {0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x2},
574 {0x2,0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x2,0x2},
575 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0}
577 { /* level 22 (Spider) by ts-x */
578 {0x31,0x3,0x1,0x1,0x0,0x0,0x1,0x1,0x3,0x31},
579 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
580 {0x33,0x1,0x1,0x36,0x1,0x1,0x36,0x1,0x1,0x33},
581 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
582 {0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0},
583 {0x21,0x3,0x1,0x21,0x2,0x2,0x21,0x1,0x3,0x21},
584 {0x0,0x0,0x0,0x1,0x21,0x1,0x1,0x0,0x0,0x0},
585 {0x3,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x3}
587 { /* level 23 (Pool) by ts-x */
588 {0x0,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x7,0x0},
589 {0x0,0x0,0x5,0x0,0x2,0x0,0x0,0x0,0x2,0x0},
590 {0x7,0x3,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x7},
591 {0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0x7},
592 {0x7,0x0,0x4,0x0,0x0,0x3,0x0,0x0,0x0,0x7},
593 {0x7,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x4,0x7},
594 {0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
595 {0x0,0x7,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x0}
597 { /* level 24 (Vorbis Fish) by ts-x */
598 {0x0,0x0,0x4,0x4,0x5,0x5,0x5,0x0,0x0,0x5},
599 {0x0,0x4,0x6,0x4,0x4,0x5,0x5,0x5,0x0,0x5},
600 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x5,0x5,0x5},
601 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x4,0x5,0x5},
602 {0x0,0x5,0x6,0x4,0x4,0x5,0x5,0x4,0x5,0x0},
603 {0x5,0x5,0x4,0x4,0x5,0x5,0x5,0x4,0x5,0x5},
604 {0x5,0x4,0x4,0x4,0x5,0x5,0x4,0x4,0x5,0x5},
605 {0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x5,0x0,0x5}
607 {/* level 25 (Rainbow) by ts-x */
608 {0x0,0x4,0x1,0x0,0x0,0x0,0x0,0x1,0x4,0x0},
609 {0x24,0x1,0x3,0x1,0x0,0x0,0x21,0x3,0x1,0x24},
610 {0x1,0x23,0x5,0x3,0x1,0x21,0x3,0x5,0x3,0x21},
611 {0x3,0x5,0x6,0x5,0x3,0x3,0x5,0x6,0x5,0x3},
612 {0x5,0x6,0x7,0x6,0x5,0x5,0x6,0x7,0x6,0x5},
613 {0x6,0x7,0x2,0x27,0x6,0x6,0x27,0x2,0x7,0x6},
614 {0x7,0x2,0x0,0x2,0x27,0x27,0x2,0x0,0x2,0x7},
615 {0x32,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x32}
617 { /* level 26 (Bowtie) by ts-x */
618 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5},
619 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
620 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
621 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
622 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
623 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
624 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
625 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5}
627 { /* level 27 (Frog) by ts-x */
628 {0x0,0x5,0x25,0x0,0x0,0x0,0x0,0x25,0x5,0x0},
629 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
630 {0x25,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x25},
631 {0x5,0x0,0x3,0x0,0x6,0x6,0x0,0x3,0x0,0x5},
632 {0x5,0x0,0x31,0x0,0x6,0x6,0x0,0x31,0x0,0x5},
633 {0x5,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x5},
634 {0x5,0x5,0x5,0x35,0x0,0x0,0x35,0x5,0x5,0x5},
635 {0x0,0x25,0x5,0x0,0x4,0x4,0x0,0x5,0x25,0x0}
637 { /* level 28 (DigDug) by ts-x */
638 {0x35,0x5,0x5,0x25,0x0,0x25,0x25,0x5,0x5,0x35},
639 {0x6,0x0,0x0,0x6,0x0,0x6,0x6,0x0,0x0,0x6},
640 {0x7,0x0,0x37,0x37,0x0,0x37,0x37,0x7,0x0,0x7},
641 {0x7,0x0,0x7,0x0,0x0,0x0,0x7,0x7,0x7,0x7},
642 {0x4,0x4,0x4,0x24,0x0,0x24,0x4,0x0,0x0,0x4},
643 {0x4,0x4,0x0,0x0,0x0,0x4,0x4,0x0,0x4,0x4},
644 {0x24,0x24,0x4,0x4,0x4,0x4,0x0,0x0,0x24,0x4},
645 {0x1,0x1,0x1,0x1,0x1,0x1,0x21,0x21,0x1,0x1}
647 { /* level 29 UK Flag by Seth Opgenorth */
648 {0x32,0x0,0x3,0x3,0x2,0x2,0x3,0x3,0x0,0x32},
649 {0x0,0x2,0x0,0x3,0x32,0x22,0x33,0x0,0x32,0x0},
650 {0x33,0x0,0x22,0x0,0x2,0x2,0x0,0x2,0x0,0x33},
651 {0x22,0x32,0x2,0x2,0x2,0x2,0x2,0x2,0x22,0x2},
652 {0x3,0x0,0x0,0x32,0x22,0x2,0x2,0x0,0x0,0x3},
653 {0x23,0x0,0x32,0x0,0x32,0x2,0x0,0x2,0x0,0x3},
654 {0x0,0x2,0x0,0x3,0x2,0x2,0x3,0x0,0x22,0x0},
655 {0x32,0x0,0x3,0x23,0x2,0x2,0x23,0x33,0x0,0x32}
657 { /* level 30 Win-Logo by Seth Opgenorth */
658 {0x0,0x0,0x0,0x22,0x0,0x0,0x0,0x0,0x0,0x0},
659 {0x0,0x0,0x32,0x2,0x2,0x25,0x0,0x5,0x0,0x0},
660 {0x0,0x0,0x2,0x22,0x2,0x5,0x5,0x35,0x0,0x0},
661 {0x0,0x0,0x2,0x1,0x2,0x5,0x5,0x25,0x0,0x0},
662 {0x0,0x0,0x21,0x1,0x1,0x36,0x7,0x26,0x0,0x0},
663 {0x0,0x0,0x1,0x1,0x1,0x6,0x6,0x6,0x0,0x0},
664 {0x0,0x0,0x21,0x0,0x21,0x6,0x6,0x26,0x0,0x0},
665 {0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0}
667 { /* level 31 Color wave/V by Seth Opgenorth */
668 {0x25,0x34,0x2,0x31,0x33,0x23,0x1,0x2,0x34,0x5},
669 {0x3,0x5,0x24,0x2,0x1,0x1,0x2,0x4,0x5,0x3},
670 {0x1,0x3,0x5,0x4,0x2,0x2,0x4,0x5,0x3,0x1},
671 {0x2,0x1,0x33,0x35,0x4,0x4,0x5,0x33,0x1,0x22},
672 {0x31,0x22,0x1,0x3,0x5,0x25,0x3,0x1,0x2,0x31},
673 {0x3,0x1,0x2,0x1,0x3,0x3,0x1,0x2,0x21,0x3},
674 {0x5,0x23,0x1,0x32,0x1,0x1,0x2,0x1,0x3,0x5},
675 {0x4,0x35,0x3,0x1,0x2,0x22,0x31,0x3,0x5,0x4}
677 { /* level 32 Sweedish Flag by Seth Opgenorth */
678 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
679 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
680 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
681 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
682 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
683 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
684 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
685 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3}
687 { /* level 33 Color Pyramid by Seth Opgenorth */
688 {0x0,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x0},
689 {0x0,0x0,0x0,0x4,0x24,0x4,0x24,0x0,0x0,0x0},
690 {0x0,0x0,0x23,0x3,0x3,0x3,0x23,0x3,0x0,0x0},
691 {0x0,0x0,0x25,0x5,0x25,0x35,0x5,0x35,0x0,0x0},
692 {0x0,0x36,0x6,0x6,0x6,0x6,0x26,0x6,0x6,0x0},
693 {0x0,0x7,0x7,0x7,0x7,0x25,0x27,0x7,0x27,0x0},
694 {0x2,0x2,0x22,0x2,0x2,0x2,0x22,0x2,0x2,0x2},
695 {0x21,0x1,0x1,0x31,0x1,0x21,0x1,0x1,0x31,0x1}
697 { /* level 34 Rhombus by Seth Opgenorth */
698 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0},
699 {0x0,0x0,0x0,0x3,0x32,0x22,0x23,0x0,0x0,0x0},
700 {0x0,0x0,0x3,0x2,0x24,0x4,0x2,0x23,0x0,0x0},
701 {0x26,0x3,0x2,0x4,0x5,0x5,0x4,0x22,0x3,0x6},
702 {0x36,0x3,0x2,0x34,0x5,0x5,0x4,0x2,0x3,0x36},
703 {0x0,0x0,0x3,0x2,0x4,0x34,0x2,0x23,0x0,0x0},
704 {0x0,0x0,0x0,0x23,0x2,0x2,0x3,0x0,0x0,0x0},
705 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0}
707 { /* level 35 PacMan Ghost by Seth Opgenorth */
708 {0x0,0x0,0x0,0x0,0x2,0x32,0x2,0x0,0x0,0x0},
709 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
710 {0x0,0x0,0x2,0x24,0x4,0x2,0x4,0x4,0x32,0x0},
711 {0x0,0x0,0x2,0x24,0x0,0x22,0x24,0x0,0x22,0x0},
712 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
713 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
714 {0x0,0x0,0x2,0x32,0x2,0x2,0x22,0x2,0x32,0x0},
715 {0x0,0x0,0x0,0x22,0x0,0x32,0x0,0x22,0x0,0x0}
717 { /* level 36 Star by Seth Opgenorth */
718 {0x3,0x4,0x3,0x4,0x6,0x24,0x3,0x24,0x3,0x0},
719 {0x24,0x0,0x0,0x6,0x6,0x6,0x0,0x0,0x4,0x0},
720 {0x3,0x26,0x6,0x2,0x6,0x2,0x6,0x26,0x23,0x0},
721 {0x4,0x0,0x6,0x6,0x36,0x6,0x6,0x0,0x4,0x0},
722 {0x3,0x0,0x0,0x26,0x6,0x26,0x0,0x0,0x33,0x0},
723 {0x34,0x0,0x6,0x6,0x0,0x6,0x6,0x0,0x4,0x0},
724 {0x3,0x26,0x6,0x0,0x0,0x0,0x6,0x6,0x3,0x0},
725 {0x4,0x3,0x4,0x23,0x24,0x3,0x4,0x33,0x4,0x0}
727 { /* level 37 It's 8-Bit by Seth Opgenorth */
728 {0x26,0x26,0x6,0x6,0x5,0x6,0x26,0x6,0x26,0x6},
729 {0x2,0x2,0x22,0x3,0x3,0x0,0x0,0x0,0x4,0x0},
730 {0x2,0x0,0x2,0x33,0x3,0x3,0x5,0x0,0x24,0x0},
731 {0x32,0x2,0x2,0x33,0x0,0x23,0x0,0x4,0x4,0x4},
732 {0x2,0x22,0x2,0x3,0x3,0x0,0x5,0x4,0x4,0x24},
733 {0x2,0x0,0x2,0x23,0x0,0x3,0x25,0x0,0x4,0x0},
734 {0x22,0x2,0x2,0x3,0x23,0x0,0x5,0x0,0x4,0x0},
735 {0x6,0x26,0x6,0x36,0x6,0x36,0x6,0x6,0x6,0x6}
737 { /* level 38 Linux by Seth Opgenorth */
738 {0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
739 {0x7,0x0,0x0,0x0,0x33,0x0,0x23,0x0,0x0,0x0},
740 {0x7,0x32,0x0,0x0,0x3,0x0,0x23,0x6,0x0,0x6},
741 {0x37,0x0,0x0,0x0,0x23,0x0,0x3,0x6,0x0,0x26},
742 {0x7,0x22,0x24,0x0,0x3,0x33,0x3,0x0,0x26,0x0},
743 {0x37,0x22,0x24,0x24,0x4,0x0,0x0,0x0,0x26,0x0},
744 {0x7,0x2,0x4,0x0,0x4,0x0,0x0,0x6,0x0,0x26},
745 {0x7,0x27,0x4,0x0,0x34,0x0,0x0,0x6,0x0,0x26}
747 { /* level 39 Colorful Squares by Seth Opgenorth*/
748 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0},
749 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
750 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
751 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
752 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
753 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
754 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
755 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0}
758 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
759 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
760 {0x32,0x0,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
761 {0x32,0x32,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
762 {0x32,0x32,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
763 {0x32,0x0,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
764 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
765 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
771 enum difficulty_options
{
777 enum { ST_READY
, ST_START
, ST_PAUSE
} game_state
= ST_READY
;
785 int score
=0,vscore
=0;
786 bool flip_sides
=false;
788 int brick_on_board
=0;
790 int difficulty
= NORMAL
;
794 bool resume_file
= false;
798 int powertop
; /* Stores the powerup Y top pos, it is a fixed point num */
799 int power
; /* What powerup is in the brick? */
800 bool poweruse
; /* Stores whether a powerup is falling or not */
801 bool used
; /* Is the brick still in play? */
803 int hits
; /* How many hits can this brick take? */
810 /* pos_x and y store the current center position of the ball */
813 /* tempx and tempy store an absolute position the ball should be in. If
814 * they are equal to 0, they are not used when positioning the ball.
818 /* speedx and speedy store the current speed of the ball */
821 bool glue
; /* Is the ball stuck to the paddle? */
824 balls ball
[MAX_BALLS
];
826 typedef struct sfire
{
827 int top
; /* This stores the fire y position, it is a fixed point num */
828 int x_pos
; /* This stores the fire x position, it is a whole number */
832 #define CONFIG_FILE_NAME "brickmania.cfg"
833 #define SAVE_FILE PLUGIN_GAMES_DIR "/brickmania.save"
834 #define HIGH_SCORE PLUGIN_GAMES_DIR "/brickmania.score"
837 static struct configdata config
[] = {
838 {TYPE_INT
, 0, 1, { .int_p
= &difficulty
}, "difficulty", NULL
},
841 struct highscore highest
[NUM_SCORES
];
857 * This is based off an explanation and expanded math presented by Paul Bourke:
858 * http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
860 * It takes two lines as inputs and returns 1 if they intersect, 0 if they do
861 * not. hitp returns the point where the two lines intersected.
863 * This function expects fixed point inputs with a precision of 3. When a
864 * collision occurs hitp is updated with a fixed point location (precision 3)
865 * where the collision happened. The internal calculations are fixed
866 * point with a 7 bit fractional precision.
868 * If you choose 10 bits of precision a screen size of about 640x480 is the
869 * largest this can go. 7 bits allows for an accurate intersection calculation
870 * with a line length of about 64 and a rougher line lenght of 128 which is
871 * larger than any target currently needs (the pad is the longest line and it
872 * only needs an accuracy of 2^4 at most to figure out which section of the pad
873 * the ball hit). A precision of 7 gives breathing room for larger screens.
874 * Longer line sizes that need accurate intersection points will need more
875 * precision, but will decrease the maximum screen resolution.
879 int check_lines(line
*line1
, line
*line2
, point
*hitp
)
882 * This code is based on the solution of these two input equations:
883 * Pa = P1 + ua (P2-P1)
884 * Pb = P3 + ub (P4-P3)
886 * Where line one is composed of points P1 and P2 and line two is composed
887 * of points P3 and P4.
889 * ua/b is the fractional value you can multiply the x and y legs of the
890 * triangle formed by each line to find a point on the line.
892 * The two equations can be expanded to their x/y components:
893 * Pa.x = p1.x + ua(p2.x - p1.x)
894 * Pa.y = p1.y + ua(p2.y - p1.y)
896 * Pb.x = p3.x + ub(p4.x - p3.x)
897 * Pb.y = p3.y + ub(p4.y - p3.y)
899 * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
900 * up with two equations (one for x and one for y):
902 * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
903 * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
905 * ua and ub can then be individually solved for. This results in the
906 * equations used in the following code.
909 /* Denominator for ua and ub are the same so store this calculation */
910 int d
= FIXED3_MUL((line2
->p2
.y
- line2
->p1
.y
),(line1
->p2
.x
-line1
->p1
.x
))
911 -FIXED3_MUL((line2
->p2
.x
- line2
->p1
.x
),(line1
->p2
.y
-line1
->p1
.y
));
913 /* n_a and n_b are calculated as seperate values for readability */
914 int n_a
= FIXED3_MUL((line2
->p2
.x
- line2
->p1
.x
),(line1
->p1
.y
-line2
->p1
.y
))
915 -FIXED3_MUL((line2
->p2
.y
- line2
->p1
.y
),(line1
->p1
.x
-line2
->p1
.x
));
917 int n_b
= FIXED3_MUL((line1
->p2
.x
- line1
->p1
.x
),(line1
->p1
.y
-line2
->p1
.y
))
918 -FIXED3_MUL((line1
->p2
.y
- line1
->p1
.y
),(line1
->p1
.x
-line2
->p1
.x
));
920 /* Make sure there is not a division by zero - this also indicates that
921 * the lines are parallel.
923 * If n_a and n_b were both equal to zero the lines would be on top of each
924 * other (coincidental). This check is not done because it is not
925 * necessary for this implementation (the parallel check accounts for this).
930 /* Calculate the intermediate fractional point that the lines potentially
933 int ua
= (n_a
<< LINE_PREC
)/d
;
934 int ub
= (n_b
<< LINE_PREC
)/d
;
936 /* The fractional point will be between 0 and 1 inclusive if the lines
937 * intersect. If the fractional calculation is larger than 1 or smaller
938 * than 0 the lines would need to be longer to intersect.
940 if(ua
>=0 && ua
<= (1<<LINE_PREC
) && ub
>= 0 && ub
<= (1<<LINE_PREC
))
942 hitp
->x
= line1
->p1
.x
+ ((ua
* (line1
->p2
.x
- line1
->p1
.x
))>>LINE_PREC
);
943 hitp
->y
= line1
->p1
.y
+ ((ua
* (line1
->p2
.y
- line1
->p1
.y
))>>LINE_PREC
);
949 static void brickmania_init_game(bool new_game
)
953 pad_pos_x
= GAMESCREEN_WIDTH
/2 - PAD_WIDTH
/2;
955 for(i
=0;i
<MAX_BALLS
;i
++)
961 ball
[i
].pos_y
= PAD_POS_Y
- HALFBALL
;
962 ball
[i
].pos_x
= GAMESCREEN_WIDTH
/2;
963 ball
[i
].glue
= false;
967 game_state
= ST_READY
;
969 pad_width
= PAD_WIDTH
;
975 /* add one life per achieved level */
976 if (difficulty
==EASY
&& life
<2) {
983 /* No fire should be active */
990 brick
[bnum
].poweruse
= false;
992 brick
[bnum
].power
=rb
->rand()%25;
993 /* +8 make the game with less powerups */
995 brick
[bnum
].hits
=levels
[level
][i
][j
]>=10?
996 levels
[level
][i
][j
]/16-1:0;
997 brick
[bnum
].hiteffect
=0;
998 brick
[bnum
].powertop
= TOPMARGIN
+ i
*BRICK_HEIGHT
;
999 brick
[bnum
].used
=!(levels
[level
][i
][j
]==0);
1000 brick
[bnum
].color
=(levels
[level
][i
][j
]>=10?
1001 levels
[level
][i
][j
]%16:
1002 levels
[level
][i
][j
])-1;
1003 if (levels
[level
][i
][j
]!=0)
1010 static void brickmania_loadgame(void)
1016 /* open game file */
1017 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
1020 /* read in saved game */
1022 if(rb
->read(fd
, &pad_pos_x
, sizeof(pad_pos_x
)) <= 0) break;
1023 if(rb
->read(fd
, &life
, sizeof(life
)) <= 0) break;
1024 if(rb
->read(fd
, &game_state
, sizeof(game_state
)) <= 0) break;
1025 if(rb
->read(fd
, &pad_type
, sizeof(pad_type
)) <= 0) break;
1026 if(rb
->read(fd
, &score
, sizeof(score
)) <= 0) break;
1027 if(rb
->read(fd
, &flip_sides
, sizeof(flip_sides
)) <= 0) break;
1028 if(rb
->read(fd
, &level
, sizeof(level
)) <= 0) break;
1029 if(rb
->read(fd
, &brick_on_board
, sizeof(brick_on_board
)) <= 0) break;
1030 if(rb
->read(fd
, &used_balls
, sizeof(used_balls
)) <= 0) break;
1031 if(rb
->read(fd
, &pad_width
, sizeof(pad_width
)) <= 0) break;
1032 if(rb
->read(fd
, &num_count
, sizeof(num_count
)) <= 0) break;
1033 if(rb
->read(fd
, &brick
, sizeof(brick
)) <= 0) break;
1034 if(rb
->read(fd
, &ball
, sizeof(ball
)) <= 0) break;
1035 if(rb
->read(fd
, &fire
, sizeof(fire
)) <= 0) break;
1046 static void brickmania_savegame(void)
1050 /* write out the game state to the save file */
1051 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
1054 rb
->write(fd
, &pad_pos_x
, sizeof(pad_pos_x
));
1055 rb
->write(fd
, &life
, sizeof(life
));
1056 rb
->write(fd
, &game_state
, sizeof(game_state
));
1057 rb
->write(fd
, &pad_type
, sizeof(pad_type
));
1058 rb
->write(fd
, &score
, sizeof(score
));
1059 rb
->write(fd
, &flip_sides
, sizeof(flip_sides
));
1060 rb
->write(fd
, &level
, sizeof(level
));
1061 rb
->write(fd
, &brick_on_board
, sizeof(brick_on_board
));
1062 rb
->write(fd
, &used_balls
, sizeof(used_balls
));
1063 rb
->write(fd
, &pad_width
, sizeof(pad_width
));
1064 rb
->write(fd
, &num_count
, sizeof(num_count
));
1065 rb
->write(fd
, &brick
, sizeof(brick
));
1066 rb
->write(fd
, &ball
, sizeof(ball
));
1067 rb
->write(fd
, &fire
, sizeof(fire
));
1071 /* brickmania_sleep timer counting the score */
1072 static void brickmania_sleep(int secs
)
1082 count
= *rb
->current_tick
+ HZ
*secs
;
1083 if ( (TIME_AFTER(*rb
->current_tick
, count
)) && (vscore
== score
) )
1092 rb
->snprintf(s
, sizeof(s
), "%d", vscore
);
1093 rb
->lcd_getstringsize(s
, &sw
, &w
);
1094 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, 0, s
);
1095 rb
->lcd_update_rect(0,0,LCD_WIDTH
,w
+2);
1101 static int brickmania_help(void)
1103 #define WORDS (sizeof help_text / sizeof (char*))
1104 static char *help_text
[] = {
1105 "Brickmania", "", "Aim", "",
1106 "Destroy", "all", "the", "bricks", "by", "bouncing",
1107 "the", "ball", "of", "them", "using", "the", "paddle.", "", "",
1109 #if CONFIG_KEYPAD == COWON_D2_PAD
1114 "Moves", "the", "paddle", "",
1115 #if CONFIG_KEYPAD == ONDIO_PAD
1117 #elif (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
1119 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
1121 #elif CONFIG_KEYPAD == COWON_D2_PAD
1126 "Releases", "the", "ball/Fire!", "",
1127 #if CONFIG_KEYPAD == IAUDIO_M3_PAD
1129 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
1130 (CONFIG_KEYPAD == CREATIVEZVM_PAD)
1132 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1133 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1134 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1135 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1137 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
1138 (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
1139 (CONFIG_KEYPAD == ONDIO_PAD) || \
1140 (CONFIG_KEYPAD == RECORDER_PAD) || \
1141 (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
1146 "Returns", "to", "menu", "", "",
1148 "N", "Normal:", "returns", "paddle", "to", "normal", "",
1149 "D", "DIE!:", "loses", "a", "life", "",
1150 "L", "Life:", "gains", "a", "life/power", "up", "",
1151 "F", "Fire:", "allows", "you", "to", "shoot", "bricks", "",
1152 "G", "Glue:", "ball", "sticks", "to", "paddle", "",
1153 "B", "Ball:", "generates", "another", "ball", "",
1154 "FL", "Flip:", "flips", "left / right", "movement", "",
1155 "<->", "or", "<E>:", "enlarges", "the", "paddle", "",
1156 ">-<", "or", ">S<:", "shrinks", "the", "paddle", "",
1158 static struct style_text formation
[]={
1159 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1174 rb
->lcd_setfont(FONT_UI
);
1175 #ifdef HAVE_LCD_COLOR
1176 rb
->lcd_set_background(LCD_BLACK
);
1177 rb
->lcd_set_foreground(LCD_WHITE
);
1180 if (display_text(WORDS
, help_text
, formation
, NULL
))
1183 button
= rb
->button_get(true);
1184 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
) {
1187 } while( ( button
== BUTTON_NONE
)
1188 || ( button
& (BUTTON_REL
|BUTTON_REPEAT
) ) );
1189 rb
->lcd_setfont(FONT_SYSFIXED
);
1193 static int brickmania_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1195 int i
= ((intptr_t)this_item
);
1196 if(action
== ACTION_REQUEST_MENUITEM
1197 && !resume
&& (i
==0 || i
==6))
1198 return ACTION_EXIT_MENUITEM
;
1202 static int brickmania_menu(void)
1206 static struct opt_items options
[] = {
1211 #ifdef HAVE_TOUCHSCREEN
1212 /* Entering Menu, set the touchscreen to the global setting */
1213 rb
->touchscreen_set_mode(rb
->global_settings
->touch_mode
);
1216 MENUITEM_STRINGLIST(main_menu
, "Brickmania Menu", brickmania_menu_cb
,
1217 "Resume Game", "Start New Game",
1218 "Difficulty", "Help", "High Scores",
1220 "Quit without Saving", "Quit");
1222 rb
->button_clear_queue();
1224 switch (rb
->do_menu(&main_menu
, &selected
, NULL
, false)) {
1226 if(game_state
!=ST_READY
)
1227 game_state
= ST_PAUSE
;
1229 rb
->remove(SAVE_FILE
);
1236 brickmania_init_game(true);
1239 rb
->set_option("Difficulty", &difficulty
, INT
,
1243 if (brickmania_help())
1247 highscore_show(NUM_SCORES
, highest
, NUM_SCORES
, true);
1250 if (playback_control(NULL
))
1257 rb
->splash(HZ
*1, "Saving game ...");
1258 brickmania_savegame();
1261 case MENU_ATTACHED_USB
:
1267 #ifdef HAVE_TOUCHSCREEN
1268 rb
->touchscreen_set_mode(TOUCHSCREEN_POINT
);
1272 /* Find an unused fire position */
1273 static int brickmania_find_empty_fire(void)
1277 if (fire
[t
].top
< 0)
1283 void brick_hit(int brick_number
)
1285 if(!brick
[brick_number
].used
)
1288 /* if this is a crackable brick hits starts as
1291 if (brick
[brick_number
].hits
> 0) {
1292 brick
[brick_number
].hits
--;
1293 brick
[brick_number
].hiteffect
++;
1297 brick
[brick_number
].used
=false;
1298 /* Was there a powerup on the brick? */
1299 if (brick
[brick_number
].power
<NUMBER_OF_POWERUPS
) {
1300 /* Activate the powerup */
1301 brick
[brick_number
].poweruse
= true;
1308 static int brickmania_game_loop(void)
1316 /* pad_line used for powerup/ball checks */
1318 /* This is used for various lines that are checked (ball and powerup) */
1321 /* This stores the point that the two lines intersected in a test */
1324 if (brickmania_menu()) {
1328 resume_file
= false;
1330 #ifdef HAVE_LCD_COLOR
1331 rb
->lcd_set_background(LCD_BLACK
);
1332 rb
->lcd_set_foreground(LCD_WHITE
);
1333 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1334 rb
->lcd_clear_display();
1338 /* Convert CYCLETIME (in ms) to HZ */
1339 end
= *rb
->current_tick
+ (CYCLETIME
* HZ
) / 1000;
1342 rb
->lcd_clear_display();
1346 if (TIME_AFTER(*rb
->current_tick
, sec_count
))
1348 sec_count
=*rb
->current_tick
+HZ
;
1354 rb
->snprintf(s
, sizeof(s
), "%d", num_count
);
1355 rb
->lcd_getstringsize(s
, &sw
, NULL
);
1356 rb
->lcd_putsxy(LCD_WIDTH
/2-2, INT3(STRINGPOS_FLIP
), s
);
1359 /* write life num */
1360 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1361 rb
->snprintf(s
, sizeof(s
), "L:%d", life
);
1363 rb
->snprintf(s
, sizeof(s
), "Life: %d", life
);
1365 rb
->lcd_putsxy(0, 0, s
);
1367 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1368 rb
->snprintf(s
, sizeof(s
), "L%d", level
+1);
1370 rb
->snprintf(s
, sizeof(s
), "Level %d", level
+1);
1373 rb
->lcd_getstringsize(s
, &sw
, NULL
);
1374 rb
->lcd_putsxy(LCD_WIDTH
-sw
, 0, s
);
1376 if (vscore
<score
) vscore
++;
1377 rb
->snprintf(s
, sizeof(s
), "%d", vscore
);
1378 rb
->lcd_getstringsize(s
, &sw
, NULL
);
1379 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, 0, s
);
1382 if (game_state
== ST_PAUSE
)
1384 rb
->snprintf(s
, sizeof(s
), CONTINUE_TEXT
);
1385 rb
->lcd_getstringsize(s
, &sw
, NULL
);
1386 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, INT3(STRINGPOS_NAVI
), s
);
1388 sec_count
=*rb
->current_tick
+HZ
;
1392 for(i
=0;i
<used_balls
;i
++)
1393 rb
->lcd_bitmap(brickmania_ball
,
1394 INT3(ball
[i
].pos_x
- HALFBALL
),
1395 INT3(ball
[i
].pos_y
- HALFBALL
),
1396 INT3(BALL
), INT3(BALL
));
1398 if (brick_on_board
==0)
1401 /* if the pad is fire */
1404 /* If the projectile is active (>0 inactive) */
1405 if (fire
[i
].top
>= 0)
1407 if (game_state
!=ST_PAUSE
)
1408 fire
[i
].top
-= SPEED_FIRE
;
1409 /* Draw the projectile */
1410 rb
->lcd_vline( INT3(fire
[i
].x_pos
), INT3(fire
[i
].top
),
1411 INT3(fire
[i
].top
+ FIRE_LENGTH
));
1415 /* Setup the pad line-later used in intersection test */
1416 pad_line
.p1
.x
= pad_pos_x
;
1417 pad_line
.p1
.y
= PAD_POS_Y
;
1419 pad_line
.p2
.x
= pad_pos_x
+ pad_width
;
1420 pad_line
.p2
.y
= PAD_POS_Y
;
1422 /* handle all of the bricks/powerups */
1423 for (i
=0; i
<=7; i
++)
1425 for (j
=0; j
<=9 ;j
++)
1430 /* This brick is not really a brick, it is a powerup if
1431 * poweruse is set. Perform appropriate powerup checks.
1433 if(brick
[bnum
].poweruse
)
1435 brickx
= LEFTMARGIN
+ j
*BRICK_WIDTH
+
1436 (BRICK_WIDTH
- POWERUP_WIDTH
) / 2;
1438 /* Update powertop if the game is not paused */
1439 if (game_state
!=ST_PAUSE
)
1440 brick
[bnum
].powertop
+=SPEED_POWER
;
1442 /* Draw the powerup */
1443 rb
->lcd_bitmap_part(brickmania_powerups
,0,
1444 INT3(POWERUP_HEIGHT
)*brick
[bnum
].power
,
1445 STRIDE( SCREEN_MAIN
,
1446 BMPWIDTH_brickmania_powerups
,
1447 BMPHEIGHT_brickmania_powerups
),
1449 INT3(brick
[bnum
].powertop
),
1450 INT3(POWERUP_WIDTH
),
1451 INT3(POWERUP_HEIGHT
) );
1453 /* Use misc_line to check if the center of the powerup
1456 misc_line
.p1
.x
= brickx
+ (POWERUP_WIDTH
>> 1);
1457 misc_line
.p1
.y
= brick
[bnum
].powertop
+ POWERUP_HEIGHT
;
1459 misc_line
.p2
.x
= brickx
+ (POWERUP_WIDTH
>> 1);
1460 misc_line
.p2
.y
= SPEED_POWER
+ brick
[bnum
].powertop
+
1463 /* Check if the powerup will hit the paddle */
1464 if ( check_lines(&misc_line
, &pad_line
, &pt_hit
) )
1466 switch(brick
[bnum
].power
) {
1467 case 0: /* Extra Life */
1471 case 1: /* Loose a life */
1475 brickmania_init_game(false);
1476 brickmania_sleep(2);
1479 case 2: /* Make the paddle sticky */
1483 case 3: /* Give the paddle shooter */
1486 for(k
=0;k
<used_balls
;k
++)
1489 case 4: /* Normal brick */
1492 for(k
=0;k
<used_balls
;k
++)
1496 pad_pos_x
+= (pad_width
-PAD_WIDTH
)/2;
1497 pad_width
= PAD_WIDTH
;
1499 case 5: /* Flip the paddle */
1501 sec_count
= *rb
->current_tick
+HZ
;
1505 case 6: /* Extra Ball */
1507 if(used_balls
<MAX_BALLS
)
1510 if(rb
->rand()%2 == 0)
1511 ball
[used_balls
].speedx
=-SPEED_4Q_X
;
1513 ball
[used_balls
].speedx
= SPEED_4Q_X
;
1515 ball
[used_balls
].speedy
= SPEED_4Q_Y
;
1517 /* Ball is not glued */
1518 ball
[used_balls
].glue
= false;
1522 case 7: /* Long paddle */
1524 if (pad_width
==PAD_WIDTH
)
1526 pad_width
= LONG_PAD_WIDTH
;
1527 pad_pos_x
-= (LONG_PAD_WIDTH
-
1530 else if (pad_width
==SHORT_PAD_WIDTH
)
1532 pad_width
= PAD_WIDTH
;
1533 pad_pos_x
-=(PAD_WIDTH
-
1539 else if(pad_pos_x
+ pad_width
>
1541 pad_pos_x
= GAMESCREEN_WIDTH
-pad_width
;
1543 case 8: /* Short Paddle */
1544 if (pad_width
==PAD_WIDTH
)
1546 pad_width
=SHORT_PAD_WIDTH
;
1547 pad_pos_x
+=(PAD_WIDTH
-
1550 else if (pad_width
==LONG_PAD_WIDTH
)
1552 pad_width
=PAD_WIDTH
;
1553 pad_pos_x
+=(LONG_PAD_WIDTH
-PAD_WIDTH
)/2;
1557 /* Disable the powerup (it was picked up) */
1558 brick
[bnum
].poweruse
= false;
1561 if (brick
[bnum
].powertop
>PAD_POS_Y
)
1563 /* Disable the powerup (it was missed) */
1564 brick
[bnum
].poweruse
= false;
1567 /* The brick is a brick, but it may or may not be in use */
1568 else if(brick
[bnum
].used
)
1570 /* these lines are used to describe the brick */
1571 line bot_brick
, top_brick
, left_brick
, rght_brick
;
1572 brickx
= LEFTMARGIN
+ j
*BRICK_WIDTH
;
1574 /* Describe the brick for later collision checks */
1575 /* Setup the bottom of the brick */
1576 bot_brick
.p1
.x
= brickx
;
1577 bot_brick
.p1
.y
= brick
[bnum
].powertop
+ BRICK_HEIGHT
;
1579 bot_brick
.p2
.x
= brickx
+ BRICK_WIDTH
;
1580 bot_brick
.p2
.y
= brick
[bnum
].powertop
+ BRICK_HEIGHT
;
1582 /* Setup the top of the brick */
1583 top_brick
.p1
.x
= brickx
;
1584 top_brick
.p1
.y
= brick
[bnum
].powertop
;
1586 top_brick
.p2
.x
= brickx
+ BRICK_WIDTH
;
1587 top_brick
.p2
.y
= brick
[bnum
].powertop
;
1589 /* Setup the left of the brick */
1590 left_brick
.p1
.x
= brickx
;
1591 left_brick
.p1
.y
= brick
[bnum
].powertop
;
1593 left_brick
.p2
.x
= brickx
;
1594 left_brick
.p2
.y
= brick
[bnum
].powertop
+ BRICK_HEIGHT
;
1596 /* Setup the right of the brick */
1597 rght_brick
.p1
.x
= brickx
+ BRICK_WIDTH
;
1598 rght_brick
.p1
.y
= brick
[bnum
].powertop
;
1600 rght_brick
.p2
.x
= brickx
+ BRICK_WIDTH
;
1601 rght_brick
.p2
.y
= brick
[bnum
].powertop
+ BRICK_HEIGHT
;
1603 /* Check if any of the active fires hit a brick */
1608 /* Use misc_line to check if fire hit brick */
1609 misc_line
.p1
.x
= fire
[k
].x_pos
;
1610 misc_line
.p1
.y
= fire
[k
].top
;
1612 misc_line
.p2
.x
= fire
[k
].x_pos
;
1613 misc_line
.p2
.y
= fire
[k
].top
+ SPEED_FIRE
;
1615 /* If the fire hit the brick take care of it */
1616 if (check_lines(&misc_line
, &bot_brick
,
1620 /* De-activate the fire */
1627 /* Draw the brick */
1628 rb
->lcd_bitmap_part(brickmania_bricks
,0,
1629 INT3(BRICK_HEIGHT
)*brick
[bnum
].color
,
1630 STRIDE( SCREEN_MAIN
,
1631 BMPWIDTH_brickmania_bricks
,
1632 BMPHEIGHT_brickmania_bricks
),
1634 INT3(brick
[bnum
].powertop
),
1635 INT3(BRICK_WIDTH
), INT3(BRICK_HEIGHT
) );
1637 #ifdef HAVE_LCD_COLOR /* No transparent effect for greyscale lcds for now */
1638 if (brick
[bnum
].hiteffect
> 0)
1639 rb
->lcd_bitmap_transparent_part(brickmania_break
,0,
1640 INT3(BRICK_HEIGHT
)*brick
[bnum
].hiteffect
,
1641 STRIDE( SCREEN_MAIN
,
1642 BMPWIDTH_brickmania_break
,
1643 BMPHEIGHT_brickmania_break
),
1645 INT3(brick
[bnum
].powertop
),
1646 INT3(BRICK_WIDTH
), INT3(BRICK_HEIGHT
) );
1649 /* Check if any balls collided with the brick */
1650 for(k
=0; k
<used_balls
; k
++)
1652 /* Setup the ball path to describe the current ball
1653 * position and the line it makes to its next
1656 misc_line
.p1
.x
= ball
[k
].pos_x
;
1657 misc_line
.p1
.y
= ball
[k
].pos_y
;
1659 misc_line
.p2
.x
= ball
[k
].pos_x
+ ball
[k
].speedx
;
1660 misc_line
.p2
.y
= ball
[k
].pos_y
+ ball
[k
].speedy
;
1662 /* Check to see if the ball and the bottom hit. If
1663 * the ball is moving down we don't want to
1664 * include the bottom line intersection.
1666 * The order that the sides are checked matters.
1668 * Note that tempx/tempy store the next position
1669 * that the ball should be drawn.
1671 if(ball
[k
].speedy
<= 0 &&
1672 check_lines(&misc_line
, &bot_brick
, &pt_hit
))
1674 ball
[k
].speedy
= -ball
[k
].speedy
;
1675 ball
[k
].tempy
= pt_hit
.y
;
1676 ball
[k
].tempx
= pt_hit
.x
;
1679 /* Check the top, if the ball is moving up dont
1680 * count it as a hit.
1682 else if(ball
[k
].speedy
> 0 &&
1683 check_lines(&misc_line
, &top_brick
, &pt_hit
))
1685 ball
[k
].speedy
= -ball
[k
].speedy
;
1686 ball
[k
].tempy
= pt_hit
.y
;
1687 ball
[k
].tempx
= pt_hit
.x
;
1690 /* Check the left side of the brick */
1692 check_lines(&misc_line
, &left_brick
, &pt_hit
))
1694 ball
[k
].speedx
= -ball
[k
].speedx
;
1695 ball
[k
].tempy
= pt_hit
.y
;
1696 ball
[k
].tempx
= pt_hit
.x
;
1699 /* Check the right side of the brick */
1701 check_lines(&misc_line
, &rght_brick
, &pt_hit
))
1703 ball
[k
].speedx
= -ball
[k
].speedx
;
1704 ball
[k
].tempy
= pt_hit
.y
;
1705 ball
[k
].tempx
= pt_hit
.x
;
1714 /* draw the paddle according to the PAD_WIDTH */
1715 if( pad_width
== PAD_WIDTH
) /* Normal width */
1717 rb
->lcd_bitmap_part(
1719 0, pad_type
*INT3(PAD_HEIGHT
),
1720 STRIDE( SCREEN_MAIN
, BMPWIDTH_brickmania_pads
,
1721 BMPHEIGHT_brickmania_pads
),
1722 INT3(pad_pos_x
), INT3(PAD_POS_Y
),
1723 INT3(pad_width
), INT3(PAD_HEIGHT
) );
1725 else if( pad_width
== LONG_PAD_WIDTH
) /* Long Pad */
1727 rb
->lcd_bitmap_part(
1728 brickmania_long_pads
,
1729 0,pad_type
*INT3(PAD_HEIGHT
),
1730 STRIDE( SCREEN_MAIN
, BMPWIDTH_brickmania_long_pads
,
1731 BMPHEIGHT_brickmania_long_pads
),
1732 INT3(pad_pos_x
), INT3(PAD_POS_Y
),
1733 INT3(pad_width
), INT3(PAD_HEIGHT
) );
1735 else /* Short pad */
1737 rb
->lcd_bitmap_part(
1738 brickmania_short_pads
,
1739 0,pad_type
*INT3(PAD_HEIGHT
),
1740 STRIDE( SCREEN_MAIN
, BMPWIDTH_brickmania_short_pads
,
1741 BMPHEIGHT_brickmania_short_pads
),
1742 INT3(pad_pos_x
), INT3(PAD_POS_Y
),
1743 INT3(pad_width
), INT3(PAD_HEIGHT
) );
1746 /* If the game is not paused continue */
1747 if (game_state
!=ST_PAUSE
)
1749 /* Loop through all of the balls in play */
1750 for(k
=0;k
<used_balls
;k
++)
1754 /* Describe the ball movement for the edge collision detection */
1755 misc_line
.p1
.x
= ball
[k
].pos_x
;
1756 misc_line
.p1
.y
= ball
[k
].pos_y
;
1758 misc_line
.p2
.x
= ball
[k
].pos_x
+ ball
[k
].speedx
;
1759 misc_line
.p2
.y
= ball
[k
].pos_y
+ ball
[k
].speedy
;
1761 /* Did the Ball hit the top of the screen? */
1762 screen_edge
.p1
.x
= 0;
1763 screen_edge
.p1
.y
= 0;
1765 screen_edge
.p2
.x
= FIXED3(LCD_WIDTH
);
1766 screen_edge
.p2
.y
= 0;
1767 if (check_lines(&misc_line
, &screen_edge
, &pt_hit
))
1769 ball
[k
].tempy
= pt_hit
.y
+ 1;
1770 ball
[k
].tempx
= pt_hit
.x
;
1771 /* Reverse the direction */
1772 ball
[k
].speedy
= -ball
[k
].speedy
;
1775 /* Player missed the ball and hit bottom of screen */
1776 if (ball
[k
].pos_y
>= GAMESCREEN_HEIGHT
)
1778 /* Player had balls to spare, so handle the removal */
1781 /* decrease number of balls in play */
1783 /* Replace removed ball with the last ball */
1784 ball
[k
].pos_x
= ball
[used_balls
].pos_x
;
1785 ball
[k
].pos_y
= ball
[used_balls
].pos_y
;
1786 ball
[k
].speedy
= ball
[used_balls
].speedy
;
1787 ball
[k
].tempy
= ball
[used_balls
].tempy
;
1788 ball
[k
].speedx
= ball
[used_balls
].speedx
;
1789 ball
[k
].tempx
= ball
[used_balls
].tempx
;
1790 ball
[k
].glue
= ball
[used_balls
].glue
;
1792 /* Reset the last ball that was removed */
1793 ball
[used_balls
].speedx
=0;
1794 ball
[used_balls
].speedy
=0;
1795 ball
[used_balls
].tempy
=0;
1796 ball
[used_balls
].tempx
=0;
1797 ball
[used_balls
].pos_y
=PAD_POS_Y
-BALL
;
1798 ball
[used_balls
].pos_x
=pad_pos_x
+(pad_width
/2)-2;
1805 /* Player lost a life */
1809 /* No lives left reset game */
1810 brickmania_init_game(false);
1811 brickmania_sleep(2);
1812 rb
->button_clear_queue();
1817 /* Check if the ball hit the left side */
1818 screen_edge
.p1
.x
= 0;
1819 screen_edge
.p1
.y
= 0;
1821 screen_edge
.p2
.x
= 0;
1822 screen_edge
.p2
.y
= FIXED3(LCD_HEIGHT
);
1823 if ( check_lines(&misc_line
, &screen_edge
, &pt_hit
))
1825 /* Reverse direction */
1826 ball
[k
].speedx
= -ball
[k
].speedx
;
1828 /* Re-position ball in gameboard */
1829 ball
[k
].tempy
= pt_hit
.y
;
1833 /* Check if the ball hit the right side */
1834 screen_edge
.p1
.x
= FIXED3(LCD_WIDTH
);
1835 screen_edge
.p1
.y
= 0;
1837 screen_edge
.p2
.x
= FIXED3(LCD_WIDTH
);
1838 screen_edge
.p2
.y
= FIXED3(LCD_HEIGHT
);
1839 if ( check_lines(&misc_line
, &screen_edge
, &pt_hit
))
1841 /* Reverse direction */
1842 ball
[k
].speedx
= -ball
[k
].speedx
;
1844 /* Re-position ball in gameboard */
1845 ball
[k
].tempy
= pt_hit
.y
;
1846 ball
[k
].tempx
= FIXED3(LCD_WIDTH
- 1);
1849 /* Did the ball hit the paddle? Depending on where the ball
1850 * Hit set the x/y speed appropriately.
1852 if( game_state
!=ST_READY
&& !ball
[k
].glue
&&
1853 check_lines(&misc_line
, &pad_line
, &pt_hit
) )
1855 /* Re-position ball based on collision */
1856 ball
[k
].tempy
= pt_hit
.y
- 1;
1857 ball
[k
].tempx
= pt_hit
.x
;
1859 /* Calculate the ball position relative to the paddle width */
1860 int ball_repos
= pt_hit
.x
- pad_pos_x
;
1861 /* If the ball hits the right half of paddle, x speed
1862 * should be positive, if it hits the left half it
1863 * should be negative.
1865 int x_direction
= -1;
1867 /* Comparisons are done with respect to 1/2 pad_width */
1868 if(ball_repos
> pad_width
/2)
1870 /* flip the relative position */
1871 ball_repos
-= ((ball_repos
- pad_width
/2) << 1);
1872 /* Ball hit the right half so X speed calculations
1873 * should be positive.
1878 /* Figure out where the ball hit relative to 1/2 pad
1879 * and in divisions of 4.
1881 ball_repos
= ball_repos
/ (pad_width
/2/4);
1885 /* Ball hit the outer edge of the paddle */
1887 ball
[k
].speedy
= SPEED_1Q_Y
;
1888 ball
[k
].speedx
= SPEED_1Q_X
* x_direction
;
1890 /* Ball hit the next fourth of the paddle */
1892 ball
[k
].speedy
= SPEED_2Q_Y
;
1893 ball
[k
].speedx
= SPEED_2Q_X
* x_direction
;
1895 /* Ball hit the third fourth of the paddle */
1897 ball
[k
].speedy
= SPEED_3Q_Y
;
1898 ball
[k
].speedx
= SPEED_3Q_X
* x_direction
;
1900 /* Ball hit the fourth fourth of the paddle or dead
1905 ball
[k
].speedy
= SPEED_4Q_Y
;
1906 /* Since this is the middle we don't want to
1907 * force the ball in a different direction.
1908 * Just keep it going in the same direction
1909 * with a specific speed.
1911 if(ball
[k
].speedx
> 0)
1913 ball
[k
].speedx
= SPEED_4Q_X
;
1917 ball
[k
].speedx
= -SPEED_4Q_X
;
1922 ball
[k
].speedy
= SPEED_4Q_Y
;
1926 if(pad_type
== STICKY
)
1928 ball
[k
].speedy
= -ball
[k
].speedy
;
1931 /* X location should not be forced since that is moved with the paddle. The Y
1932 * position should be forced to keep the ball at the paddle.
1935 ball
[k
].tempy
= pt_hit
.y
- BALL
;
1939 /* Update the ball position */
1943 ball
[k
].pos_x
= ball
[k
].tempx
;
1945 ball
[k
].pos_x
+= ball
[k
].speedx
;
1948 ball
[k
].pos_y
= ball
[k
].tempy
;
1950 ball
[k
].pos_y
+= ball
[k
].speedy
;
1960 if (brick_on_board
< 0)
1962 if (level
+1<levels_num
)
1965 if (difficulty
==NORMAL
)
1967 brickmania_init_game(true);
1968 brickmania_sleep(2);
1969 rb
->button_clear_queue();
1973 rb
->lcd_getstringsize("Congratulations!", &sw
, NULL
);
1974 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, INT3(STRINGPOS_CONGRATS
),
1975 "Congratulations!");
1976 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1977 rb
->lcd_getstringsize("No more levels", &sw
, NULL
);
1978 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, INT3(STRINGPOS_FINISH
),
1981 rb
->lcd_getstringsize("You have finished the game!",
1983 rb
->lcd_putsxy(LCD_WIDTH
/2-sw
/2, INT3(STRINGPOS_FINISH
),
1984 "You have finished the game!");
1988 brickmania_sleep(2);
1993 int button
=rb
->button_get(false);
1994 int move_button
= rb
->button_status();
1996 #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
1997 /* FIXME: Should probably check remote hold here */
1998 if (rb
->button_hold())
2002 #ifdef HAVE_TOUCHSCREEN
2003 if( move_button
& BUTTON_TOUCHSCREEN
)
2006 short touch_x
, touch_y
;
2007 rb
->button_status_wdata(&data
);
2008 touch_x
= FIXED3(data
>> 16);
2009 touch_y
= FIXED3(data
& 0xffff);
2013 pad_pos_x
= GAMESCREEN_WIDTH
- (touch_x
+ pad_width
/2);
2017 pad_pos_x
= (touch_x
- pad_width
/2);
2022 else if(pad_pos_x
+ pad_width
> GAMESCREEN_WIDTH
)
2023 pad_pos_x
= GAMESCREEN_WIDTH
-pad_width
;
2024 for(k
=0; k
<used_balls
; k
++)
2025 if (game_state
==ST_READY
|| ball
[k
].glue
)
2026 ball
[k
].pos_x
= pad_pos_x
+ pad_width
/2;
2031 int button_right
, button_left
;
2033 button_right
= move_button
& (RIGHT
| ALTRIGHT
);
2034 button_left
= move_button
& (LEFT
| ALTLEFT
);
2036 button_right
=((move_button
& RIGHT
)|| SCROLL_FWD(button
));
2037 button_left
=((move_button
& LEFT
) ||SCROLL_BACK(button
));
2039 if ((game_state
==ST_PAUSE
) && (button_right
|| button_left
))
2041 if ((button_right
&& !flip_sides
) ||
2042 (button_left
&& flip_sides
))
2044 if (pad_pos_x
+SPEED_PAD
+pad_width
> GAMESCREEN_WIDTH
)
2046 for(k
=0;k
<used_balls
;k
++)
2047 if (game_state
==ST_READY
|| ball
[k
].glue
)
2048 ball
[k
].pos_x
+= GAMESCREEN_WIDTH
-pad_pos_x
-
2050 pad_pos_x
+= GAMESCREEN_WIDTH
- pad_pos_x
- pad_width
;
2053 for(k
=0;k
<used_balls
;k
++)
2054 if ((game_state
==ST_READY
|| ball
[k
].glue
))
2055 ball
[k
].pos_x
+=SPEED_PAD
;
2056 pad_pos_x
+=SPEED_PAD
;
2059 else if ((button_left
&& !flip_sides
) ||
2060 (button_right
&& flip_sides
))
2062 if (pad_pos_x
-SPEED_PAD
< 0)
2064 for(k
=0;k
<used_balls
;k
++)
2065 if (game_state
==ST_READY
|| ball
[k
].glue
)
2066 ball
[k
].pos_x
-=pad_pos_x
;
2067 pad_pos_x
-= pad_pos_x
;
2071 for(k
=0;k
<used_balls
;k
++)
2072 if (game_state
==ST_READY
|| ball
[k
].glue
)
2073 ball
[k
].pos_x
-=SPEED_PAD
;
2074 pad_pos_x
-=SPEED_PAD
;
2081 #if defined(HAVE_TOUCHSCREEN)
2082 case (BUTTON_REL
| BUTTON_TOUCHSCREEN
):
2089 if (game_state
==ST_READY
)
2091 /* Initialize used balls starting speed */
2092 for(k
=0 ; k
< used_balls
; k
++)
2094 ball
[k
].speedy
= SPEED_4Q_Y
;
2095 if(pad_pos_x
+ (pad_width
/2) >= GAMESCREEN_WIDTH
/2)
2097 ball
[k
].speedx
= SPEED_4Q_X
;
2101 ball
[k
].speedx
= -SPEED_4Q_X
;
2104 game_state
=ST_START
;
2106 else if (game_state
==ST_PAUSE
)
2108 game_state
=ST_START
;
2110 else if (pad_type
== STICKY
)
2112 for(k
=0;k
<used_balls
;k
++)
2117 ball
[k
].speedy
= -ball
[k
].speedy
;
2121 else if (pad_type
== SHOOTER
)
2123 k
=brickmania_find_empty_fire();
2124 fire
[k
].top
=PAD_POS_Y
- FIRE_LENGTH
;
2125 fire
[k
].x_pos
= pad_pos_x
+ 1; /* Add 1 for edge */
2127 k
=brickmania_find_empty_fire();
2128 fire
[k
].top
=PAD_POS_Y
- FIRE_LENGTH
;
2129 fire
[k
].x_pos
= pad_pos_x
+ pad_width
-1; /* Sub1 edge*/
2141 if(rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
2148 #ifdef HAVE_LCD_COLOR
2149 rb
->lcd_bitmap_transparent(brickmania_gameover
,
2150 (LCD_WIDTH
- INT3(GAMEOVER_WIDTH
))/2,
2151 INT3(GAMESCREEN_HEIGHT
- GAMEOVER_HEIGHT
)/2,
2152 INT3(GAMEOVER_WIDTH
),INT3(GAMEOVER_HEIGHT
));
2153 #else /* greyscale and mono */
2154 rb
->lcd_bitmap(brickmania_gameover
,(LCD_WIDTH
-
2155 INT3(GAMEOVER_WIDTH
))/2,
2156 INT3(GAMESCREEN_HEIGHT
- GAMEOVER_HEIGHT
)/2,
2157 INT3(GAMEOVER_WIDTH
),INT3(GAMEOVER_HEIGHT
) );
2160 brickmania_sleep(2);
2164 /* Game always needs to yield for other threads */
2167 /* Sleep for a bit if there is time to spare */
2168 if (TIME_BEFORE(*rb
->current_tick
, end
))
2169 rb
->sleep(end
-*rb
->current_tick
);
2174 /* this is the plugin entry point */
2175 enum plugin_status
plugin_start(const void* parameter
)
2178 int last_difficulty
;
2180 highscore_load(HIGH_SCORE
,highest
,NUM_SCORES
);
2181 configfile_load(CONFIG_FILE_NAME
,config
,1,0);
2182 last_difficulty
= difficulty
;
2184 #ifdef HAVE_TOUCHSCREEN
2185 rb
->touchscreen_set_mode(TOUCHSCREEN_POINT
);
2188 rb
->lcd_setfont(FONT_SYSFIXED
);
2190 rb
->lcd_set_backdrop(NULL
);
2192 /* Turn off backlight timeout */
2193 backlight_force_on(); /* backlight control in lib/helper.c */
2195 /* now go ahead and have fun! */
2196 rb
->srand( *rb
->current_tick
);
2197 brickmania_loadgame();
2198 resume_file
= resume
;
2199 while(!brickmania_game_loop())
2203 int position
= highscore_update(score
, level
+1, "", highest
,
2207 rb
->splash(HZ
*2, "New High Score");
2212 highscore_show(position
, highest
, NUM_SCORES
, true);
2216 brickmania_sleep(3);
2221 highscore_save(HIGH_SCORE
,highest
,NUM_SCORES
);
2222 if(last_difficulty
!= difficulty
)
2223 configfile_save(CONFIG_FILE_NAME
,config
,1,0);
2224 /* Restore user's original backlight setting */
2225 rb
->lcd_setfont(FONT_UI
);
2226 /* Turn on backlight timeout (revert to settings) */
2227 backlight_use_settings(); /* backlight control in lib/helper.c */