Tweaked dependencies a bit
[kugel-rb.git] / apps / plugins / brickmania.c
blobcdb254557222cd42824bdb1d5850279ccc3c8193
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 PLUGIN_HEADER
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
53 #define UP BUTTON_UP
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
63 #define UP BUTTON_UP
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
71 #define UP BUTTON_UP
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
79 #define UP BUTTON_UP
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
99 #define UP BUTTON_UP
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
107 #define UP BUTTON_UP
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
115 #define UP BUTTON_UP
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
126 #define UP BUTTON_UP
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
142 #define UP BUTTON_UP
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
158 #define UP BUTTON_UP
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
166 #define UP BUTTON_UP
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
184 #define UP BUTTON_UP
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
192 #define UP BUTTON_UP
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
200 #define UP BUTTON_UP
201 #define DOWN BUTTON_DOWN
203 #elif CONFIG_KEYPAD == COWON_D2_PAD
204 #define CONTINUE_TEXT "MENU To Continue"
205 #define QUIT BUTTON_POWER
206 #define LEFT BUTTON_MINUS
207 #define RIGHT BUTTON_PLUS
208 #define SELECT BUTTON_MENU
210 #elif CONFIG_KEYPAD == ONDAVX747_PAD
211 #define QUIT BUTTON_POWER
212 #define LEFT BUTTON_VOL_DOWN
213 #define RIGHT BUTTON_VOL_UP
214 #define SELECT BUTTON_MENU
215 #elif CONFIG_KEYPAD == ONDAVX777_PAD
216 #define QUIT BUTTON_POWER
218 #elif CONFIG_KEYPAD == MROBE500_PAD
219 #define QUIT BUTTON_POWER
221 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
222 #define QUIT BUTTON_FFWD
223 #define SELECT BUTTON_PLAY
224 #define LEFT BUTTON_LEFT
225 #define RIGHT BUTTON_RIGHT
226 #define UP BUTTON_UP
227 #define DOWN BUTTON_DOWN
229 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
230 #define QUIT BUTTON_REC
231 #define LEFT BUTTON_PREV
232 #define RIGHT BUTTON_NEXT
233 #define ALTLEFT BUTTON_MENU
234 #define ALTRIGHT BUTTON_PLAY
235 #define SELECT BUTTON_OK
236 #define UP BUTTON_UP
237 #define DOWN BUTTON_DOWN
239 #else
240 #error No keymap defined!
241 #endif
243 #ifdef HAVE_TOUCHSCREEN
244 #ifdef LEFT
245 #define ALTLEFT BUTTON_BOTTOMLEFT
246 #else
247 #define LEFT BUTTON_BOTTOMLEFT
248 #endif
249 #ifdef RIGHT
250 #define ALTRIGHT BUTTON_BOTTOMRIGHT
251 #else
252 #define RIGHT BUTTON_BOTTOMRIGHT
253 #endif
254 #ifdef SELECT
255 #define ALTSELECT BUTTON_CENTER
256 #else
257 #define SELECT BUTTON_CENTER
258 #endif
259 #ifndef UP
260 #define UP BUTTON_TOPMIDDLE
261 #endif
262 #ifndef DOWN
263 #define DOWN BUTTON_BOTTOMMIDDLE
264 #endif
265 #endif
267 /* Continue text is used as a string later when the game is paused. This allows
268 * targets to specify their own text if needed.
270 #if !defined(CONTINUE_TEXT)
271 #define CONTINUE_TEXT "Press SELECT To Continue"
272 #endif
274 #ifndef SCROLL_FWD /* targets without scroll wheel*/
275 #define SCROLL_FWD(x) (0)
276 #define SCROLL_BACK(x) (0)
277 #endif
279 #include "pluginbitmaps/brickmania_pads.h"
280 #include "pluginbitmaps/brickmania_short_pads.h"
281 #include "pluginbitmaps/brickmania_long_pads.h"
282 #include "pluginbitmaps/brickmania_bricks.h"
283 #include "pluginbitmaps/brickmania_powerups.h"
284 #include "pluginbitmaps/brickmania_ball.h"
285 #include "pluginbitmaps/brickmania_gameover.h"
287 #define GAMESCREEN_WIDTH FIXED3(LCD_WIDTH)
288 #define GAMESCREEN_HEIGHT FIXED3(LCD_HEIGHT)
290 #define PAD_WIDTH FIXED3(BMPWIDTH_brickmania_pads)
291 #define PAD_HEIGHT FIXED3(BMPHEIGHT_brickmania_pads/3)
292 #define SHORT_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_short_pads)
293 #define LONG_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_long_pads)
294 #define BRICK_HEIGHT FIXED3(BMPHEIGHT_brickmania_bricks/7)
295 #define BRICK_WIDTH FIXED3(BMPWIDTH_brickmania_bricks)
296 #define LEFTMARGIN ((GAMESCREEN_WIDTH-10*BRICK_WIDTH)/2)
297 #define NUMBER_OF_POWERUPS 9
298 #define POWERUP_HEIGHT FIXED3(BMPHEIGHT_brickmania_powerups/NUMBER_OF_POWERUPS)
299 #define POWERUP_WIDTH FIXED3(BMPWIDTH_brickmania_powerups)
300 #define BALL FIXED3(BMPHEIGHT_brickmania_ball)
301 #define HALFBALL (BALL / 2)
302 #define ON_PAD_POS_Y (PAD_POS_Y - HALFBALL)
304 #define GAMEOVER_WIDTH FIXED3(BMPWIDTH_brickmania_gameover)
305 #define GAMEOVER_HEIGHT FIXED3(BMPHEIGHT_brickmania_gameover)
307 #ifdef HAVE_LCD_COLOR /* currently no transparency for non-colour */
308 #include "pluginbitmaps/brickmania_break.h"
309 #endif
311 /* The time (in ms) for one iteration through the game loop - decrease this
312 * to speed up the game - note that current_tick is (currently) only accurate
313 * to 10ms.
315 #define CYCLETIME 30
317 #define TOPMARGIN MAX(BRICK_HEIGHT, FIXED3(8))
319 #define STRINGPOS_FINISH (GAMESCREEN_HEIGHT - (GAMESCREEN_HEIGHT / 6))
320 #define STRINGPOS_CONGRATS (STRINGPOS_FINISH - 20)
321 #define STRINGPOS_NAVI (STRINGPOS_FINISH - 10)
322 #define STRINGPOS_FLIP (STRINGPOS_FINISH - 10)
324 /* Brickmania was originally designed for the H300, other targets should scale
325 * the speed up/down as needed based on the screen height.
327 #define SPEED_SCALE_H(y) FIXED3_DIV(GAMESCREEN_HEIGHT, FIXED3(176)/(y) )
328 #define SPEED_SCALE_W(x) FIXED3_DIV(GAMESCREEN_WIDTH, FIXED3(220)/(x) )
330 /* These are all used as ball speeds depending on where the ball hit the
331 * paddle.
333 * Note that all of these speeds (including pad, power, and fire)
334 * could be made variable and could be raised to be much higher to add
335 * additional difficulty to the game. The line intersection tests allow this
336 * to be drastically increased without the collision detection failing
337 * (ideally).
339 #define SPEED_1Q_X SPEED_SCALE_W( 6)
340 #define SPEED_1Q_Y SPEED_SCALE_H(-2)
342 #define SPEED_2Q_X SPEED_SCALE_W( 4)
343 #define SPEED_2Q_Y SPEED_SCALE_H(-3)
345 #define SPEED_3Q_X SPEED_SCALE_W( 3)
346 #define SPEED_3Q_Y SPEED_SCALE_H(-4)
348 #define SPEED_4Q_X SPEED_SCALE_W( 2)
349 #define SPEED_4Q_Y SPEED_SCALE_H(-4)
351 /* This is used to determine the speed of the paddle */
352 #define SPEED_PAD SPEED_SCALE_W( 8)
354 /* This defines the speed that the powerups drop */
355 #define SPEED_POWER SPEED_SCALE_H( 2)
357 /* This defines the speed that the shot moves */
358 #define SPEED_FIRE SPEED_SCALE_H( 4)
359 #define FIRE_LENGTH SPEED_SCALE_H( 7)
361 /*calculate paddle y-position */
362 #define PAD_POS_Y (GAMESCREEN_HEIGHT - PAD_HEIGHT - 1)
364 /* change to however many levels there are, i.e. how many arrays there are total */
365 #define NUM_LEVELS 40
367 #define NUM_BRICKS_ROWS 8
368 #define NUM_BRICKS_COLS 10
369 #define FLIP_SIDES_DELAY 10
371 /* change the first number in [ ] to however many levels there are */
372 static unsigned char levels[NUM_LEVELS][NUM_BRICKS_ROWS][NUM_BRICKS_COLS] =
373 /* You can set up new levels with the level editor
374 ( http://plugbox.rockbox-lounge.com/brickmania.htm ).
375 With 0x1, it refers to the first brick in the bitmap, 0x2 would refer to the
376 second, ect., 0x0 leaves a empty space. If you add a 2 before the 2nd number,
377 it will take two hits to break, and 3 hits if you add a 3. That is 0x24, will
378 result with the fourth brick being displayed and having take 2 hits to break.
379 You could do the same with the 3, just replace the 2 with a 3 for it to take
380 three hits to break it apart. */
382 { /* level1 */
383 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
384 {0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2},
385 {0x0,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x0},
386 {0x0,0x0,0x2,0x1,0x0,0x0,0x1,0x2,0x0,0x0},
387 {0x0,0x0,0x0,0x2,0x1,0x1,0x2,0x0,0x0,0x0},
388 {0x7,0x0,0x0,0x7,0x2,0x2,0x7,0x0,0x0,0x7},
389 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
390 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
392 { /* level2 */
393 {0x0,0x0,0x7,0x7,0x1,0x1,0x7,0x7,0x0,0x0},
394 {0x0,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0},
395 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
396 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
397 {0x1,0x1,0x2,0x1,0x0,0x0,0x1,0x2,0x1,0x1},
398 {0x1,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x1},
399 {0x0,0x1,0x2,0x0,0x0,0x0,0x0,0x2,0x1,0x0},
400 {0x0,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x0}
402 { /* level3 */
403 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
404 {0x3,0x23,0x23,0x3,0x0,0x0,0x2,0x22,0x22,0x2},
405 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
406 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
407 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
408 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6},
409 {0x5,0x25,0x25,0x5,0x0,0x0,0x6,0x26,0x26,0x6},
410 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6}
412 { /* level4 */
413 {0x0,0x0,0x0,0x27,0x27,0x27,0x27,0x0,0x0,0x0},
414 {0x0,0x0,0x0,0x27,0x7,0x7,0x27,0x0,0x0,0x0},
415 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
416 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
417 {0x26,0x6,0x0,0x2,0x2,0x2,0x2,0x0,0x6,0x26},
418 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
419 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
420 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1}
422 { /* level5 */
423 {0x1,0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4},
424 {0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0},
425 {0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5},
426 {0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5,0x5},
427 {0x0,0x33,0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0},
428 {0x3,0x33,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x36},
429 {0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x6,0x36},
430 {0x0,0x24,0x24,0x0,0x25,0x25,0x0,0x26,0x26,0x0}
432 { /* level6 */
433 {0x0,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x0},
434 {0x3,0x1,0x3,0x7,0x0,0x0,0x7,0x3,0x1,0x3},
435 {0x3,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x3},
436 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x0},
437 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
438 {0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5},
439 {0x0,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x0},
440 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
442 { /* level7 */
443 {0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x0},
444 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
445 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
446 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
447 {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x6},
448 {0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0},
449 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
450 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
452 { /* level8 */
453 {0x0,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x0},
454 {0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0},
455 {0x6,0x6,0x0,0x2,0x32,0x32,0x2,0x0,0x6,0x6},
456 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
457 {0x0,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x0},
458 {0x0,0x0,0x0,0x5,0x25,0x25,0x5,0x0,0x0,0x0},
459 {0x0,0x5,0x5,0x25,0x5,0x5,0x25,0x5,0x5,0x0},
460 {0x5,0x5,0x25,0x5,0x5,0x5,0x5,0x25,0x5,0x5}
462 { /* level9 */
463 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
464 {0x2,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x2},
465 {0x2,0x0,0x3,0x0,0x1,0x1,0x0,0x3,0x0,0x2},
466 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
467 {0x2,0x0,0x1,0x0,0x3,0x3,0x0,0x1,0x0,0x2},
468 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
469 {0x2,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x2,0x2},
470 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
472 { /* level10 */
473 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
474 {0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5},
475 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
476 {0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0},
477 {0x0,0x0,0x0,0x4,0x1,0x1,0x4,0x0,0x0,0x0},
478 {0x0,0x0,0x3,0x4,0x1,0x1,0x4,0x3,0x0,0x0},
479 {0x0,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x0},
480 {0x1,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x1}
482 { /* level11 */
483 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
484 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2},
485 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
486 {0x2,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x2},
487 {0x2,0x0,0x0,0x7,0x7,0x7,0x7,0x0,0x0,0x2},
488 {0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x0},
489 {0x0,0x2,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x0},
490 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5}
492 { /* level 12 */
493 {0x2,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x2},
494 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
495 {0x1,0x1,0x1,0x0,0x1,0x1,0x0,0x1,0x1,0x1},
496 {0x0,0x1,0x0,0x1,0x6,0x6,0x1,0x0,0x1,0x0},
497 {0x0,0x0,0x1,0x1,0x6,0x6,0x1,0x1,0x0,0x0},
498 {0x1,0x1,0x1,0x7,0x0,0x0,0x7,0x1,0x1,0x1},
499 {0x1,0x1,0x7,0x1,0x0,0x0,0x1,0x7,0x1,0x1},
500 {0x2,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x2}
502 {/* levell13 */
503 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
504 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
505 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x2},
506 {0x2,0x0,0x2,0x3,0x3,0x3,0x3,0x3,0x0,0x2},
507 {0x2,0x0,0x2,0x4,0x4,0x4,0x4,0x4,0x0,0x2},
508 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
509 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
510 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
512 {/* level14 */
513 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
514 {0x4,0x4,0x4,0x4,0x2,0x2,0x4,0x4,0x4,0x4},
515 {0x4,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x4},
516 {0x4,0x0,0x0,0x2,0x3,0x3,0x2,0x0,0x0,0x4},
517 {0x4,0x0,0x2,0x23,0x3,0x3,0x23,0x2,0x0,0x4},
518 {0x4,0x0,0x2,0x22,0x2,0x2,0x22,0x2,0x0,0x4},
519 {0x4,0x0,0x6,0x21,0x5,0x5,0x21,0x6,0x0,0x4},
520 {0x4,0x6,0x1,0x1,0x5,0x5,0x1,0x1,0x6,0x4}
522 {/* level 15 */
523 {0x4,0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,0x3},
524 {0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x5,0x0,0x0},
525 {0x2,0x2,0x1,0x1,0x1,0x0,0x1,0x6,0x0,0x0},
526 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x5,0x0,0x0},
527 {0x2,0x1,0x2,0x2,0x2,0x1,0x1,0x6,0x0,0x0},
528 {0x2,0x1,0x2,0x2,0x2,0x1,0x3,0x5,0x3,0x0},
529 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x6,0x0,0x0},
530 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
532 {/* level 16 (Rockbox) by ts-x */
533 {0x2,0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
534 {0x2,0x0,0x3,0x0,0x3,0x4,0x0,0x5,0x5,0x0},
535 {0x2,0x0,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
536 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
537 {0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
538 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0},
539 {0x7,0x0,0x7,0x1,0x0,0x1,0x0,0x2,0x0,0x0},
540 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0}
542 {/* level 17 (Alien) by ts-x */
543 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
544 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
545 {0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1},
546 {0x2,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x2},
547 {0x1,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x1},
548 {0x2,0x0,0x0,0x1,0x2,0x2,0x1,0x0,0x0,0x2},
549 {0x2,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x2},
550 {0x2,0x2,0x1,0x0,0x1,0x1,0x0,0x1,0x2,0x2}
552 {/* level 18 (Tetris) by ts-x */
553 {0x0,0x2,0x0,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
554 {0x0,0x2,0x7,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
555 {0x2,0x2,0x7,0x0,0x3,0x4,0x0,0x6,0x2,0x2},
556 {0x2,0x2,0x7,0x7,0x3,0x4,0x0,0x6,0x2,0x2},
557 {0x2,0x1,0x7,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
558 {0x2,0x1,0x0,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
559 {0x1,0x1,0x1,0x7,0x3,0x0,0x6,0x6,0x5,0x5},
560 {0x1,0x1,0x1,0x0,0x3,0x0,0x6,0x6,0x5,0x5}
562 { /* level 19 (Stalactites) by ts-x */
563 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
564 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
565 {0x5,0x0,0x6,0x3,0x4,0x7,0x5,0x0,0x1,0x2},
566 {0x5,0x2,0x6,0x3,0x4,0x0,0x5,0x3,0x1,0x2},
567 {0x5,0x0,0x6,0x0,0x4,0x7,0x5,0x0,0x1,0x0},
568 {0x5,0x0,0x0,0x3,0x4,0x0,0x0,0x0,0x1,0x2},
569 {0x0,0x0,0x6,0x0,0x0,0x0,0x5,0x0,0x0,0x0},
570 {0x5,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0}
572 { /* level 20 (Maze) by ts-x */
573 {0x1,0x1,0x21,0x1,0x1,0x1,0x1,0x1,0x1,0x21},
574 {0x1,0x0,0x0,0x3,0x0,0x0,0x3,0x1,0x31,0x1},
575 {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x1},
576 {0x21,0x0,0x21,0x3,0x0,0x3,0x0,0x3,0x0,0x2},
577 {0x1,0x0,0x1,0x21,0x0,0x12,0x0,0x0,0x0,0x0},
578 {0x31,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x3,0x0},
579 {0x1,0x0,0x1,0x0,0x1,0x1,0x31,0x1,0x1,0x2},
580 {0x22,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x21}
582 { /* level 21 (Dentist) by ts-x */
583 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
584 {0x2,0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x2,0x2},
585 {0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x2},
586 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x2},
587 {0x2,0x0,0x6,0x0,0x6,0x0,0x0,0x0,0x0,0x2},
588 {0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x2},
589 {0x2,0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x2,0x2},
590 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0}
592 { /* level 22 (Spider) by ts-x */
593 {0x31,0x3,0x1,0x1,0x0,0x0,0x1,0x1,0x3,0x31},
594 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
595 {0x33,0x1,0x1,0x36,0x1,0x1,0x36,0x1,0x1,0x33},
596 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
597 {0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0},
598 {0x21,0x3,0x1,0x21,0x2,0x2,0x21,0x1,0x3,0x21},
599 {0x0,0x0,0x0,0x1,0x21,0x1,0x1,0x0,0x0,0x0},
600 {0x3,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x3}
602 { /* level 23 (Pool) by ts-x */
603 {0x0,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x7,0x0},
604 {0x0,0x0,0x5,0x0,0x2,0x0,0x0,0x0,0x2,0x0},
605 {0x7,0x3,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x7},
606 {0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0x7},
607 {0x7,0x0,0x4,0x0,0x0,0x3,0x0,0x0,0x0,0x7},
608 {0x7,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x4,0x7},
609 {0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
610 {0x0,0x7,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x0}
612 { /* level 24 (Vorbis Fish) by ts-x */
613 {0x0,0x0,0x4,0x4,0x5,0x5,0x5,0x0,0x0,0x5},
614 {0x0,0x4,0x6,0x4,0x4,0x5,0x5,0x5,0x0,0x5},
615 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x5,0x5,0x5},
616 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x4,0x5,0x5},
617 {0x0,0x5,0x6,0x4,0x4,0x5,0x5,0x4,0x5,0x0},
618 {0x5,0x5,0x4,0x4,0x5,0x5,0x5,0x4,0x5,0x5},
619 {0x5,0x4,0x4,0x4,0x5,0x5,0x4,0x4,0x5,0x5},
620 {0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x5,0x0,0x5}
622 {/* level 25 (Rainbow) by ts-x */
623 {0x0,0x4,0x1,0x0,0x0,0x0,0x0,0x1,0x4,0x0},
624 {0x24,0x1,0x3,0x1,0x0,0x0,0x21,0x3,0x1,0x24},
625 {0x1,0x23,0x5,0x3,0x1,0x21,0x3,0x5,0x3,0x21},
626 {0x3,0x5,0x6,0x5,0x3,0x3,0x5,0x6,0x5,0x3},
627 {0x5,0x6,0x7,0x6,0x5,0x5,0x6,0x7,0x6,0x5},
628 {0x6,0x7,0x2,0x27,0x6,0x6,0x27,0x2,0x7,0x6},
629 {0x7,0x2,0x0,0x2,0x27,0x27,0x2,0x0,0x2,0x7},
630 {0x32,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x32}
632 { /* level 26 (Bowtie) by ts-x */
633 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5},
634 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
635 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
636 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
637 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
638 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
639 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
640 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5}
642 { /* level 27 (Frog) by ts-x */
643 {0x0,0x5,0x25,0x0,0x0,0x0,0x0,0x25,0x5,0x0},
644 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
645 {0x25,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x25},
646 {0x5,0x0,0x3,0x0,0x6,0x6,0x0,0x3,0x0,0x5},
647 {0x5,0x0,0x31,0x0,0x6,0x6,0x0,0x31,0x0,0x5},
648 {0x5,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x5},
649 {0x5,0x5,0x5,0x35,0x0,0x0,0x35,0x5,0x5,0x5},
650 {0x0,0x25,0x5,0x0,0x4,0x4,0x0,0x5,0x25,0x0}
652 { /* level 28 (DigDug) by ts-x */
653 {0x35,0x5,0x5,0x25,0x0,0x25,0x25,0x5,0x5,0x35},
654 {0x6,0x0,0x0,0x6,0x0,0x6,0x6,0x0,0x0,0x6},
655 {0x7,0x0,0x37,0x37,0x0,0x37,0x37,0x7,0x0,0x7},
656 {0x7,0x0,0x7,0x0,0x0,0x0,0x7,0x7,0x7,0x7},
657 {0x4,0x4,0x4,0x24,0x0,0x24,0x4,0x0,0x0,0x4},
658 {0x4,0x4,0x0,0x0,0x0,0x4,0x4,0x0,0x4,0x4},
659 {0x24,0x24,0x4,0x4,0x4,0x4,0x0,0x0,0x24,0x4},
660 {0x1,0x1,0x1,0x1,0x1,0x1,0x21,0x21,0x1,0x1}
662 { /* level 29 UK Flag by Seth Opgenorth */
663 {0x32,0x0,0x3,0x3,0x2,0x2,0x3,0x3,0x0,0x32},
664 {0x0,0x2,0x0,0x3,0x32,0x22,0x33,0x0,0x32,0x0},
665 {0x33,0x0,0x22,0x0,0x2,0x2,0x0,0x2,0x0,0x33},
666 {0x22,0x32,0x2,0x2,0x2,0x2,0x2,0x2,0x22,0x2},
667 {0x3,0x0,0x0,0x32,0x22,0x2,0x2,0x0,0x0,0x3},
668 {0x23,0x0,0x32,0x0,0x32,0x2,0x0,0x2,0x0,0x3},
669 {0x0,0x2,0x0,0x3,0x2,0x2,0x3,0x0,0x22,0x0},
670 {0x32,0x0,0x3,0x23,0x2,0x2,0x23,0x33,0x0,0x32}
672 { /* level 30 Win-Logo by Seth Opgenorth */
673 {0x0,0x0,0x0,0x22,0x0,0x0,0x0,0x0,0x0,0x0},
674 {0x0,0x0,0x32,0x2,0x2,0x25,0x0,0x5,0x0,0x0},
675 {0x0,0x0,0x2,0x22,0x2,0x5,0x5,0x35,0x0,0x0},
676 {0x0,0x0,0x2,0x1,0x2,0x5,0x5,0x25,0x0,0x0},
677 {0x0,0x0,0x21,0x1,0x1,0x36,0x7,0x26,0x0,0x0},
678 {0x0,0x0,0x1,0x1,0x1,0x6,0x6,0x6,0x0,0x0},
679 {0x0,0x0,0x21,0x0,0x21,0x6,0x6,0x26,0x0,0x0},
680 {0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0}
682 { /* level 31 Color wave/V by Seth Opgenorth */
683 {0x25,0x34,0x2,0x31,0x33,0x23,0x1,0x2,0x34,0x5},
684 {0x3,0x5,0x24,0x2,0x1,0x1,0x2,0x4,0x5,0x3},
685 {0x1,0x3,0x5,0x4,0x2,0x2,0x4,0x5,0x3,0x1},
686 {0x2,0x1,0x33,0x35,0x4,0x4,0x5,0x33,0x1,0x22},
687 {0x31,0x22,0x1,0x3,0x5,0x25,0x3,0x1,0x2,0x31},
688 {0x3,0x1,0x2,0x1,0x3,0x3,0x1,0x2,0x21,0x3},
689 {0x5,0x23,0x1,0x32,0x1,0x1,0x2,0x1,0x3,0x5},
690 {0x4,0x35,0x3,0x1,0x2,0x22,0x31,0x3,0x5,0x4}
692 { /* level 32 Sweedish Flag by Seth Opgenorth */
693 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
694 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
695 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
696 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
697 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
698 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
699 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
700 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3}
702 { /* level 33 Color Pyramid by Seth Opgenorth */
703 {0x0,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x0},
704 {0x0,0x0,0x0,0x4,0x24,0x4,0x24,0x0,0x0,0x0},
705 {0x0,0x0,0x23,0x3,0x3,0x3,0x23,0x3,0x0,0x0},
706 {0x0,0x0,0x25,0x5,0x25,0x35,0x5,0x35,0x0,0x0},
707 {0x0,0x36,0x6,0x6,0x6,0x6,0x26,0x6,0x6,0x0},
708 {0x0,0x7,0x7,0x7,0x7,0x25,0x27,0x7,0x27,0x0},
709 {0x2,0x2,0x22,0x2,0x2,0x2,0x22,0x2,0x2,0x2},
710 {0x21,0x1,0x1,0x31,0x1,0x21,0x1,0x1,0x31,0x1}
712 { /* level 34 Rhombus by Seth Opgenorth */
713 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0},
714 {0x0,0x0,0x0,0x3,0x32,0x22,0x23,0x0,0x0,0x0},
715 {0x0,0x0,0x3,0x2,0x24,0x4,0x2,0x23,0x0,0x0},
716 {0x26,0x3,0x2,0x4,0x5,0x5,0x4,0x22,0x3,0x6},
717 {0x36,0x3,0x2,0x34,0x5,0x5,0x4,0x2,0x3,0x36},
718 {0x0,0x0,0x3,0x2,0x4,0x34,0x2,0x23,0x0,0x0},
719 {0x0,0x0,0x0,0x23,0x2,0x2,0x3,0x0,0x0,0x0},
720 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0}
722 { /* level 35 PacMan Ghost by Seth Opgenorth */
723 {0x0,0x0,0x0,0x0,0x2,0x32,0x2,0x0,0x0,0x0},
724 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
725 {0x0,0x0,0x2,0x24,0x4,0x2,0x4,0x4,0x32,0x0},
726 {0x0,0x0,0x2,0x24,0x0,0x22,0x24,0x0,0x22,0x0},
727 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
728 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
729 {0x0,0x0,0x2,0x32,0x2,0x2,0x22,0x2,0x32,0x0},
730 {0x0,0x0,0x0,0x22,0x0,0x32,0x0,0x22,0x0,0x0}
732 { /* level 36 Star by Seth Opgenorth */
733 {0x3,0x4,0x3,0x4,0x6,0x24,0x3,0x24,0x3,0x0},
734 {0x24,0x0,0x0,0x6,0x6,0x6,0x0,0x0,0x4,0x0},
735 {0x3,0x26,0x6,0x2,0x6,0x2,0x6,0x26,0x23,0x0},
736 {0x4,0x0,0x6,0x6,0x36,0x6,0x6,0x0,0x4,0x0},
737 {0x3,0x0,0x0,0x26,0x6,0x26,0x0,0x0,0x33,0x0},
738 {0x34,0x0,0x6,0x6,0x0,0x6,0x6,0x0,0x4,0x0},
739 {0x3,0x26,0x6,0x0,0x0,0x0,0x6,0x6,0x3,0x0},
740 {0x4,0x3,0x4,0x23,0x24,0x3,0x4,0x33,0x4,0x0}
742 { /* level 37 It's 8-Bit by Seth Opgenorth */
743 {0x26,0x26,0x6,0x6,0x5,0x6,0x26,0x6,0x26,0x6},
744 {0x2,0x2,0x22,0x3,0x3,0x0,0x0,0x0,0x4,0x0},
745 {0x2,0x0,0x2,0x33,0x3,0x3,0x5,0x0,0x24,0x0},
746 {0x32,0x2,0x2,0x33,0x0,0x23,0x0,0x4,0x4,0x4},
747 {0x2,0x22,0x2,0x3,0x3,0x0,0x5,0x4,0x4,0x24},
748 {0x2,0x0,0x2,0x23,0x0,0x3,0x25,0x0,0x4,0x0},
749 {0x22,0x2,0x2,0x3,0x23,0x0,0x5,0x0,0x4,0x0},
750 {0x6,0x26,0x6,0x36,0x6,0x36,0x6,0x6,0x6,0x6}
752 { /* level 38 Linux by Seth Opgenorth */
753 {0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
754 {0x7,0x0,0x0,0x0,0x33,0x0,0x23,0x0,0x0,0x0},
755 {0x7,0x32,0x0,0x0,0x3,0x0,0x23,0x6,0x0,0x6},
756 {0x37,0x0,0x0,0x0,0x23,0x0,0x3,0x6,0x0,0x26},
757 {0x7,0x22,0x24,0x0,0x3,0x33,0x3,0x0,0x26,0x0},
758 {0x37,0x22,0x24,0x24,0x4,0x0,0x0,0x0,0x26,0x0},
759 {0x7,0x2,0x4,0x0,0x4,0x0,0x0,0x6,0x0,0x26},
760 {0x7,0x27,0x4,0x0,0x34,0x0,0x0,0x6,0x0,0x26}
762 { /* level 39 Colorful Squares by Seth Opgenorth*/
763 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0},
764 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
765 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
766 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
767 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
768 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
769 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
770 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0}
772 { /* TheEnd */
773 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
774 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
775 {0x32,0x0,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
776 {0x32,0x32,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
777 {0x32,0x32,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
778 {0x32,0x0,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
779 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
780 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
784 #define MAX_BALLS 10
785 #define MAX_FIRES 30
787 enum difficulty_options {
788 EASY, NORMAL
791 int pad_pos_x;
792 int life;
793 enum { ST_READY, ST_START, ST_PAUSE } game_state = ST_READY;
795 enum {
796 PLAIN = 0,
797 STICKY = 1,
798 SHOOTER = 2
799 } pad_type;
801 int score=0,vscore=0;
802 bool flip_sides=false;
803 int level=0;
804 int brick_on_board=0;
805 int used_balls=1;
806 int difficulty = NORMAL;
807 int pad_width;
808 int flip_sides_delay;
809 bool resume = false;
810 bool resume_file = false;
812 typedef struct cube
814 int powertop; /* Stores the powerup Y top pos, it is a fixed point num */
815 int power; /* What powerup is in the brick? */
816 bool poweruse; /* Stores whether a powerup is falling or not */
817 bool used; /* Is the brick still in play? */
818 int color;
819 int hits; /* How many hits can this brick take? */
820 int hiteffect;
821 } cube;
822 cube brick[NUM_BRICKS_ROWS * NUM_BRICKS_COLS];
824 typedef struct balls
826 /* pos_x and y store the current center position of the ball */
827 int pos_x;
828 int pos_y;
829 /* tempx and tempy store an absolute position the ball should be in. If
830 * they are equal to 0, they are not used when positioning the ball.
832 int tempx;
833 int tempy;
834 /* speedx and speedy store the current speed of the ball */
835 int speedx;
836 int speedy;
837 bool glue; /* Is the ball stuck to the paddle? */
838 } balls;
840 balls ball[MAX_BALLS];
842 typedef struct sfire {
843 int top; /* This stores the fire y position, it is a fixed point num */
844 int x_pos; /* This stores the fire x position, it is a whole number */
845 } sfire;
846 sfire fire[MAX_FIRES];
848 #define CONFIG_FILE_NAME "brickmania.cfg"
849 #define SAVE_FILE PLUGIN_GAMES_DIR "/brickmania.save"
850 #define HIGH_SCORE PLUGIN_GAMES_DIR "/brickmania.score"
851 #define NUM_SCORES 5
853 static struct configdata config[] = {
854 {TYPE_INT, 0, 1, { .int_p = &difficulty }, "difficulty", NULL},
857 struct highscore highest[NUM_SCORES];
859 typedef struct point
861 int x;
862 int y;
863 } point;
865 typedef struct line
867 point p1;
868 point p2;
869 } line;
872 * check_lines:
873 * This is based off an explanation and expanded math presented by Paul Bourke:
874 * http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
876 * It takes two lines as inputs and returns 1 if they intersect, 0 if they do
877 * not. hitp returns the point where the two lines intersected.
879 * This function expects fixed point inputs with a precision of 3. When a
880 * collision occurs hitp is updated with a fixed point location (precision 3)
881 * where the collision happened. The internal calculations are fixed
882 * point with a 7 bit fractional precision.
884 * If you choose 10 bits of precision a screen size of about 640x480 is the
885 * largest this can go. 7 bits allows for an accurate intersection calculation
886 * with a line length of about 64 and a rougher line lenght of 128 which is
887 * larger than any target currently needs (the pad is the longest line and it
888 * only needs an accuracy of 2^4 at most to figure out which section of the pad
889 * the ball hit). A precision of 7 gives breathing room for larger screens.
890 * Longer line sizes that need accurate intersection points will need more
891 * precision, but will decrease the maximum screen resolution.
894 #define LINE_PREC 7
895 int check_lines(line *line1, line *line2, point *hitp)
897 /* Introduction:
898 * This code is based on the solution of these two input equations:
899 * Pa = P1 + ua (P2-P1)
900 * Pb = P3 + ub (P4-P3)
902 * Where line one is composed of points P1 and P2 and line two is composed
903 * of points P3 and P4.
905 * ua/b is the fractional value you can multiply the x and y legs of the
906 * triangle formed by each line to find a point on the line.
908 * The two equations can be expanded to their x/y components:
909 * Pa.x = p1.x + ua(p2.x - p1.x)
910 * Pa.y = p1.y + ua(p2.y - p1.y)
912 * Pb.x = p3.x + ub(p4.x - p3.x)
913 * Pb.y = p3.y + ub(p4.y - p3.y)
915 * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
916 * up with two equations (one for x and one for y):
918 * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
919 * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
921 * ua and ub can then be individually solved for. This results in the
922 * equations used in the following code.
925 /* Denominator for ua and ub are the same so store this calculation */
926 int d = FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p2.x-line1->p1.x))
927 -FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p2.y-line1->p1.y));
929 /* n_a and n_b are calculated as seperate values for readability */
930 int n_a = FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p1.y-line2->p1.y))
931 -FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p1.x-line2->p1.x));
933 int n_b = FIXED3_MUL((line1->p2.x - line1->p1.x),(line1->p1.y-line2->p1.y))
934 -FIXED3_MUL((line1->p2.y - line1->p1.y),(line1->p1.x-line2->p1.x));
936 /* Make sure there is not a division by zero - this also indicates that
937 * the lines are parallel.
939 * If n_a and n_b were both equal to zero the lines would be on top of each
940 * other (coincidental). This check is not done because it is not
941 * necessary for this implementation (the parallel check accounts for this).
943 if(d == 0)
944 return 0;
946 /* Calculate the intermediate fractional point that the lines potentially
947 * intersect.
949 int ua = (n_a << LINE_PREC)/d;
950 int ub = (n_b << LINE_PREC)/d;
952 /* The fractional point will be between 0 and 1 inclusive if the lines
953 * intersect. If the fractional calculation is larger than 1 or smaller
954 * than 0 the lines would need to be longer to intersect.
956 if(ua >=0 && ua <= (1<<LINE_PREC) && ub >= 0 && ub <= (1<<LINE_PREC))
958 hitp->x = line1->p1.x + ((ua * (line1->p2.x - line1->p1.x))>>LINE_PREC);
959 hitp->y = line1->p1.y + ((ua * (line1->p2.y - line1->p1.y))>>LINE_PREC);
960 return 1;
962 return 0;
965 static void brickmania_init_game(bool new_game)
967 int i,j;
969 pad_pos_x = GAMESCREEN_WIDTH/2 - PAD_WIDTH/2;
971 for(i=0;i<MAX_BALLS;i++)
973 ball[i].speedx = 0;
974 ball[i].speedy = 0;
975 ball[i].tempy = 0;
976 ball[i].tempx = 0;
977 ball[i].pos_y = ON_PAD_POS_Y;
978 ball[i].pos_x = GAMESCREEN_WIDTH/2;
979 ball[i].glue = false;
982 used_balls = 1;
983 game_state = ST_READY;
984 pad_type = PLAIN;
985 pad_width = PAD_WIDTH;
986 flip_sides = false;
987 flip_sides_delay = FLIP_SIDES_DELAY;
989 if (new_game) {
990 brick_on_board=0;
991 /* add one life per achieved level */
992 if (difficulty==EASY && life<2) {
993 score-=100;
994 life++;
998 for(i=0;i<MAX_FIRES;i++) {
999 /* No fire should be active */
1000 fire[i].top=-1;
1003 for(i=0;i<NUM_BRICKS_ROWS;i++) {
1004 for(j=0;j<NUM_BRICKS_COLS;j++) {
1005 int bnum = i*NUM_BRICKS_COLS+j;
1006 brick[bnum].poweruse = false;
1007 if (new_game) {
1008 brick[bnum].power=rb->rand()%25;
1009 /* +8 make the game with less powerups */
1011 brick[bnum].hits=levels[level][i][j]>=10?
1012 levels[level][i][j]/16-1:0;
1013 brick[bnum].hiteffect=0;
1014 brick[bnum].powertop = TOPMARGIN + i*BRICK_HEIGHT;
1015 brick[bnum].used=!(levels[level][i][j]==0);
1016 brick[bnum].color=(levels[level][i][j]>=10?
1017 levels[level][i][j]%16:
1018 levels[level][i][j])-1;
1019 if (levels[level][i][j]!=0)
1020 brick_on_board++;
1026 static void brickmania_loadgame(void)
1028 int fd;
1030 resume = false;
1032 /* open game file */
1033 fd = rb->open(SAVE_FILE, O_RDONLY);
1034 if(fd < 0) return;
1036 /* read in saved game */
1037 if((rb->read(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1038 (rb->read(fd, &life, sizeof(life)) <= 0) ||
1039 (rb->read(fd, &game_state, sizeof(game_state)) <= 0) ||
1040 (rb->read(fd, &pad_type, sizeof(pad_type)) <= 0) ||
1041 (rb->read(fd, &score, sizeof(score)) <= 0) ||
1042 (rb->read(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1043 (rb->read(fd, &level, sizeof(level)) <= 0) ||
1044 (rb->read(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1045 (rb->read(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1046 (rb->read(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1047 (rb->read(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1048 (rb->read(fd, &brick, sizeof(brick)) <= 0) ||
1049 (rb->read(fd, &ball, sizeof(ball)) <= 0) ||
1050 (rb->read(fd, &fire, sizeof(fire)) <= 0))
1052 rb->splash(HZ/2, "Failed to load game");
1054 else
1056 vscore = score;
1057 resume = true;
1060 rb->close(fd);
1062 return;
1065 static void brickmania_savegame(void)
1067 int fd;
1069 /* write out the game state to the save file */
1070 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
1071 if(fd < 0) return;
1073 if ((rb->write(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1074 (rb->write(fd, &life, sizeof(life)) <= 0) ||
1075 (rb->write(fd, &game_state, sizeof(game_state)) <= 0) ||
1076 (rb->write(fd, &pad_type, sizeof(pad_type)) <= 0) ||
1077 (rb->write(fd, &score, sizeof(score)) <= 0) ||
1078 (rb->write(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1079 (rb->write(fd, &level, sizeof(level)) <= 0) ||
1080 (rb->write(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1081 (rb->write(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1082 (rb->write(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1083 (rb->write(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1084 (rb->write(fd, &brick, sizeof(brick)) <= 0) ||
1085 (rb->write(fd, &ball, sizeof(ball)) <= 0) ||
1086 (rb->write(fd, &fire, sizeof(fire)) <= 0))
1088 rb->close(fd);
1089 rb->remove(SAVE_FILE);
1090 rb->splash(HZ/2, "Failed to save game");
1091 return;
1094 rb->close(fd);
1097 /* brickmania_sleep timer counting the score */
1098 static void brickmania_sleep(int secs)
1100 bool done=false;
1101 char s[20];
1102 int count=0;
1103 int sw, w;
1105 while (!done)
1107 if (count == 0)
1108 count = *rb->current_tick + HZ*secs;
1109 if ( (TIME_AFTER(*rb->current_tick, count)) && (vscore == score) )
1110 done = true;
1112 if(vscore != score)
1114 if (vscore<score)
1115 vscore++;
1116 if (vscore>score)
1117 vscore--;
1118 rb->snprintf(s, sizeof(s), "%d", vscore);
1119 rb->lcd_getstringsize(s, &sw, &w);
1120 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1121 rb->lcd_update_rect(0,0,LCD_WIDTH,w+2);
1123 rb->yield();
1127 static int brickmania_help(void)
1129 #define WORDS (sizeof help_text / sizeof (char*))
1130 static char *help_text[] = {
1131 "Brickmania", "", "Aim", "",
1132 "Destroy", "all", "the", "bricks", "by", "bouncing",
1133 "the", "ball", "of", "them", "using", "the", "paddle.", "", "",
1134 "Controls", "",
1135 #if CONFIG_KEYPAD == COWON_D2_PAD
1136 "- & +:",
1137 #else
1138 "< & >:",
1139 #endif
1140 "Moves", "the", "paddle", "",
1141 #if CONFIG_KEYPAD == ONDIO_PAD
1142 "MENU:",
1143 #elif (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
1144 "PLAY:",
1145 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
1146 "NAVI:",
1147 #elif CONFIG_KEYPAD == COWON_D2_PAD
1148 "MENU:",
1149 #else
1150 "SELECT:",
1151 #endif
1152 "Releases", "the", "ball/Fire!", "",
1153 #if CONFIG_KEYPAD == IAUDIO_M3_PAD
1154 "REC:",
1155 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
1156 (CONFIG_KEYPAD == CREATIVEZVM_PAD)
1157 "BACK:",
1158 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1159 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1160 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1161 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1162 "MENU:",
1163 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
1164 (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
1165 (CONFIG_KEYPAD == ONDIO_PAD) || \
1166 (CONFIG_KEYPAD == RECORDER_PAD) || \
1167 (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
1168 "STOP:",
1169 #else
1170 "POWER:",
1171 #endif
1172 "Returns", "to", "menu", "", "",
1173 "Specials", "",
1174 "N", "Normal:", "returns", "paddle", "to", "normal", "",
1175 "D", "DIE!:", "loses", "a", "life", "",
1176 "L", "Life:", "gains", "a", "life/power", "up", "",
1177 "F", "Fire:", "allows", "you", "to", "shoot", "bricks", "",
1178 "G", "Glue:", "ball", "sticks", "to", "paddle", "",
1179 "B", "Ball:", "generates", "another", "ball", "",
1180 "FL", "Flip:", "flips", "left / right", "movement", "",
1181 "<->", "or", "<E>:", "enlarges", "the", "paddle", "",
1182 ">-<", "or", ">S<:", "shrinks", "the", "paddle", "",
1184 static struct style_text formation[]={
1185 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1186 { 2, C_RED },
1187 { 19, C_RED },
1188 { 37, C_RED },
1189 { 39, C_BLUE },
1190 { 46, C_RED },
1191 { 52, C_GREEN },
1192 { 59, C_ORANGE },
1193 { 67, C_GREEN },
1194 { 74, C_YELLOW },
1195 { 80, C_RED },
1196 { -1, 0 }
1198 int button;
1200 rb->lcd_setfont(FONT_UI);
1201 #ifdef HAVE_LCD_COLOR
1202 rb->lcd_set_background(LCD_BLACK);
1203 rb->lcd_set_foreground(LCD_WHITE);
1204 #endif
1206 if (display_text(WORDS, help_text, formation, NULL))
1207 return 1;
1208 do {
1209 button = rb->button_get(true);
1210 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
1211 return 1;
1213 } while( ( button == BUTTON_NONE )
1214 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1215 rb->lcd_setfont(FONT_SYSFIXED);
1216 return 0;
1219 static int brickmania_menu_cb(int action, const struct menu_item_ex *this_item)
1221 int i = ((intptr_t)this_item);
1222 if(action == ACTION_REQUEST_MENUITEM
1223 && !resume && (i==0 || i==6))
1224 return ACTION_EXIT_MENUITEM;
1225 return action;
1228 static int brickmania_menu(void)
1230 int selected = 0;
1232 static struct opt_items options[] = {
1233 { "Easy", -1 },
1234 { "Normal", -1 },
1237 #ifdef HAVE_TOUCHSCREEN
1238 /* Entering Menu, set the touchscreen to the global setting */
1239 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
1240 #endif
1242 MENUITEM_STRINGLIST(main_menu, "Brickmania Menu", brickmania_menu_cb,
1243 "Resume Game", "Start New Game",
1244 "Difficulty", "Help", "High Scores",
1245 "Playback Control",
1246 "Quit without Saving", "Quit");
1248 rb->button_clear_queue();
1249 while (true) {
1250 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1251 case 0:
1252 if(game_state!=ST_READY)
1253 game_state = ST_PAUSE;
1254 if(resume_file)
1255 rb->remove(SAVE_FILE);
1256 return 0;
1257 case 1:
1258 score=0;
1259 vscore=0;
1260 life=2;
1261 level=0;
1262 brickmania_init_game(true);
1263 return 0;
1264 case 2:
1265 rb->set_option("Difficulty", &difficulty, INT,
1266 options, 2, NULL);
1267 break;
1268 case 3:
1269 if (brickmania_help())
1270 return 1;
1271 break;
1272 case 4:
1273 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
1274 break;
1275 case 5:
1276 if (playback_control(NULL))
1277 return 1;
1278 break;
1279 case 6:
1280 return 1;
1281 case 7:
1282 if (resume) {
1283 rb->splash(HZ*1, "Saving game ...");
1284 brickmania_savegame();
1286 return 1;
1287 case MENU_ATTACHED_USB:
1288 return 1;
1289 default:
1290 break;
1293 #ifdef HAVE_TOUCHSCREEN
1294 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
1295 #endif
1298 /* Find an unused fire position */
1299 static int brickmania_find_empty_fire(void)
1301 int t;
1302 for(t=0;t<MAX_FIRES;t++)
1303 if (fire[t].top < 0)
1304 return t;
1306 return 0;
1309 void brick_hit(int brick_number)
1311 if(!brick[brick_number].used)
1312 return;
1314 /* if this is a crackable brick hits starts as
1315 * greater than 0.
1317 if (brick[brick_number].hits > 0) {
1318 brick[brick_number].hits--;
1319 brick[brick_number].hiteffect++;
1320 score+=2;
1322 else {
1323 brick[brick_number].used=false;
1324 /* Was there a powerup on the brick? */
1325 if (brick[brick_number].power<NUMBER_OF_POWERUPS) {
1326 /* Activate the powerup */
1327 brick[brick_number].poweruse = true;
1329 brick_on_board--;
1330 score+=8;
1334 static int brickmania_game_loop(void)
1336 int j,i,k;
1337 int sw;
1338 char s[30];
1339 int sec_count=0;
1340 int end;
1342 /* pad_line used for powerup/ball checks */
1343 line pad_line;
1344 /* This is used for various lines that are checked (ball and powerup) */
1345 line misc_line;
1347 /* This stores the point that the two lines intersected in a test */
1348 point pt_hit;
1350 if (brickmania_menu()) {
1351 return 1;
1353 resume = false;
1354 resume_file = false;
1356 #ifdef HAVE_LCD_COLOR
1357 rb->lcd_set_background(LCD_BLACK);
1358 rb->lcd_set_foreground(LCD_WHITE);
1359 rb->lcd_set_drawmode(DRMODE_SOLID);
1360 rb->lcd_clear_display();
1361 #endif
1363 while(true) {
1364 /* Convert CYCLETIME (in ms) to HZ */
1365 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1367 if (life >= 0) {
1368 rb->lcd_clear_display();
1370 if (flip_sides)
1372 if (TIME_AFTER(*rb->current_tick, sec_count))
1374 sec_count=*rb->current_tick+HZ;
1375 if (flip_sides_delay!=0)
1376 flip_sides_delay--;
1377 else
1378 flip_sides=false;
1380 rb->snprintf(s, sizeof(s), "%d", flip_sides_delay);
1381 rb->lcd_getstringsize(s, &sw, NULL);
1382 rb->lcd_putsxy(LCD_WIDTH/2-2, INT3(STRINGPOS_FLIP), s);
1385 /* write life num */
1386 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1387 rb->snprintf(s, sizeof(s), "L:%d", life);
1388 #else
1389 rb->snprintf(s, sizeof(s), "Life: %d", life);
1390 #endif
1391 rb->lcd_putsxy(0, 0, s);
1393 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1394 rb->snprintf(s, sizeof(s), "L%d", level+1);
1395 #else
1396 rb->snprintf(s, sizeof(s), "Level %d", level+1);
1397 #endif
1399 rb->lcd_getstringsize(s, &sw, NULL);
1400 rb->lcd_putsxy(LCD_WIDTH-sw, 0, s);
1402 if (vscore<score) vscore++;
1403 rb->snprintf(s, sizeof(s), "%d", vscore);
1404 rb->lcd_getstringsize(s, &sw, NULL);
1405 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1407 /* continue game */
1408 if (game_state == ST_PAUSE)
1410 rb->snprintf(s, sizeof(s), CONTINUE_TEXT);
1411 rb->lcd_getstringsize(s, &sw, NULL);
1412 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_NAVI), s);
1414 sec_count=*rb->current_tick+HZ;
1417 /* draw the ball */
1418 for(i=0;i<used_balls;i++)
1419 rb->lcd_bitmap(brickmania_ball,
1420 INT3(ball[i].pos_x - HALFBALL),
1421 INT3(ball[i].pos_y - HALFBALL),
1422 INT3(BALL), INT3(BALL));
1424 if (brick_on_board==0)
1425 brick_on_board--;
1427 /* if the pad is fire */
1428 for(i=0; i<MAX_FIRES; i++)
1430 /* If the projectile is active (>0 inactive) */
1431 if (fire[i].top >= 0)
1433 if (game_state!=ST_PAUSE)
1434 fire[i].top -= SPEED_FIRE;
1435 /* Draw the projectile */
1436 rb->lcd_vline( INT3(fire[i].x_pos), INT3(fire[i].top),
1437 INT3(fire[i].top + FIRE_LENGTH));
1441 /* Setup the pad line-later used in intersection test */
1442 pad_line.p1.x = pad_pos_x;
1443 pad_line.p1.y = PAD_POS_Y;
1445 pad_line.p2.x = pad_pos_x + pad_width;
1446 pad_line.p2.y = PAD_POS_Y;
1448 /* handle all of the bricks/powerups */
1449 for (i=0; i<NUM_BRICKS_ROWS; i++)
1451 for (j=0; j<NUM_BRICKS_COLS ;j++)
1453 int brickx;
1454 int bnum = i*NUM_BRICKS_COLS+j;
1456 /* This brick is not really a brick, it is a powerup if
1457 * poweruse is set. Perform appropriate powerup checks.
1459 if(brick[bnum].poweruse)
1461 brickx = LEFTMARGIN + j*BRICK_WIDTH +
1462 (BRICK_WIDTH - POWERUP_WIDTH) / 2;
1464 /* Update powertop if the game is not paused */
1465 if (game_state!=ST_PAUSE)
1466 brick[bnum].powertop+=SPEED_POWER;
1468 /* Draw the powerup */
1469 rb->lcd_bitmap_part(brickmania_powerups,0,
1470 INT3(POWERUP_HEIGHT)*brick[bnum].power,
1471 STRIDE( SCREEN_MAIN,
1472 BMPWIDTH_brickmania_powerups,
1473 BMPHEIGHT_brickmania_powerups),
1474 INT3(brickx),
1475 INT3(brick[bnum].powertop),
1476 INT3(POWERUP_WIDTH),
1477 INT3(POWERUP_HEIGHT) );
1479 /* Use misc_line to check if the center of the powerup
1480 * hit the paddle.
1482 misc_line.p1.x = brickx + (POWERUP_WIDTH >> 1);
1483 misc_line.p1.y = brick[bnum].powertop + POWERUP_HEIGHT;
1485 misc_line.p2.x = brickx + (POWERUP_WIDTH >> 1);
1486 misc_line.p2.y = SPEED_POWER + brick[bnum].powertop +
1487 POWERUP_HEIGHT;
1489 /* Check if the powerup will hit the paddle */
1490 if ( check_lines(&misc_line, &pad_line, &pt_hit) )
1492 switch(brick[bnum].power) {
1493 case 0: /* Extra Life */
1494 life++;
1495 score += 50;
1496 break;
1497 case 1: /* Loose a life */
1498 life--;
1499 if (life>=0)
1501 brickmania_init_game(false);
1502 brickmania_sleep(2);
1504 break;
1505 case 2: /* Make the paddle sticky */
1506 score += 34;
1507 pad_type = STICKY;
1508 break;
1509 case 3: /* Give the paddle shooter */
1510 score += 47;
1511 pad_type = SHOOTER;
1512 for(k=0;k<used_balls;k++)
1513 ball[k].glue=false;
1514 break;
1515 case 4: /* Normal brick */
1516 score += 23;
1517 pad_type = PLAIN;
1518 for(k=0;k<used_balls;k++)
1519 ball[k].glue=false;
1520 flip_sides=false;
1522 pad_pos_x += (pad_width-PAD_WIDTH)/2;
1523 pad_width = PAD_WIDTH;
1524 break;
1525 case 5: /* Flip the paddle */
1526 score += 23;
1527 sec_count = *rb->current_tick+HZ;
1528 flip_sides_delay = FLIP_SIDES_DELAY;
1529 flip_sides = true;
1530 break;
1531 case 6: /* Extra Ball */
1532 score += 23;
1533 if(used_balls<MAX_BALLS)
1535 /* Set the speed */
1536 if(rb->rand()%2 == 0)
1537 ball[used_balls].speedx=-SPEED_4Q_X;
1538 else
1539 ball[used_balls].speedx= SPEED_4Q_X;
1541 ball[used_balls].speedy= SPEED_4Q_Y;
1543 /* Ball is not glued */
1544 ball[used_balls].glue= false;
1545 used_balls++;
1547 break;
1548 case 7: /* Long paddle */
1549 score+=23;
1550 if (pad_width==PAD_WIDTH)
1552 pad_width = LONG_PAD_WIDTH;
1553 pad_pos_x -= (LONG_PAD_WIDTH -
1554 PAD_WIDTH)/2;
1556 else if (pad_width==SHORT_PAD_WIDTH)
1558 pad_width = PAD_WIDTH;
1559 pad_pos_x-=(PAD_WIDTH-
1560 SHORT_PAD_WIDTH)/2;
1563 if (pad_pos_x < 0)
1564 pad_pos_x = 0;
1565 else if(pad_pos_x + pad_width >
1566 GAMESCREEN_WIDTH)
1567 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
1568 break;
1569 case 8: /* Short Paddle */
1570 if (pad_width==PAD_WIDTH)
1572 pad_width=SHORT_PAD_WIDTH;
1573 pad_pos_x+=(PAD_WIDTH-
1574 SHORT_PAD_WIDTH)/2;
1576 else if (pad_width==LONG_PAD_WIDTH)
1578 pad_width=PAD_WIDTH;
1579 pad_pos_x+=(LONG_PAD_WIDTH-PAD_WIDTH)/2;
1581 break;
1583 /* Disable the powerup (it was picked up) */
1584 brick[bnum].poweruse = false;
1587 if (brick[bnum].powertop>PAD_POS_Y)
1589 /* Disable the powerup (it was missed) */
1590 brick[bnum].poweruse = false;
1593 /* The brick is a brick, but it may or may not be in use */
1594 else if(brick[bnum].used)
1596 /* these lines are used to describe the brick */
1597 line bot_brick, top_brick, left_brick, rght_brick;
1598 brickx = LEFTMARGIN + j*BRICK_WIDTH;
1600 /* Describe the brick for later collision checks */
1601 /* Setup the bottom of the brick */
1602 bot_brick.p1.x = brickx;
1603 bot_brick.p1.y = brick[bnum].powertop + BRICK_HEIGHT;
1605 bot_brick.p2.x = brickx + BRICK_WIDTH;
1606 bot_brick.p2.y = brick[bnum].powertop + BRICK_HEIGHT;
1608 /* Setup the top of the brick */
1609 top_brick.p1.x = brickx;
1610 top_brick.p1.y = brick[bnum].powertop;
1612 top_brick.p2.x = brickx + BRICK_WIDTH;
1613 top_brick.p2.y = brick[bnum].powertop;
1615 /* Setup the left of the brick */
1616 left_brick.p1.x = brickx;
1617 left_brick.p1.y = brick[bnum].powertop;
1619 left_brick.p2.x = brickx;
1620 left_brick.p2.y = brick[bnum].powertop + BRICK_HEIGHT;
1622 /* Setup the right of the brick */
1623 rght_brick.p1.x = brickx + BRICK_WIDTH;
1624 rght_brick.p1.y = brick[bnum].powertop;
1626 rght_brick.p2.x = brickx + BRICK_WIDTH;
1627 rght_brick.p2.y = brick[bnum].powertop + BRICK_HEIGHT;
1629 /* Check if any of the active fires hit a brick */
1630 for (k=0;k<MAX_FIRES;k++)
1632 if(fire[k].top > 0)
1634 /* Use misc_line to check if fire hit brick */
1635 misc_line.p1.x = fire[k].x_pos;
1636 misc_line.p1.y = fire[k].top;
1638 misc_line.p2.x = fire[k].x_pos;
1639 misc_line.p2.y = fire[k].top + SPEED_FIRE;
1641 /* If the fire hit the brick take care of it */
1642 if (check_lines(&misc_line, &bot_brick,
1643 &pt_hit))
1645 score+=13;
1646 /* De-activate the fire */
1647 fire[k].top=-1;
1648 brick_hit(bnum);
1653 /* Draw the brick */
1654 rb->lcd_bitmap_part(brickmania_bricks,0,
1655 INT3(BRICK_HEIGHT)*brick[bnum].color,
1656 STRIDE( SCREEN_MAIN,
1657 BMPWIDTH_brickmania_bricks,
1658 BMPHEIGHT_brickmania_bricks),
1659 INT3(brickx),
1660 INT3(brick[bnum].powertop),
1661 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1663 #ifdef HAVE_LCD_COLOR /* No transparent effect for greyscale lcds for now */
1664 if (brick[bnum].hiteffect > 0)
1665 rb->lcd_bitmap_transparent_part(brickmania_break,0,
1666 INT3(BRICK_HEIGHT)*brick[bnum].hiteffect,
1667 STRIDE( SCREEN_MAIN,
1668 BMPWIDTH_brickmania_break,
1669 BMPHEIGHT_brickmania_break),
1670 INT3(brickx),
1671 INT3(brick[bnum].powertop),
1672 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1673 #endif
1675 /* Check if any balls collided with the brick */
1676 for(k=0; k<used_balls; k++)
1678 /* Setup the ball path to describe the current ball
1679 * position and the line it makes to its next
1680 * position.
1682 misc_line.p1.x = ball[k].pos_x;
1683 misc_line.p1.y = ball[k].pos_y;
1685 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1686 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1688 /* Check to see if the ball and the bottom hit. If
1689 * the ball is moving down we don't want to
1690 * include the bottom line intersection.
1692 * The order that the sides are checked matters.
1694 * Note that tempx/tempy store the next position
1695 * that the ball should be drawn.
1697 if(ball[k].speedy <= 0 &&
1698 check_lines(&misc_line, &bot_brick, &pt_hit))
1700 ball[k].speedy = -ball[k].speedy;
1701 ball[k].tempy = pt_hit.y;
1702 ball[k].tempx = pt_hit.x;
1703 brick_hit(bnum);
1705 /* Check the top, if the ball is moving up dont
1706 * count it as a hit.
1708 else if(ball[k].speedy > 0 &&
1709 check_lines(&misc_line, &top_brick, &pt_hit))
1711 ball[k].speedy = -ball[k].speedy;
1712 ball[k].tempy = pt_hit.y;
1713 ball[k].tempx = pt_hit.x;
1714 brick_hit(bnum);
1716 /* Check the left side of the brick */
1717 else if(
1718 check_lines(&misc_line, &left_brick, &pt_hit))
1720 ball[k].speedx = -ball[k].speedx;
1721 ball[k].tempy = pt_hit.y;
1722 ball[k].tempx = pt_hit.x;
1723 brick_hit(bnum);
1725 /* Check the right side of the brick */
1726 else if(
1727 check_lines(&misc_line, &rght_brick, &pt_hit))
1729 ball[k].speedx = -ball[k].speedx;
1730 ball[k].tempy = pt_hit.y;
1731 ball[k].tempx = pt_hit.x;
1732 brick_hit(bnum);
1734 } /* for k */
1735 } /* if(used) */
1737 } /* for j */
1738 } /* for i */
1740 /* draw the paddle according to the PAD_WIDTH */
1741 if( pad_width == PAD_WIDTH ) /* Normal width */
1743 rb->lcd_bitmap_part(
1744 brickmania_pads,
1745 0, pad_type*INT3(PAD_HEIGHT),
1746 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_pads,
1747 BMPHEIGHT_brickmania_pads),
1748 INT3(pad_pos_x), INT3(PAD_POS_Y),
1749 INT3(pad_width), INT3(PAD_HEIGHT) );
1751 else if( pad_width == LONG_PAD_WIDTH ) /* Long Pad */
1753 rb->lcd_bitmap_part(
1754 brickmania_long_pads,
1755 0,pad_type*INT3(PAD_HEIGHT),
1756 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_long_pads,
1757 BMPHEIGHT_brickmania_long_pads),
1758 INT3(pad_pos_x), INT3(PAD_POS_Y),
1759 INT3(pad_width), INT3(PAD_HEIGHT) );
1761 else /* Short pad */
1763 rb->lcd_bitmap_part(
1764 brickmania_short_pads,
1765 0,pad_type*INT3(PAD_HEIGHT),
1766 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_short_pads,
1767 BMPHEIGHT_brickmania_short_pads),
1768 INT3(pad_pos_x), INT3(PAD_POS_Y),
1769 INT3(pad_width), INT3(PAD_HEIGHT) );
1772 /* If the game is not paused continue */
1773 if (game_state!=ST_PAUSE)
1775 /* Loop through all of the balls in play */
1776 for(k=0;k<used_balls;k++)
1778 line screen_edge;
1780 /* Describe the ball movement for the edge collision detection */
1781 misc_line.p1.x = ball[k].pos_x;
1782 misc_line.p1.y = ball[k].pos_y;
1784 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1785 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1787 /* Did the Ball hit the top of the screen? */
1788 screen_edge.p1.x = 0;
1789 screen_edge.p1.y = 0;
1791 screen_edge.p2.x = FIXED3(LCD_WIDTH);
1792 screen_edge.p2.y = 0;
1793 /* the test for pos_y prevents the ball from bouncing back
1794 * from _over_ the top to infinity on some rare cases */
1795 if (ball[k].pos_y > 0 &&
1796 check_lines(&misc_line, &screen_edge, &pt_hit))
1798 ball[k].tempy = pt_hit.y + 1;
1799 ball[k].tempx = pt_hit.x;
1800 /* Reverse the direction */
1801 ball[k].speedy = -ball[k].speedy;
1804 /* Player missed the ball and hit bottom of screen */
1805 if (ball[k].pos_y >= GAMESCREEN_HEIGHT)
1807 /* Player had balls to spare, so handle the removal */
1808 if (used_balls>1)
1810 /* decrease number of balls in play */
1811 used_balls--;
1812 /* Replace removed ball with the last ball */
1813 ball[k].pos_x = ball[used_balls].pos_x;
1814 ball[k].pos_y = ball[used_balls].pos_y;
1815 ball[k].speedy = ball[used_balls].speedy;
1816 ball[k].tempy = ball[used_balls].tempy;
1817 ball[k].speedx = ball[used_balls].speedx;
1818 ball[k].tempx = ball[used_balls].tempx;
1819 ball[k].glue = ball[used_balls].glue;
1821 /* Reset the last ball that was removed */
1822 ball[used_balls].speedx=0;
1823 ball[used_balls].speedy=0;
1824 ball[used_balls].tempy=0;
1825 ball[used_balls].tempx=0;
1826 ball[used_balls].pos_y=ON_PAD_POS_Y;
1827 ball[used_balls].pos_x=pad_pos_x+(pad_width/2)-2;
1829 k--;
1830 continue;
1832 else
1834 /* Player lost a life */
1835 life--;
1836 if (life>=0)
1838 /* No lives left reset game */
1839 brickmania_init_game(false);
1840 brickmania_sleep(2);
1841 rb->button_clear_queue();
1846 /* Check if the ball hit the left side */
1847 screen_edge.p1.x = 0;
1848 screen_edge.p1.y = 0;
1850 screen_edge.p2.x = 0;
1851 screen_edge.p2.y = FIXED3(LCD_HEIGHT);
1852 if ( !ball[k].glue &&
1853 check_lines(&misc_line, &screen_edge, &pt_hit))
1855 /* Reverse direction */
1856 ball[k].speedx = -ball[k].speedx;
1858 /* Re-position ball in gameboard */
1859 ball[k].tempy = pt_hit.y;
1860 ball[k].tempx = 0;
1863 /* Check if the ball hit the right side */
1864 screen_edge.p1.x = FIXED3(LCD_WIDTH);
1865 screen_edge.p1.y = 0;
1867 screen_edge.p2.x = FIXED3(LCD_WIDTH);
1868 screen_edge.p2.y = FIXED3(LCD_HEIGHT);
1869 if ( !ball[k].glue &&
1870 check_lines(&misc_line, &screen_edge, &pt_hit))
1872 /* Reverse direction */
1873 ball[k].speedx = -ball[k].speedx;
1875 /* Re-position ball in gameboard */
1876 ball[k].tempy = pt_hit.y;
1877 ball[k].tempx = FIXED3(LCD_WIDTH - 1);
1880 /* Did the ball hit the paddle? Depending on where the ball
1881 * Hit set the x/y speed appropriately.
1883 if( game_state!=ST_READY && !ball[k].glue &&
1884 check_lines(&misc_line, &pad_line, &pt_hit) )
1886 /* Re-position ball based on collision */
1887 ball[k].tempy = ON_PAD_POS_Y;
1888 ball[k].tempx = pt_hit.x;
1890 /* Calculate the ball position relative to the paddle width */
1891 int ball_repos = pt_hit.x - pad_pos_x;
1892 /* If the ball hits the right half of paddle, x speed
1893 * should be positive, if it hits the left half it
1894 * should be negative.
1896 int x_direction = -1;
1898 /* Comparisons are done with respect to 1/2 pad_width */
1899 if(ball_repos > pad_width/2)
1901 /* flip the relative position */
1902 ball_repos -= ((ball_repos - pad_width/2) << 1);
1903 /* Ball hit the right half so X speed calculations
1904 * should be positive.
1906 x_direction = 1;
1909 /* Figure out where the ball hit relative to 1/2 pad
1910 * and in divisions of 4.
1912 ball_repos = ball_repos / (pad_width/2/4);
1914 switch(ball_repos)
1916 /* Ball hit the outer edge of the paddle */
1917 case 0:
1918 ball[k].speedy = SPEED_1Q_Y;
1919 ball[k].speedx = SPEED_1Q_X * x_direction;
1920 break;
1921 /* Ball hit the next fourth of the paddle */
1922 case 1:
1923 ball[k].speedy = SPEED_2Q_Y;
1924 ball[k].speedx = SPEED_2Q_X * x_direction;
1925 break;
1926 /* Ball hit the third fourth of the paddle */
1927 case 2:
1928 ball[k].speedy = SPEED_3Q_Y;
1929 ball[k].speedx = SPEED_3Q_X * x_direction;
1930 break;
1931 /* Ball hit the fourth fourth of the paddle or dead
1932 * center.
1934 case 3:
1935 case 4:
1936 ball[k].speedy = SPEED_4Q_Y;
1937 /* Since this is the middle we don't want to
1938 * force the ball in a different direction.
1939 * Just keep it going in the same direction
1940 * with a specific speed.
1942 if(ball[k].speedx > 0)
1944 ball[k].speedx = SPEED_4Q_X;
1946 else
1948 ball[k].speedx = -SPEED_4Q_X;
1950 break;
1952 default:
1953 ball[k].speedy = SPEED_4Q_Y;
1954 break;
1957 if(pad_type == STICKY)
1959 ball[k].speedy = -ball[k].speedy;
1960 ball[k].glue=true;
1962 /* X location should not be forced since that is moved with the paddle. The Y
1963 * position should be forced to keep the ball at the paddle.
1965 ball[k].tempx = 0;
1966 ball[k].tempy = ON_PAD_POS_Y;
1970 /* Update the ball position */
1971 if (!ball[k].glue)
1973 if(ball[k].tempx)
1974 ball[k].pos_x = ball[k].tempx;
1975 else
1976 ball[k].pos_x += ball[k].speedx;
1978 if(ball[k].tempy)
1979 ball[k].pos_y = ball[k].tempy;
1980 else
1981 ball[k].pos_y += ball[k].speedy;
1983 ball[k].tempy=0;
1984 ball[k].tempx=0;
1986 } /* for k */
1989 rb->lcd_update();
1991 if (brick_on_board < 0)
1993 if (level+1<NUM_LEVELS)
1995 level++;
1996 if (difficulty==NORMAL)
1997 score+=100;
1998 brickmania_init_game(true);
1999 brickmania_sleep(2);
2000 rb->button_clear_queue();
2002 else
2004 rb->lcd_getstringsize("Congratulations!", &sw, NULL);
2005 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_CONGRATS),
2006 "Congratulations!");
2007 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
2008 rb->lcd_getstringsize("No more levels", &sw, NULL);
2009 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2010 "No more levels");
2011 #else
2012 rb->lcd_getstringsize("You have finished the game!",
2013 &sw, NULL);
2014 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2015 "You have finished the game!");
2016 #endif
2017 vscore=score;
2018 rb->lcd_update();
2019 brickmania_sleep(2);
2020 return 0;
2024 int button=rb->button_get(false);
2025 int move_button = rb->button_status();
2027 #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
2028 /* FIXME: Should probably check remote hold here */
2029 if (rb->button_hold())
2030 button = QUIT;
2031 #endif
2033 #ifdef HAVE_TOUCHSCREEN
2034 if( move_button & BUTTON_TOUCHSCREEN)
2036 int data;
2037 short touch_x, touch_y;
2038 rb->button_status_wdata(&data);
2039 touch_x = FIXED3(data >> 16);
2040 touch_y = FIXED3(data & 0xffff);
2042 if(flip_sides)
2044 pad_pos_x = GAMESCREEN_WIDTH - (touch_x + pad_width/2);
2046 else
2048 pad_pos_x = (touch_x - pad_width/2);
2051 if(pad_pos_x < 0)
2052 pad_pos_x = 0;
2053 else if(pad_pos_x + pad_width > GAMESCREEN_WIDTH)
2054 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
2055 for(k=0; k<used_balls; k++)
2056 if (game_state==ST_READY || ball[k].glue)
2057 ball[k].pos_x = pad_pos_x + pad_width/2;
2059 else
2060 #endif
2062 int button_right, button_left;
2063 #ifdef ALTRIGHT
2064 button_right = move_button & (RIGHT | ALTRIGHT);
2065 button_left = move_button & (LEFT | ALTLEFT);
2066 #else
2067 button_right =((move_button & RIGHT)|| SCROLL_FWD(button));
2068 button_left =((move_button & LEFT) ||SCROLL_BACK(button));
2069 #endif
2070 if ((game_state==ST_PAUSE) && (button_right || button_left))
2071 continue;
2072 if ((button_right && !flip_sides) ||
2073 (button_left && flip_sides))
2075 if (pad_pos_x+SPEED_PAD+pad_width > GAMESCREEN_WIDTH)
2077 for(k=0;k<used_balls;k++)
2078 if (game_state==ST_READY || ball[k].glue)
2079 ball[k].pos_x += GAMESCREEN_WIDTH-pad_pos_x -
2080 pad_width;
2081 pad_pos_x += GAMESCREEN_WIDTH - pad_pos_x - pad_width;
2083 else {
2084 for(k=0;k<used_balls;k++)
2085 if ((game_state==ST_READY || ball[k].glue))
2086 ball[k].pos_x+=SPEED_PAD;
2087 pad_pos_x+=SPEED_PAD;
2090 else if ((button_left && !flip_sides) ||
2091 (button_right && flip_sides))
2093 if (pad_pos_x-SPEED_PAD < 0)
2095 for(k=0;k<used_balls;k++)
2096 if (game_state==ST_READY || ball[k].glue)
2097 ball[k].pos_x-=pad_pos_x;
2098 pad_pos_x -= pad_pos_x;
2100 else
2102 for(k=0;k<used_balls;k++)
2103 if (game_state==ST_READY || ball[k].glue)
2104 ball[k].pos_x-=SPEED_PAD;
2105 pad_pos_x-=SPEED_PAD;
2110 switch(button)
2112 #if defined(HAVE_TOUCHSCREEN)
2113 case (BUTTON_REL | BUTTON_TOUCHSCREEN):
2114 #endif
2115 case UP:
2116 case SELECT:
2117 #ifdef ALTSELECT
2118 case ALTSELECT:
2119 #endif
2120 if (game_state==ST_READY)
2122 /* Initialize used balls starting speed */
2123 for(k=0 ; k < used_balls ; k++)
2125 ball[k].speedy = SPEED_4Q_Y;
2126 if(pad_pos_x + (pad_width/2) >= GAMESCREEN_WIDTH/2)
2128 ball[k].speedx = SPEED_4Q_X;
2130 else
2132 ball[k].speedx = -SPEED_4Q_X;
2135 game_state=ST_START;
2137 else if (game_state==ST_PAUSE)
2139 game_state=ST_START;
2141 else if (pad_type == STICKY)
2143 for(k=0;k<used_balls;k++)
2145 if (ball[k].glue)
2147 ball[k].glue=false;
2148 ball[k].speedy = -ball[k].speedy;
2152 else if (pad_type == SHOOTER)
2154 k=brickmania_find_empty_fire();
2155 fire[k].top=PAD_POS_Y - FIRE_LENGTH;
2156 fire[k].x_pos = pad_pos_x + 1; /* Add 1 for edge */
2158 k=brickmania_find_empty_fire();
2159 fire[k].top=PAD_POS_Y - FIRE_LENGTH;
2160 fire[k].x_pos = pad_pos_x + pad_width -1; /* Sub1 edge*/
2162 break;
2163 #ifdef RC_QUIT
2164 case RC_QUIT:
2165 #endif
2166 case QUIT:
2167 resume = true;
2168 return 0;
2169 break;
2171 default:
2172 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
2173 return 1;
2174 break;
2177 else
2179 #ifdef HAVE_LCD_COLOR
2180 rb->lcd_bitmap_transparent(brickmania_gameover,
2181 (LCD_WIDTH - INT3(GAMEOVER_WIDTH))/2,
2182 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2183 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT));
2184 #else /* greyscale and mono */
2185 rb->lcd_bitmap(brickmania_gameover,(LCD_WIDTH -
2186 INT3(GAMEOVER_WIDTH))/2,
2187 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2188 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT) );
2189 #endif
2190 rb->lcd_update();
2191 brickmania_sleep(2);
2192 return 0;
2195 /* Game always needs to yield for other threads */
2196 rb->yield();
2198 /* Sleep for a bit if there is time to spare */
2199 if (TIME_BEFORE(*rb->current_tick, end))
2200 rb->sleep(end-*rb->current_tick);
2202 return 0;
2205 /* this is the plugin entry point */
2206 enum plugin_status plugin_start(const void* parameter)
2208 (void)parameter;
2209 int last_difficulty;
2211 highscore_load(HIGH_SCORE,highest,NUM_SCORES);
2212 configfile_load(CONFIG_FILE_NAME,config,1,0);
2213 last_difficulty = difficulty;
2215 #ifdef HAVE_TOUCHSCREEN
2216 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
2217 #endif
2219 rb->lcd_setfont(FONT_SYSFIXED);
2220 #if LCD_DEPTH > 1
2221 rb->lcd_set_backdrop(NULL);
2222 #endif
2223 /* Turn off backlight timeout */
2224 backlight_force_on(); /* backlight control in lib/helper.c */
2226 /* now go ahead and have fun! */
2227 rb->srand( *rb->current_tick );
2228 brickmania_loadgame();
2229 resume_file = resume;
2230 while(!brickmania_game_loop())
2232 if(!resume)
2234 int position = highscore_update(score, level+1, "", highest,
2235 NUM_SCORES);
2236 if (position == 0)
2238 rb->splash(HZ*2, "New High Score");
2241 if (position != -1)
2243 highscore_show(position, highest, NUM_SCORES, true);
2245 else
2247 brickmania_sleep(3);
2252 highscore_save(HIGH_SCORE,highest,NUM_SCORES);
2253 if(last_difficulty != difficulty)
2254 configfile_save(CONFIG_FILE_NAME,config,1,0);
2255 /* Restore user's original backlight setting */
2256 rb->lcd_setfont(FONT_UI);
2257 /* Turn on backlight timeout (revert to settings) */
2258 backlight_use_settings(); /* backlight control in lib/helper.c */
2260 return PLUGIN_OK;