use same variable/macro name for highscore among plugins.
[kugel-rb.git] / apps / plugins / brickmania.c
blobf932e4563a051bfa931bbabbef4dd6e80e1a2fd3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005, 2006 Ben Basha (Paprica)
11 * Copyright (C) 2009 Karl Kurbjun
12 * check_lines is based off an explanation and expanded math presented by Paul
13 * Bourke: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
25 #include "plugin.h"
26 #include "lib/configfile.h"
27 #include "lib/display_text.h"
28 #include "lib/helper.h"
29 #include "lib/highscore.h"
30 #include "lib/playback_control.h"
32 #include "pluginbitmaps/brickmania_pads.h"
33 #include "pluginbitmaps/brickmania_short_pads.h"
34 #include "pluginbitmaps/brickmania_long_pads.h"
35 #include "pluginbitmaps/brickmania_bricks.h"
36 #include "pluginbitmaps/brickmania_powerups.h"
37 #include "pluginbitmaps/brickmania_ball.h"
38 #include "pluginbitmaps/brickmania_gameover.h"
40 #ifdef HAVE_LCD_COLOR /* currently no transparency for non-colour */
41 #include "pluginbitmaps/brickmania_break.h"
42 #endif
44 PLUGIN_HEADER
49 * Keymaps
53 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
54 (CONFIG_KEYPAD == IRIVER_H300_PAD)
55 #define CONTINUE_TEXT "Press NAVI To Continue"
56 #define QUIT BUTTON_OFF
57 #define LEFT BUTTON_LEFT
58 #define RIGHT BUTTON_RIGHT
59 #define SELECT BUTTON_SELECT
60 #define UP BUTTON_UP
61 #define DOWN BUTTON_DOWN
62 #define RC_QUIT BUTTON_RC_STOP
64 #elif CONFIG_KEYPAD == ONDIO_PAD
65 #define CONTINUE_TEXT "MENU To Continue"
66 #define QUIT BUTTON_OFF
67 #define LEFT BUTTON_LEFT
68 #define RIGHT BUTTON_RIGHT
69 #define SELECT BUTTON_MENU
70 #define UP BUTTON_UP
71 #define DOWN BUTTON_DOWN
73 #elif CONFIG_KEYPAD == RECORDER_PAD
74 #define QUIT BUTTON_OFF
75 #define LEFT BUTTON_LEFT
76 #define RIGHT BUTTON_RIGHT
77 #define SELECT BUTTON_PLAY
78 #define UP BUTTON_UP
79 #define DOWN BUTTON_DOWN
81 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
82 #define QUIT BUTTON_OFF
83 #define LEFT BUTTON_LEFT
84 #define RIGHT BUTTON_RIGHT
85 #define SELECT BUTTON_SELECT
86 #define UP BUTTON_UP
87 #define DOWN BUTTON_DOWN
89 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
90 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
91 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
92 #define QUIT BUTTON_MENU
93 #define LEFT BUTTON_LEFT
94 #define RIGHT BUTTON_RIGHT
95 #define SELECT BUTTON_SELECT
96 #define UP BUTTON_SCROLL_BACK
97 #define DOWN BUTTON_SCROLL_FWD
98 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
99 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
101 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
102 #define QUIT BUTTON_POWER
103 #define LEFT BUTTON_LEFT
104 #define RIGHT BUTTON_RIGHT
105 #define SELECT BUTTON_SELECT
106 #define UP BUTTON_UP
107 #define DOWN BUTTON_DOWN
109 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
110 #define QUIT BUTTON_POWER
111 #define LEFT BUTTON_LEFT
112 #define RIGHT BUTTON_RIGHT
113 #define SELECT BUTTON_PLAY
114 #define UP BUTTON_UP
115 #define DOWN BUTTON_DOWN
117 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
118 #define QUIT BUTTON_POWER
119 #define LEFT BUTTON_LEFT
120 #define RIGHT BUTTON_RIGHT
121 #define SELECT BUTTON_SELECT
122 #define UP BUTTON_UP
123 #define DOWN BUTTON_DOWN
124 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
125 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
128 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
129 #define QUIT (BUTTON_HOME|BUTTON_REPEAT)
130 #define LEFT BUTTON_LEFT
131 #define RIGHT BUTTON_RIGHT
132 #define SELECT BUTTON_SELECT
133 #define UP BUTTON_UP
134 #define DOWN BUTTON_DOWN
136 #define SCROLL_FWD(x) ((x) & BUTTON_SCROLL_FWD)
137 #define SCROLL_BACK(x) ((x) & BUTTON_SCROLL_BACK)
140 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
141 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
142 CONFIG_KEYPAD == SANSA_M200_PAD
143 #define QUIT BUTTON_POWER
144 #define LEFT BUTTON_LEFT
145 #define RIGHT BUTTON_RIGHT
146 #define ALTLEFT BUTTON_VOL_DOWN
147 #define ALTRIGHT BUTTON_VOL_UP
148 #define SELECT BUTTON_SELECT
149 #define UP BUTTON_UP
150 #define DOWN BUTTON_DOWN
152 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
153 #define QUIT BUTTON_POWER
154 #define LEFT BUTTON_LEFT
155 #define RIGHT BUTTON_RIGHT
156 #define SELECT BUTTON_PLAY
157 #define UP BUTTON_SCROLL_UP
158 #define DOWN BUTTON_SCROLL_DOWN
160 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
161 #define QUIT BUTTON_BACK
162 #define LEFT BUTTON_LEFT
163 #define RIGHT BUTTON_RIGHT
164 #define SELECT BUTTON_SELECT
165 #define UP BUTTON_UP
166 #define DOWN BUTTON_DOWN
168 #elif (CONFIG_KEYPAD == MROBE100_PAD)
169 #define QUIT BUTTON_POWER
170 #define LEFT BUTTON_LEFT
171 #define RIGHT BUTTON_RIGHT
172 #define SELECT BUTTON_SELECT
173 #define UP BUTTON_UP
174 #define DOWN BUTTON_DOWN
176 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
177 #define CONTINUE_TEXT "PLAY To Continue"
178 #define QUIT BUTTON_RC_REC
179 #define LEFT BUTTON_RC_REW
180 #define RIGHT BUTTON_RC_FF
181 #define SELECT BUTTON_RC_PLAY
182 #define UP BUTTON_RC_VOL_UP
183 #define DOWN BUTTON_RC_VOL_DOWN
184 #define RC_QUIT BUTTON_REC
186 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
187 #define QUIT BUTTON_BACK
188 #define LEFT BUTTON_LEFT
189 #define RIGHT BUTTON_RIGHT
190 #define SELECT BUTTON_SELECT
191 #define UP BUTTON_UP
192 #define DOWN BUTTON_DOWN
194 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
195 #define QUIT BUTTON_POWER
196 #define LEFT BUTTON_LEFT
197 #define RIGHT BUTTON_RIGHT
198 #define SELECT BUTTON_SELECT
199 #define UP BUTTON_UP
200 #define DOWN BUTTON_DOWN
202 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
203 #define QUIT BUTTON_POWER
204 #define LEFT BUTTON_PREV
205 #define RIGHT BUTTON_NEXT
206 #define SELECT BUTTON_PLAY
207 #define UP BUTTON_UP
208 #define DOWN BUTTON_DOWN
210 #elif CONFIG_KEYPAD == COWON_D2_PAD
211 #define CONTINUE_TEXT "MENU To Continue"
212 #define QUIT BUTTON_POWER
213 #define LEFT BUTTON_MINUS
214 #define RIGHT BUTTON_PLUS
215 #define SELECT BUTTON_MENU
217 #elif CONFIG_KEYPAD == ONDAVX747_PAD
218 #define QUIT BUTTON_POWER
219 #define LEFT BUTTON_VOL_DOWN
220 #define RIGHT BUTTON_VOL_UP
221 #define SELECT BUTTON_MENU
222 #elif CONFIG_KEYPAD == ONDAVX777_PAD
223 #define QUIT BUTTON_POWER
225 #elif CONFIG_KEYPAD == MROBE500_PAD
226 #define QUIT BUTTON_POWER
228 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
229 #define QUIT BUTTON_FFWD
230 #define SELECT BUTTON_PLAY
231 #define LEFT BUTTON_LEFT
232 #define RIGHT BUTTON_RIGHT
233 #define UP BUTTON_UP
234 #define DOWN BUTTON_DOWN
236 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
237 #define QUIT BUTTON_REC
238 #define LEFT BUTTON_PREV
239 #define RIGHT BUTTON_NEXT
240 #define ALTLEFT BUTTON_MENU
241 #define ALTRIGHT BUTTON_PLAY
242 #define SELECT BUTTON_OK
243 #define UP BUTTON_UP
244 #define DOWN BUTTON_DOWN
246 #else
247 #error No keymap defined!
248 #endif
250 #ifdef HAVE_TOUCHSCREEN
251 #ifdef LEFT
252 #define ALTLEFT BUTTON_BOTTOMLEFT
253 #else
254 #define LEFT BUTTON_BOTTOMLEFT
255 #endif
256 #ifdef RIGHT
257 #define ALTRIGHT BUTTON_BOTTOMRIGHT
258 #else
259 #define RIGHT BUTTON_BOTTOMRIGHT
260 #endif
261 #ifdef SELECT
262 #define ALTSELECT BUTTON_CENTER
263 #else
264 #define SELECT BUTTON_CENTER
265 #endif
266 #ifndef UP
267 #define UP BUTTON_TOPMIDDLE
268 #endif
269 #ifndef DOWN
270 #define DOWN BUTTON_BOTTOMMIDDLE
271 #endif
272 #endif
274 /* Continue text is used as a string later when the game is paused. This allows
275 * targets to specify their own text if needed.
277 #if !defined(CONTINUE_TEXT)
278 #define CONTINUE_TEXT "Press SELECT To Continue"
279 #endif
281 #ifndef SCROLL_FWD /* targets without scroll wheel*/
282 #define SCROLL_FWD(x) (0)
283 #define SCROLL_BACK(x) (0)
284 #endif
289 * Geometric dimensions
293 /* If there are three fractional bits, the smallest screen size that will scale
294 * properly is 28x22. If you have a smaller screen increase the fractional
295 * precision. If you have a precision of 4 the smallest screen size would be
296 * 14x11. Note though that this will decrease the maximum resolution due to
297 * the line intersection tests. These defines are used for all of the fixed
298 * point calculations/conversions.
300 #define FIXED3(x) ((x)<<3)
301 #define FIXED3_MUL(x, y) ((long long)((x)*(y))>>3)
302 #define FIXED3_DIV(x, y) (((x)<<3)/(y))
303 #define INT3(x) ((x)>>3)
305 #define GAMESCREEN_WIDTH FIXED3(LCD_WIDTH)
306 #define GAMESCREEN_HEIGHT FIXED3(LCD_HEIGHT)
308 #define PAD_WIDTH FIXED3(BMPWIDTH_brickmania_pads)
309 #define PAD_HEIGHT FIXED3(BMPHEIGHT_brickmania_pads/3)
310 #define SHORT_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_short_pads)
311 #define LONG_PAD_WIDTH FIXED3(BMPWIDTH_brickmania_long_pads)
312 #define BRICK_HEIGHT FIXED3(BMPHEIGHT_brickmania_bricks/7)
313 #define BRICK_WIDTH FIXED3(BMPWIDTH_brickmania_bricks)
314 #define LEFTMARGIN ((GAMESCREEN_WIDTH-10*BRICK_WIDTH)/2)
315 #define POWERUP_WIDTH FIXED3(BMPWIDTH_brickmania_powerups)
316 #define BALL FIXED3(BMPHEIGHT_brickmania_ball)
317 #define HALFBALL (BALL / 2)
318 #define PAD_POS_Y (GAMESCREEN_HEIGHT - PAD_HEIGHT - 1)
319 #define ON_PAD_POS_Y (PAD_POS_Y - HALFBALL)
321 #define GAMEOVER_WIDTH FIXED3(BMPWIDTH_brickmania_gameover)
322 #define GAMEOVER_HEIGHT FIXED3(BMPHEIGHT_brickmania_gameover)
324 #define TOPMARGIN MAX(BRICK_HEIGHT, FIXED3(8))
326 #define STRINGPOS_FINISH (GAMESCREEN_HEIGHT - (GAMESCREEN_HEIGHT / 6))
327 #define STRINGPOS_CONGRATS (STRINGPOS_FINISH - 20)
328 #define STRINGPOS_NAVI (STRINGPOS_FINISH - 10)
329 #define STRINGPOS_FLIP (STRINGPOS_FINISH - 10)
334 * Speeds
338 /* Brickmania was originally designed for the H300, other targets should scale
339 * the speed up/down as needed based on the screen height.
341 #define SPEED_SCALE_H(y) FIXED3_DIV(GAMESCREEN_HEIGHT, FIXED3(176)/(y) )
342 #define SPEED_SCALE_W(x) FIXED3_DIV(GAMESCREEN_WIDTH, FIXED3(220)/(x) )
344 /* These are all used as ball speeds depending on where the ball hit the
345 * paddle.
347 * Note that all of these speeds (including pad, power, and fire)
348 * could be made variable and could be raised to be much higher to add
349 * additional difficulty to the game. The line intersection tests allow this
350 * to be drastically increased without the collision detection failing
351 * (ideally).
353 #define SPEED_1Q_X SPEED_SCALE_W( 6)
354 #define SPEED_1Q_Y SPEED_SCALE_H(-2)
356 #define SPEED_2Q_X SPEED_SCALE_W( 4)
357 #define SPEED_2Q_Y SPEED_SCALE_H(-3)
359 #define SPEED_3Q_X SPEED_SCALE_W( 3)
360 #define SPEED_3Q_Y SPEED_SCALE_H(-4)
362 #define SPEED_4Q_X SPEED_SCALE_W( 2)
363 #define SPEED_4Q_Y SPEED_SCALE_H(-4)
365 /* This is used to determine the speed of the paddle */
366 #define SPEED_PAD SPEED_SCALE_W( 8)
368 /* This defines the speed that the powerups drop */
369 #define SPEED_POWER SPEED_SCALE_H( 2)
371 /* This defines the speed that the shot moves */
372 #define SPEED_FIRE SPEED_SCALE_H( 4)
373 #define FIRE_LENGTH SPEED_SCALE_H( 7)
378 * Timings
382 /* The time ms for one iteration through the game loop - decrease this to speed
383 * up the game - note that current_tick is (currently) only accurate to 10ms.
385 #define CYCLETIME 30 /* ms */
387 #define FLIP_SIDES_DELAY 10 /* seconds */
392 * Scores
396 #define SCORE_BALL_HIT_BRICK 2
397 #define SCORE_BALL_DEMOLISHED_BRICK 8
398 #define SCORE_FIRE_HIT_BRICK 13
399 #define SCORE_LEVEL_COMPLETED 100
400 #define SCORE_POWER_LIFE_GAIN 50
401 #define SCORE_POWER_PADDLE_STICKY 34
402 #define SCORE_POWER_PADDLE_SHOOTER 47
403 #define SCORE_POWER_PADDLE_NORMAL 23
404 #define SCORE_POWER_FLIP 23
405 #define SCORE_POWER_EXTRA_BALL 23
406 #define SCORE_POWER_LONG_PADDLE 23
411 * Limits
415 #define MAX_BALLS 10
416 #define MAX_FIRES 30
417 #define MAX_POWERS 10
422 * Files
426 #define CONFIG_FILE_NAME "brickmania.cfg"
427 #define SAVE_FILE PLUGIN_GAMES_DIR "/brickmania.save"
428 #define SCORE_FILE PLUGIN_GAMES_DIR "/brickmania.score"
429 #define NUM_SCORES 5
434 * Game levels
438 #define NUM_BRICKS_ROWS 8
439 #define NUM_BRICKS_COLS 10
441 /* change to however many levels there are, i.e. how many arrays there are total */
442 #define NUM_LEVELS 40
444 /* change the first number in [ ] to however many levels there are */
445 static unsigned char levels[NUM_LEVELS][NUM_BRICKS_ROWS][NUM_BRICKS_COLS] =
446 /* You can set up new levels with the level editor
447 ( http://plugbox.rockbox-lounge.com/brickmania.htm ).
448 With 0x1, it refers to the first brick in the bitmap, 0x2 would refer to the
449 second, ect., 0x0 leaves a empty space. If you add a 2 before the 2nd number,
450 it will take two hits to break, and 3 hits if you add a 3. That is 0x24, will
451 result with the fourth brick being displayed and having take 2 hits to break.
452 You could do the same with the 3, just replace the 2 with a 3 for it to take
453 three hits to break it apart. */
455 { /* level 1 */
456 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
457 {0x2,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2},
458 {0x0,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x0},
459 {0x0,0x0,0x2,0x1,0x0,0x0,0x1,0x2,0x0,0x0},
460 {0x0,0x0,0x0,0x2,0x1,0x1,0x2,0x0,0x0,0x0},
461 {0x7,0x0,0x0,0x7,0x2,0x2,0x7,0x0,0x0,0x7},
462 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
463 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
465 { /* level 2 */
466 {0x0,0x0,0x7,0x7,0x1,0x1,0x7,0x7,0x0,0x0},
467 {0x0,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0},
468 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
469 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
470 {0x1,0x1,0x2,0x1,0x0,0x0,0x1,0x2,0x1,0x1},
471 {0x1,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x1},
472 {0x0,0x1,0x2,0x0,0x0,0x0,0x0,0x2,0x1,0x0},
473 {0x0,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x0}
475 { /* level 3 */
476 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
477 {0x3,0x23,0x23,0x3,0x0,0x0,0x2,0x22,0x22,0x2},
478 {0x3,0x3,0x3,0x3,0x0,0x0,0x2,0x2,0x2,0x2},
479 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
480 {0x0,0x0,0x0,0x0,0x37,0x37,0x0,0x0,0x0,0x0},
481 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6},
482 {0x5,0x25,0x25,0x5,0x0,0x0,0x6,0x26,0x26,0x6},
483 {0x5,0x5,0x5,0x5,0x0,0x0,0x6,0x6,0x6,0x6}
485 { /* level 4 */
486 {0x0,0x0,0x0,0x27,0x27,0x27,0x27,0x0,0x0,0x0},
487 {0x0,0x0,0x0,0x27,0x7,0x7,0x27,0x0,0x0,0x0},
488 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
489 {0x22,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x22},
490 {0x26,0x6,0x0,0x2,0x2,0x2,0x2,0x0,0x6,0x26},
491 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
492 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
493 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1}
495 { /* level 5 */
496 {0x1,0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4},
497 {0x0,0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0},
498 {0x2,0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5},
499 {0x2,0x0,0x3,0x3,0x0,0x4,0x4,0x0,0x5,0x5},
500 {0x0,0x33,0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0},
501 {0x3,0x33,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x36},
502 {0x3,0x0,0x4,0x4,0x0,0x5,0x5,0x0,0x6,0x36},
503 {0x0,0x24,0x24,0x0,0x25,0x25,0x0,0x26,0x26,0x0}
505 { /* level 6 */
506 {0x0,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x0},
507 {0x3,0x1,0x3,0x7,0x0,0x0,0x7,0x3,0x1,0x3},
508 {0x3,0x1,0x3,0x7,0x7,0x7,0x7,0x3,0x1,0x3},
509 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x0},
510 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
511 {0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5},
512 {0x0,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x0},
513 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
515 { /* level 7 */
516 {0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x0},
517 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
518 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
519 {0x6,0x0,0x0,0x2,0x2,0x2,0x2,0x0,0x0,0x6},
520 {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x6},
521 {0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0},
522 {0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0},
523 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
525 { /* level 8 */
526 {0x0,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x0},
527 {0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0},
528 {0x6,0x6,0x0,0x2,0x32,0x32,0x2,0x0,0x6,0x6},
529 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
530 {0x0,0x6,0x6,0x0,0x0,0x0,0x0,0x6,0x6,0x0},
531 {0x0,0x0,0x0,0x5,0x25,0x25,0x5,0x0,0x0,0x0},
532 {0x0,0x5,0x5,0x25,0x5,0x5,0x25,0x5,0x5,0x0},
533 {0x5,0x5,0x25,0x5,0x5,0x5,0x5,0x25,0x5,0x5}
535 { /* level 9 */
536 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
537 {0x2,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x2},
538 {0x2,0x0,0x3,0x0,0x1,0x1,0x0,0x3,0x0,0x2},
539 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
540 {0x2,0x0,0x1,0x0,0x3,0x3,0x0,0x1,0x0,0x2},
541 {0x2,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x2},
542 {0x2,0x2,0x0,0x0,0x1,0x1,0x0,0x0,0x2,0x2},
543 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
545 { /* level 10 */
546 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
547 {0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5,0x0,0x5},
548 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
549 {0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0},
550 {0x0,0x0,0x0,0x4,0x1,0x1,0x4,0x0,0x0,0x0},
551 {0x0,0x0,0x3,0x4,0x1,0x1,0x4,0x3,0x0,0x0},
552 {0x0,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x0},
553 {0x1,0x2,0x3,0x4,0x1,0x1,0x4,0x3,0x2,0x1}
555 { /* level 11 */
556 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3},
557 {0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2},
558 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
559 {0x2,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x2},
560 {0x2,0x0,0x0,0x7,0x7,0x7,0x7,0x0,0x0,0x2},
561 {0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x0},
562 {0x0,0x2,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x0},
563 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5}
565 { /* level 12 */
566 {0x2,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x2},
567 {0x1,0x1,0x1,0x1,0x0,0x0,0x1,0x1,0x1,0x1},
568 {0x1,0x1,0x1,0x0,0x1,0x1,0x0,0x1,0x1,0x1},
569 {0x0,0x1,0x0,0x1,0x6,0x6,0x1,0x0,0x1,0x0},
570 {0x0,0x0,0x1,0x1,0x6,0x6,0x1,0x1,0x0,0x0},
571 {0x1,0x1,0x1,0x7,0x0,0x0,0x7,0x1,0x1,0x1},
572 {0x1,0x1,0x7,0x1,0x0,0x0,0x1,0x7,0x1,0x1},
573 {0x2,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x2,0x2}
575 {/* levell13 */
576 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
577 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
578 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x2},
579 {0x2,0x0,0x2,0x3,0x3,0x3,0x3,0x3,0x0,0x2},
580 {0x2,0x0,0x2,0x4,0x4,0x4,0x4,0x4,0x0,0x2},
581 {0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2},
582 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
583 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
585 {/* level 14 */
586 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
587 {0x4,0x4,0x4,0x4,0x2,0x2,0x4,0x4,0x4,0x4},
588 {0x4,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x4},
589 {0x4,0x0,0x0,0x2,0x3,0x3,0x2,0x0,0x0,0x4},
590 {0x4,0x0,0x2,0x23,0x3,0x3,0x23,0x2,0x0,0x4},
591 {0x4,0x0,0x2,0x22,0x2,0x2,0x22,0x2,0x0,0x4},
592 {0x4,0x0,0x6,0x21,0x5,0x5,0x21,0x6,0x0,0x4},
593 {0x4,0x6,0x1,0x1,0x5,0x5,0x1,0x1,0x6,0x4}
595 {/* level 15 */
596 {0x4,0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,0x3},
597 {0x2,0x2,0x1,0x1,0x1,0x1,0x1,0x5,0x0,0x0},
598 {0x2,0x2,0x1,0x1,0x1,0x0,0x1,0x6,0x0,0x0},
599 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x5,0x0,0x0},
600 {0x2,0x1,0x2,0x2,0x2,0x1,0x1,0x6,0x0,0x0},
601 {0x2,0x1,0x2,0x2,0x2,0x1,0x3,0x5,0x3,0x0},
602 {0x2,0x1,0x1,0x2,0x1,0x1,0x1,0x6,0x0,0x0},
603 {0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2}
605 {/* level 16 (Rockbox) by ts-x */
606 {0x2,0x2,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
607 {0x2,0x0,0x3,0x0,0x3,0x4,0x0,0x5,0x5,0x0},
608 {0x2,0x0,0x3,0x3,0x3,0x4,0x4,0x5,0x0,0x5},
609 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
610 {0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
611 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0},
612 {0x7,0x0,0x7,0x1,0x0,0x1,0x0,0x2,0x0,0x0},
613 {0x7,0x7,0x7,0x1,0x1,0x1,0x2,0x0,0x2,0x0}
615 {/* level 17 (Alien) by ts-x */
616 {0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1},
617 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2},
618 {0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1},
619 {0x2,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x2},
620 {0x1,0x0,0x1,0x2,0x2,0x2,0x2,0x1,0x0,0x1},
621 {0x2,0x0,0x0,0x1,0x2,0x2,0x1,0x0,0x0,0x2},
622 {0x2,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x2},
623 {0x2,0x2,0x1,0x0,0x1,0x1,0x0,0x1,0x2,0x2}
625 {/* level 18 (Tetris) by ts-x */
626 {0x0,0x2,0x0,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
627 {0x0,0x2,0x7,0x0,0x3,0x4,0x0,0x2,0x2,0x0},
628 {0x2,0x2,0x7,0x0,0x3,0x4,0x0,0x6,0x2,0x2},
629 {0x2,0x2,0x7,0x7,0x3,0x4,0x0,0x6,0x2,0x2},
630 {0x2,0x1,0x7,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
631 {0x2,0x1,0x0,0x7,0x3,0x4,0x4,0x6,0x5,0x5},
632 {0x1,0x1,0x1,0x7,0x3,0x0,0x6,0x6,0x5,0x5},
633 {0x1,0x1,0x1,0x0,0x3,0x0,0x6,0x6,0x5,0x5}
635 { /* level 19 (Stalactites) by ts-x */
636 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
637 {0x5,0x2,0x6,0x3,0x4,0x7,0x5,0x3,0x1,0x2},
638 {0x5,0x0,0x6,0x3,0x4,0x7,0x5,0x0,0x1,0x2},
639 {0x5,0x2,0x6,0x3,0x4,0x0,0x5,0x3,0x1,0x2},
640 {0x5,0x0,0x6,0x0,0x4,0x7,0x5,0x0,0x1,0x0},
641 {0x5,0x0,0x0,0x3,0x4,0x0,0x0,0x0,0x1,0x2},
642 {0x0,0x0,0x6,0x0,0x0,0x0,0x5,0x0,0x0,0x0},
643 {0x5,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0}
645 { /* level 20 (Maze) by ts-x */
646 {0x1,0x1,0x21,0x1,0x1,0x1,0x1,0x1,0x1,0x21},
647 {0x1,0x0,0x0,0x3,0x0,0x0,0x3,0x1,0x31,0x1},
648 {0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x1},
649 {0x21,0x0,0x21,0x3,0x0,0x3,0x0,0x3,0x0,0x2},
650 {0x1,0x0,0x1,0x21,0x0,0x12,0x0,0x0,0x0,0x0},
651 {0x31,0x0,0x1,0x0,0x0,0x1,0x0,0x0,0x3,0x0},
652 {0x1,0x0,0x1,0x0,0x1,0x1,0x31,0x1,0x1,0x2},
653 {0x22,0x0,0x2,0x1,0x1,0x1,0x1,0x1,0x1,0x21}
655 { /* level 21 (Dentist) by ts-x */
656 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
657 {0x2,0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x2,0x2},
658 {0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x2},
659 {0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x2},
660 {0x2,0x0,0x6,0x0,0x6,0x0,0x0,0x0,0x0,0x2},
661 {0x2,0x0,0x6,0x0,0x6,0x0,0x6,0x0,0x6,0x2},
662 {0x2,0x2,0x6,0x0,0x6,0x0,0x6,0x0,0x2,0x2},
663 {0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0}
665 { /* level 22 (Spider) by ts-x */
666 {0x31,0x3,0x1,0x1,0x0,0x0,0x1,0x1,0x3,0x31},
667 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
668 {0x33,0x1,0x1,0x36,0x1,0x1,0x36,0x1,0x1,0x33},
669 {0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0},
670 {0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0},
671 {0x21,0x3,0x1,0x21,0x2,0x2,0x21,0x1,0x3,0x21},
672 {0x0,0x0,0x0,0x1,0x21,0x1,0x1,0x0,0x0,0x0},
673 {0x3,0x1,0x3,0x1,0x0,0x0,0x1,0x3,0x1,0x3}
675 { /* level 23 (Pool) by ts-x */
676 {0x0,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x7,0x0},
677 {0x0,0x0,0x5,0x0,0x2,0x0,0x0,0x0,0x2,0x0},
678 {0x7,0x3,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x7},
679 {0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0x7},
680 {0x7,0x0,0x4,0x0,0x0,0x3,0x0,0x0,0x0,0x7},
681 {0x7,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x4,0x7},
682 {0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
683 {0x0,0x7,0x7,0x7,0x7,0x0,0x7,0x7,0x7,0x0}
685 { /* level 24 (Vorbis Fish) by ts-x */
686 {0x0,0x0,0x4,0x4,0x5,0x5,0x5,0x0,0x0,0x5},
687 {0x0,0x4,0x6,0x4,0x4,0x5,0x5,0x5,0x0,0x5},
688 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x5,0x5,0x5},
689 {0x5,0x6,0x0,0x6,0x4,0x4,0x4,0x4,0x5,0x5},
690 {0x0,0x5,0x6,0x4,0x4,0x5,0x5,0x4,0x5,0x0},
691 {0x5,0x5,0x4,0x4,0x5,0x5,0x5,0x4,0x5,0x5},
692 {0x5,0x4,0x4,0x4,0x5,0x5,0x4,0x4,0x5,0x5},
693 {0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x5,0x0,0x5}
695 {/* level 25 (Rainbow) by ts-x */
696 {0x0,0x4,0x1,0x0,0x0,0x0,0x0,0x1,0x4,0x0},
697 {0x24,0x1,0x3,0x1,0x0,0x0,0x21,0x3,0x1,0x24},
698 {0x1,0x23,0x5,0x3,0x1,0x21,0x3,0x5,0x3,0x21},
699 {0x3,0x5,0x6,0x5,0x3,0x3,0x5,0x6,0x5,0x3},
700 {0x5,0x6,0x7,0x6,0x5,0x5,0x6,0x7,0x6,0x5},
701 {0x6,0x7,0x2,0x27,0x6,0x6,0x27,0x2,0x7,0x6},
702 {0x7,0x2,0x0,0x2,0x27,0x27,0x2,0x0,0x2,0x7},
703 {0x32,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x32}
705 { /* level 26 (Bowtie) by ts-x */
706 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5},
707 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
708 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
709 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
710 {0x1,0x0,0x6,0x6,0x0,0x0,0x6,0x6,0x0,0x1},
711 {0x5,0x0,0x6,0x0,0x1,0x1,0x0,0x6,0x0,0x5},
712 {0x1,0x0,0x0,0x1,0x5,0x5,0x1,0x0,0x0,0x1},
713 {0x5,0x1,0x5,0x1,0x0,0x0,0x1,0x5,0x1,0x5}
715 { /* level 27 (Frog) by ts-x */
716 {0x0,0x5,0x25,0x0,0x0,0x0,0x0,0x25,0x5,0x0},
717 {0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5},
718 {0x25,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x25},
719 {0x5,0x0,0x3,0x0,0x6,0x6,0x0,0x3,0x0,0x5},
720 {0x5,0x0,0x31,0x0,0x6,0x6,0x0,0x31,0x0,0x5},
721 {0x5,0x0,0x0,0x5,0x6,0x6,0x5,0x0,0x0,0x5},
722 {0x5,0x5,0x5,0x35,0x0,0x0,0x35,0x5,0x5,0x5},
723 {0x0,0x25,0x5,0x0,0x4,0x4,0x0,0x5,0x25,0x0}
725 { /* level 28 (DigDug) by ts-x */
726 {0x35,0x5,0x5,0x25,0x0,0x25,0x25,0x5,0x5,0x35},
727 {0x6,0x0,0x0,0x6,0x0,0x6,0x6,0x0,0x0,0x6},
728 {0x7,0x0,0x37,0x37,0x0,0x37,0x37,0x7,0x0,0x7},
729 {0x7,0x0,0x7,0x0,0x0,0x0,0x7,0x7,0x7,0x7},
730 {0x4,0x4,0x4,0x24,0x0,0x24,0x4,0x0,0x0,0x4},
731 {0x4,0x4,0x0,0x0,0x0,0x4,0x4,0x0,0x4,0x4},
732 {0x24,0x24,0x4,0x4,0x4,0x4,0x0,0x0,0x24,0x4},
733 {0x1,0x1,0x1,0x1,0x1,0x1,0x21,0x21,0x1,0x1}
735 { /* level 29 UK Flag by Seth Opgenorth */
736 {0x32,0x0,0x3,0x3,0x2,0x2,0x3,0x3,0x0,0x32},
737 {0x0,0x2,0x0,0x3,0x32,0x22,0x33,0x0,0x32,0x0},
738 {0x33,0x0,0x22,0x0,0x2,0x2,0x0,0x2,0x0,0x33},
739 {0x22,0x32,0x2,0x2,0x2,0x2,0x2,0x2,0x22,0x2},
740 {0x3,0x0,0x0,0x32,0x22,0x2,0x2,0x0,0x0,0x3},
741 {0x23,0x0,0x32,0x0,0x32,0x2,0x0,0x2,0x0,0x3},
742 {0x0,0x2,0x0,0x3,0x2,0x2,0x3,0x0,0x22,0x0},
743 {0x32,0x0,0x3,0x23,0x2,0x2,0x23,0x33,0x0,0x32}
745 { /* level 30 Win-Logo by Seth Opgenorth */
746 {0x0,0x0,0x0,0x22,0x0,0x0,0x0,0x0,0x0,0x0},
747 {0x0,0x0,0x32,0x2,0x2,0x25,0x0,0x5,0x0,0x0},
748 {0x0,0x0,0x2,0x22,0x2,0x5,0x5,0x35,0x0,0x0},
749 {0x0,0x0,0x2,0x1,0x2,0x5,0x5,0x25,0x0,0x0},
750 {0x0,0x0,0x21,0x1,0x1,0x36,0x7,0x26,0x0,0x0},
751 {0x0,0x0,0x1,0x1,0x1,0x6,0x6,0x6,0x0,0x0},
752 {0x0,0x0,0x21,0x0,0x21,0x6,0x6,0x26,0x0,0x0},
753 {0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0}
755 { /* level 31 Color wave/V by Seth Opgenorth */
756 {0x25,0x34,0x2,0x31,0x33,0x23,0x1,0x2,0x34,0x5},
757 {0x3,0x5,0x24,0x2,0x1,0x1,0x2,0x4,0x5,0x3},
758 {0x1,0x3,0x5,0x4,0x2,0x2,0x4,0x5,0x3,0x1},
759 {0x2,0x1,0x33,0x35,0x4,0x4,0x5,0x33,0x1,0x22},
760 {0x31,0x22,0x1,0x3,0x5,0x25,0x3,0x1,0x2,0x31},
761 {0x3,0x1,0x2,0x1,0x3,0x3,0x1,0x2,0x21,0x3},
762 {0x5,0x23,0x1,0x32,0x1,0x1,0x2,0x1,0x3,0x5},
763 {0x4,0x35,0x3,0x1,0x2,0x22,0x31,0x3,0x5,0x4}
765 { /* level 32 Sweedish Flag by Seth Opgenorth */
766 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
767 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
768 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
769 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
770 {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
771 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
772 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3},
773 {0x3,0x3,0x3,0x36,0x3,0x3,0x3,0x3,0x3,0x3}
775 { /* level 33 Color Pyramid by Seth Opgenorth */
776 {0x0,0x0,0x0,0x0,0x2,0x2,0x0,0x0,0x0,0x0},
777 {0x0,0x0,0x0,0x4,0x24,0x4,0x24,0x0,0x0,0x0},
778 {0x0,0x0,0x23,0x3,0x3,0x3,0x23,0x3,0x0,0x0},
779 {0x0,0x0,0x25,0x5,0x25,0x35,0x5,0x35,0x0,0x0},
780 {0x0,0x36,0x6,0x6,0x6,0x6,0x26,0x6,0x6,0x0},
781 {0x0,0x7,0x7,0x7,0x7,0x25,0x27,0x7,0x27,0x0},
782 {0x2,0x2,0x22,0x2,0x2,0x2,0x22,0x2,0x2,0x2},
783 {0x21,0x1,0x1,0x31,0x1,0x21,0x1,0x1,0x31,0x1}
785 { /* level 34 Rhombus by Seth Opgenorth */
786 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0},
787 {0x0,0x0,0x0,0x3,0x32,0x22,0x23,0x0,0x0,0x0},
788 {0x0,0x0,0x3,0x2,0x24,0x4,0x2,0x23,0x0,0x0},
789 {0x26,0x3,0x2,0x4,0x5,0x5,0x4,0x22,0x3,0x6},
790 {0x36,0x3,0x2,0x34,0x5,0x5,0x4,0x2,0x3,0x36},
791 {0x0,0x0,0x3,0x2,0x4,0x34,0x2,0x23,0x0,0x0},
792 {0x0,0x0,0x0,0x23,0x2,0x2,0x3,0x0,0x0,0x0},
793 {0x0,0x0,0x0,0x0,0x3,0x33,0x0,0x0,0x0,0x0}
795 { /* level 35 PacMan Ghost by Seth Opgenorth */
796 {0x0,0x0,0x0,0x0,0x2,0x32,0x2,0x0,0x0,0x0},
797 {0x0,0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x0,0x0},
798 {0x0,0x0,0x2,0x24,0x4,0x2,0x4,0x4,0x32,0x0},
799 {0x0,0x0,0x2,0x24,0x0,0x22,0x24,0x0,0x22,0x0},
800 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
801 {0x0,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0},
802 {0x0,0x0,0x2,0x32,0x2,0x2,0x22,0x2,0x32,0x0},
803 {0x0,0x0,0x0,0x22,0x0,0x32,0x0,0x22,0x0,0x0}
805 { /* level 36 Star by Seth Opgenorth */
806 {0x3,0x4,0x3,0x4,0x6,0x24,0x3,0x24,0x3,0x0},
807 {0x24,0x0,0x0,0x6,0x6,0x6,0x0,0x0,0x4,0x0},
808 {0x3,0x26,0x6,0x2,0x6,0x2,0x6,0x26,0x23,0x0},
809 {0x4,0x0,0x6,0x6,0x36,0x6,0x6,0x0,0x4,0x0},
810 {0x3,0x0,0x0,0x26,0x6,0x26,0x0,0x0,0x33,0x0},
811 {0x34,0x0,0x6,0x6,0x0,0x6,0x6,0x0,0x4,0x0},
812 {0x3,0x26,0x6,0x0,0x0,0x0,0x6,0x6,0x3,0x0},
813 {0x4,0x3,0x4,0x23,0x24,0x3,0x4,0x33,0x4,0x0}
815 { /* level 37 It's 8-Bit by Seth Opgenorth */
816 {0x26,0x26,0x6,0x6,0x5,0x6,0x26,0x6,0x26,0x6},
817 {0x2,0x2,0x22,0x3,0x3,0x0,0x0,0x0,0x4,0x0},
818 {0x2,0x0,0x2,0x33,0x3,0x3,0x5,0x0,0x24,0x0},
819 {0x32,0x2,0x2,0x33,0x0,0x23,0x0,0x4,0x4,0x4},
820 {0x2,0x22,0x2,0x3,0x3,0x0,0x5,0x4,0x4,0x24},
821 {0x2,0x0,0x2,0x23,0x0,0x3,0x25,0x0,0x4,0x0},
822 {0x22,0x2,0x2,0x3,0x23,0x0,0x5,0x0,0x4,0x0},
823 {0x6,0x26,0x6,0x36,0x6,0x36,0x6,0x6,0x6,0x6}
825 { /* level 38 Linux by Seth Opgenorth */
826 {0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
827 {0x7,0x0,0x0,0x0,0x33,0x0,0x23,0x0,0x0,0x0},
828 {0x7,0x32,0x0,0x0,0x3,0x0,0x23,0x6,0x0,0x6},
829 {0x37,0x0,0x0,0x0,0x23,0x0,0x3,0x6,0x0,0x26},
830 {0x7,0x22,0x24,0x0,0x3,0x33,0x3,0x0,0x26,0x0},
831 {0x37,0x22,0x24,0x24,0x4,0x0,0x0,0x0,0x26,0x0},
832 {0x7,0x2,0x4,0x0,0x4,0x0,0x0,0x6,0x0,0x26},
833 {0x7,0x27,0x4,0x0,0x34,0x0,0x0,0x6,0x0,0x26}
835 { /* level 39 Colorful Squares by Seth Opgenorth*/
836 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0},
837 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
838 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
839 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
840 {0x0,0x4,0x5,0x3,0x4,0x4,0x3,0x5,0x4,0x0},
841 {0x0,0x4,0x5,0x3,0x3,0x3,0x3,0x5,0x4,0x0},
842 {0x0,0x4,0x5,0x5,0x5,0x5,0x5,0x5,0x4,0x0},
843 {0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0}
845 { /* TheEnd */
846 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
847 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
848 {0x32,0x0,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
849 {0x32,0x32,0x36,0x36,0x0,0x36,0x34,0x0,0x34,0x0},
850 {0x32,0x32,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
851 {0x32,0x0,0x36,0x0,0x36,0x36,0x34,0x0,0x34,0x0},
852 {0x32,0x32,0x36,0x0,0x0,0x36,0x34,0x34,0x0,0x0},
853 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
860 * Enums and structs
864 enum power_types
866 POWER_TYPE_LIFE_GAIN = 0,
867 POWER_TYPE_LIFE_LOSS,
868 POWER_TYPE_PADDLE_STICKY,
869 POWER_TYPE_PADDLE_SHOOTER,
870 POWER_TYPE_PADDLE_NORMAL,
871 POWER_TYPE_PADDLE_FLIP,
872 POWER_TYPE_EXTRA_BALL,
873 POWER_TYPE_PADDLE_LONG,
874 POWER_TYPE_PADDLE_SHORT,
875 NUMBER_OF_POWERUPS,
878 #define POWERUP_HEIGHT FIXED3(BMPHEIGHT_brickmania_powerups/NUMBER_OF_POWERUPS)
879 /* Increasing this value makes the game with less powerups */
880 #define POWER_RAND (NUMBER_OF_POWERUPS + 15)
882 enum difficulty_options
884 EASY,
885 NORMAL
888 enum game_state
890 ST_READY,
891 ST_START,
892 ST_PAUSE
895 enum paddle_type
897 PADDLE_TYPE_NORMAL = 0,
898 PADDLE_TYPE_STICKY,
899 PADDLE_TYPE_SHOOTER,
902 struct brick
904 bool used; /* Is the brick still in play? */
905 int color;
906 int hits; /* How many hits can this brick take? */
907 int hiteffect;
910 struct ball
912 /* pos_x and y store the current center position of the ball */
913 int pos_x;
914 int pos_y;
915 /* tempx and tempy store an absolute position the ball should be in. If
916 * they are equal to 0, they are not used when positioning the ball.
918 int tempx;
919 int tempy;
920 /* speedx and speedy store the current speed of the ball */
921 int speedx;
922 int speedy;
923 bool glue; /* Is the ball stuck to the paddle? */
926 struct fire
928 int top; /* This stores the fire y position, it is a fixed point num */
929 int x_pos; /* This stores the fire x position, it is a whole number */
932 struct power
934 int top; /* This stores the powerup y position, it is a fixed point num */
935 int x_pos; /* This stores the (middle of) powerup x position, it is a whole number */
936 enum power_types type; /* This stores the powerup type */
939 struct point
941 int x;
942 int y;
945 struct line
947 struct point p1;
948 struct point p2;
954 * Globals
958 static enum game_state game_state = ST_READY;
959 static int pad_pos_x;
960 static int life;
961 static int score=0,vscore=0;
962 static bool flip_sides=false;
963 static int level=0;
964 static int brick_on_board=0;
965 static int used_balls=1;
966 static int used_fires=0;
967 static int used_powers=0;
968 static int difficulty = NORMAL;
969 static int pad_width;
970 static int flip_sides_delay;
971 static bool resume = false;
972 static bool resume_file = false;
973 static struct brick brick[NUM_BRICKS_ROWS][NUM_BRICKS_COLS];
974 static struct ball ball[MAX_BALLS];
975 static struct fire fire[MAX_FIRES];
976 static struct power power[MAX_POWERS];
977 static enum paddle_type paddle_type;
979 static struct configdata config[] =
981 {TYPE_INT, 0, 1, { .int_p = &difficulty }, "difficulty", NULL},
984 static struct highscore highscores[NUM_SCORES];
989 * Functions
994 * check_lines:
995 * This is based off an explanation and expanded math presented by Paul Bourke:
996 * http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
998 * It takes two lines as inputs and returns 1 if they intersect, 0 if they do
999 * not. hitp returns the point where the two lines intersected.
1001 * This function expects fixed point inputs with a precision of 3. When a
1002 * collision occurs hitp is updated with a fixed point location (precision 3)
1003 * where the collision happened. The internal calculations are fixed
1004 * point with a 7 bit fractional precision.
1006 * If you choose 10 bits of precision a screen size of about 640x480 is the
1007 * largest this can go. 7 bits allows for an accurate intersection calculation
1008 * with a line length of about 64 and a rougher line lenght of 128 which is
1009 * larger than any target currently needs (the pad is the longest line and it
1010 * only needs an accuracy of 2^4 at most to figure out which section of the pad
1011 * the ball hit). A precision of 7 gives breathing room for larger screens.
1012 * Longer line sizes that need accurate intersection points will need more
1013 * precision, but will decrease the maximum screen resolution.
1016 #define LINE_PREC 7
1017 static int check_lines(struct line *line1, struct line *line2,
1018 struct point *hitp)
1020 /* Introduction:
1021 * This code is based on the solution of these two input equations:
1022 * Pa = P1 + ua (P2-P1)
1023 * Pb = P3 + ub (P4-P3)
1025 * Where line one is composed of points P1 and P2 and line two is composed
1026 * of points P3 and P4.
1028 * ua/b is the fractional value you can multiply the x and y legs of the
1029 * triangle formed by each line to find a point on the line.
1031 * The two equations can be expanded to their x/y components:
1032 * Pa.x = p1.x + ua(p2.x - p1.x)
1033 * Pa.y = p1.y + ua(p2.y - p1.y)
1035 * Pb.x = p3.x + ub(p4.x - p3.x)
1036 * Pb.y = p3.y + ub(p4.y - p3.y)
1038 * When Pa.x == Pb.x and Pa.y == Pb.y the lines intersect so you can come
1039 * up with two equations (one for x and one for y):
1041 * p1.x + ua(p2.x - p1.x) = p3.x + ub(p4.x - p3.x)
1042 * p1.y + ua(p2.y - p1.y) = p3.y + ub(p4.y - p3.y)
1044 * ua and ub can then be individually solved for. This results in the
1045 * equations used in the following code.
1048 /* Denominator for ua and ub are the same so store this calculation */
1049 int d = FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p2.x-line1->p1.x))
1050 -FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p2.y-line1->p1.y));
1052 /* n_a and n_b are calculated as seperate values for readability */
1053 int n_a = FIXED3_MUL((line2->p2.x - line2->p1.x),(line1->p1.y-line2->p1.y))
1054 -FIXED3_MUL((line2->p2.y - line2->p1.y),(line1->p1.x-line2->p1.x));
1056 int n_b = FIXED3_MUL((line1->p2.x - line1->p1.x),(line1->p1.y-line2->p1.y))
1057 -FIXED3_MUL((line1->p2.y - line1->p1.y),(line1->p1.x-line2->p1.x));
1059 /* Make sure there is not a division by zero - this also indicates that
1060 * the lines are parallel.
1062 * If n_a and n_b were both equal to zero the lines would be on top of each
1063 * other (coincidental). This check is not done because it is not
1064 * necessary for this implementation (the parallel check accounts for this).
1066 if(d == 0)
1067 return 0;
1069 /* Calculate the intermediate fractional point that the lines potentially
1070 * intersect.
1072 int ua = (n_a << LINE_PREC)/d;
1073 int ub = (n_b << LINE_PREC)/d;
1075 /* The fractional point will be between 0 and 1 inclusive if the lines
1076 * intersect. If the fractional calculation is larger than 1 or smaller
1077 * than 0 the lines would need to be longer to intersect.
1079 if(ua >=0 && ua <= (1<<LINE_PREC) && ub >= 0 && ub <= (1<<LINE_PREC))
1081 hitp->x = line1->p1.x + ((ua * (line1->p2.x - line1->p1.x))>>LINE_PREC);
1082 hitp->y = line1->p1.y + ((ua * (line1->p2.y - line1->p1.y))>>LINE_PREC);
1083 return 1;
1085 return 0;
1088 static void brickmania_init_game(bool new_game)
1090 int i,j;
1092 pad_pos_x = GAMESCREEN_WIDTH/2 - PAD_WIDTH/2;
1094 for(i=0;i<MAX_BALLS;i++)
1096 ball[i].speedx = 0;
1097 ball[i].speedy = 0;
1098 ball[i].tempy = 0;
1099 ball[i].tempx = 0;
1100 ball[i].pos_y = ON_PAD_POS_Y;
1101 ball[i].pos_x = GAMESCREEN_WIDTH/2;
1102 ball[i].glue = false;
1105 used_balls = 1;
1106 used_fires = 0;
1107 used_powers = 0;
1108 game_state = ST_READY;
1109 paddle_type = PADDLE_TYPE_NORMAL;
1110 pad_width = PAD_WIDTH;
1111 flip_sides = false;
1112 flip_sides_delay = FLIP_SIDES_DELAY;
1114 if (new_game) {
1115 brick_on_board=0;
1116 /* add one life per achieved level */
1117 if (difficulty==EASY && life<2) {
1118 score+=SCORE_LEVEL_COMPLETED;
1119 life++;
1123 for(i=0;i<NUM_BRICKS_ROWS;i++) {
1124 for(j=0;j<NUM_BRICKS_COLS;j++) {
1125 if (new_game) {
1126 brick[i][j].hits=levels[level][i][j]>=10?
1127 levels[level][i][j]/16-1:0;
1128 brick[i][j].hiteffect=0;
1129 brick[i][j].used=!(levels[level][i][j]==0);
1130 brick[i][j].color=(levels[level][i][j]>=10?
1131 levels[level][i][j]%16:
1132 levels[level][i][j])-1;
1133 if (levels[level][i][j]!=0)
1134 brick_on_board++;
1140 static void brickmania_loadgame(void)
1142 int fd;
1144 resume = false;
1146 /* open game file */
1147 fd = rb->open(SAVE_FILE, O_RDONLY);
1148 if(fd < 0) return;
1150 /* read in saved game */
1151 if((rb->read(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1152 (rb->read(fd, &life, sizeof(life)) <= 0) ||
1153 (rb->read(fd, &game_state, sizeof(game_state)) <= 0) ||
1154 (rb->read(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1155 (rb->read(fd, &score, sizeof(score)) <= 0) ||
1156 (rb->read(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1157 (rb->read(fd, &level, sizeof(level)) <= 0) ||
1158 (rb->read(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1159 (rb->read(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1160 (rb->read(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1161 (rb->read(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1162 (rb->read(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1163 (rb->read(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1164 (rb->read(fd, &brick, sizeof(brick)) <= 0) ||
1165 (rb->read(fd, &ball, sizeof(ball)) <= 0) ||
1166 (rb->read(fd, &fire, sizeof(fire)) <= 0) ||
1167 (rb->read(fd, &power, sizeof(power)) <= 0))
1169 rb->splash(HZ/2, "Failed to load game");
1171 else
1173 vscore = score;
1174 resume = true;
1177 rb->close(fd);
1179 return;
1182 static void brickmania_savegame(void)
1184 int fd;
1186 /* write out the game state to the save file */
1187 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
1188 if(fd < 0) return;
1190 if ((rb->write(fd, &pad_pos_x, sizeof(pad_pos_x)) <= 0) ||
1191 (rb->write(fd, &life, sizeof(life)) <= 0) ||
1192 (rb->write(fd, &game_state, sizeof(game_state)) <= 0) ||
1193 (rb->write(fd, &paddle_type, sizeof(paddle_type)) <= 0) ||
1194 (rb->write(fd, &score, sizeof(score)) <= 0) ||
1195 (rb->write(fd, &flip_sides, sizeof(flip_sides)) <= 0) ||
1196 (rb->write(fd, &level, sizeof(level)) <= 0) ||
1197 (rb->write(fd, &brick_on_board, sizeof(brick_on_board)) <= 0) ||
1198 (rb->write(fd, &used_balls, sizeof(used_balls)) <= 0) ||
1199 (rb->write(fd, &used_fires, sizeof(used_fires)) <= 0) ||
1200 (rb->write(fd, &used_powers, sizeof(used_powers)) <= 0) ||
1201 (rb->write(fd, &pad_width, sizeof(pad_width)) <= 0) ||
1202 (rb->write(fd, &flip_sides_delay, sizeof(flip_sides_delay)) <= 0) ||
1203 (rb->write(fd, &brick, sizeof(brick)) <= 0) ||
1204 (rb->write(fd, &ball, sizeof(ball)) <= 0) ||
1205 (rb->write(fd, &fire, sizeof(fire)) <= 0) ||
1206 (rb->write(fd, &power, sizeof(power)) <= 0))
1208 rb->close(fd);
1209 rb->remove(SAVE_FILE);
1210 rb->splash(HZ/2, "Failed to save game");
1211 return;
1214 rb->close(fd);
1217 /* brickmania_sleep timer counting the score */
1218 static void brickmania_sleep(int secs)
1220 bool done=false;
1221 char s[20];
1222 int count=0;
1223 int sw, w;
1225 while (!done)
1227 if (count == 0)
1228 count = *rb->current_tick + HZ*secs;
1229 if ( (TIME_AFTER(*rb->current_tick, count)) && (vscore == score) )
1230 done = true;
1232 if(vscore != score)
1234 if (vscore<score)
1235 vscore++;
1236 if (vscore>score)
1237 vscore--;
1238 rb->snprintf(s, sizeof(s), "%d", vscore);
1239 rb->lcd_getstringsize(s, &sw, &w);
1240 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1241 rb->lcd_update_rect(0,0,LCD_WIDTH,w+2);
1243 rb->yield();
1247 static int brickmania_help(void)
1249 static char *help_text[] = {
1250 "Brickmania", "", "Aim", "",
1251 "Destroy", "all", "the", "bricks", "by", "bouncing",
1252 "the", "ball", "of", "them", "using", "the", "paddle.", "", "",
1253 "Controls", "",
1254 #if CONFIG_KEYPAD == COWON_D2_PAD
1255 "- & +:",
1256 #else
1257 "< & >:",
1258 #endif
1259 "Moves", "the", "paddle", "",
1260 #if CONFIG_KEYPAD == ONDIO_PAD
1261 "MENU:",
1262 #elif (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
1263 "PLAY:",
1264 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
1265 "NAVI:",
1266 #elif CONFIG_KEYPAD == COWON_D2_PAD
1267 "MENU:",
1268 #else
1269 "SELECT:",
1270 #endif
1271 "Releases", "the", "ball/Fire!", "",
1272 #if CONFIG_KEYPAD == IAUDIO_M3_PAD
1273 "REC:",
1274 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
1275 (CONFIG_KEYPAD == CREATIVEZVM_PAD)
1276 "BACK:",
1277 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
1278 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1279 (CONFIG_KEYPAD == IPOD_1G2G_PAD) || \
1280 (CONFIG_KEYPAD == SANSA_FUZE_PAD)
1281 "MENU:",
1282 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
1283 (CONFIG_KEYPAD == IRIVER_H300_PAD) || \
1284 (CONFIG_KEYPAD == ONDIO_PAD) || \
1285 (CONFIG_KEYPAD == RECORDER_PAD) || \
1286 (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
1287 "STOP:",
1288 #else
1289 "POWER:",
1290 #endif
1291 "Returns", "to", "menu", "", "",
1292 "Specials", "",
1293 "N", "Normal:", "returns", "paddle", "to", "normal", "",
1294 "D", "DIE!:", "loses", "a", "life", "",
1295 "L", "Life:", "gains", "a", "life/power", "up", "",
1296 "F", "Fire:", "allows", "you", "to", "shoot", "bricks", "",
1297 "G", "Glue:", "ball", "sticks", "to", "paddle", "",
1298 "B", "Ball:", "generates", "another", "ball", "",
1299 "FL", "Flip:", "flips", "left / right", "movement", "",
1300 "<->", "or", "<E>:", "enlarges", "the", "paddle", "",
1301 ">-<", "or", ">S<:", "shrinks", "the", "paddle", "",
1303 static struct style_text formation[]={
1304 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1305 { 2, C_RED },
1306 { 19, C_RED },
1307 { 37, C_RED },
1308 { 39, C_BLUE },
1309 { 46, C_RED },
1310 { 52, C_GREEN },
1311 { 59, C_ORANGE },
1312 { 67, C_GREEN },
1313 { 74, C_YELLOW },
1314 { 80, C_RED },
1315 LAST_STYLE_ITEM
1318 rb->lcd_setfont(FONT_UI);
1319 #ifdef HAVE_LCD_COLOR
1320 rb->lcd_set_background(LCD_BLACK);
1321 rb->lcd_set_foreground(LCD_WHITE);
1322 #endif
1323 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1324 return 1;
1325 rb->lcd_setfont(FONT_SYSFIXED);
1327 return 0;
1330 static int brickmania_menu_cb(int action, const struct menu_item_ex *this_item)
1332 int i = ((intptr_t)this_item);
1333 if(action == ACTION_REQUEST_MENUITEM
1334 && !resume && (i==0 || i==6))
1335 return ACTION_EXIT_MENUITEM;
1336 return action;
1339 static int brickmania_menu(void)
1341 int selected = 0;
1343 static struct opt_items options[] = {
1344 { "Easy", -1 },
1345 { "Normal", -1 },
1348 #ifdef HAVE_TOUCHSCREEN
1349 /* Entering Menu, set the touchscreen to the global setting */
1350 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
1351 #endif
1353 MENUITEM_STRINGLIST(main_menu, "Brickmania Menu", brickmania_menu_cb,
1354 "Resume Game", "Start New Game",
1355 "Difficulty", "Help", "High Scores",
1356 "Playback Control",
1357 "Quit without Saving", "Quit");
1359 rb->button_clear_queue();
1360 while (true) {
1361 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1362 case 0:
1363 if(game_state!=ST_READY)
1364 game_state = ST_PAUSE;
1365 if(resume_file)
1366 rb->remove(SAVE_FILE);
1367 return 0;
1368 case 1:
1369 score=0;
1370 vscore=0;
1371 life=2;
1372 level=0;
1373 brickmania_init_game(true);
1374 return 0;
1375 case 2:
1376 rb->set_option("Difficulty", &difficulty, INT,
1377 options, 2, NULL);
1378 break;
1379 case 3:
1380 if (brickmania_help())
1381 return 1;
1382 break;
1383 case 4:
1384 highscore_show(-1, highscores, NUM_SCORES, true);
1385 break;
1386 case 5:
1387 if (playback_control(NULL))
1388 return 1;
1389 break;
1390 case 6:
1391 return 1;
1392 case 7:
1393 if (resume) {
1394 rb->splash(HZ*1, "Saving game ...");
1395 brickmania_savegame();
1397 return 1;
1398 case MENU_ATTACHED_USB:
1399 return 1;
1400 default:
1401 break;
1404 #ifdef HAVE_TOUCHSCREEN
1405 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
1406 #endif
1409 static void brick_hit(int i, int j)
1411 if(!brick[i][j].used)
1412 return;
1414 /* if this is a crackable brick hits starts as
1415 * greater than 0.
1417 if (brick[i][j].hits > 0) {
1418 brick[i][j].hits--;
1419 brick[i][j].hiteffect++;
1420 score+=SCORE_BALL_HIT_BRICK;
1422 else {
1423 brick[i][j].used=false;
1424 if (used_powers<MAX_POWERS)
1426 int ran = rb->rand()%POWER_RAND;
1428 if (ran<NUMBER_OF_POWERUPS)
1430 power[used_powers].top = TOPMARGIN + i*BRICK_HEIGHT;
1431 power[used_powers].x_pos = LEFTMARGIN + j*BRICK_WIDTH +
1432 (BRICK_WIDTH >> 1);
1433 power[used_powers].type = ran;
1434 used_powers++;
1437 brick_on_board--;
1438 score+=SCORE_BALL_DEMOLISHED_BRICK;
1442 static int brickmania_game_loop(void)
1444 int j,i,k;
1445 int sw;
1446 char s[30];
1447 int sec_count=0;
1448 int end;
1450 /* pad_line used for powerup/ball checks */
1451 struct line pad_line;
1452 /* This is used for various lines that are checked (ball and powerup) */
1453 struct line misc_line;
1455 /* This stores the point that the two lines intersected in a test */
1456 struct point pt_hit;
1458 if (brickmania_menu()) {
1459 return 1;
1461 resume = false;
1462 resume_file = false;
1464 #ifdef HAVE_LCD_COLOR
1465 rb->lcd_set_background(LCD_BLACK);
1466 rb->lcd_set_foreground(LCD_WHITE);
1467 rb->lcd_set_drawmode(DRMODE_SOLID);
1468 rb->lcd_clear_display();
1469 #endif
1471 while(true) {
1472 /* Convert CYCLETIME (in ms) to HZ */
1473 end = *rb->current_tick + (CYCLETIME * HZ) / 1000;
1475 if (life >= 0) {
1476 rb->lcd_clear_display();
1478 if (flip_sides)
1480 if (TIME_AFTER(*rb->current_tick, sec_count))
1482 sec_count=*rb->current_tick+HZ;
1483 if (flip_sides_delay!=0)
1484 flip_sides_delay--;
1485 else
1486 flip_sides=false;
1488 rb->snprintf(s, sizeof(s), "%d", flip_sides_delay);
1489 rb->lcd_getstringsize(s, &sw, NULL);
1490 rb->lcd_putsxy(LCD_WIDTH/2-2, INT3(STRINGPOS_FLIP), s);
1493 /* write life num */
1494 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1495 rb->snprintf(s, sizeof(s), "L:%d", life);
1496 #else
1497 rb->snprintf(s, sizeof(s), "Life: %d", life);
1498 #endif
1499 rb->lcd_putsxy(0, 0, s);
1501 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
1502 rb->snprintf(s, sizeof(s), "L%d", level+1);
1503 #else
1504 rb->snprintf(s, sizeof(s), "Level %d", level+1);
1505 #endif
1507 rb->lcd_getstringsize(s, &sw, NULL);
1508 rb->lcd_putsxy(LCD_WIDTH-sw, 0, s);
1510 if (vscore<score) vscore++;
1511 rb->snprintf(s, sizeof(s), "%d", vscore);
1512 rb->lcd_getstringsize(s, &sw, NULL);
1513 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, 0, s);
1515 /* continue game */
1516 if (game_state == ST_PAUSE)
1518 rb->snprintf(s, sizeof(s), CONTINUE_TEXT);
1519 rb->lcd_getstringsize(s, &sw, NULL);
1520 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_NAVI), s);
1522 sec_count=*rb->current_tick+HZ;
1525 /* draw the ball */
1526 for(i=0;i<used_balls;i++)
1527 rb->lcd_bitmap(brickmania_ball,
1528 INT3(ball[i].pos_x - HALFBALL),
1529 INT3(ball[i].pos_y - HALFBALL),
1530 INT3(BALL), INT3(BALL));
1532 if (brick_on_board==0)
1533 brick_on_board--;
1535 /* Setup the pad line-later used in intersection test */
1536 pad_line.p1.x = pad_pos_x;
1537 pad_line.p1.y = PAD_POS_Y;
1539 pad_line.p2.x = pad_pos_x + pad_width;
1540 pad_line.p2.y = PAD_POS_Y;
1542 if (game_state!=ST_PAUSE)
1544 /* move the fires */
1545 for(k=0;k<used_fires;k++)
1547 fire[k].top -= SPEED_FIRE;
1548 if (fire[k].top < 0)
1550 used_fires--;
1551 fire[k].top = fire[used_fires].top;
1552 fire[k].x_pos = fire[used_fires].x_pos;
1553 k--;
1555 else if (fire[k].x_pos >= LEFTMARGIN &&
1556 fire[k].x_pos < LEFTMARGIN + NUM_BRICKS_COLS * BRICK_WIDTH)
1558 j = (fire[k].x_pos - LEFTMARGIN) / BRICK_WIDTH;
1559 for (i=NUM_BRICKS_ROWS-1;i>=0;i--)
1562 if (brick[i][j].used)
1564 score += SCORE_FIRE_HIT_BRICK;
1565 brick_hit(i, j);
1566 used_fires--;
1567 fire[k].top = fire[used_fires].top;
1568 fire[k].x_pos = fire[used_fires].x_pos;
1569 k--;
1570 break;
1572 if (TOPMARGIN + i*BRICK_HEIGHT<=fire[k].top)
1573 break;
1578 /* move and handle the powerups */
1579 for (k=0;k<used_powers;k++)
1581 int remove_power = 0;
1583 power[k].top += SPEED_POWER;
1585 if (power[k].top > PAD_POS_Y)
1587 /* power hit bottom */
1588 remove_power = 1;
1590 else
1592 /* Use misc_line to check if the center of the powerup
1593 * hit the paddle.
1595 misc_line.p1.x = power[k].x_pos;
1596 misc_line.p1.y = power[k].top;
1598 misc_line.p2 = misc_line.p1;
1599 misc_line.p2.y += SPEED_POWER;
1601 /* Check if the powerup will hit the paddle */
1602 if (check_lines(&misc_line, &pad_line, &pt_hit))
1605 /* power hit paddle */
1606 remove_power = 1;
1607 switch(power[k].type)
1609 case POWER_TYPE_LIFE_GAIN:
1610 life++;
1611 score += SCORE_POWER_LIFE_GAIN;
1612 break;
1613 case POWER_TYPE_LIFE_LOSS:
1614 life--;
1615 if (life>=0)
1617 brickmania_init_game(false);
1618 brickmania_sleep(2);
1620 break;
1621 case POWER_TYPE_PADDLE_STICKY:
1622 score += SCORE_POWER_PADDLE_STICKY;
1623 paddle_type = PADDLE_TYPE_STICKY;
1624 break;
1625 case POWER_TYPE_PADDLE_SHOOTER:
1626 score += SCORE_POWER_PADDLE_SHOOTER;
1627 paddle_type = PADDLE_TYPE_SHOOTER;
1628 for(i=0;i<used_balls;i++)
1629 ball[i].glue=false;
1630 break;
1631 case POWER_TYPE_PADDLE_NORMAL:
1632 score += SCORE_POWER_PADDLE_NORMAL;
1633 paddle_type = PADDLE_TYPE_NORMAL;
1634 for(i=0;i<used_balls;i++)
1635 ball[i].glue=false;
1636 flip_sides=false;
1637 pad_pos_x += (pad_width-PAD_WIDTH)/2;
1638 pad_width = PAD_WIDTH;
1639 break;
1640 case POWER_TYPE_PADDLE_FLIP:
1641 score += SCORE_POWER_FLIP;
1642 sec_count = *rb->current_tick+HZ;
1643 flip_sides_delay = FLIP_SIDES_DELAY;
1644 flip_sides = true;
1645 break;
1646 case POWER_TYPE_EXTRA_BALL:
1647 score += SCORE_POWER_EXTRA_BALL;
1648 if(used_balls<MAX_BALLS)
1650 /* Set the speed */
1651 if(rb->rand()%2 == 0)
1652 ball[used_balls].speedx=-SPEED_4Q_X;
1653 else
1654 ball[used_balls].speedx= SPEED_4Q_X;
1655 ball[used_balls].speedy= SPEED_4Q_Y;
1656 /* Ball is not glued */
1657 ball[used_balls].glue= false;
1658 used_balls++;
1660 break;
1661 case POWER_TYPE_PADDLE_LONG:
1662 score+=SCORE_POWER_LONG_PADDLE;
1663 if (pad_width==PAD_WIDTH)
1665 pad_width = LONG_PAD_WIDTH;
1666 pad_pos_x -= (LONG_PAD_WIDTH -
1667 PAD_WIDTH)/2;
1669 else if (pad_width==SHORT_PAD_WIDTH)
1671 pad_width = PAD_WIDTH;
1672 pad_pos_x-=(PAD_WIDTH-
1673 SHORT_PAD_WIDTH)/2;
1675 if (pad_pos_x < 0)
1676 pad_pos_x = 0;
1677 else if(pad_pos_x + pad_width >
1678 GAMESCREEN_WIDTH)
1679 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
1680 break;
1681 case POWER_TYPE_PADDLE_SHORT:
1682 if (pad_width==PAD_WIDTH)
1684 pad_width=SHORT_PAD_WIDTH;
1685 pad_pos_x+=(PAD_WIDTH-
1686 SHORT_PAD_WIDTH)/2;
1688 else if (pad_width==LONG_PAD_WIDTH)
1690 pad_width=PAD_WIDTH;
1691 pad_pos_x+=(LONG_PAD_WIDTH-PAD_WIDTH)/2;
1693 break;
1694 default:
1695 break;
1699 if (remove_power)
1701 used_powers--;
1702 if (k != used_powers)
1704 power[k].top = power[used_powers].top;
1705 power[k].x_pos = power[used_powers].x_pos;
1706 power[k].type = power[used_powers].type;
1708 k--;
1714 /* draw the fires */
1715 for(k=0;k<used_fires;k++)
1717 rb->lcd_vline(INT3(fire[k].x_pos), INT3(fire[k].top),
1718 INT3(fire[k].top + FIRE_LENGTH));
1721 /* draw the powerups */
1722 for(k=0;k<used_powers;k++)
1724 rb->lcd_bitmap_part(brickmania_powerups,0,
1725 INT3(POWERUP_HEIGHT)*power[k].type,
1726 STRIDE(SCREEN_MAIN, BMPWIDTH_brickmania_powerups,
1727 BMPHEIGHT_brickmania_powerups),
1728 INT3(power[k].x_pos - (POWERUP_WIDTH >> 1)),
1729 INT3(power[k].top), INT3(POWERUP_WIDTH),
1730 INT3(POWERUP_HEIGHT));
1733 /* handle all of the bricks */
1734 for (i=0; i<NUM_BRICKS_ROWS; i++)
1736 for (j=0; j<NUM_BRICKS_COLS ;j++)
1738 int brickx,bricky;
1740 /* The brick is a brick, but it may or may not be in use */
1741 if(brick[i][j].used)
1743 /* these lines are used to describe the brick */
1744 struct line bot_brick, top_brick, left_brick, rght_brick;
1745 brickx = LEFTMARGIN + j*BRICK_WIDTH;
1746 bricky = TOPMARGIN + i*BRICK_HEIGHT;
1748 /* Describe the brick for later collision checks */
1749 /* Setup the bottom of the brick */
1750 bot_brick.p1.x = brickx;
1751 bot_brick.p1.y = bricky + BRICK_HEIGHT;
1753 bot_brick.p2.x = brickx + BRICK_WIDTH;
1754 bot_brick.p2.y = bricky + BRICK_HEIGHT;
1756 /* Setup the top of the brick */
1757 top_brick.p1.x = brickx;
1758 top_brick.p1.y = bricky;
1760 top_brick.p2.x = brickx + BRICK_WIDTH;
1761 top_brick.p2.y = bricky;
1763 /* Setup the left of the brick */
1764 left_brick.p1.x = brickx;
1765 left_brick.p1.y = bricky;
1767 left_brick.p2.x = brickx;
1768 left_brick.p2.y = bricky + BRICK_HEIGHT;
1770 /* Setup the right of the brick */
1771 rght_brick.p1.x = brickx + BRICK_WIDTH;
1772 rght_brick.p1.y = bricky;
1774 rght_brick.p2.x = brickx + BRICK_WIDTH;
1775 rght_brick.p2.y = bricky + BRICK_HEIGHT;
1777 /* Draw the brick */
1778 rb->lcd_bitmap_part(brickmania_bricks,0,
1779 INT3(BRICK_HEIGHT)*brick[i][j].color,
1780 STRIDE( SCREEN_MAIN,
1781 BMPWIDTH_brickmania_bricks,
1782 BMPHEIGHT_brickmania_bricks),
1783 INT3(brickx),
1784 INT3(bricky),
1785 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1787 #ifdef HAVE_LCD_COLOR /* No transparent effect for greyscale lcds for now */
1788 if (brick[i][j].hiteffect > 0)
1789 rb->lcd_bitmap_transparent_part(brickmania_break,0,
1790 INT3(BRICK_HEIGHT)*brick[i][j].hiteffect,
1791 STRIDE( SCREEN_MAIN,
1792 BMPWIDTH_brickmania_break,
1793 BMPHEIGHT_brickmania_break),
1794 INT3(brickx),
1795 INT3(bricky),
1796 INT3(BRICK_WIDTH), INT3(BRICK_HEIGHT) );
1797 #endif
1799 /* Check if any balls collided with the brick */
1800 for(k=0; k<used_balls; k++)
1802 /* Setup the ball path to describe the current ball
1803 * position and the line it makes to its next
1804 * position.
1806 misc_line.p1.x = ball[k].pos_x;
1807 misc_line.p1.y = ball[k].pos_y;
1809 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1810 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1812 /* Check to see if the ball and the bottom hit. If
1813 * the ball is moving down we don't want to
1814 * include the bottom line intersection.
1816 * The order that the sides are checked matters.
1818 * Note that tempx/tempy store the next position
1819 * that the ball should be drawn.
1821 if(ball[k].speedy <= 0 &&
1822 check_lines(&misc_line, &bot_brick, &pt_hit))
1824 ball[k].speedy = -ball[k].speedy;
1825 ball[k].tempy = pt_hit.y;
1826 ball[k].tempx = pt_hit.x;
1827 brick_hit(i, j);
1829 /* Check the top, if the ball is moving up dont
1830 * count it as a hit.
1832 else if(ball[k].speedy > 0 &&
1833 check_lines(&misc_line, &top_brick, &pt_hit))
1835 ball[k].speedy = -ball[k].speedy;
1836 ball[k].tempy = pt_hit.y;
1837 ball[k].tempx = pt_hit.x;
1838 brick_hit(i, j);
1840 /* Check the left side of the brick */
1841 else if(
1842 check_lines(&misc_line, &left_brick, &pt_hit))
1844 ball[k].speedx = -ball[k].speedx;
1845 ball[k].tempy = pt_hit.y;
1846 ball[k].tempx = pt_hit.x;
1847 brick_hit(i, j);
1849 /* Check the right side of the brick */
1850 else if(
1851 check_lines(&misc_line, &rght_brick, &pt_hit))
1853 ball[k].speedx = -ball[k].speedx;
1854 ball[k].tempy = pt_hit.y;
1855 ball[k].tempx = pt_hit.x;
1856 brick_hit(i, j);
1858 } /* for k */
1859 } /* if(used) */
1861 } /* for j */
1862 } /* for i */
1864 /* draw the paddle according to the PAD_WIDTH */
1865 if( pad_width == PAD_WIDTH ) /* Normal width */
1867 rb->lcd_bitmap_part(
1868 brickmania_pads,
1869 0, paddle_type*INT3(PAD_HEIGHT),
1870 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_pads,
1871 BMPHEIGHT_brickmania_pads),
1872 INT3(pad_pos_x), INT3(PAD_POS_Y),
1873 INT3(pad_width), INT3(PAD_HEIGHT) );
1875 else if( pad_width == LONG_PAD_WIDTH ) /* Long Pad */
1877 rb->lcd_bitmap_part(
1878 brickmania_long_pads,
1879 0,paddle_type*INT3(PAD_HEIGHT),
1880 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_long_pads,
1881 BMPHEIGHT_brickmania_long_pads),
1882 INT3(pad_pos_x), INT3(PAD_POS_Y),
1883 INT3(pad_width), INT3(PAD_HEIGHT) );
1885 else /* Short pad */
1887 rb->lcd_bitmap_part(
1888 brickmania_short_pads,
1889 0,paddle_type*INT3(PAD_HEIGHT),
1890 STRIDE( SCREEN_MAIN, BMPWIDTH_brickmania_short_pads,
1891 BMPHEIGHT_brickmania_short_pads),
1892 INT3(pad_pos_x), INT3(PAD_POS_Y),
1893 INT3(pad_width), INT3(PAD_HEIGHT) );
1896 /* If the game is not paused continue */
1897 if (game_state!=ST_PAUSE)
1899 /* Loop through all of the balls in play */
1900 for(k=0;k<used_balls;k++)
1902 struct line screen_edge;
1904 /* Describe the ball movement for the edge collision detection */
1905 misc_line.p1.x = ball[k].pos_x;
1906 misc_line.p1.y = ball[k].pos_y;
1908 misc_line.p2.x = ball[k].pos_x + ball[k].speedx;
1909 misc_line.p2.y = ball[k].pos_y + ball[k].speedy;
1911 /* Did the Ball hit the top of the screen? */
1912 screen_edge.p1.x = 0;
1913 screen_edge.p1.y = 0;
1915 screen_edge.p2.x = GAMESCREEN_WIDTH;
1916 screen_edge.p2.y = 0;
1917 /* the test for pos_y prevents the ball from bouncing back
1918 * from _over_ the top to infinity on some rare cases */
1919 if (ball[k].pos_y > 0 &&
1920 check_lines(&misc_line, &screen_edge, &pt_hit))
1922 ball[k].tempy = pt_hit.y + 1;
1923 ball[k].tempx = pt_hit.x;
1924 /* Reverse the direction */
1925 ball[k].speedy = -ball[k].speedy;
1928 /* Player missed the ball and hit bottom of screen */
1929 if (ball[k].pos_y >= GAMESCREEN_HEIGHT)
1931 /* Player had balls to spare, so handle the removal */
1932 if (used_balls>1)
1934 /* decrease number of balls in play */
1935 used_balls--;
1936 /* Replace removed ball with the last ball */
1937 ball[k].pos_x = ball[used_balls].pos_x;
1938 ball[k].pos_y = ball[used_balls].pos_y;
1939 ball[k].speedy = ball[used_balls].speedy;
1940 ball[k].tempy = ball[used_balls].tempy;
1941 ball[k].speedx = ball[used_balls].speedx;
1942 ball[k].tempx = ball[used_balls].tempx;
1943 ball[k].glue = ball[used_balls].glue;
1945 /* Reset the last ball that was removed */
1946 ball[used_balls].speedx=0;
1947 ball[used_balls].speedy=0;
1948 ball[used_balls].tempy=0;
1949 ball[used_balls].tempx=0;
1950 ball[used_balls].pos_y=ON_PAD_POS_Y;
1951 ball[used_balls].pos_x=pad_pos_x+(pad_width/2)-2;
1953 k--;
1954 continue;
1956 else
1958 /* Player lost a life */
1959 life--;
1960 if (life>=0)
1962 /* No lives left reset game */
1963 brickmania_init_game(false);
1964 brickmania_sleep(2);
1965 rb->button_clear_queue();
1970 if (game_state != ST_READY && !ball[k].glue)
1972 /* Check if the ball hit the left side */
1973 screen_edge.p1.x = 0;
1974 screen_edge.p1.y = 0;
1976 screen_edge.p2.x = 0;
1977 screen_edge.p2.y = GAMESCREEN_HEIGHT;
1978 if (check_lines(&misc_line, &screen_edge, &pt_hit))
1980 /* Reverse direction */
1981 ball[k].speedx = -ball[k].speedx;
1983 /* Re-position ball in gameboard */
1984 ball[k].tempy = pt_hit.y;
1985 ball[k].tempx = 0;
1988 /* Check if the ball hit the right side */
1989 screen_edge.p1.x = GAMESCREEN_WIDTH;
1990 screen_edge.p1.y = 0;
1992 screen_edge.p2.x = GAMESCREEN_WIDTH;
1993 screen_edge.p2.y = GAMESCREEN_HEIGHT;
1994 if (check_lines(&misc_line, &screen_edge, &pt_hit))
1996 /* Reverse direction */
1997 ball[k].speedx = -ball[k].speedx;
1999 /* Re-position ball in gameboard */
2000 ball[k].tempy = pt_hit.y;
2001 ball[k].tempx = GAMESCREEN_WIDTH - FIXED3(1);
2004 /* Did the ball hit the paddle? Depending on where the ball
2005 * Hit set the x/y speed appropriately.
2007 if(check_lines(&misc_line, &pad_line, &pt_hit) )
2009 /* Re-position ball based on collision */
2010 ball[k].tempy = ON_PAD_POS_Y;
2011 ball[k].tempx = pt_hit.x;
2013 /* Calculate the ball position relative to the paddle width */
2014 int ball_repos = pt_hit.x - pad_pos_x;
2015 /* If the ball hits the right half of paddle, x speed
2016 * should be positive, if it hits the left half it
2017 * should be negative.
2019 int x_direction = -1;
2021 /* Comparisons are done with respect to 1/2 pad_width */
2022 if(ball_repos > pad_width/2)
2024 /* flip the relative position */
2025 ball_repos -= ((ball_repos - pad_width/2) << 1);
2026 /* Ball hit the right half so X speed calculations
2027 * should be positive.
2029 x_direction = 1;
2032 /* Figure out where the ball hit relative to 1/2 pad
2033 * and in divisions of 4.
2035 ball_repos = ball_repos / (pad_width/2/4);
2037 switch(ball_repos)
2039 /* Ball hit the outer edge of the paddle */
2040 case 0:
2041 ball[k].speedy = SPEED_1Q_Y;
2042 ball[k].speedx = SPEED_1Q_X * x_direction;
2043 break;
2044 /* Ball hit the next fourth of the paddle */
2045 case 1:
2046 ball[k].speedy = SPEED_2Q_Y;
2047 ball[k].speedx = SPEED_2Q_X * x_direction;
2048 break;
2049 /* Ball hit the third fourth of the paddle */
2050 case 2:
2051 ball[k].speedy = SPEED_3Q_Y;
2052 ball[k].speedx = SPEED_3Q_X * x_direction;
2053 break;
2054 /* Ball hit the fourth fourth of the paddle or dead
2055 * center.
2057 case 3:
2058 case 4:
2059 ball[k].speedy = SPEED_4Q_Y;
2060 /* Since this is the middle we don't want to
2061 * force the ball in a different direction.
2062 * Just keep it going in the same direction
2063 * with a specific speed.
2065 if(ball[k].speedx > 0)
2067 ball[k].speedx = SPEED_4Q_X;
2069 else
2071 ball[k].speedx = -SPEED_4Q_X;
2073 break;
2075 default:
2076 ball[k].speedy = SPEED_4Q_Y;
2077 break;
2080 if(paddle_type == PADDLE_TYPE_STICKY)
2082 ball[k].speedy = -ball[k].speedy;
2083 ball[k].glue=true;
2085 /* X location should not be forced since that is moved with the paddle. The Y
2086 * position should be forced to keep the ball at the paddle.
2088 ball[k].tempx = 0;
2089 ball[k].tempy = ON_PAD_POS_Y;
2094 /* Update the ball position */
2095 if (!ball[k].glue)
2097 if(ball[k].tempx)
2098 ball[k].pos_x = ball[k].tempx;
2099 else
2100 ball[k].pos_x += ball[k].speedx;
2102 if(ball[k].tempy)
2103 ball[k].pos_y = ball[k].tempy;
2104 else
2105 ball[k].pos_y += ball[k].speedy;
2107 ball[k].tempy=0;
2108 ball[k].tempx=0;
2110 } /* for k */
2113 rb->lcd_update();
2115 if (brick_on_board < 0)
2117 if (level+1<NUM_LEVELS)
2119 level++;
2120 if (difficulty==NORMAL)
2121 score+=SCORE_LEVEL_COMPLETED;
2122 brickmania_init_game(true);
2123 brickmania_sleep(2);
2124 rb->button_clear_queue();
2126 else
2128 rb->lcd_getstringsize("Congratulations!", &sw, NULL);
2129 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_CONGRATS),
2130 "Congratulations!");
2131 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
2132 rb->lcd_getstringsize("No more levels", &sw, NULL);
2133 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2134 "No more levels");
2135 #else
2136 rb->lcd_getstringsize("You have finished the game!",
2137 &sw, NULL);
2138 rb->lcd_putsxy(LCD_WIDTH/2-sw/2, INT3(STRINGPOS_FINISH),
2139 "You have finished the game!");
2140 #endif
2141 vscore=score;
2142 rb->lcd_update();
2143 brickmania_sleep(2);
2144 return 0;
2148 int button=rb->button_get(false);
2149 int move_button = rb->button_status();
2151 #if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
2152 /* FIXME: Should probably check remote hold here */
2153 if (rb->button_hold())
2154 button = QUIT;
2155 #endif
2157 #ifdef HAVE_TOUCHSCREEN
2158 if( move_button & BUTTON_TOUCHSCREEN)
2160 int data;
2161 short touch_x, touch_y;
2162 rb->button_status_wdata(&data);
2163 touch_x = FIXED3(data >> 16);
2164 touch_y = FIXED3(data & 0xffff);
2166 if(flip_sides)
2168 pad_pos_x = GAMESCREEN_WIDTH - (touch_x + pad_width/2);
2170 else
2172 pad_pos_x = (touch_x - pad_width/2);
2175 if(pad_pos_x < 0)
2176 pad_pos_x = 0;
2177 else if(pad_pos_x + pad_width > GAMESCREEN_WIDTH)
2178 pad_pos_x = GAMESCREEN_WIDTH-pad_width;
2179 for(k=0; k<used_balls; k++)
2180 if (game_state==ST_READY || ball[k].glue)
2181 ball[k].pos_x = pad_pos_x + pad_width/2;
2183 else
2184 #endif
2186 int button_right, button_left;
2187 #ifdef ALTRIGHT
2188 button_right = move_button & (RIGHT | ALTRIGHT);
2189 button_left = move_button & (LEFT | ALTLEFT);
2190 #else
2191 button_right =((move_button & RIGHT)|| SCROLL_FWD(button));
2192 button_left =((move_button & LEFT) ||SCROLL_BACK(button));
2193 #endif
2194 if ((game_state==ST_PAUSE) && (button_right || button_left))
2195 continue;
2196 if ((button_right && !flip_sides) ||
2197 (button_left && flip_sides))
2199 if (pad_pos_x+SPEED_PAD+pad_width > GAMESCREEN_WIDTH)
2201 for(k=0;k<used_balls;k++)
2202 if (game_state==ST_READY || ball[k].glue)
2203 ball[k].pos_x += GAMESCREEN_WIDTH-pad_pos_x -
2204 pad_width;
2205 pad_pos_x += GAMESCREEN_WIDTH - pad_pos_x - pad_width;
2207 else {
2208 for(k=0;k<used_balls;k++)
2209 if ((game_state==ST_READY || ball[k].glue))
2210 ball[k].pos_x+=SPEED_PAD;
2211 pad_pos_x+=SPEED_PAD;
2214 else if ((button_left && !flip_sides) ||
2215 (button_right && flip_sides))
2217 if (pad_pos_x-SPEED_PAD < 0)
2219 for(k=0;k<used_balls;k++)
2220 if (game_state==ST_READY || ball[k].glue)
2221 ball[k].pos_x-=pad_pos_x;
2222 pad_pos_x -= pad_pos_x;
2224 else
2226 for(k=0;k<used_balls;k++)
2227 if (game_state==ST_READY || ball[k].glue)
2228 ball[k].pos_x-=SPEED_PAD;
2229 pad_pos_x-=SPEED_PAD;
2234 switch(button)
2236 #if defined(HAVE_TOUCHSCREEN)
2237 case (BUTTON_REL | BUTTON_TOUCHSCREEN):
2238 #endif
2239 case UP:
2240 case SELECT:
2241 #ifdef ALTSELECT
2242 case ALTSELECT:
2243 #endif
2244 if (game_state==ST_READY)
2246 /* Initialize used balls starting speed */
2247 for(k=0 ; k < used_balls ; k++)
2249 ball[k].speedy = SPEED_4Q_Y;
2250 if(pad_pos_x + (pad_width/2) >= GAMESCREEN_WIDTH/2)
2252 ball[k].speedx = SPEED_4Q_X;
2254 else
2256 ball[k].speedx = -SPEED_4Q_X;
2259 game_state=ST_START;
2261 else if (game_state==ST_PAUSE)
2263 game_state=ST_START;
2265 else if (paddle_type == PADDLE_TYPE_STICKY)
2267 for(k=0;k<used_balls;k++)
2269 if (ball[k].glue)
2271 ball[k].glue=false;
2272 ball[k].speedy = -ball[k].speedy;
2276 else if (paddle_type == PADDLE_TYPE_SHOOTER)
2278 if (used_fires < MAX_FIRES)
2280 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2281 fire[used_fires].x_pos = pad_pos_x + 1; /* Add 1 for edge */
2282 used_fires++;
2284 if (used_fires < MAX_FIRES)
2286 fire[used_fires].top = PAD_POS_Y - FIRE_LENGTH;
2287 fire[used_fires].x_pos = pad_pos_x + pad_width - 1; /* Sub1 edge*/
2288 used_fires++;
2291 break;
2292 #ifdef RC_QUIT
2293 case RC_QUIT:
2294 #endif
2295 case QUIT:
2296 resume = true;
2297 return 0;
2298 break;
2300 default:
2301 if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
2302 return 1;
2303 break;
2306 else
2308 #ifdef HAVE_LCD_COLOR
2309 rb->lcd_bitmap_transparent(brickmania_gameover,
2310 (LCD_WIDTH - INT3(GAMEOVER_WIDTH))/2,
2311 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2312 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT));
2313 #else /* greyscale and mono */
2314 rb->lcd_bitmap(brickmania_gameover,(LCD_WIDTH -
2315 INT3(GAMEOVER_WIDTH))/2,
2316 INT3(GAMESCREEN_HEIGHT - GAMEOVER_HEIGHT)/2,
2317 INT3(GAMEOVER_WIDTH),INT3(GAMEOVER_HEIGHT) );
2318 #endif
2319 rb->lcd_update();
2320 brickmania_sleep(2);
2321 return 0;
2324 /* Game always needs to yield for other threads */
2325 rb->yield();
2327 /* Sleep for a bit if there is time to spare */
2328 if (TIME_BEFORE(*rb->current_tick, end))
2329 rb->sleep(end-*rb->current_tick);
2331 return 0;
2334 /* this is the plugin entry point */
2335 enum plugin_status plugin_start(const void* parameter)
2337 (void)parameter;
2338 int last_difficulty;
2340 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
2341 configfile_load(CONFIG_FILE_NAME,config,1,0);
2342 last_difficulty = difficulty;
2344 #ifdef HAVE_TOUCHSCREEN
2345 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
2346 #endif
2348 rb->lcd_setfont(FONT_SYSFIXED);
2349 #if LCD_DEPTH > 1
2350 rb->lcd_set_backdrop(NULL);
2351 #endif
2352 /* Turn off backlight timeout */
2353 backlight_force_on(); /* backlight control in lib/helper.c */
2355 /* now go ahead and have fun! */
2356 rb->srand( *rb->current_tick );
2357 brickmania_loadgame();
2358 resume_file = resume;
2359 while(!brickmania_game_loop())
2361 if(!resume)
2363 int position = highscore_update(score, level+1, "",
2364 highscores, NUM_SCORES);
2365 if (position != -1)
2367 if (position == 0)
2368 rb->splash(HZ*2, "New High Score");
2369 highscore_show(position, highscores, NUM_SCORES, true);
2371 else
2373 brickmania_sleep(3);
2378 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2379 if(last_difficulty != difficulty)
2380 configfile_save(CONFIG_FILE_NAME,config,1,0);
2381 /* Restore user's original backlight setting */
2382 rb->lcd_setfont(FONT_UI);
2383 /* Turn on backlight timeout (revert to settings) */
2384 backlight_use_settings(); /* backlight control in lib/helper.c */
2386 return PLUGIN_OK;