A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2005 Adam Boot
11*
12* Color graphics from Frozen Bubble (http://www.frozen-bubble.org/)
13*
14* This program is free software; you can redistribute it and/or
15* modify it under the terms of the GNU General Public License
16* as published by the Free Software Foundation; either version 2
17* of the License, or (at your option) any later version.
18*
19* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20* KIND, either express or implied.
21*
22****************************************************************************/
23
24#include "plugin.h"
25#include "fixedpoint.h"
26
27#include "lib/xlcd.h"
28#include "lib/pluginlib_actions.h"
29#include "lib/playback_control.h"
30#include "lib/highscore.h"
31
32/* files */
33#define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/bubbles.score"
34#define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/bubbles.save"
35#define DATA_FILE PLUGIN_GAMES_DATA_DIR "/bubbles.data"
36
37/* final game return status */
38enum {
39 BB_LOSE,
40 BB_QUIT_WITHOUT_SAVING,
41 BB_QUIT,
42 BB_USB,
43 BB_END,
44 BB_WIN,
45 BB_NONE,
46};
47
48/* play board dimension */
49#define BB_HEIGHT 12
50#define BB_WIDTH 8
51#define BB_LEVEL_HEIGHT 10
52
53/* various amounts */
54#define NUM_SCORES 5
55#define NUM_LEVELS 100
56#define NUM_QUEUE 2
57#define NUM_BUBBLES 8
58#define MIN_ANGLE -76
59#define MAX_ANGLE 76
60#define NUM_COMPRESS 9
61#define MAX_SHOTTIME 1000
62
63/* keyboard layouts */
64
65#ifdef HAVE_SCROLLWHEEL
66/* sansas use the wheel instead of left/right if available */
67#define BUBBLES_LEFT PLA_SCROLL_BACK
68#define BUBBLES_LEFT_REP PLA_SCROLL_BACK_REPEAT
69#define BUBBLES_RIGHT PLA_SCROLL_FWD
70#define BUBBLES_RIGHT_REP PLA_SCROLL_FWD_REPEAT
71#else
72#define BUBBLES_LEFT PLA_LEFT
73#define BUBBLES_LEFT_REP PLA_LEFT_REPEAT
74#define BUBBLES_RIGHT PLA_RIGHT
75#define BUBBLES_RIGHT_REP PLA_RIGHT_REPEAT
76#endif
77
78#define ANGLE_STEP 2
79#define ANGLE_STEP_REP 6
80
81#define BUBBLES_QUIT1 PLA_EXIT
82
83/* these are better off shooting with up */
84#if (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) \
85 || (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) \
86 || (CONFIG_KEYPAD == IRIVER_H10_PAD)
87#define SHOOT_WITH_UP
88#endif
89
90#ifdef SHOOT_WITH_UP
91#define BUBBLES_FIRE PLA_UP
92#define BUBBLES_FIRE_REPEAT PLA_UP_REPEAT
93#define BUBBLES_PAUSE PLA_SELECT
94#define BUBBLES_QUIT2 PLA_CANCEL
95#elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
96 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
97 || (CONFIG_KEYPAD == IPOD_4G_PAD)
98#define BUBBLES_FIRE PLA_SELECT
99#define BUBBLES_FIRE_REPEAT PLA_SELECT_REPEAT
100#define BUBBLES_PAUSE PLA_DOWN
101#define BUBBLES_QUIT2 PLA_UP
102#else
103#define BUBBLES_FIRE PLA_SELECT
104#define BUBBLES_FIRE_REPEAT PLA_SELECT_REPEAT
105#define BUBBLES_PAUSE PLA_UP
106#define BUBBLES_QUIT2 PLA_CANCEL
107#endif
108
109/* external bitmaps */
110#ifdef HAVE_LCD_COLOR
111#include "pluginbitmaps/bubbles_background.h"
112#endif
113#include "pluginbitmaps/bubbles_bubble.h"
114#include "pluginbitmaps/bubbles_emblem.h"
115
116#define BUBBLE_WIDTH BMPWIDTH_bubbles_bubble
117#define BUBBLE_HEIGHT BMPHEIGHT_bubbles_bubble
118#define EMBLEM_WIDTH BMPWIDTH_bubbles_emblem
119#define EMBLEM_HEIGHT (BMPHEIGHT_bubbles_emblem/8)
120
121/* bubbles will consume height of ROW_HEIGHT*(BB_HEIGHT-1)+BUBBLE_HEIGHT*3/2 */
122/* 44x44 bubbles (m:robe 500) */
123#if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
124#define XOFS 144
125#define MAX_FPS 40
126
127/* custom text positioning */
128#define LEVEL_TXT_X 58
129#define LEVEL_TXT_WIDTH 32
130#define LEVEL_TXT_Y 8
131#define SCORE_TXT_X 58
132#define SCORE_TXT_WIDTH 32
133#define SCORE_TXT_Y 62
134#define NEXT_BB_X 58
135#define NEXT_BB_WIDTH 32
136#define NEXT_BB_Y 402
137
138#elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
139#define XOFS 128
140#define MAX_FPS 40
141
142#elif (LCD_WIDTH == 360) && (LCD_HEIGHT == 400)
143#define XOFS 86
144#define YOFS 100
145#define SCORE_TXT_X 28
146#define SCORE_TXT_WIDTH 32
147#define SCORE_TXT_Y 48
148#define LEVEL_TXT_X 27
149#define LEVEL_TXT_WIDTH 32
150#define LEVEL_TXT_Y 5
151#define MAX_FPS 40
152
153/* 22x22 bubbles (iPod Video) */
154#elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 320)
155#define XOFS 72
156#define MAX_FPS 40
157
158/* custom text positioning */
159#define NEXT_BB_X 20
160#define NEXT_BB_WIDTH 32
161#define NEXT_BB_Y 200
162
163/* 22x22 bubbles (Gigabeat, Onda VX747) */
164#elif ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400)) && (LCD_WIDTH == 240)
165#define XOFS 64
166#define MAX_FPS 30
167
168/* custom text positioning */
169#define LEVEL_TXT_X 21
170#define LEVEL_TXT_WIDTH 32
171#define LEVEL_TXT_Y 2
172#define SCORE_TXT_X 20
173#define SCORE_TXT_WIDTH 32
174#define SCORE_TXT_Y 29
175#define NEXT_BB_X 20
176#define NEXT_BB_WIDTH 32
177#define NEXT_BB_Y 200
178
179/* 22x22 bubbles (Anbernic RG Nano) */
180#elif (LCD_HEIGHT == 240) && (LCD_WIDTH == 240)
181#define XOFS 64
182#define MAX_FPS 40
183
184/* custom text positioning */
185#define SCORE_TXT_X 12
186#define SCORE_TXT_WIDTH 32
187#define SCORE_TXT_Y 29
188#define LEVEL_TXT_X 12
189#define LEVEL_TXT_WIDTH 32
190#define LEVEL_TXT_Y 2
191#define NEXT_BB_X 12
192#define NEXT_BB_WIDTH 32
193#define NEXT_BB_Y 200
194
195/* 16x16 bubbles (H300, iPod Color, HDD6330) */
196#elif (LCD_HEIGHT == 176) && (LCD_WIDTH == 220)
197#define XOFS 46
198#define MAX_FPS 30
199
200/* 16x16 bubbles (Sansa E200) */
201#elif (LCD_HEIGHT == 220) && (LCD_WIDTH == 176)
202#define XOFS 24
203#define MAX_FPS 30
204#define YOFS 45
205
206/* custom text positioning */
207#define LEVEL_TXT_X 24
208#define LEVEL_TXT_WIDTH 31
209#define LEVEL_TXT_Y 5
210#define SCORE_TXT_X 58
211#define SCORE_TXT_WIDTH 31
212#define SCORE_TXT_Y 5
213#define NEXT_BB_X 112
214#define NEXT_BB_WIDTH 31
215#define NEXT_BB_Y 3
216
217/* 12x12 bubbles (iPod Nano) */
218#elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
219#define XOFS 40
220#define MAX_FPS 40
221
222/* 12x12 bubbles (H100, H10, iAudio X5, HDD1630, iPod 3G, iPod 4G grayscale) */
223#elif (LCD_HEIGHT == 128) && ((LCD_WIDTH == 160) || (LCD_WIDTH == 128))
224#define XOFS 33
225#define MAX_FPS 30
226
227/* 12x12 bubbles (GoGear SA9200) */
228#elif (LCD_HEIGHT == 160) && (LCD_WIDTH == 128)
229#define XOFS 16
230#define YOFS 32
231#define ROW_HEIGHT 10
232#define ROW_INDENT 6
233#define MAX_FPS 30
234
235/* custom text positioning */
236#define LEVEL_TXT_X 2
237#define LEVEL_TXT_WIDTH 31
238#define LEVEL_TXT_Y 3
239#define SCORE_TXT_X 34
240#define SCORE_TXT_WIDTH 31
241#define SCORE_TXT_Y 3
242#define NEXT_BB_X 81
243#define NEXT_BB_WIDTH 31
244#define NEXT_BB_Y 2
245
246/* 10x10 bubbles (iPod Mini) */
247#elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
248#define XOFS 33
249#define MAX_FPS 30
250
251/* 9x9 bubbles (iAudio M3, Samsung YH-820) */
252#elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
253#define XOFS 29
254#define MAX_FPS 30
255
256/* 8x8 bubbles (Sansa C200) */
257#elif ((LCD_HEIGHT == 80) && (LCD_WIDTH == 132))
258#define XOFS 45
259#define ROW_HEIGHT 6
260#define MAX_FPS 30
261
262/* 7x7 bubbles (Sansa Clip/m200) */
263#elif (LCD_HEIGHT == 64 && LCD_WIDTH == 128)
264#define XOFS 33
265#define ROW_HEIGHT 5
266#define MAX_FPS 30
267
268/* 8x7 bubbles (Archos recorder, Ondio) */
269#elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
270#define XOFS 33
271#define ROW_HEIGHT 5
272#define MAX_FPS 20
273
274/* 7x7 bubbles (Sansa Clip Zip) */
275#elif (LCD_HEIGHT == 96 && LCD_WIDTH == 96)
276#define XOFS 33
277#define ROW_HEIGHT 5
278#define MAX_FPS 30
279
280/* custom text positioning */
281#define LEVEL_TXT_X 1
282#define LEVEL_TXT_WIDTH 31
283#define LEVEL_TXT_Y 4
284#define SCORE_TXT_X 1
285#define SCORE_TXT_WIDTH 31
286#define SCORE_TXT_Y 31
287#define NEXT_BB_X 1
288#define NEXT_BB_WIDTH 31
289#define NEXT_BB_Y 72
290
291#else
292 #error BUBBLES: Unsupported LCD type
293#endif
294
295#if !defined(ROW_HEIGHT)
296#define ROW_HEIGHT (BUBBLE_WIDTH-(BUBBLE_WIDTH-EMBLEM_WIDTH)/2)
297#endif
298
299#if !defined(ROW_INDENT)
300#define ROW_INDENT (BUBBLE_WIDTH/2)
301#endif
302
303#define TEXT_LINES (LCD_HEIGHT/8)
304
305#ifndef YOFS
306#define YOFS 0
307#endif
308
309/* shot position */
310#define SHOTX XOFS+ROW_INDENT+BUBBLE_WIDTH*3
311#define SHOTY (YOFS+ROW_HEIGHT*(BB_HEIGHT-1)+BUBBLE_HEIGHT/2)
312
313/* collision distance squared */
314#define MIN_DISTANCE ((BUBBLE_WIDTH*8)/10)*((BUBBLE_HEIGHT*8)/10)
315
316/* levels */
317char level[NUM_LEVELS][BB_LEVEL_HEIGHT][BB_WIDTH] = {
318 {{ 6, 6, 4, 4, 2, 2, 3, 3},
319 { 6, 6, 4, 4, 2, 2, 3, -1},
320 { 2, 2, 3, 3, 6, 6, 4, 4},
321 { 2, 3, 3, 6, 6, 4, 4, -1},
322 {-1, -1, -1, -1, -1, -1, -1, -1},
323 {-1, -1, -1, -1, -1, -1, -1, -1},
324 {-1, -1, -1, -1, -1, -1, -1, -1},
325 {-1, -1, -1, -1, -1, -1, -1, -1},
326 {-1, -1, -1, -1, -1, -1, -1, -1},
327 {-1, -1, -1, -1, -1, -1, -1, -1}},
328 {{-1, 7, 7, 7, 7, 7, 7, -1},
329 {-1, 1, 1, 1, 1, 1, -1, -1},
330 {-1, -1, 2, 2, 2, 2, -1, -1},
331 {-1, -1, -1, 2, -1, -1, -1, -1},
332 {-1, -1, -1, 2, 2, -1, -1, -1},
333 {-1, -1, -1, 5, -1, -1, -1, -1},
334 {-1, -1, -1, 5, 5, -1, -1, -1},
335 {-1, -1, -1, -1, -1, -1, -1, -1},
336 {-1, -1, -1, -1, -1, -1, -1, -1},
337 {-1, -1, -1, -1, -1, -1, -1, -1}},
338 {{-1, -1, 7, -1, -1, 7, -1, -1},
339 {-1, -1, 7, 1, 7, -1, -1, -1},
340 {-1, -1, -1, 1, 2, -1, -1, -1},
341 {-1, -1, 1, 2, 1, -1, -1, -1},
342 {-1, -1, -1, 2, 5, -1, -1, -1},
343 {-1, -1, 3, 5, 3, -1, -1, -1},
344 {-1, -1, -1, 5, 3, -1, -1, -1},
345 {-1, -1, -1, 3, -1, -1, -1, -1},
346 {-1, -1, -1, -1, -1, -1, -1, -1},
347 {-1, -1, -1, -1, -1, -1, -1, -1}},
348 {{-1, -1, -1, 0, 0, -1, -1, -1},
349 {-1, -1, 5, 0, 1, -1, -1, -1},
350 {-1, -1, 3, 5, 1, 6, -1, -1},
351 {-1, 4, 3, -1, 6, 7, -1, -1},
352 {-1, 7, 4, -1, -1, 7, 4, -1},
353 { 6, 7, -1, -1, -1, 4, 3, -1},
354 { 1, 6, -1, -1, -1, -1, 3, 5},
355 { 1, -1, -1, -1, -1, -1, 5, -1},
356 {-1, -1, -1, -1, -1, -1, -1, -1},
357 {-1, -1, -1, -1, -1, -1, -1, -1}},
358 {{-1, -1, 0, 0, 0, 0, -1, -1},
359 {-1, 0, 1, 1, 1, 0, -1, -1},
360 {-1, 0, 1, 0, 0, 1, 0, -1},
361 {-1, 0, 1, 1, 1, 0, -1, -1},
362 {-1, -1, 0, 0, 0, 0, -1, -1},
363 {-1, -1, 7, -1, 7, -1, -1, -1},
364 {-1, -1, 7, 7, 7, 7, -1, -1},
365 {-1, -1, -1, -1, -1, -1, -1, -1},
366 {-1, -1, -1, -1, -1, -1, -1, -1},
367 {-1, -1, -1, -1, -1, -1, -1, -1}},
368 {{-1, 4, 4, 4, 6, 6, 6, -1},
369 { 4, -1, -1, -1, -1, -1, 6, -1},
370 {-1, 4, -1, -1, -1, -1, 6, -1},
371 { 4, 2, 3, 1, 2, 3, 6, -1},
372 {-1, 3, 1, 2, 3, 1, 2, -1},
373 {-1, -1, -1, -1, -1, -1, -1, -1},
374 {-1, -1, -1, -1, -1, -1, -1, -1},
375 {-1, -1, -1, -1, -1, -1, -1, -1},
376 {-1, -1, -1, -1, -1, -1, -1, -1},
377 {-1, -1, -1, -1, -1, -1, -1, -1}},
378 {{-1, 4, 4, 4, 6, 6, 6, -1},
379 { 4, -1, -1, -1, -1, -1, 6, -1},
380 {-1, 4, -1, -1, -1, -1, 6, -1},
381 { 4, 2, 3, 1, 2, 3, 6, -1},
382 {-1, 3, 1, 2, 3, 1, 2, -1},
383 {-1, 2, 3, 1, 2, 3, -1, -1},
384 {-1, -1, -1, -1, -1, -1, -1, -1},
385 {-1, -1, -1, -1, -1, -1, -1, -1},
386 {-1, -1, -1, -1, -1, -1, -1, -1},
387 {-1, -1, -1, -1, -1, -1, -1, -1}},
388 {{-1, 0, 0, -1, -1, 2, 2, -1},
389 {-1, 5, -1, -1, -1, 3, -1, -1},
390 {-1, 0, -1, -1, -1, 6, -1, -1},
391 {-1, 3, -1, -1, -1, 0, -1, -1},
392 {-1, 4, -1, -1, -1, 5, -1, -1},
393 {-1, 2, -1, -1, -1, 3, -1, -1},
394 {-1, 2, -1, -1, -1, 1, -1, -1},
395 {-1, 3, -1, -1, -1, 4, -1, -1},
396 {-1, -1, -1, -1, -1, -1, -1, -1},
397 {-1, -1, -1, -1, -1, -1, -1, -1}},
398 {{ 3, -1, -1, -1, -1, -1, -1, 3},
399 { 6, 3, 2, 4, 6, 3, 2, -1},
400 { 4, -1, -1, -1, -1, -1, -1, 4},
401 { 2, 4, 6, 3, 2, 4, 6, -1},
402 {-1, -1, -1, 6, -1, -1, -1, -1},
403 {-1, -1, -1, 3, -1, -1, -1, -1},
404 {-1, -1, -1, -1, -1, -1, -1, -1},
405 {-1, -1, -1, -1, -1, -1, -1, -1},
406 {-1, -1, -1, -1, -1, -1, -1, -1},
407 {-1, -1, -1, -1, -1, -1, -1, -1}},
408 {{-1, 2, -1, 1, -1, 1, -1, 2},
409 { 1, 2, -1, 2, 1, -1, 1, -1},
410 { 1, -1, 1, -1, 2, -1, 2, -1},
411 { 2, 1, -1, 1, 2, -1, 2, -1},
412 {-1, 2, -1, 2, -1, 2, -1, 2},
413 { 1, 2, -1, 2, 1, -1, 1, -1},
414 { 1, -1, 1, -1, 2, -1, 1, -1},
415 { 2, 2, -1, 1, 1, -1, 2, -1},
416 {-1, 2, -1, 1, -1, 1, -1, 1},
417 {-1, -1, -1, -1, -1, -1, -1, -1}},
418 {{-1, 7, 7, -1, -1, 5, 5, -1},
419 { 1, -1, -1, -1, -1, -1, 4, -1},
420 { 2, 1, -1, -1, -1, -1, 4, 3},
421 { 2, -1, -1, -1, -1, -1, 3, -1},
422 { 1, 2, -1, -1, -1, -1, 3, 4},
423 { 1, -1, -1, -1, -1, -1, 4, -1},
424 { 7, 1, -1, -1, -1, -1, 4, 5},
425 { 7, 7, -1, -1, -1, 5, 5, -1},
426 {-1, -1, -1, -1, -1, -1, -1, -1},
427 {-1, -1, -1, -1, -1, -1, -1, -1}},
428 {{ 7, 7, -1, -1, -1, -1, 5, 5},
429 { 1, 5, -1, -1, -1, 7, 4, -1},
430 { 2, 1, -1, -1, -1, -1, 4, 3},
431 { 2, -1, -1, -1, -1, -1, 3, -1},
432 { 1, 5, -1, -1, -1, -1, 7, 4},
433 { 1, -1, -1, -1, -1, -1, 4, -1},
434 { 7, 1, -1, -1, -1, -1, 4, 5},
435 { 7, 5, -1, -1, -1, 7, 5, -1},
436 {-1, -1, -1, -1, -1, -1, -1, -1},
437 {-1, -1, -1, -1, -1, -1, -1, -1}},
438 {{-1, -1, -1, 0, 0, -1, -1, -1},
439 {-1, -1, 5, 0, 1, -1, -1, -1},
440 {-1, -1, 3, 5, 1, 6, -1, -1},
441 {-1, 4, 3, 2, 6, 2, -1, -1},
442 {-1, 7, 4, 7, 2, 2, 4, -1},
443 { 6, 7, 7, 3, 3, 4, 3, -1},
444 { 1, 6, 1, 1, 1, 3, 3, 5},
445 { 1, 1, -1, -1, -1, -1, 5, -1},
446 {-1, -1, -1, -1, -1, -1, -1, -1},
447 {-1, -1, -1, -1, -1, -1, -1, -1}},
448 {{-1, -1, 0, -1, -1, 0, -1, -1},
449 {-1, 3, 3, -1, 3, 3, -1, -1},
450 {-1, 0, 2, 0, 0, 2, 0, -1},
451 {-1, 3, 3, -1, 3, 3, -1, -1},
452 {-1, -1, 0, -1, -1, 0, -1, -1},
453 {-1, -1, -1, -1, -1, -1, -1, -1},
454 {-1, -1, -1, -1, -1, -1, -1, -1},
455 {-1, -1, -1, -1, -1, -1, -1, -1},
456 {-1, -1, -1, -1, -1, -1, -1, -1},
457 {-1, -1, -1, -1, -1, -1, -1, -1}},
458 {{-1, -1, -1, 1, 1, -1, -1, -1},
459 {-1, -1, 2, 2, 2, -1, -1, -1},
460 {-1, -1, 3, 3, 3, 3, -1, -1},
461 {-1, 4, 4, 4, 4, 4, -1, -1},
462 {-1, 5, 5, 5, 5, 5, 5, -1},
463 {-1, -1, -1, 6, -1, -1, -1, -1},
464 {-1, -1, -1, 7, 7, -1, -1, -1},
465 {-1, -1, -1, 0, -1, -1, -1, -1},
466 {-1, -1, -1, -1, -1, -1, -1, -1},
467 {-1, -1, -1, -1, -1, -1, -1, -1}},
468 {{-1, -1, -1, 2, 5, -1, -1, -1},
469 {-1, 4, 3, -1, -1, -1, -1, -1},
470 { 6, 7, -1, 5, 2, -1, -1, -1},
471 {-1, -1, -1, -1, 3, 4, -1, -1},
472 {-1, -1, -1, 2, 5, -1, 7, 6},
473 {-1, 4, 3, -1, -1, -1, -1, -1},
474 { 6, 7, -1, 5, 2, -1, -1, -1},
475 {-1, -1, -1, -1, 3, 4, -1, -1},
476 {-1, -1, -1, -1, -1, -1, 7, 6},
477 {-1, -1, -1, -1, -1, -1, -1, -1}},
478 {{-1, -1, -1, 5, 5, -1, -1, -1},
479 {-1, -1, -1, 3, -1, -1, -1, -1},
480 {-1, -1, -1, 1, -1, -1, -1, -1},
481 {-1, -1, -1, 7, -1, -1, -1, -1},
482 {-1, -1, -1, 2, -1, -1, -1, -1},
483 {-1, -1, -1, 4, -1, -1, -1, -1},
484 {-1, -1, -1, 5, -1, -1, -1, -1},
485 {-1, -1, -1, 3, -1, -1, -1, -1},
486 {-1, -1, -1, -1, -1, -1, -1, -1},
487 {-1, -1, -1, -1, -1, -1, -1, -1}},
488 {{-1, -1, -1, 0, 1, -1, -1, -1},
489 {-1, -1, 0, 2, 7, 7, -1, -1},
490 {-1, -1, -1, 0, 1, 7, -1, -1},
491 {-1, 0, 0, 0, 0, -1, -1, -1},
492 {-1, 0, 0, 0, 1, 1, -1, -1},
493 { 0, 0, 0, 1, 1, 1, -1, -1},
494 {-1, 0, 0, 1, 1, 1, -1, -1},
495 {-1, 0, 0, 0, 7, 7, -1, -1},
496 {-1, -1, 7, 7, -1, -1, -1, -1},
497 {-1, -1, -1, -1, -1, -1, -1, -1}},
498 {{-1, 1, -1, -1, -1, -1, -1, -1},
499 { 1, -1, -1, -1, -1, -1, -1, -1},
500 {-1, 2, 3, 4, 7, 6, 5, -1},
501 {-1, -1, -1, -1, -1, -1, 1, -1},
502 {-1, -1, -1, -1, -1, -1, 1, -1},
503 {-1, 2, 3, 4, 7, 6, -1, -1},
504 {-1, 1, -1, -1, -1, -1, -1, -1},
505 { 1, -1, -1, -1, -1, -1, -1, -1},
506 {-1, 2, 3, 4, 7, 6, 5, -1},
507 {-1, -1, -1, -1, -1, -1, -1, -1}},
508 {{-1, 6, -1, -1, -1, -1, -1, -1},
509 { 5, -1, -1, -1, -1, -1, -1, -1},
510 { 2, 3, 4, 7, 6, 5, 2, 3},
511 {-1, -1, -1, -1, -1, -1, 4, -1},
512 {-1, -1, -1, -1, -1, -1, 7, -1},
513 {-1, 4, 3, 2, 5, 6, -1, -1},
514 {-1, 7, -1, -1, -1, -1, -1, -1},
515 { 6, -1, -1, -1, -1, -1, -1, -1},
516 { 5, 2, 3, 4, 7, 6, 5, -1},
517 {-1, -1, -1, -1, -1, -1, -1, -1}},
518 {{ 3, 2, 1, 0, 0, 1, 2, 3},
519 { 3, 2, 1, 0, 1, 2, 3, -1},
520 { 4, 3, 2, 1, 1, 2, 3, 4},
521 { 4, 3, 2, 1, 2, 3, 4, -1},
522 { 5, 4, 3, 2, 2, 3, 4, 5},
523 { 5, 4, 3, 2, 3, 4, 5, -1},
524 { 6, 5, 4, 3, 3, 4, 5, 6},
525 { 6, 5, 4, 3, 4, 5, 6, -1},
526 { 7, 6, 5, 4, 4, 5, 6, 7},
527 {-1, -1, -1, -1, -1, -1, -1, -1}},
528 {{-1, -1, -1, 5, 5, -1, -1, -1},
529 {-1, -1, -1, 3, -1, -1, -1, -1},
530 {-1, -1, -1, 2, 4, -1, -1, -1},
531 {-1, -1, -1, 6, -1, -1, -1, -1},
532 {-1, -1, -1, 2, 4, -1, -1, -1},
533 {-1, 2, -1, 5, -1, 4, -1, -1},
534 { 1, 0, 1, 0, 1, 0, 1, 0},
535 { 3, -1, 3, -1, 2, -1, 6, -1},
536 {-1, -1, -1, -1, -1, -1, -1, -1},
537 {-1, -1, -1, -1, -1, -1, -1, -1}},
538 {{-1, -1, -1, -1, 1, -1, -1, -1},
539 { 7, 4, 3, 5, -1, -1, -1, -1},
540 { 6, -1, -1, 1, -1, -1, -1, -1},
541 {-1, -1, -1, 5, 3, 4, 7, -1},
542 { 6, -1, -1, -1, 1, -1, -1, 6},
543 { 7, 4, 3, 5, -1, -1, -1, -1},
544 {-1, -1, -1, 1, -1, -1, -1, 6},
545 {-1, -1, -1, 5, 3, 4, 7, -1},
546 {-1, -1, -1, -1, -1, -1, -1, -1},
547 {-1, -1, -1, -1, -1, -1, -1, -1}},
548 {{-1, -1, -1, -1, 7, 3, 6, -1},
549 {-1, -1, 3, 7, 3, 6, 3, -1},
550 {-1, -1, 5, 7, 3, 6, 3, -1},
551 {-1, 6, 7, 3, 6, 7, -1, -1},
552 {-1, 7, 7, 3, 6, 1, -1, -1},
553 { 3, 7, 3, 6, 3, -1, -1, -1},
554 { 5, 6, 2, 7, 1, -1, -1, -1},
555 {-1, -1, -1, -1, -1, -1, -1, -1},
556 {-1, -1, -1, -1, -1, -1, -1, -1},
557 {-1, -1, -1, -1, -1, -1, -1, -1}},
558 {{ 5, -1, -1, -1, -1, -1, -1, 5},
559 { 5, -1, 6, 6, 6, -1, 5, -1},
560 {-1, 5, 4, -1, -1, 4, 5, -1},
561 {-1, 3, -1, -1, -1, 3, -1, -1},
562 {-1, 6, 0, -1, -1, 0, 6, -1},
563 {-1, 3, -1, -1, -1, 3, -1, -1},
564 {-1, -1, 4, -1, -1, 4, -1, -1},
565 {-1, -1, 6, 6, 6, -1, -1, -1},
566 {-1, -1, -1, -1, -1, -1, -1, -1},
567 {-1, -1, -1, -1, -1, -1, -1, -1}},
568 {{-1, 7, 0, -1, -1, 0, 7, -1},
569 { 7, -1, 0, -1, 0, -1, 7, -1},
570 { 7, 1, -1, 0, 0, -1, 1, 7},
571 { 7, 1, 2, 0, 2, 1, 7, -1},
572 { 7, 6, 3, 2, 2, 3, 6, 7},
573 { 7, -1, 3, 2, 3, -1, 7, -1},
574 {-1, 7, 7, 3, 3, 7, 7, -1},
575 {-1, -1, -1, 3, -1, -1, -1, -1},
576 {-1, -1, -1, -1, -1, -1, -1, -1},
577 {-1, -1, -1, -1, -1, -1, -1, -1}},
578 {{-1, 3, -1, 1, -1, 7, -1, 6},
579 { 5, -1, 7, -1, 7, -1, 6, -1},
580 { 6, -1, 0, -1, 5, -1, 3, -1},
581 {-1, 2, -1, 1, -1, 5, -1, -1},
582 {-1, 4, -1, 3, -1, 4, -1, -1},
583 { 2, -1, 3, -1, 2, -1, -1, -1},
584 {-1, -1, 4, -1, 6, -1, -1, -1},
585 {-1, -1, -1, 5, -1, -1, -1, -1},
586 {-1, -1, -1, -1, -1, -1, -1, -1},
587 {-1, -1, -1, -1, -1, -1, -1, -1}},
588 {{-1, -1, -1, -1, 1, -1, -1, -1},
589 {-1, -1, -1, -1, 3, -1, -1, -1},
590 { 6, 1, 3, 1, 2, 1, 4, 1},
591 {-1, -1, -1, -1, 6, -1, -1, -1},
592 {-1, -1, -1, 4, 1, -1, -1, -1},
593 {-1, -1, 1, -1, 3, -1, -1, -1},
594 {-1, -1, -1, 2, 1, -1, -1, -1},
595 {-1, -1, -1, -1, 4, -1, -1, -1},
596 {-1, -1, -1, 6, 1, -1, -1, -1},
597 {-1, -1, -1, 6, -1, -1, -1, -1}},
598 {{-1, -1, -1, 5, 4, -1, -1, -1},
599 {-1, -1, 4, 1, 0, -1, -1, -1},
600 {-1, -1, -1, 2, 3, -1, -1, -1},
601 {-1, 1, 4, -1, 2, 2, -1, -1},
602 {-1, 3, 1, 2, 5, 1, 4, -1},
603 {-1, 4, 2, -1, 0, 4, -1, -1},
604 {-1, -1, -1, -1, -1, -1, -1, -1},
605 {-1, -1, -1, -1, -1, -1, -1, -1},
606 {-1, -1, -1, -1, -1, -1, -1, -1},
607 {-1, -1, -1, -1, -1, -1, -1, -1}},
608 {{-1, -1, -1, -1, 1, -1, -1, -1},
609 {-1, -1, -1, 1, -1, -1, -1, -1},
610 {-1, 2, -1, -1, 1, -1, 5, -1},
611 { 5, -1, -1, 1, -1, -1, 0, -1},
612 {-1, 6, -1, -1, 1, -1, 4, -1},
613 {-1, 0, -1, 1, -1, 5, -1, -1},
614 {-1, -1, 5, 5, 0, 1, -1, -1},
615 {-1, -1, -1, -1, -1, -1, -1, -1},
616 {-1, -1, -1, -1, -1, -1, -1, -1},
617 {-1, -1, -1, -1, -1, -1, -1, -1}},
618 {{-1, -1, -1, 6, 3, -1, -1, -1},
619 {-1, -1, 3, 2, 6, -1, -1, -1},
620 {-1, -1, 2, 6, 3, 2, -1, -1},
621 {-1, 6, 3, 2, 6, 3, -1, -1},
622 {-1, 3, 2, 6, 3, 2, 6, -1},
623 { 2, 6, 3, 2, 6, 3, 2, -1},
624 { 6, 3, 2, 6, 3, 2, 6, 3},
625 {-1, -1, -1, -1, -1, -1, -1, -1},
626 {-1, -1, -1, -1, -1, -1, -1, -1},
627 {-1, -1, -1, -1, -1, -1, -1, -1}},
628 {{ 6, 6, 6, 6, 6, 6, 6, 6},
629 { 4, -1, -1, -1, -1, -1, -1, -1},
630 {-1, 3, 2, 5, 7, 6, 4, 3},
631 {-1, 5, -1, -1, -1, -1, -1, -1},
632 {-1, -1, 7, 6, 4, 3, 2, 5},
633 {-1, -1, 4, -1, -1, -1, -1, -1},
634 {-1, -1, -1, 3, 2, 5, 7, 6},
635 {-1, -1, -1, -1, -1, -1, -1, -1},
636 {-1, -1, -1, -1, -1, -1, -1, -1},
637 {-1, -1, -1, -1, -1, -1, -1, -1}},
638 {{ 1, -1, 7, -1, -1, 6, -1, 2},
639 { 6, -1, 1, -1, 6, 1, 3, -1},
640 {-1, 4, -1, 7, 2, -1, 7, -1},
641 { 2, 7, -1, -1, -1, 4, -1, -1},
642 { 6, -1, 3, 5, 0, 2, -1, 7},
643 { 1, -1, -1, -1, -1, -1, 1, -1},
644 {-1, 1, 4, 5, 7, 5, 1, -1},
645 {-1, -1, -1, -1, -1, -1, -1, -1},
646 {-1, -1, -1, -1, -1, -1, -1, -1},
647 {-1, -1, -1, -1, -1, -1, -1, -1}},
648 {{ 6, 6, 6, -1, -1, 6, 6, 6},
649 {-1, -1, 6, -1, 6, -1, -1, -1},
650 {-1, -1, 2, 3, 3, 2, -1, -1},
651 {-1, 3, -1, 5, -1, 3, -1, -1},
652 {-1, -1, 5, 3, 3, 5, -1, -1},
653 {-1, -1, 6, 1, 6, -1, -1, -1},
654 {-1, 4, 2, -1, -1, 2, 4, -1},
655 {-1, -1, -1, -1, -1, -1, -1, -1},
656 {-1, -1, -1, -1, -1, -1, -1, -1},
657 {-1, -1, -1, -1, -1, -1, -1, -1}},
658 {{-1, -1, -1, 5, 5, -1, -1, -1},
659 {-1, -1, 5, -1, -1, -1, -1, -1},
660 {-1, 3, 4, 6, 6, -1, -1, 5},
661 { 3, 3, 4, 6, 5, -1, 5, -1},
662 { 3, 2, 3, 6, 6, 5, 5, -1},
663 { 3, 3, 4, 6, 5, -1, 5, -1},
664 {-1, 3, 4, 6, 6, -1, -1, 5},
665 {-1, -1, 5, -1, -1, -1, -1, -1},
666 {-1, -1, -1, 5, 5, -1, -1, -1},
667 {-1, -1, -1, -1, -1, -1, -1, -1}},
668 {{ 1, -1, -1, -1, -1, -1, -1, 1},
669 { 1, -1, 2, 2, 2, -1, 1, -1},
670 {-1, 1, 2, 3, 3, 2, 1, -1},
671 { 6, 2, 3, -1, 3, 2, 6, -1},
672 { 6, 2, 3, -1, -1, 3, 2, 6},
673 { 6, 2, 3, -1, 3, 2, 6, -1},
674 { 3, 3, 3, 7, 7, 3, 3, 3},
675 { 0, 5, 0, 2, 0, 5, 0, -1},
676 {-1, -1, -1, -1, -1, -1, -1, -1},
677 {-1, -1, -1, -1, -1, -1, -1, -1}},
678 {{-1, -1, 7, 7, 7, -1, -1, -1},
679 {-1, 7, 2, 2, 7, -1, -1, -1},
680 {-1, 7, 5, 5, 5, 7, -1, -1},
681 { 7, 7, 7, 7, 7, 7, -1, -1},
682 {-1, -1, 6, -1, 6, -1, -1, -1},
683 {-1, 6, -1, -1, 6, -1, -1, -1},
684 {-1, 6, 4, 4, -1, 6, 4, 4},
685 {-1, -1, -1, -1, -1, -1, -1, -1},
686 {-1, -1, -1, -1, -1, -1, -1, -1},
687 {-1, -1, -1, -1, -1, -1, -1, -1}},
688 {{-1, 3, 3, -1, 3, 3, 3, -1},
689 { 3, 7, 5, 4, 6, 5, 3, -1},
690 { 1, 3, 3, 3, -1, 3, 3, 1},
691 { 2, 1, 2, 1, 2, 1, 2, -1},
692 { 1, 3, 3, -1, 3, 3, 3, 1},
693 { 3, 5, 6, 4, 5, 7, 3, -1},
694 { 2, 3, 3, 3, -1, 3, 3, 2},
695 { 1, 1, 2, 2, 2, 1, 1, -1},
696 {-1, -1, -1, -1, -1, -1, -1, -1},
697 {-1, -1, -1, -1, -1, -1, -1, -1}},
698 {{-1, 6, 5, -1, -1, -1, -1, -1},
699 { 3, 1, 3, -1, -1, -1, -1, -1},
700 {-1, 5, 6, -1, -1, -1, -1, -1},
701 {-1, -1, 5, 3, -1, -1, -1, -1},
702 {-1, -1, 6, 1, 6, -1, -1, -1},
703 {-1, -1, 3, 5, -1, -1, -1, -1},
704 {-1, -1, -1, -1, 3, 6, -1, -1},
705 {-1, -1, -1, 5, 6, 5, -1, -1},
706 {-1, -1, -1, -1, 6, 3, -1, -1},
707 {-1, -1, -1, -1, -1, -1, -1, -1}},
708 {{ 6, 3, 7, 4, 5, 1, 6, 3},
709 { 5, 1, 6, 3, 7, 4, 5, -1},
710 { 6, 3, 7, 4, 5, 1, 6, 3},
711 {-1, -1, -1, -1, -1, -1, -1, -1},
712 {-1, -1, -1, -1, -1, -1, -1, -1},
713 {-1, -1, -1, -1, -1, -1, -1, -1},
714 {-1, -1, -1, -1, -1, -1, -1, -1},
715 {-1, -1, -1, -1, -1, -1, -1, -1},
716 {-1, -1, -1, -1, -1, -1, -1, -1},
717 {-1, -1, -1, -1, -1, -1, -1, -1}},
718 {{-1, -1, -1, -1, -1, -1, 4, 4},
719 {-1, -1, 7, 7, 7, 4, 4, -1},
720 {-1, -1, -1, -1, -1, -1, 4, 4},
721 {-1, 1, -1, -1, -1, 7, -1, -1},
722 {-1, 1, 1, -1, -1, 7, -1, -1},
723 { 3, 3, 3, -1, 7, -1, -1, -1},
724 { 3, -1, 2, 3, 3, 3, -1, 3},
725 {-1, 2, -1, 3, -1, 3, 3, -1},
726 {-1, 2, -1, -1, -1, -1, -1, -1},
727 {-1, -1, -1, -1, -1, -1, -1, -1}},
728 {{-1, -1, 4, -1, -1, -1, -1, -1},
729 {-1, 7, 4, -1, -1, -1, -1, -1},
730 {-1, -1, 7, 4, -1, -1, -1, -1},
731 {-1, 4, 7, 4, -1, -1, -1, -1},
732 { 1, 1, 1, 1, 1, 1, 1, -1},
733 { 1, 2, 1, 2, 1, 1, -1, -1},
734 { 2, 2, 2, 2, 2, 2, 2, 2},
735 {-1, -1, -1, -1, -1, -1, -1, -1},
736 {-1, -1, -1, -1, -1, -1, -1, -1},
737 {-1, -1, -1, -1, -1, -1, -1, -1}},
738 {{ 0, -1, -1, -1, -1, -1, -1, 6},
739 { 6, 1, 4, 3, 7, 5, 0, -1},
740 { 0, -1, -1, -1, -1, -1, -1, 6},
741 { 6, 1, 4, 3, 7, 5, 0, -1},
742 { 0, -1, -1, -1, -1, -1, -1, 6},
743 { 6, 1, 4, 3, 7, 5, 0, -1},
744 {-1, -1, -1, -1, -1, -1, -1, -1},
745 {-1, -1, -1, -1, -1, -1, -1, -1},
746 {-1, -1, -1, -1, -1, -1, -1, -1},
747 {-1, -1, -1, -1, -1, -1, -1, -1}},
748 {{ 3, 3, 4, 6, 6, 4, 3, 3},
749 { 0, 3, 4, 6, 4, 3, 1, -1},
750 { 5, 1, 3, 4, 4, 3, 0, 1},
751 { 0, 1, 3, 4, 3, 1, 0, -1},
752 { 2, 1, 6, 3, 3, 0, 0, 1},
753 { 0, 3, 4, 3, 6, 1, 5, -1},
754 { 6, 1, 2, 6, 4, 0, 0, 2},
755 {-1, -1, -1, -1, -1, -1, -1, -1},
756 {-1, -1, -1, -1, -1, -1, -1, -1},
757 {-1, -1, -1, -1, -1, -1, -1, -1}},
758 {{ 6, 6, -1, -1, -1, -1, 4, 4},
759 { 4, 0, -1, -1, -1, 3, 6, -1},
760 { 0, 6, -1, -1, -1, -1, 4, 2},
761 { 7, -1, -1, -1, -1, -1, 7, -1},
762 { 4, 4, -1, -1, -1, -1, 5, 6},
763 { 6, 4, 7, 7, 5, 6, 4, -1},
764 {-1, 7, 6, 4, 6, 4, 7, -1},
765 {-1, 0, -1, 7, -1, 7, -1, -1},
766 {-1, -1, -1, -1, -1, -1, -1, -1},
767 {-1, -1, -1, -1, -1, -1, -1, -1}},
768 {{-1, 5, -1, -1, -1, -1, 4, -1},
769 {-1, 5, -1, -1, -1, 4, -1, -1},
770 {-1, -1, 5, 6, 6, 4, -1, -1},
771 {-1, -1, 2, -1, 2, -1, -1, -1},
772 { 0, 0, 6, -1, -1, 6, 1, 1},
773 {-1, -1, 2, -1, 2, -1, -1, -1},
774 {-1, -1, 7, 6, 6, 3, -1, -1},
775 {-1, 7, -1, -1, -1, 3, -1, -1},
776 {-1, 7, -1, -1, -1, -1, 3, -1},
777 {-1, -1, -1, -1, -1, -1, -1, -1}},
778 {{-1, 6, -1, -1, -1, -1, 2, -1},
779 { 1, 7, 1, 1, 1, 3, 1, -1},
780 {-1, -1, 4, 1, 1, 4, -1, -1},
781 {-1, 1, 3, 1, 7, 1, -1, -1},
782 {-1, -1, -1, 2, 6, -1, -1, -1},
783 {-1, -1, 1, 5, 1, -1, -1, -1},
784 {-1, -1, -1, -1, -1, -1, -1, -1},
785 {-1, -1, -1, -1, -1, -1, -1, -1},
786 {-1, -1, -1, -1, -1, -1, -1, -1},
787 {-1, -1, -1, -1, -1, -1, -1, -1}},
788 {{ 7, 7, 7, 7, 7, 7, 7, 7},
789 { 7, -1, -1, -1, -1, -1, 7, -1},
790 { 7, -1, -1, 2, 0, 5, 2, 2},
791 { 7, -1, -1, -1, 0, 3, 6, -1},
792 { 7, -1, -1, -1, -1, -1, 4, 0},
793 { 5, 5, -1, -1, -1, -1, -1, -1},
794 { 4, 3, 6, 2, -1, -1, -1, -1},
795 { 0, 2, 0, 4, -1, -1, -1, -1},
796 {-1, -1, -1, -1, -1, -1, -1, -1},
797 {-1, -1, -1, -1, -1, -1, -1, -1}},
798 {{-1, -1, 1, -1, -1, 1, -1, -1},
799 {-1, 4, -1, -1, 5, -1, -1, -1},
800 {-1, 7, -1, -1, 1, 1, 1, -1},
801 { 6, -1, -1, -1, -1, 7, -1, -1},
802 { 1, 1, 1, 1, -1, 4, -1, -1},
803 {-1, -1, 5, -1, -1, -1, -1, -1},
804 {-1, -1, 0, -1, -1, -1, -1, -1},
805 {-1, 3, -1, -1, -1, -1, -1, -1},
806 {-1, 1, -1, -1, -1, -1, -1, -1},
807 {-1, -1, -1, -1, -1, -1, -1, -1}},
808 {{-1, 7, 7, -1, -1, 7, 7, -1},
809 { 6, -1, 4, -1, 4, -1, 6, -1},
810 { 5, -1, -1, 3, 3, -1, -1, 5},
811 { 6, -1, -1, -1, -1, -1, 6, -1},
812 {-1, 7, -1, -1, -1, -1, 7, -1},
813 {-1, 4, -1, -1, -1, 4, -1, -1},
814 {-1, -1, 3, -1, -1, 3, -1, -1},
815 {-1, -1, 2, -1, 2, -1, -1, -1},
816 {-1, -1, -1, 5, 5, -1, -1, -1},
817 {-1, -1, -1, -1, -1, -1, -1, -1}},
818 {{-1, 0, 0, -1, -1, 0, 0, -1},
819 { 7, 4, 6, 6, 6, 4, 3, -1},
820 { 5, 6, 6, 6, 2, 6, 6, 3},
821 { 7, 4, 6, 6, 6, 4, 3, -1},
822 {-1, 0, 0, -1, -1, 0, 0, -1},
823 {-1, -1, -1, -1, -1, -1, -1, -1},
824 {-1, -1, -1, -1, -1, -1, -1, -1},
825 {-1, -1, -1, -1, -1, -1, -1, -1},
826 {-1, -1, -1, -1, -1, -1, -1, -1},
827 {-1, -1, -1, -1, -1, -1, -1, -1}},
828 {{-1, -1, -1, -1, -1, 7, 7, 7},
829 {-1, -1, -1, -1, 2, 7, 7, -1},
830 {-1, 0, 7, 7, 7, -1, 7, 7},
831 { 6, 7, 7, 7, -1, -1, -1, -1},
832 { 6, -1, -1, -1, 7, 7, 7, 7},
833 { 6, -1, -1, -1, -1, -1, -1, -1},
834 { 4, 2, 2, 2, 4, -1, 3, -1},
835 { 4, 4, 4, 4, 3, 3, 3, -1},
836 {-1, -1, -1, -1, -1, -1, -1, -1},
837 {-1, -1, -1, -1, -1, -1, -1, -1}},
838 {{ 4, -1, -1, 7, -1, 6, -1, 7},
839 { 7, 6, 7, -1, -1, 7, 4, -1},
840 {-1, -1, 7, -1, -1, 7, -1, -1},
841 {-1, 0, 0, 0, 0, 0, 3, -1},
842 {-1, -1, 0, 2, 2, 0, 6, 4},
843 {-1, -1, 0, 0, 0, 1, 3, -1},
844 {-1, -1, -1, 0, 0, -1, 3, 4},
845 {-1, -1, -1, 6, -1, 5, 6, -1},
846 {-1, -1, -1, -1, -1, -1, 1, 0},
847 {-1, -1, -1, -1, -1, -1, -1, -1}},
848 {{-1, 5, -1, -1, -1, -1, 5, -1},
849 { 0, -1, -1, 0, -1, -1, 0, -1},
850 { 0, 0, 0, 2, 2, 0, 0, 0},
851 { 0, -1, -1, 0, -1, -1, 0, -1},
852 {-1, 7, -1, 3, -1, -1, 7, -1},
853 {-1, -1, 3, 6, -1, -1, -1, -1},
854 {-1, -1, -1, 6, -1, -1, -1, -1},
855 {-1, 3, 6, -1, -1, -1, -1, -1},
856 {-1, 3, -1, -1, -1, -1, -1, -1},
857 {-1, -1, -1, -1, -1, -1, -1, -1}},
858 {{-1, -1, -1, 6, 5, -1, -1, -1},
859 {-1, -1, 2, 6, 3, -1, -1, -1},
860 {-1, -1, 5, 4, 7, 1, -1, -1},
861 {-1, 6, 2, 2, 3, 4, -1, -1},
862 {-1, -1, 3, 7, 3, 6, -1, -1},
863 {-1, -1, 1, 3, 2, -1, -1, -1},
864 {-1, -1, -1, 4, 5, -1, -1, -1},
865 {-1, -1, -1, 4, -1, -1, -1, -1},
866 {-1, -1, -1, -1, -1, -1, -1, -1},
867 {-1, -1, -1, -1, -1, -1, -1, -1}},
868 {{ 7, 7, -1, 2, 2, -1, 6, 6},
869 { 6, -1, -1, 6, -1, -1, 3, -1},
870 { 2, -1, -1, 1, -1, -1, 2, -1},
871 { 5, -1, -1, 3, -1, -1, 2, -1},
872 { 1, -1, -1, 2, -1, -1, 1, -1},
873 { 5, -1, -1, 2, -1, -1, 2, -1},
874 { 6, -1, -1, 1, -1, -1, 7, -1},
875 { 5, -1, -1, 5, -1, -1, 4, -1},
876 {-1, -1, -1, -1, -1, -1, -1, -1},
877 {-1, -1, -1, -1, -1, -1, -1, -1}},
878 {{-1, -1, -1, 6, 6, -1, -1, -1},
879 {-1, 0, 4, 4, 4, 0, -1, -1},
880 {-1, -1, -1, 6, 6, -1, -1, -1},
881 {-1, -1, 2, 7, 2, -1, -1, -1},
882 {-1, -1, -1, 6, 6, -1, -1, -1},
883 {-1, 0, 5, 5, 5, 0, -1, -1},
884 {-1, -1, -1, 3, 3, -1, -1, -1},
885 {-1, -1, -1, -1, -1, -1, -1, -1},
886 {-1, -1, -1, -1, -1, -1, -1, -1},
887 {-1, -1, -1, -1, -1, -1, -1, -1}},
888 {{-1, -1, 4, 1, 3, -1, -1, -1},
889 {-1, 1, -1, -1, 1, -1, -1, -1},
890 {-1, -1, 4, 1, 3, 4, 1, -1},
891 {-1, 1, 3, 4, -1, -1, 4, -1},
892 {-1, 3, -1, -1, 3, 4, 1, -1},
893 {-1, 1, 3, 4, 1, 3, -1, -1},
894 {-1, -1, 4, 1, -1, -1, -1, -1},
895 {-1, -1, -1, -1, -1, -1, -1, -1},
896 {-1, -1, -1, -1, -1, -1, -1, -1},
897 {-1, -1, -1, -1, -1, -1, -1, -1}},
898 {{-1, 6, 4, -1, 3, 2, 5, -1},
899 { 0, -1, -1, -1, -1, -1, 1, -1},
900 {-1, 2, 3, 5, -1, 4, 6, -1},
901 { 0, -1, -1, -1, -1, -1, 1, -1},
902 {-1, 4, 6, -1, 2, 5, 3, -1},
903 { 0, -1, -1, -1, -1, -1, 1, -1},
904 {-1, 5, 2, 3, -1, 4, 6, -1},
905 {-1, -1, -1, -1, -1, -1, -1, -1},
906 {-1, -1, -1, -1, -1, -1, -1, -1},
907 {-1, -1, -1, -1, -1, -1, -1, -1}},
908 {{-1, -1, -1, 6, 6, -1, -1, -1},
909 {-1, -1, 7, 6, 4, -1, -1, -1},
910 {-1, 2, 1, 7, 4, 1, 3, -1},
911 { 2, 1, 1, 1, 1, 1, 3, -1},
912 {-1, 2, 2, 2, 3, 3, 3, -1},
913 {-1, -1, -1, 5, -1, -1, -1, -1},
914 {-1, -1, -1, 2, 3, -1, -1, -1},
915 {-1, -1, -1, 5, -1, -1, -1, -1},
916 {-1, -1, 2, 2, 3, 3, -1, -1},
917 {-1, -1, -1, -1, -1, -1, -1, -1}},
918 {{ 4, -1, 5, -1, -1, 3, -1, 6},
919 { 2, -1, 3, -1, 2, -1, 4, -1},
920 { 4, -1, -1, 1, 0, -1, -1, 6},
921 { 6, -1, 2, 3, 5, -1, 4, -1},
922 { 4, -1, -1, 0, 1, -1, -1, 6},
923 { 2, -1, 5, -1, 3, -1, 4, -1},
924 { 4, -1, 3, -1, -1, 2, -1, 6},
925 { 6, -1, -1, -1, -1, -1, 4, -1},
926 {-1, -1, -1, -1, -1, -1, -1, -1},
927 {-1, -1, -1, -1, -1, -1, -1, -1}},
928 {{ 2, 6, 0, 5, 5, 1, 3, 4},
929 { 1, -1, -1, 2, -1, -1, 0, -1},
930 { 4, -1, -1, 3, 6, -1, -1, 2},
931 {-1, -1, -1, 0, -1, -1, -1, -1},
932 {-1, -1, -1, 1, 4, -1, -1, -1},
933 {-1, -1, -1, 2, -1, -1, -1, -1},
934 {-1, -1, -1, 6, 3, -1, -1, -1},
935 {-1, -1, -1, 5, -1, -1, -1, -1},
936 {-1, -1, -1, 4, 1, -1, -1, -1},
937 {-1, -1, -1, -1, -1, -1, -1, -1}},
938 {{-1, -1, -1, -1, 5, 1, 1, 3},
939 { 0, 5, 1, 0, 5, 3, 3, -1},
940 { 5, 1, 0, 5, 1, 0, 5, 1},
941 { 0, 5, 1, 0, 5, 1, 6, -1},
942 {-1, -1, -1, -1, 1, 6, 5, 1},
943 {-1, -1, -1, -1, 5, 1, 6, -1},
944 {-1, -1, -1, -1, 1, 0, 5, 1},
945 {-1, -1, -1, -1, 5, 1, 0, -1},
946 {-1, -1, -1, -1, -1, -1, -1, -1},
947 {-1, -1, -1, -1, -1, -1, -1, -1}},
948 {{-1, 0, 7, 3, -1, -1, 2, 2},
949 {-1, 0, 7, 3, -1, -1, 2, -1},
950 {-1, 0, 7, 3, -1, -1, 2, 2},
951 {-1, 0, 7, 3, -1, 3, 1, -1},
952 {-1, 0, 7, 3, -1, 6, 4, 5},
953 {-1, 0, 7, 3, -1, 7, 0, -1},
954 {-1, 0, 7, 3, -1, 2, 3, 4},
955 {-1, 0, 7, 3, -1, 5, 6, -1},
956 {-1, -1, -1, -1, -1, 7, 0, 1},
957 {-1, -1, -1, -1, -1, -1, -1, -1}},
958 {{-1, -1, -1, 7, 7, 7, 7, -1},
959 { 3, 4, 5, -1, -1, -1, 7, -1},
960 { 2, -1, -1, -1, -1, -1, -1, 3},
961 { 7, -1, -1, -1, -1, -1, 4, -1},
962 { 7, -1, -1, -1, 3, 4, 5, 6},
963 { 7, -1, -1, 2, 0, 1, 2, -1},
964 { 6, -1, -1, -1, 3, 4, 5, 6},
965 { 0, 1, -1, -1, -1, -1, -1, -1},
966 { 2, 3, 4, -1, -1, -1, -1, -1},
967 { 5, 6, 0, -1, -1, -1, -1, -1}},
968 {{-1, 7, -1, -1, -1, -1, 2, -1},
969 { 1, 1, -1, -1, -1, 3, 3, -1},
970 {-1, 2, -1, -1, -1, -1, 4, -1},
971 { 3, 3, -1, -1, -1, 5, 5, -1},
972 {-1, 4, -1, -1, -1, -1, 6, -1},
973 { 5, 5, -1, -1, -1, 1, 1, -1},
974 {-1, 6, -1, -1, -1, -1, 7, -1},
975 {-1, -1, -1, -1, -1, -1, -1, -1},
976 {-1, -1, -1, -1, -1, -1, -1, -1},
977 {-1, -1, -1, -1, -1, -1, -1, -1}},
978 {{-1, 4, -1, -1, -1, -1, 4, -1},
979 { 2, -1, -1, 1, -1, -1, 2, -1},
980 { 5, -1, -1, 0, 0, -1, -1, 5},
981 { 5, -1, -1, 1, -1, -1, 6, -1},
982 {-1, 4, 2, 7, 7, 5, 4, -1},
983 {-1, -1, -1, 6, -1, -1, -1, -1},
984 {-1, -1, -1, 3, 3, -1, -1, -1},
985 {-1, -1, -1, 7, -1, -1, -1, -1},
986 {-1, -1, -1, -1, -1, -1, -1, -1},
987 {-1, -1, -1, -1, -1, -1, -1, -1}},
988 {{-1, 1, -1, -1, 2, 3, 4, -1},
989 { 2, -1, -1, 3, 0, 4, -1, -1},
990 { 4, -1, -1, 2, 3, 1, -1, -1},
991 { 3, -1, 4, 3, 0, -1, -1, -1},
992 { 4, -1, -1, 2, 5, 1, -1, -1},
993 { 3, -1, 4, 5, 0, 4, -1, -1},
994 {-1, -1, -1, -1, -1, -1, -1, -1},
995 {-1, -1, -1, -1, -1, -1, -1, -1},
996 {-1, -1, -1, -1, -1, -1, -1, -1},
997 {-1, -1, -1, -1, -1, -1, -1, -1}},
998 {{ 2, -1, -1, 1, 1, -1, -1, 2},
999 { 2, -1, 3, 3, 3, -1, 2, -1},
1000 {-1, 2, -1, 4, 4, -1, 2, -1},
1001 {-1, 7, 7, 0, 7, 7, -1, -1},
1002 {-1, -1, -1, 4, 4, -1, -1, -1},
1003 {-1, -1, 5, 7, 5, -1, -1, -1},
1004 { 6, 3, 2, 6, 4, 2, 3, 6},
1005 { 5, -1, -1, -1, -1, -1, 1, -1},
1006 {-1, -1, -1, -1, -1, -1, -1, -1},
1007 {-1, -1, -1, -1, -1, -1, -1, -1}},
1008 {{ 4, 2, 3, 5, 7, 1, 3, 6},
1009 { 1, -1, -1, 1, -1, -1, 1, -1},
1010 { 3, 0, 1, 3, 2, 4, 3, 5},
1011 { 4, -1, -1, 4, -1, -1, 4, -1},
1012 {-1, 5, -1, -1, 5, -1, -1, 5},
1013 { 0, 3, 2, 0, 4, 5, 0, -1},
1014 {-1, 6, -1, -1, 6, -1, -1, 6},
1015 { 7, -1, -1, 7, -1, -1, 7, -1},
1016 {-1, -1, -1, -1, -1, -1, -1, -1},
1017 {-1, -1, -1, -1, -1, -1, -1, -1}},
1018 {{-1, 5, 4, -1, 1, 1, -1, -1},
1019 { 5, -1, 4, 1, -1, 1, -1, -1},
1020 { 0, -1, -1, -1, -1, -1, 0, -1},
1021 { 0, 6, 4, -1, -1, 4, 2, -1},
1022 {-1, 4, 3, 5, 2, 6, 3, 6},
1023 {-1, 2, 6, -1, -1, 5, 4, -1},
1024 {-1, -1, -1, -1, -1, -1, -1, -1},
1025 {-1, -1, -1, -1, -1, -1, -1, -1},
1026 {-1, -1, -1, -1, -1, -1, -1, -1},
1027 {-1, -1, -1, -1, -1, -1, -1, -1}},
1028 {{-1, -1, -1, 6, 6, -1, -1, -1},
1029 {-1, -1, 5, 5, 4, -1, -1, -1},
1030 {-1, -1, 1, 6, 6, 4, -1, -1},
1031 {-1, 1, 7, 2, 5, 3, -1, -1},
1032 {-1, 2, 7, 2, 1, 5, 3, -1},
1033 { 2, 1, 3, 1, 4, 2, 7, -1},
1034 {-1, 3, 1, 3, 4, 2, 7, -1},
1035 {-1, 3, 5, 5, 6, 6, -1, -1},
1036 {-1, -1, -1, -1, -1, -1, -1, -1},
1037 {-1, -1, -1, -1, -1, -1, -1, -1}},
1038 {{-1, -1, 7, 3, -1, -1, -1, -1},
1039 {-1, 1, 7, 6, -1, -1, -1, -1},
1040 {-1, 3, 7, 5, 1, 5, -1, -1},
1041 { 7, 7, 0, 2, 4, 0, 4, -1},
1042 { 7, 1, 4, 6, 5, 6, 5, 7},
1043 { 1, 7, 7, 1, 7, 7, 1, -1},
1044 {-1, -1, -1, -1, -1, -1, -1, -1},
1045 {-1, -1, -1, -1, -1, -1, -1, -1},
1046 {-1, -1, -1, -1, -1, -1, -1, -1},
1047 {-1, -1, -1, -1, -1, -1, -1, -1}},
1048 {{-1, -1, 1, -1, -1, 1, -1, -1},
1049 {-1, 5, 6, 1, 5, 6, -1, -1},
1050 {-1, 1, 1, 2, 2, 1, 1, -1},
1051 { 4, 7, 1, 0, 1, 7, 4, -1},
1052 {-1, 3, 7, 5, 7, 5, 3, -1},
1053 {-1, 1, 1, 1, 1, 1, -1, -1},
1054 {-1, -1, -1, -1, -1, -1, -1, -1},
1055 {-1, -1, -1, -1, -1, -1, -1, -1},
1056 {-1, -1, -1, -1, -1, -1, -1, -1},
1057 {-1, -1, -1, -1, -1, -1, -1, -1}},
1058 {{ 4, -1, -1, -1, 5, -1, -1, 4},
1059 { 6, 6, 7, 6, -1, 4, 5, -1},
1060 { 4, 2, 7, 5, 2, 2, 6, 4},
1061 {-1, -1, 4, 1, -1, 5, 2, -1},
1062 {-1, 5, 2, 7, 7, -1, 7, 4},
1063 { 4, 6, 5, 4, -1, 4, 2, -1},
1064 {-1, -1, -1, 4, -1, 4, 1, -1},
1065 { 0, 0, 0, 5, -1, -1, -1, -1},
1066 {-1, -1, -1, -1, 0, 0, 0, 0},
1067 {-1, -1, -1, -1, -1, -1, -1, -1}},
1068 {{ 1, -1, -1, -1, 0, 0, -1, -1},
1069 { 2, -1, -1, 0, 1, 0, -1, -1},
1070 { 3, -1, -1, 0, 2, 2, 0, -1},
1071 { 4, -1, 0, 1, 1, 1, 0, -1},
1072 { 5, -1, -1, 0, 4, 4, 0, -1},
1073 { 6, -1, -1, 4, 4, 4, -1, -1},
1074 { 7, -1, -1, -1, 4, 4, -1, -1},
1075 {-1, -1, -1, 0, 1, 0, -1, -1},
1076 {-1, -1, -1, 0, 1, 1, 0, -1},
1077 {-1, -1, -1, -1, -1, -1, -1, -1}},
1078 {{-1, -1, 3, -1, -1, 1, 7, -1},
1079 {-1, 7, 4, -1, -1, 4, 3, -1},
1080 { 1, -1, -1, 0, 2, 0, -1, -1},
1081 { 5, 4, -1, 3, -1, -1, -1, -1},
1082 { 4, -1, 3, 6, 1, 1, 6, -1},
1083 {-1, 1, -1, -1, 4, -1, 1, -1},
1084 {-1, 7, 5, -1, -1, -1, 3, -1},
1085 {-1, -1, 3, -1, -1, -1, -1, -1},
1086 {-1, -1, -1, -1, -1, -1, -1, -1},
1087 {-1, -1, -1, -1, -1, -1, -1, -1}},
1088 {{ 1, -1, -1, -1, 1, -1, -1, -1},
1089 { 2, -1, -1, -1, 2, -1, -1, -1},
1090 {-1, 3, -1, -1, 3, 3, -1, -1},
1091 {-1, 4, -1, 4, -1, 4, -1, -1},
1092 {-1, 5, -1, -1, 5, 5, -1, -1},
1093 { 6, -1, -1, 7, 1, 7, -1, -1},
1094 { 7, -1, -1, -1, 6, 6, -1, -1},
1095 {-1, -1, -1, -1, -1, -1, -1, -1},
1096 {-1, -1, -1, -1, -1, -1, -1, -1},
1097 {-1, -1, -1, -1, -1, -1, -1, -1}},
1098 {{ 2, -1, -1, 6, -1, 2, 5, 1},
1099 { 5, -1, 4, -1, 4, -1, 4, -1},
1100 { 6, -1, -1, 3, -1, -1, -1, 3},
1101 { 4, 2, 0, -1, -1, -1, 5, -1},
1102 {-1, -1, -1, 6, -1, 3, 6, -1},
1103 {-1, -1, 5, -1, 5, -1, -1, -1},
1104 {-1, -1, -1, 3, -1, 4, 2, 5},
1105 {-1, -1, -1, -1, -1, -1, -1, -1},
1106 {-1, -1, -1, -1, -1, -1, -1, -1},
1107 {-1, -1, -1, -1, -1, -1, -1, -1}},
1108 {{ 6, -1, -1, -1, 4, -1, -1, 3},
1109 { 0, 3, -1, -1, 6, -1, 0, -1},
1110 {-1, -1, 7, -1, 1, -1, 3, -1},
1111 { 7, -1, 4, 7, -1, 2, -1, -1},
1112 { 5, 2, 3, 2, 1, 6, -1, 3},
1113 {-1, -1, 0, 4, 3, 5, 4, -1},
1114 {-1, 7, 6, -1, -1, 0, -1, -1},
1115 { 4, 3, -1, -1, -1, 4, 2, -1},
1116 { 0, -1, -1, -1, -1, -1, 6, -1},
1117 {-1, -1, -1, -1, -1, -1, -1, -1}},
1118 {{ 6, 1, 2, 5, 1, 6, 3, 0},
1119 {-1, -1, -1, -1, -1, -1, 4, -1},
1120 { 0, 5, 2, 7, 1, 6, 2, -1},
1121 { 3, -1, -1, -1, -1, -1, -1, -1},
1122 { 6, 7, 6, 4, 0, 5, 2, 6},
1123 {-1, -1, -1, -1, -1, -1, 1, -1},
1124 { 6, 1, 4, 0, 6, 2, 3, -1},
1125 { 0, -1, -1, -1, -1, -1, -1, -1},
1126 {-1, 0, 4, 5, 3, 7, 6, 0},
1127 {-1, -1, -1, -1, -1, -1, -1, -1}},
1128 {{-1, -1, -1, 0, 1, -1, -1, -1},
1129 {-1, -1, 0, 7, 0, -1, -1, -1},
1130 {-1, -1, 1, 2, 2, 0, -1, -1},
1131 {-1, 0, 7, 0, 7, 0, -1, -1},
1132 {-1, 6, -1, 7, 7, -1, 6, -1},
1133 { 4, 1, 6, 6, 6, 4, 1, -1},
1134 {-1, 5, -1, 7, 7, -1, 5, -1},
1135 {-1, -1, -1, -1, -1, -1, -1, -1},
1136 {-1, -1, -1, -1, -1, -1, -1, -1},
1137 {-1, -1, -1, -1, -1, -1, -1, -1}},
1138 {{-1, -1, -1, 5, 6, -1, -1, -1},
1139 {-1, -1, 3, 3, 3, -1, -1, -1},
1140 {-1, -1, 7, 5, 3, 7, -1, -1},
1141 {-1, 3, -1, 6, -1, 3, -1, -1},
1142 { 2, -1, -1, 3, 7, -1, -1, 1},
1143 { 2, 2, -1, 3, -1, 1, 1, -1},
1144 {-1, 0, 2, 5, 6, 1, 0, -1},
1145 {-1, -1, -1, 3, -1, -1, -1, -1},
1146 {-1, -1, -1, 3, 7, -1, -1, -1},
1147 {-1, -1, -1, -1, -1, -1, -1, -1}},
1148 {{-1, 6, -1, -1, -1, -1, 2, -1},
1149 {-1, 2, 6, 0, 6, 0, -1, -1},
1150 {-1, 0, -1, -1, -1, -1, -1, -1},
1151 { 6, -1, -1, -1, -1, -1, -1, -1},
1152 {-1, 3, 3, 2, 0, 6, 0, 0},
1153 {-1, 6, -1, -1, -1, -1, 0, -1},
1154 {-1, -1, -1, 6, 0, 2, 6, -1},
1155 {-1, 2, 0, -1, -1, -1, -1, -1},
1156 {-1, -1, -1, -1, -1, -1, -1, -1},
1157 {-1, -1, -1, -1, -1, -1, -1, -1}},
1158 {{ 0, 7, -1, -1, -1, -1, -1, -1},
1159 { 1, 5, -1, -1, -1, -1, -1, -1},
1160 { 7, 2, 5, -1, -1, -1, -1, -1},
1161 { 6, 3, 4, -1, -1, -1, -1, -1},
1162 { 5, 5, 4, 4, -1, -1, -1, -1},
1163 { 3, 3, 5, 3, -1, -1, -1, -1},
1164 { 1, 2, 2, 5, 3, -1, -1, -1},
1165 { 1, 0, 0, 7, 6, -1, -1, -1},
1166 { 3, 3, 5, 5, 7, 6, -1, -1},
1167 {-1, -1, -1, -1, -1, -1, -1, -1}},
1168 {{-1, -1, 2, 6, 6, 2, -1, -1},
1169 {-1, 2, 1, 1, 0, 2, -1, -1},
1170 {-1, 2, 3, 2, 2, 0, 2, -1},
1171 { 2, 3, 2, 5, 2, 7, 2, -1},
1172 { 2, 4, 2, 5, 2, 7, 2, 0},
1173 { 2, 4, 2, 6, 6, 2, 0, -1},
1174 {-1, 2, 5, 2, 2, 2, 7, 2},
1175 {-1, 2, 5, 6, 6, 7, 2, -1},
1176 {-1, -1, 2, 2, 2, 2, 2, -1},
1177 {-1, -1, -1, -1, -1, -1, -1, -1}},
1178 {{-1, -1, 0, -1, -1, 0, -1, -1},
1179 { 1, 0, 0, 1, 0, 0, 1, -1},
1180 { 1, 7, 7, 5, 5, 7, 7, 1},
1181 { 3, 2, -1, 2, -1, 2, 3, -1},
1182 { 3, 7, -1, 6, 6, -1, 7, 3},
1183 { 7, -1, -1, 6, -1, -1, 7, -1},
1184 { 4, 4, 5, -1, -1, 5, 4, 4},
1185 {-1, -1, -1, -1, -1, -1, -1, -1},
1186 {-1, -1, -1, -1, -1, -1, -1, -1},
1187 {-1, -1, -1, -1, -1, -1, -1, -1}},
1188 {{-1, 6, 3, -1, -1, 3, 6, -1},
1189 { 6, -1, 2, -1, 2, -1, 6, -1},
1190 { 2, -1, 0, 1, 1, 0, -1, 2},
1191 { 5, 0, -1, 7, -1, 0, 5, -1},
1192 {-1, 5, -1, 6, 6, -1, 5, -1},
1193 { 7, 1, 4, -1, 4, 1, 7, -1},
1194 { 7, -1, 4, -1, -1, 4, -1, 7},
1195 { 2, 0, -1, -1, -1, 0, 2, -1},
1196 {-1, 2, -1, -1, -1, -1, 2, -1},
1197 {-1, -1, -1, -1, -1, -1, -1, -1}},
1198 {{ 6, 1, -1, -1, -1, -1, 4, 0},
1199 { 2, 7, 5, 5, 5, 7, 3, -1},
1200 { 6, 1, -1, -1, -1, -1, 4, 0},
1201 { 2, 5, 7, 7, 7, 5, 3, -1},
1202 { 6, 1, -1, -1, -1, -1, 4, 0},
1203 { 2, 0, 6, 6, 6, 0, 3, -1},
1204 { 6, 1, -1, -1, -1, -1, 4, 0},
1205 {-1, -1, -1, -1, -1, -1, -1, -1},
1206 {-1, -1, -1, -1, -1, -1, -1, -1},
1207 {-1, -1, -1, -1, -1, -1, -1, -1}},
1208 {{ 5, -1, -1, 1, 1, -1, -1, 5},
1209 { 5, -1, 4, -1, 4, -1, 5, -1},
1210 {-1, 2, 4, -1, -1, 4, 2, -1},
1211 { 7, 2, -1, -1, -1, 2, 7, -1},
1212 { 0, -1, 0, 4, 4, 0, -1, 0},
1213 { 7, 2, -1, -1, -1, 2, 7, -1},
1214 {-1, 2, 3, -1, -1, 3, 2, -1},
1215 { 5, -1, 3, -1, 3, -1, 5, -1},
1216 { 5, -1, -1, 6, 6, -1, -1, 5},
1217 {-1, -1, -1, -1, -1, -1, -1, -1}},
1218 {{ 2, 2, -1, -1, -1, -1, 5, 5},
1219 { 5, -1, -1, -1, -1, -1, 2, -1},
1220 { 5, -1, -1, -1, -1, -1, -1, 2},
1221 { 1, -1, 1, 5, 1, -1, 3, -1},
1222 { 5, 2, 5, 3, 1, 2, 5, 2},
1223 { 2, 0, 5, -1, 2, 0, 5, -1},
1224 {-1, 3, 7, -1, -1, 3, 7, -1},
1225 {-1, -1, 2, 0, 5, -1, -1, -1},
1226 {-1, -1, -1, -1, -1, -1, -1, -1},
1227 {-1, -1, -1, -1, -1, -1, -1, -1}},
1228 {{ 0, 6, 5, 2, 3, 4, 1, 7},
1229 {-1, -1, -1, -1, 1, -1, -1, -1},
1230 {-1, -1, -1, 1, 1, -1, -1, -1},
1231 {-1, -1, 1, -1, -1, -1, -1, -1},
1232 { 7, 1, 4, 3, 2, 5, 6, 0},
1233 {-1, -1, -1, -1, 1, -1, -1, -1},
1234 {-1, -1, -1, 1, 1, -1, -1, -1},
1235 {-1, -1, 1, -1, -1, -1, -1, -1},
1236 { 0, 6, 5, 2, 3, 4, 1, 7},
1237 {-1, -1, -1, -1, -1, -1, -1, -1}},
1238 {{-1, -1, 1, -1, -1, 1, -1, -1},
1239 {-1, 2, 4, -1, 2, 4, -1, -1},
1240 {-1, 2, 3, 6, 5, 3, 2, -1},
1241 {-1, 6, 5, -1, 6, 5, -1, -1},
1242 {-1, -1, -1, 7, 7, -1, -1, -1},
1243 {-1, -1, -1, 7, -1, -1, -1, -1},
1244 { 1, -1, -1, 7, 7, -1, -1, 3},
1245 { 2, -1, -1, 7, -1, -1, 2, -1},
1246 {-1, 3, 4, 5, 6, 4, 1, -1},
1247 {-1, -1, -1, -1, -1, -1, -1, -1}},
1248 {{ 1, -1, -1, 2, 2, -1, -1, 2},
1249 { 1, 3, 7, 3, 7, 4, 2, -1},
1250 {-1, 1, 6, -1, -1, 6, 2, -1},
1251 { 6, -1, 7, 3, 7, -1, 6, -1},
1252 {-1, 4, 2, -1, -1, 1, 3, -1},
1253 {-1, -1, 2, 6, 1, -1, -1, -1},
1254 {-1, 4, 3, 3, 4, 4, 3, -1},
1255 {-1, -1, -1, -1, -1, -1, -1, -1},
1256 {-1, -1, -1, -1, -1, -1, -1, -1},
1257 {-1, -1, -1, -1, -1, -1, -1, -1}},
1258 {{-1, -1, -1, 5, 6, -1, -1, -1},
1259 {-1, -1, -1, 3, -1, -1, -1, -1},
1260 {-1, -1, -1, 1, 2, -1, -1, -1},
1261 {-1, -1, -1, 4, -1, -1, -1, -1},
1262 {-1, -1, -1, 5, 7, -1, -1, -1},
1263 {-1, -1, -1, 2, -1, -1, -1, -1},
1264 { 6, 5, 4, 3, 2, 1, 7, 5},
1265 {-1, -1, -1, -1, -1, -1, -1, -1},
1266 {-1, -1, -1, -1, -1, -1, -1, -1},
1267 {-1, -1, -1, -1, -1, -1, -1, -1}},
1268 {{-1, 0, -1, 1, -1, 2, -1, -1},
1269 {-1, 4, -1, 5, -1, 6, -1, -1},
1270 {-1, 7, -1, 0, -1, 2, -1, -1},
1271 {-1, 6, -1, 3, -1, 6, -1, -1},
1272 {-1, 1, -1, 1, -1, 2, -1, -1},
1273 {-1, 3, -1, 5, -1, 0, -1, -1},
1274 {-1, 2, -1, 4, -1, 6, -1, -1},
1275 {-1, 3, -1, 6, -1, 7, -1, -1},
1276 {-1, -1, -1, -1, -1, -1, -1, -1},
1277 {-1, -1, -1, -1, -1, -1, -1, -1}},
1278 {{ 1, 1, 2, 2, 3, 3, 4, 4},
1279 { 5, 5, 6, 7, 6, 5, 5, -1},
1280 { 6, 4, 3, 3, 2, 2, 1, 6},
1281 { 4, 6, 5, 7, 6, 3, 1, -1},
1282 {-1, -1, -1, -1, -1, -1, -1, -1},
1283 {-1, -1, -1, -1, -1, -1, -1, -1},
1284 {-1, -1, -1, -1, -1, -1, -1, -1},
1285 {-1, -1, -1, -1, -1, -1, -1, -1},
1286 {-1, -1, -1, -1, -1, -1, -1, -1},
1287 {-1, -1, -1, -1, -1, -1, -1, -1}},
1288 {{ 7, 4, -1, 1, 2, -1, 4, 7},
1289 { 5, 5, -1, 2, -1, 4, 4, -1},
1290 {-1, 5, -1, 7, 7, -1, 4, -1},
1291 { 1, 0, 6, 7, 6, 0, 2, -1},
1292 {-1, 2, -1, 5, 3, -1, 1, -1},
1293 { 1, 1, -1, -1, -1, 2, 2, -1},
1294 { 6, 1, 4, -1, -1, 4, 2, 6},
1295 { 5, 3, -1, -1, -1, 3, 5, -1},
1296 {-1, -1, -1, -1, -1, -1, -1, -1},
1297 {-1, -1, -1, -1, -1, -1, -1, -1}},
1298 {{ 1, 5, 1, 0, 0, 1, 5, 1},
1299 { 1, 2, 5, -1, 5, 2, 1, -1},
1300 { 3, 6, 1, 2, 2, 1, 6, 3},
1301 { 4, 3, 4, -1, 4, 3, 4, -1},
1302 { 3, 4, 6, 5, 5, 6, 4, 3},
1303 { 0, 2, 3, -1, 3, 2, 0, -1},
1304 { 2, 3, 1, 5, 5, 1, 3, 2},
1305 {-1, -1, -1, -1, -1, -1, -1, -1},
1306 {-1, -1, -1, -1, -1, -1, -1, -1},
1307 {-1, -1, -1, -1, -1, -1, -1, -1}},
1308 {{ 3, 0, 2, 7, 5, 7, 6, 5},
1309 { 6, -1, 1, -1, 2, -1, 1, -1},
1310 {-1, 6, 4, 0, 3, 4, 5, -1},
1311 {-1, 5, -1, 1, -1, 4, -1, -1},
1312 {-1, 7, 3, 5, 6, 5, 3, -1},
1313 { 1, -1, 2, -1, 4, -1, 2, -1},
1314 { 6, 4, 4, 6, 6, 5, 5, 1},
1315 {-1, -1, -1, -1, -1, -1, -1, -1},
1316 {-1, -1, -1, -1, -1, -1, -1, -1},
1317 {-1, -1, -1, -1, -1, -1, -1, -1}}
1318};
1319
1320/* the tile struct
1321 * type is the bubble number 0-7
1322 * fallx is the x axis movement for the falling bubble
1323 * fallvel is the initial upward velocity for the falling bubble
1324 * ingroup denotes a bubble that is part of a group to be removed
1325 * anchored denotes a bubble that is anchored to the ceiling
1326 */
1327struct tile {
1328 int type;
1329 int fallx;
1330 int fallvel;
1331 bool ingroup;
1332 bool anchored;
1333 bool delete;
1334};
1335
1336/* the game context struct
1337 * score is the current score
1338 * level is the current level
1339 * angle is the current cannon direction
1340 * shots is the number of shots fired since last compression
1341 * compress is the height of the compressor
1342 * onboardcnt is the number of unique bubbles on the playing board
1343 * onboard is the unique bubbles on the playing board
1344 * nextinq is the pointer to the next bubble in the firing queue
1345 * queue is the circular buffer of bubbles to be fired
1346 * elapsedlvl is level elapsed time in 1/100s of seconds
1347 * elapsedshot is the shot elapsed time in 1/100s of seconds
1348 * startedshot is when the current shot began
1349 * playboard is the game playing board
1350 */
1351struct game_context {
1352 unsigned int score;
1353 unsigned int level;
1354 int angle;
1355 int shots;
1356 int compress;
1357 int onboardcnt;
1358 int onboard[NUM_BUBBLES];
1359 int nextinq;
1360 int queue[NUM_QUEUE];
1361 long elapsedlvl;
1362 long elapsedshot;
1363 long startedshot;
1364 struct tile playboard[BB_HEIGHT][BB_WIDTH];
1365};
1366
1367static struct highscore highscores[NUM_SCORES];
1368
1369/* used to denote available resume info */
1370static bool resume = false;
1371static bool resume_file = false;
1372static unsigned int highlevel = 0; /* the highest level beaten */
1373static unsigned int last_highlevel = 0;
1374
1375static void bubbles_init(struct game_context* bb);
1376static bool bubbles_nextlevel(struct game_context* bb);
1377static void bubbles_getonboard(struct game_context* bb);
1378static void bubbles_drawboard(struct game_context* bb);
1379static int bubbles_fire(struct game_context* bb);
1380static bool bubbles_collision(struct game_context* bb, int y, int x,
1381 int nearrow, int nearcol);
1382static bool bubbles_ingroup(struct game_context* bb, int row, int col);
1383static int bubbles_searchgroup(struct game_context* bb, int row, int col);
1384static int bubbles_remove(struct game_context* bb);
1385static void bubbles_anchored(struct game_context* bb, int row, int col);
1386static int bubbles_fall(struct game_context* bb);
1387static int bubbles_checklevel(struct game_context* bb);
1388static void bubbles_recordscore(struct game_context* bb);
1389static bool bubbles_loadgame(struct game_context* bb);
1390static void bubbles_savegame(struct game_context* bb);
1391static inline void bubbles_setcolors(void);
1392static void bubbles_callback(void* param);
1393static int bubbles_handlebuttons(struct game_context* bb, bool animblock,
1394 int timeout);
1395static int bubbles(struct game_context* bb);
1396
1397/*****************************************************************************
1398* bubbles_init() initializes bubbles data structures.
1399******************************************************************************/
1400static void bubbles_init(struct game_context* bb) {
1401 bubbles_setcolors();
1402 /* seed the rand generator */
1403 rb->srand(*rb->current_tick);
1404
1405 /* check for resumed game */
1406 if (resume)
1407 {
1408 resume = false;
1409 return;
1410 }
1411
1412 bb->score = 0;
1413 bubbles_nextlevel(bb);
1414}
1415
1416/*****************************************************************************
1417* bubbles_nextlevel() sets up the game for the next level, returns false if
1418* there are no more levels.
1419******************************************************************************/
1420static bool bubbles_nextlevel(struct game_context* bb) {
1421 int i, j, pos;
1422
1423 bb->level++;
1424
1425 /* check if there are no more levels */
1426 if(bb->level > NUM_LEVELS) return false;
1427
1428 /* save highest level */
1429 if (bb->level-1 > highlevel)
1430 highlevel = bb->level-1;
1431
1432 /* set up the play board */
1433 rb->memset(bb->playboard, 0, sizeof(bb->playboard));
1434 for(i=0; i<BB_LEVEL_HEIGHT; i++) {
1435 for(j=0; j<BB_WIDTH; j++) {
1436 pos = (int)level[bb->level-1][i][j];
1437 if(pos >=0 && pos < NUM_BUBBLES) {
1438 bb->playboard[i][j].type = pos;
1439 } else {
1440 bb->playboard[i][j].type = -1;
1441 }
1442 }
1443 }
1444 for(i=BB_LEVEL_HEIGHT; i<BB_HEIGHT; i++) {
1445 for(j=0; j<BB_WIDTH; j++) {
1446 bb->playboard[i][j].type = -1;
1447 }
1448 }
1449
1450 /* fill first bubbles in shot queue */
1451 bubbles_getonboard(bb);
1452 for(i=0; i<NUM_QUEUE; i++) {
1453 bb->queue[i] = bb->onboard[rb->rand()%bb->onboardcnt];
1454 }
1455
1456 bb->angle = 0;
1457 bb->shots = 0;
1458 bb->compress = 0;
1459 bb->nextinq = 0;
1460 bb->elapsedlvl = 0;
1461 bb->elapsedshot = 0;
1462
1463 return true;
1464}
1465
1466/*****************************************************************************
1467* bubbles_getonboard() determines which bubble types are on the play board.
1468******************************************************************************/
1469static void bubbles_getonboard(struct game_context* bb) {
1470 int i, j, k;
1471 bool found;
1472
1473 bb->onboardcnt = 0;
1474 rb->memset(bb->onboard, -1, sizeof(bb->onboard));
1475
1476 for(i=0; i<BB_HEIGHT; i++) {
1477 for(j=0; j<BB_WIDTH; j++) {
1478 if(bb->playboard[i][j].type >= 0) {
1479 found = false;
1480
1481 for(k=0; k<bb->onboardcnt; k++) {
1482 if(bb->playboard[i][j].type == bb->onboard[k]) {
1483 found = true;
1484 break;
1485 }
1486 }
1487
1488 if(!found) {
1489 bb->onboard[bb->onboardcnt] = bb->playboard[i][j].type;
1490 bb->onboardcnt++;
1491 }
1492
1493 if(bb->onboardcnt == NUM_BUBBLES) return;
1494 }
1495 }
1496 }
1497}
1498
1499/*****************************************************************************
1500* bubbles_drawboard() draws the game board to the buffer but does not update
1501* the lcd.
1502******************************************************************************/
1503static void bubbles_drawboard(struct game_context* bb) {
1504 int i, j;
1505 int w1, w2, h;
1506 int colmax, indent;
1507 int tipx, tipy;
1508 bool evenline = false;
1509 char *level = "Level";
1510 char *score = "Score";
1511 char *next = "Next";
1512 char *hurry = "HURRY!";
1513 char str[11];
1514
1515 /* clear screen */
1516 rb->lcd_clear_display();
1517#if ((LCD_HEIGHT >= 128) && (LCD_WIDTH <= 320)) || ((LCD_WIDTH == 132) && (LCD_HEIGHT == 80))
1518 h = rb->font_get(FONT_SYSFIXED)->height + 1;
1519#elif (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
1520 h = rb->font_get(FONT_SYSFIXED)->height + 6;
1521#else
1522 int font = rb->screens[SCREEN_MAIN]->getuifont();
1523 h = rb->font_get(font)->height + 1;
1524#endif
1525 /* draw background */
1526#ifdef HAVE_LCD_COLOR
1527 rb->lcd_bitmap(bubbles_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1528#endif
1529
1530 /* display play board */
1531 for(i=0; i<BB_HEIGHT; i++) {
1532 colmax = BB_WIDTH;
1533 if(evenline) {
1534 colmax--;
1535 indent = ROW_INDENT;
1536 } else {
1537 indent = 0;
1538 }
1539 evenline = !evenline;
1540
1541 for(j=0; j<colmax; j++) {
1542 if(bb->playboard[i][j].type >= 0 && !bb->playboard[i][j].delete) {
1543 rb->lcd_bitmap_part(bubbles_emblem,
1544 0, EMBLEM_HEIGHT*bb->playboard[i][j].type,
1545 STRIDE( SCREEN_MAIN,
1546 BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
1547 XOFS+indent+BUBBLE_WIDTH*j+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
1548 YOFS+ROW_HEIGHT*i+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2+bb->compress*ROW_HEIGHT,
1549 EMBLEM_WIDTH, EMBLEM_HEIGHT);
1550 rb->lcd_set_drawmode(DRMODE_FG);
1551 rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
1552 XOFS+indent+BUBBLE_WIDTH*j,
1553 YOFS+ROW_HEIGHT*i+bb->compress*ROW_HEIGHT,
1554 BUBBLE_WIDTH, BUBBLE_HEIGHT);
1555 rb->lcd_set_drawmode(DRMODE_SOLID);
1556 }
1557 }
1558 }
1559
1560 /* display bubble to be shot */
1561 rb->lcd_bitmap_part(bubbles_emblem,
1562 0, EMBLEM_HEIGHT*bb->queue[bb->nextinq],
1563 STRIDE( SCREEN_MAIN,
1564 BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
1565 SHOTX+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
1566 SHOTY+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2,
1567 EMBLEM_WIDTH, EMBLEM_HEIGHT);
1568 rb->lcd_set_drawmode(DRMODE_FG);
1569 rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
1570 SHOTX, SHOTY,
1571 BUBBLE_WIDTH, BUBBLE_HEIGHT);
1572 rb->lcd_set_drawmode(DRMODE_SOLID);
1573
1574 /* display next bubble to be shot */
1575#ifndef NEXT_BB_X
1576 rb->lcd_bitmap_part(bubbles_emblem,
1577 0, EMBLEM_HEIGHT*bb->queue[(bb->nextinq+1)%NUM_QUEUE],
1578 STRIDE( SCREEN_MAIN,
1579 BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
1580 XOFS/2-BUBBLE_WIDTH/2+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
1581 SHOTY+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2,
1582 EMBLEM_WIDTH, EMBLEM_HEIGHT);
1583 rb->lcd_set_drawmode(DRMODE_FG);
1584 rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
1585 XOFS/2-BUBBLE_WIDTH/2, SHOTY,
1586 BUBBLE_WIDTH, BUBBLE_HEIGHT);
1587 rb->lcd_set_drawmode(DRMODE_SOLID);
1588#else
1589 rb->lcd_bitmap_part(bubbles_emblem,
1590 0, EMBLEM_HEIGHT*bb->queue[(bb->nextinq+1)%NUM_QUEUE],
1591 STRIDE( SCREEN_MAIN,
1592 BMPWIDTH_bubbles_emblem, BMPHEIGHT_bubbles_emblem),
1593 NEXT_BB_X + NEXT_BB_WIDTH/2-BUBBLE_WIDTH/2+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
1594 NEXT_BB_Y + (BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2 + h,
1595 EMBLEM_WIDTH, EMBLEM_HEIGHT);
1596 rb->lcd_set_drawmode(DRMODE_FG);
1597 rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
1598 NEXT_BB_X + NEXT_BB_WIDTH/2-BUBBLE_WIDTH/2, NEXT_BB_Y + h,
1599 BUBBLE_WIDTH, BUBBLE_HEIGHT);
1600 rb->lcd_set_drawmode(DRMODE_SOLID);
1601#endif
1602
1603 /* draw bounding lines */
1604#ifndef HAVE_LCD_COLOR
1605 rb->lcd_vline(XOFS-1, 0, LCD_HEIGHT);
1606 rb->lcd_vline(XOFS+BUBBLE_WIDTH*BB_WIDTH, 0, LCD_HEIGHT);
1607#endif
1608 rb->lcd_hline(XOFS, XOFS+BUBBLE_WIDTH*BB_WIDTH-1, YOFS+bb->compress*ROW_HEIGHT-1);
1609 rb->lcd_hline(XOFS, XOFS+BUBBLE_WIDTH*BB_WIDTH-1,
1610 YOFS+ROW_HEIGHT*(BB_HEIGHT-2)+BUBBLE_HEIGHT);
1611
1612 /* draw arrow */
1613 tipx = SHOTX+BUBBLE_WIDTH/2+(((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH*3/2)>>10);
1614 tipy = SHOTY+BUBBLE_HEIGHT/2-(((fp14_cos(bb->angle)>>4)*BUBBLE_HEIGHT*3/2)>>10);
1615
1616 rb->lcd_drawline(SHOTX+BUBBLE_WIDTH/2+(((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH/2)>>10),
1617 SHOTY+BUBBLE_HEIGHT/2-(((fp14_cos(bb->angle)>>4)*BUBBLE_HEIGHT/2)>>10),
1618 tipx, tipy);
1619 xlcd_filltriangle(tipx, tipy,
1620 tipx+(((fp14_sin(bb->angle-135)>>4)*BUBBLE_WIDTH/3)>>10),
1621 tipy-(((fp14_cos(bb->angle-135)>>4)*BUBBLE_HEIGHT/3)>>10),
1622 tipx+(((fp14_sin(bb->angle+135)>>4)*BUBBLE_WIDTH/3)>>10),
1623 tipy-(((fp14_cos(bb->angle+135)>>4)*BUBBLE_HEIGHT/3)>>10));
1624
1625 /* draw text */
1626 rb->snprintf(str, 4, "%d", bb->level);
1627 rb->lcd_getstringsize(level, &w1, NULL);
1628 rb->lcd_getstringsize(str, &w2, NULL);
1629#ifndef LEVEL_TXT_X
1630 rb->lcd_putsxy(XOFS/2-w1/2, 2, level);
1631 rb->lcd_putsxy(XOFS/2-w2/2, 2+h, str);
1632#else
1633 rb->lcd_putsxy(LEVEL_TXT_X+(LEVEL_TXT_WIDTH/2-w1/2), LEVEL_TXT_Y, level);
1634 rb->lcd_putsxy(LEVEL_TXT_X+(LEVEL_TXT_WIDTH/2-w2/2), LEVEL_TXT_Y+h, str);
1635#endif
1636
1637 rb->snprintf(str, 10, "%d", bb->score);
1638 rb->lcd_getstringsize(score, &w1,NULL);
1639 rb->lcd_getstringsize(str, &w2, NULL);
1640#ifndef SCORE_TXT_X
1641 rb->lcd_putsxy(XOFS/2-w1/2, 29, score);
1642 rb->lcd_putsxy(XOFS/2-w2/2, 29+h, str);
1643#else
1644 rb->lcd_putsxy(SCORE_TXT_X+(SCORE_TXT_WIDTH/2-w1/2), SCORE_TXT_Y, score);
1645 rb->lcd_putsxy(SCORE_TXT_X+(SCORE_TXT_WIDTH/2-w2/2), SCORE_TXT_Y+h, str);
1646#endif
1647
1648 rb->lcd_getstringsize(next, &w1, NULL);
1649#ifndef NEXT_BB_X
1650 rb->lcd_putsxy(XOFS/2-w1/2, SHOTY-h, next);
1651#else
1652 rb->lcd_putsxy(NEXT_BB_X+(NEXT_BB_WIDTH/2-w1/2), NEXT_BB_Y, next);
1653#endif
1654
1655
1656 if(bb->elapsedshot >= (MAX_SHOTTIME*7)/10) {
1657 rb->lcd_getstringsize(hurry, &w1, &h);
1658 /* screen is too small for the message to be centered (Clip Zip) */
1659 #if (LCD_WIDTH <= 96)
1660 rb->lcd_putsxy(LCD_WIDTH/2-w1/2+LCD_WIDTH/6, LCD_HEIGHT/2-h/2, hurry);
1661 #else
1662 rb->lcd_putsxy(LCD_WIDTH/2-w1/2, LCD_HEIGHT/2-h/2, hurry);
1663 #endif
1664 }
1665}
1666
1667/*****************************************************************************
1668* bubbles_fire() fires the current bubble, reloads the cannon, attaches
1669* bubble to playboard, removes appropriate bubbles, and advances the
1670* the compressor.
1671******************************************************************************/
1672static int bubbles_fire(struct game_context* bb) {
1673 int bubblecur;
1674 long shotxinc, shotyinc;
1675 long shotxofs, shotyofs;
1676 int shotxdirec = 1;
1677 long tempxofs, tempyofs;
1678 int nearrow, nearcol;
1679 int lastrow = BB_HEIGHT-1;
1680 int lastcol = (BB_WIDTH-1)/2;
1681 int buttonres;
1682 long lasttick, currenttick;
1683
1684 /* get current bubble */
1685 bubblecur = bb->queue[bb->nextinq];
1686 shotxinc = ((fp14_sin(bb->angle)>>4)*BUBBLE_WIDTH)/3;
1687 shotyinc = ((-1*(fp14_cos(bb->angle)>>4))*BUBBLE_HEIGHT)/3;
1688 shotxofs = shotyofs = 0;
1689
1690 /* advance the queue */
1691 bb->queue[bb->nextinq] = bb->onboard[rb->rand()%bb->onboardcnt];
1692 bb->nextinq = (bb->nextinq+1)%NUM_QUEUE;
1693 bubbles_drawboard(bb);
1694 rb->lcd_update_rect(0, 0, XOFS, LCD_HEIGHT);
1695
1696 /* move the bubble across the play board */
1697 lasttick = *rb->current_tick;
1698
1699 while(true) {
1700 /* move the bubble one step */
1701 shotyofs += shotyinc;
1702 shotxofs += shotxinc*shotxdirec;
1703
1704 /* check for bounce off sides */
1705 if(SHOTX+(shotxofs>>10) < XOFS) {
1706 shotxofs += 2*((XOFS<<10)-(((SHOTX)<<10)+shotxofs));
1707 shotxdirec *= -1;
1708 } else if(SHOTX+(shotxofs>>10) > XOFS+(BB_WIDTH-1)*BUBBLE_WIDTH) {
1709 shotxofs -= 2*((((SHOTX)<<10)+shotxofs)-
1710 ((XOFS<<10)+(((BB_WIDTH-1)*BUBBLE_WIDTH)<<10)));
1711 shotxdirec *= -1;
1712 }
1713
1714 tempxofs = shotxofs>>10;
1715 tempyofs = shotyofs>>10;
1716
1717 /* display shot */
1718 bubbles_drawboard(bb);
1719 rb->lcd_bitmap_part(bubbles_emblem, 0, EMBLEM_HEIGHT*bubblecur,
1720 STRIDE( SCREEN_MAIN,
1721 BMPWIDTH_bubbles_emblem,
1722 BMPHEIGHT_bubbles_emblem),
1723 SHOTX+tempxofs+(BUBBLE_WIDTH-EMBLEM_WIDTH)/2,
1724 SHOTY+tempyofs+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2,
1725 EMBLEM_WIDTH, EMBLEM_HEIGHT);
1726 rb->lcd_set_drawmode(DRMODE_FG);
1727 rb->lcd_mono_bitmap((const unsigned char *)bubbles_bubble,
1728 SHOTX+tempxofs, SHOTY+tempyofs,
1729 BUBBLE_WIDTH, BUBBLE_HEIGHT);
1730 rb->lcd_set_drawmode(DRMODE_SOLID);
1731 rb->lcd_update_rect(XOFS, 0, BB_WIDTH*BUBBLE_WIDTH, LCD_HEIGHT);
1732
1733 /* find nearest position */
1734 nearrow = ((SHOTY+tempyofs)-
1735 (YOFS+bb->compress*ROW_HEIGHT)+
1736 (ROW_HEIGHT/2))/ROW_HEIGHT;
1737 if(nearrow >= BB_HEIGHT) nearrow = BB_HEIGHT-1;
1738
1739 if(nearrow%2) { /* odd row */
1740 nearcol = ((SHOTX+tempxofs)-
1741 (XOFS+ROW_INDENT)+
1742 (BUBBLE_WIDTH/2))/BUBBLE_WIDTH;
1743 if(nearcol >= BB_WIDTH-1) nearcol = BB_WIDTH-2;
1744 } else { /* even row */
1745 nearcol = ((SHOTX+tempxofs)-XOFS+(BUBBLE_WIDTH/2))/BUBBLE_WIDTH;
1746 if(nearcol >= BB_WIDTH) nearcol = BB_WIDTH-1;
1747 }
1748 if(nearcol < 0) nearcol = 0;
1749
1750 /* if nearest position is occupied attach to last position */
1751 if(bb->playboard[nearrow][nearcol].type >= 0) {
1752 bb->playboard[lastrow][lastcol].type = bubblecur;
1753 break;
1754 }
1755
1756 /* save last position */
1757 lastrow = nearrow;
1758 lastcol = nearcol;
1759
1760 /* if collision with neighbor then attach shot */
1761 if(bubbles_collision(bb, YOFS+SHOTY+tempyofs, SHOTX+tempxofs,
1762 nearrow, nearcol)) {
1763 bb->playboard[nearrow][nearcol].type = bubblecur;
1764 break;
1765 }
1766
1767 /* if at top then attach shot to the ceiling */
1768 if(nearrow == 0 && SHOTY+tempyofs <= YOFS+bb->compress*ROW_HEIGHT) {
1769 bb->playboard[nearrow][nearcol].type = bubblecur;
1770 break;
1771 }
1772
1773 /* handle button events */
1774 buttonres = bubbles_handlebuttons(bb, true, 0);
1775 if(buttonres != BB_NONE) return buttonres;
1776
1777 /* framerate limiting */
1778 currenttick = *rb->current_tick;
1779 if(currenttick-lasttick < HZ/MAX_FPS) {
1780 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
1781 } else {
1782 rb->yield();
1783 }
1784 lasttick = currenttick;
1785 }
1786
1787 bubbles_drawboard(bb);
1788 rb->lcd_update();
1789
1790 /* clear appropriate bubbles from playing board */
1791 if(bubbles_ingroup(bb, lastrow, lastcol)) {
1792 buttonres = bubbles_remove(bb);
1793 if(buttonres != BB_NONE) return buttonres;
1794 }
1795
1796 /* update shots and compress amount */
1797 bb->shots++;
1798 if(bb->shots >= NUM_COMPRESS) {
1799 bb->shots = 0;
1800 bb->compress++;
1801 }
1802
1803 return BB_NONE;
1804}
1805
1806/*****************************************************************************
1807* bubbles_collision() determines if a fired bubble has collided with another
1808* bubble.
1809******************************************************************************/
1810static bool bubbles_collision(struct game_context* bb, int y, int x,
1811 int nearrow, int nearcol) {
1812 int nx, ny;
1813 int adj = nearrow%2;
1814
1815 /* check neighbors */
1816 if(nearcol-1 >= 0) {
1817 if(bb->playboard[nearrow][nearcol-1].type >= 0) {
1818 nx = XOFS+(nearrow%2 ? ROW_INDENT : 0)+BUBBLE_WIDTH*(nearcol-1);
1819 ny = YOFS+ROW_HEIGHT*nearrow+bb->compress*ROW_HEIGHT;
1820 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1821 }
1822 }
1823
1824 if(nearcol-1+adj >= 0) {
1825 if(nearrow-1 >= 0) {
1826 if(bb->playboard[nearrow-1][nearcol-1+adj].type >= 0) {
1827 nx = XOFS+((nearrow-1)%2 ? ROW_INDENT : 0)+
1828 BUBBLE_WIDTH*(nearcol-1+adj);
1829 ny = YOFS+ROW_HEIGHT*(nearrow-1)+bb->compress*ROW_HEIGHT;
1830 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1831 }
1832 }
1833
1834 if(nearrow+1 < BB_HEIGHT) {
1835 if(bb->playboard[nearrow+1][nearcol-1+adj].type >= 0) {
1836 nx = XOFS+((nearrow+1)%2 ? ROW_INDENT : 0)+
1837 BUBBLE_WIDTH*(nearcol-1+adj);
1838 ny = YOFS+ROW_HEIGHT*(nearrow+1)+bb->compress*ROW_HEIGHT;
1839 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1840 }
1841 }
1842 }
1843
1844 if(nearcol+adj >= 0) {
1845 if(nearrow-1 >= 0) {
1846 if(bb->playboard[nearrow-1][nearcol+adj].type >= 0) {
1847 nx = XOFS+((nearrow-1)%2 ? ROW_INDENT : 0)+
1848 BUBBLE_WIDTH*(nearcol+adj);
1849 ny = YOFS+ROW_HEIGHT*(nearrow-1)+bb->compress*ROW_HEIGHT;
1850 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1851 }
1852 }
1853
1854 if(nearrow+1 < BB_HEIGHT) {
1855 if(bb->playboard[nearrow+1][nearcol+adj].type >= 0) {
1856 nx = XOFS+((nearrow+1)%2 ? ROW_INDENT : 0)+
1857 BUBBLE_WIDTH*(nearcol+adj);
1858 ny = YOFS+ROW_HEIGHT*(nearrow+1)+bb->compress*ROW_HEIGHT;
1859 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1860 }
1861 }
1862 }
1863
1864 if(nearcol+1 < BB_WIDTH-adj) {
1865 if(bb->playboard[nearrow][nearcol+1].type >= 0) {
1866 nx = XOFS+(nearrow%2 ? ROW_INDENT : 0)+BUBBLE_WIDTH*(nearcol+1);
1867 ny = YOFS+ROW_HEIGHT*nearrow+bb->compress*ROW_HEIGHT;
1868 if((x-nx)*(x-nx)+(y-ny)*(y-ny) < MIN_DISTANCE) return true;
1869 }
1870 }
1871
1872 return false;
1873}
1874
1875/*****************************************************************************
1876* bubbles_ingroup() marks all bubbles that form the current group.
1877******************************************************************************/
1878static bool bubbles_ingroup(struct game_context* bb, int row, int col) {
1879 int i, j;
1880 int count;
1881
1882 count = bubbles_searchgroup(bb, row, col);
1883
1884 /* unmark group if too small */
1885 if(count < 3) {
1886 for(i=0; i<BB_HEIGHT; i++) {
1887 for(j=0; j<BB_WIDTH; j++) {
1888 bb->playboard[i][j].ingroup = false;
1889 }
1890 }
1891
1892 return false;
1893 }
1894
1895 return true;
1896}
1897
1898/*****************************************************************************
1899* bubbles_searchgroup() return the size of the group of bubbles of the same
1900* type that the current bubble belongs to.
1901******************************************************************************/
1902static int bubbles_searchgroup(struct game_context* bb, int row, int col) {
1903 int i, adj;
1904 int myrow, mycol, mytype;
1905 int count = 0;
1906
1907 struct coord {
1908 int row;
1909 int col;
1910 } search[(2*BB_WIDTH-1)*(BB_HEIGHT/2)];
1911
1912 /* search initial bubble */
1913 bb->playboard[row][col].ingroup = true;
1914 search[count].row = row;
1915 search[count].col = col;
1916 count++;
1917
1918 /* breadth-first search neighbors */
1919 for(i=0; i<count; i++) {
1920 myrow = search[i].row;
1921 mycol = search[i].col;
1922 mytype = bb->playboard[myrow][mycol].type;
1923 adj = myrow%2;
1924
1925 if(mycol-1 >= 0) {
1926 if(bb->playboard[myrow][mycol-1].type == mytype &&
1927 !bb->playboard[myrow][mycol-1].ingroup) {
1928 bb->playboard[myrow][mycol-1].ingroup = true;
1929 search[count].row = myrow;
1930 search[count].col = mycol-1;
1931 count++;
1932 }
1933 }
1934
1935 if(mycol-1+adj >= 0) {
1936 if(myrow-1 >= 0) {
1937 if(bb->playboard[myrow-1][mycol-1+adj].type == mytype &&
1938 !bb->playboard[myrow-1][mycol-1+adj].ingroup) {
1939 bb->playboard[myrow-1][mycol-1+adj].ingroup = true;
1940 search[count].row = myrow-1;
1941 search[count].col = mycol-1+adj;
1942 count++;
1943 }
1944 }
1945
1946 if(myrow+1 < BB_HEIGHT) {
1947 if(bb->playboard[myrow+1][mycol-1+adj].type == mytype &&
1948 !bb->playboard[myrow+1][mycol-1+adj].ingroup) {
1949 bb->playboard[myrow+1][mycol-1+adj].ingroup = true;
1950 search[count].row = myrow+1;
1951 search[count].col = mycol-1+adj;
1952 count++;
1953 }
1954 }
1955 }
1956
1957 if(mycol+adj >= 0) {
1958 if(myrow-1 >= 0) {
1959 if(bb->playboard[myrow-1][mycol+adj].type == mytype &&
1960 !bb->playboard[myrow-1][mycol+adj].ingroup) {
1961 bb->playboard[myrow-1][mycol+adj].ingroup = true;
1962 search[count].row = myrow-1;
1963 search[count].col = mycol+adj;
1964 count++;
1965 }
1966 }
1967
1968 if(myrow+1 < BB_HEIGHT) {
1969 if(bb->playboard[myrow+1][mycol+adj].type == mytype &&
1970 !bb->playboard[myrow+1][mycol+adj].ingroup) {
1971 bb->playboard[myrow+1][mycol+adj].ingroup = true;
1972 search[count].row = myrow+1;
1973 search[count].col = mycol+adj;
1974 count++;
1975 }
1976 }
1977 }
1978
1979 if(mycol+1 < BB_WIDTH-adj) {
1980 if(bb->playboard[myrow][mycol+1].type == mytype &&
1981 !bb->playboard[myrow][mycol+1].ingroup) {
1982 bb->playboard[myrow][mycol+1].ingroup = true;
1983 search[count].row = myrow;
1984 search[count].col = mycol+1;
1985 count++;
1986 }
1987 }
1988 }
1989
1990 return count;
1991}
1992
1993/*****************************************************************************
1994* bubbles_remove() removes all bubbles in the current group and all
1995* unanchored bubbles from the play board.
1996******************************************************************************/
1997static int bubbles_remove(struct game_context* bb) {
1998 int i, j;
1999 int buttonres;
2000
2001 /* determine all anchored bubbles */
2002 for(j=0; j<BB_WIDTH; j++) {
2003 if(bb->playboard[0][j].type >= 0 && !bb->playboard[0][j].ingroup) {
2004 bubbles_anchored(bb, 0, j);
2005 }
2006 }
2007
2008 /* mark bubbles to be deleted */
2009 for(i=0; i<BB_HEIGHT; i++) {
2010 for(j=0; j<BB_WIDTH; j++) {
2011 if(bb->playboard[i][j].type >= 0 &&
2012 (!bb->playboard[i][j].anchored || bb->playboard[i][j].ingroup)) {
2013 bb->playboard[i][j].delete = true;
2014 }
2015 }
2016 }
2017
2018 /* animate falling bubbles */
2019 buttonres = bubbles_fall(bb);
2020 if(buttonres != BB_NONE) return buttonres;
2021
2022 /* remove bubbles */
2023 for(i=0; i<BB_HEIGHT; i++) {
2024 for(j=0; j<BB_WIDTH; j++) {
2025 if(bb->playboard[i][j].delete) {
2026 bb->playboard[i][j].ingroup = false;
2027 bb->playboard[i][j].type = -1;
2028 bb->playboard[i][j].delete = false;
2029 } else {
2030 bb->playboard[i][j].anchored = false;
2031 }
2032 }
2033 }
2034
2035 bubbles_getonboard(bb);
2036
2037 return BB_NONE;
2038}
2039
2040/*****************************************************************************
2041* bubbles_anchored() marks all bubbles that are anchored in some way to the
2042* current bubble.
2043******************************************************************************/
2044static void bubbles_anchored(struct game_context* bb, int row, int col) {
2045 int i, adj;
2046 int myrow, mycol;
2047 int count = 0;
2048
2049 struct coord {
2050 int row;
2051 int col;
2052 } search[(2*BB_WIDTH-1)*(BB_HEIGHT/2)];
2053
2054 /* search initial bubble */
2055 bb->playboard[row][col].anchored = true;
2056 search[count].row = row;
2057 search[count].col = col;
2058 count++;
2059
2060 /* breadth-first search neighbors */
2061 for(i=0; i<count; i++) {
2062 myrow = search[i].row;
2063 mycol = search[i].col;
2064 adj = myrow%2;
2065
2066 if(mycol-1 >= 0) {
2067 if(bb->playboard[myrow][mycol-1].type >= 0 &&
2068 !bb->playboard[myrow][mycol-1].ingroup &&
2069 !bb->playboard[myrow][mycol-1].anchored) {
2070 bb->playboard[myrow][mycol-1].anchored = true;
2071 search[count].row = myrow;
2072 search[count].col = mycol-1;
2073 count++;
2074 }
2075 }
2076
2077 if(mycol-1+adj >= 0) {
2078 if(myrow-1 >= 0) {
2079 if(bb->playboard[myrow-1][mycol-1+adj].type >= 0 &&
2080 !bb->playboard[myrow-1][mycol-1+adj].ingroup &&
2081 !bb->playboard[myrow-1][mycol-1+adj].anchored) {
2082 bb->playboard[myrow-1][mycol-1+adj].anchored = true;
2083 search[count].row = myrow-1;
2084 search[count].col = mycol-1+adj;
2085 count++;
2086 }
2087 }
2088
2089 if(myrow+1 < BB_HEIGHT) {
2090 if(bb->playboard[myrow+1][mycol-1+adj].type >= 0 &&
2091 !bb->playboard[myrow+1][mycol-1+adj].ingroup &&
2092 !bb->playboard[myrow+1][mycol-1+adj].anchored) {
2093 bb->playboard[myrow+1][mycol-1+adj].anchored = true;
2094 search[count].row = myrow+1;
2095 search[count].col = mycol-1+adj;
2096 count++;
2097 }
2098 }
2099 }
2100
2101 if(mycol+adj >= 0) {
2102 if(myrow-1 >= 0) {
2103 if(bb->playboard[myrow-1][mycol+adj].type >= 0 &&
2104 !bb->playboard[myrow-1][mycol+adj].ingroup &&
2105 !bb->playboard[myrow-1][mycol+adj].anchored) {
2106 bb->playboard[myrow-1][mycol+adj].anchored = true;
2107 search[count].row = myrow-1;
2108 search[count].col = mycol+adj;
2109 count++;
2110 }
2111 }
2112
2113 if(myrow+1 < BB_HEIGHT) {
2114 if(bb->playboard[myrow+1][mycol+adj].type >= 0 &&
2115 !bb->playboard[myrow+1][mycol+adj].ingroup &&
2116 !bb->playboard[myrow+1][mycol+adj].anchored) {
2117 bb->playboard[myrow+1][mycol+adj].anchored = true;
2118 search[count].row = myrow+1;
2119 search[count].col = mycol+adj;
2120 count++;
2121 }
2122 }
2123 }
2124
2125 if(mycol+1 < BB_WIDTH-adj) {
2126 if(bb->playboard[myrow][mycol+1].type >= 0 &&
2127 !bb->playboard[myrow][mycol+1].ingroup &&
2128 !bb->playboard[myrow][mycol+1].anchored) {
2129 bb->playboard[myrow][mycol+1].anchored = true;
2130 search[count].row = myrow;
2131 search[count].col = mycol+1;
2132 count++;
2133 }
2134 }
2135 }
2136}
2137
2138/*****************************************************************************
2139* bubbles_fall() makes removed bubbles fall from the screen.
2140******************************************************************************/
2141static int bubbles_fall(struct game_context* bb) {
2142 int i, j;
2143 int count;
2144 int indent;
2145 int xofs, yofs;
2146 int buttonres;
2147 bool onscreen;
2148 long lasttick, currenttick;
2149
2150 /* give all falling bubbles an x axis movement */
2151 for(i=0; i<BB_HEIGHT; i++) {
2152 for(j=0; j<BB_WIDTH; j++) {
2153 if(bb->playboard[i][j].delete) {
2154 bb->playboard[i][j].fallx = rb->rand()%25 - 12;
2155 bb->playboard[i][j].fallvel = rb->rand()%5 + 6;
2156 }
2157 }
2158 }
2159
2160 /* draw bubbles falling off the screen
2161 * follows y=x^2-8x scaled to bubble size
2162 */
2163 lasttick = *rb->current_tick;
2164
2165 for(count=1; ;count++) {
2166 onscreen = false;
2167 bubbles_drawboard(bb);
2168
2169 for(i=0; i<BB_HEIGHT; i++) {
2170 for(j=0; j<BB_WIDTH; j++) {
2171 if(bb->playboard[i][j].delete) {
2172 indent = (i%2 ? ROW_INDENT : 0);
2173 xofs = ((bb->playboard[i][j].fallx*count)*BUBBLE_WIDTH)/48;
2174 yofs = ((count*count - bb->playboard[i][j].fallvel*count)*
2175 BUBBLE_HEIGHT)/20;
2176
2177 /* draw bubble if it is still on the screen */
2178 if(YOFS+ROW_HEIGHT*i+bb->compress*ROW_HEIGHT+yofs
2179 <= LCD_HEIGHT) {
2180 onscreen = true;
2181
2182 rb->lcd_bitmap_part(bubbles_emblem, 0,
2183 EMBLEM_HEIGHT*bb->playboard[i][j].type,
2184 STRIDE( SCREEN_MAIN,
2185 BMPWIDTH_bubbles_emblem,
2186 BMPHEIGHT_bubbles_emblem),
2187 XOFS+indent+BUBBLE_WIDTH*j+
2188 (BUBBLE_WIDTH-EMBLEM_WIDTH)/2+xofs,
2189 YOFS+ROW_HEIGHT*i+(BUBBLE_HEIGHT-EMBLEM_HEIGHT)/2+
2190 bb->compress*ROW_HEIGHT+yofs,
2191 EMBLEM_WIDTH, EMBLEM_HEIGHT);
2192 rb->lcd_set_drawmode(DRMODE_FG);
2193 rb->lcd_mono_bitmap(
2194 (const unsigned char *)bubbles_bubble,
2195 XOFS+indent+BUBBLE_WIDTH*j+xofs,
2196 YOFS+ROW_HEIGHT*i+bb->compress*ROW_HEIGHT+yofs,
2197 BUBBLE_WIDTH, BUBBLE_HEIGHT);
2198 rb->lcd_set_drawmode(DRMODE_SOLID);
2199 }
2200 }
2201 }
2202 }
2203
2204 rb->lcd_update();
2205
2206 /* break out if all bubbles are off the screen */
2207 if(!onscreen) break;
2208
2209 /* handle button events */
2210 buttonres = bubbles_handlebuttons(bb, true, 0);
2211 if(buttonres != BB_NONE) return buttonres;
2212
2213 /* framerate limiting */
2214 currenttick = *rb->current_tick;
2215 if(currenttick-lasttick < HZ/MAX_FPS) {
2216 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
2217 } else {
2218 rb->yield();
2219 }
2220 lasttick = currenttick;
2221 }
2222
2223 return BB_NONE;
2224}
2225
2226/*****************************************************************************
2227* bubbles_checklevel() checks the state of the playboard for a win or loss.
2228******************************************************************************/
2229static int bubbles_checklevel(struct game_context* bb) {
2230 int i, j;
2231 int points;
2232 char str[13];
2233
2234 bubbles_drawboard(bb);
2235 rb->lcd_update();
2236
2237 /* check for bubbles below cut off point */
2238 for(i=0; i<=bb->compress; i++) {
2239 for(j=0; j<BB_WIDTH; j++) {
2240 if(bb->playboard[BB_HEIGHT-1-i][j].type >= 0) return BB_LOSE;
2241 }
2242 }
2243
2244 /* check for bubbles above cut off point */
2245 for(i=0; i<BB_HEIGHT-1-bb->compress; i++) {
2246 for(j=0; j<BB_WIDTH; j++) {
2247 if(bb->playboard[i][j].type >= 0) return BB_NONE;
2248 }
2249 }
2250
2251 /* level complete, record score */
2252 points = 100 - bb->elapsedlvl/100;
2253 if(points > 0) {
2254 bb->score += points;
2255 } else {
2256 points = 0;
2257 }
2258
2259 rb->snprintf(str, 12, "%d points", points);
2260 rb->splash(HZ, str);
2261
2262 /* advance to the next level */
2263 if(!bubbles_nextlevel(bb)) {
2264 return BB_WIN;
2265 }
2266
2267 bubbles_drawboard(bb);
2268 rb->lcd_update();
2269 rb->snprintf(str, 12, "Level %d", bb->level);
2270 rb->splash(HZ, str);
2271 bubbles_drawboard(bb);
2272 rb->lcd_update();
2273
2274 return BB_NONE;
2275}
2276
2277/*****************************************************************************
2278* bubbles_recordscore() inserts a high score into the high scores list and
2279* returns the high score position.
2280******************************************************************************/
2281static void bubbles_recordscore(struct game_context* bb) {
2282
2283 int position;
2284
2285 position = highscore_update(bb->score, bb->level-1, "",
2286 highscores, NUM_SCORES);
2287 if (position != -1)
2288 {
2289 if (position == 0)
2290 rb->splash(HZ*2, "New High Score");
2291 highscore_show(position, highscores, NUM_SCORES, true);
2292 }
2293}
2294
2295/*****************************************************************************
2296* bubbles_loaddata() loads highest level beaten.
2297******************************************************************************/
2298static void bubbles_loaddata(void) {
2299 int fd;
2300
2301 last_highlevel = highlevel = 0;
2302 /* open data file */
2303 fd = rb->open(DATA_FILE, O_RDONLY);
2304 if (fd < 0) return;
2305
2306 /* read in saved game */
2307 if (rb->read(fd, &highlevel, sizeof(highlevel)) < (long)sizeof(highlevel))
2308 {
2309 highlevel = 0;
2310 }
2311 if (highlevel >= NUM_LEVELS)
2312 highlevel = NUM_LEVELS-1;
2313 last_highlevel = highlevel;
2314
2315 rb->close(fd);
2316}
2317
2318/*****************************************************************************
2319* bubbles_savedata() saves the current game state.
2320******************************************************************************/
2321static void bubbles_savedata(void) {
2322 int fd;
2323
2324 if (last_highlevel >= highlevel) /* no need to save */
2325 return;
2326
2327 fd = rb->open(DATA_FILE, O_WRONLY|O_CREAT, 0666);
2328 if (fd < 0) return;
2329
2330 rb->write(fd, &highlevel, sizeof(highlevel));
2331
2332 rb->close(fd);
2333}
2334
2335/*****************************************************************************
2336* bubbles_loadgame() loads the saved game and returns load success.
2337******************************************************************************/
2338static bool bubbles_loadgame(struct game_context* bb) {
2339 int fd;
2340
2341 bool ret = true;
2342 /* open game file */
2343 fd = rb->open(SAVE_FILE, O_RDONLY);
2344 if(fd < 0) return false;
2345
2346 /* read in saved game */
2347 if(rb->read(fd, bb, sizeof(struct game_context))
2348 < (long)sizeof(struct game_context))
2349 {
2350 ret = false;
2351 }
2352
2353 rb->close(fd);
2354
2355 return ret;
2356}
2357
2358/*****************************************************************************
2359* bubbles_savegame() saves the current game state.
2360******************************************************************************/
2361static void bubbles_savegame(struct game_context* bb) {
2362 int fd;
2363
2364 if (!resume) /* nothing to save */
2365 return;
2366 /* write out the game state to the save file */
2367 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
2368 if (fd < 0)
2369 {
2370 rb->splash(HZ/2, "Failed to save game");
2371 return;
2372 }
2373 if (rb->write(fd, bb, sizeof(struct game_context)) <= 0)
2374 {
2375 rb->splash(HZ/2, "Failed to save game");
2376 }
2377
2378 rb->close(fd);
2379}
2380
2381/*****************************************************************************
2382* bubbles_setcolors() set the foreground and background colors.
2383******************************************************************************/
2384static inline void bubbles_setcolors(void) {
2385#ifdef HAVE_LCD_COLOR
2386 rb->lcd_set_background(LCD_RGBPACK(181,181,222));
2387 rb->lcd_set_foreground(LCD_BLACK);
2388#endif
2389}
2390
2391/*****************************************************************************
2392* bubbles_callback() is the default event handler callback which is called
2393* on usb connect and shutdown.
2394******************************************************************************/
2395static void bubbles_callback(void* param) {
2396 (void) param;
2397 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2398}
2399
2400/*****************************************************************************
2401* bubbles_handlebuttons() handles button events during a game.
2402******************************************************************************/
2403static int bubbles_handlebuttons(struct game_context* bb, bool animblock,
2404 int timeout) {
2405 int button;
2406 int buttonres;
2407 long start;
2408 const struct button_mapping *plugin_contexts[]
2409 = { pla_main_ctx,
2410#ifdef HAVE_REMOTE_LCD
2411 pla_remote_ctx,
2412#endif
2413 };
2414
2415 if (timeout < 0)
2416 timeout = 0;
2417 button = pluginlib_getaction(timeout,plugin_contexts,ARRAYLEN(plugin_contexts));
2418#if defined(HAS_BUTTON_HOLD) && !defined(HAVE_REMOTE_LCD_AS_MAIN)
2419 /* FIXME: Should probably check remote hold here */
2420 if (rb->button_hold())
2421 button = BUBBLES_PAUSE;
2422#endif
2423
2424 switch(button){
2425 case BUBBLES_LEFT_REP:
2426 if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP_REP;
2427 break;
2428 case BUBBLES_LEFT: /* change angle to the left */
2429 if(bb->angle > MIN_ANGLE) bb->angle -= ANGLE_STEP;
2430 break;
2431
2432 case BUBBLES_RIGHT_REP:
2433 if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP_REP;
2434 break;
2435 case BUBBLES_RIGHT: /* change angle to the right */
2436 if(bb->angle < MAX_ANGLE) bb->angle += ANGLE_STEP;
2437 break;
2438
2439 case BUBBLES_FIRE: /* fire the shot */
2440 case BUBBLES_FIRE_REPEAT:
2441 if(!animblock) {
2442 bb->elapsedlvl += bb->elapsedshot;
2443 bb->elapsedshot = 0;
2444 buttonres = bubbles_fire(bb);
2445 if(buttonres != BB_NONE) return buttonres;
2446 buttonres = bubbles_checklevel(bb);
2447 if(buttonres != BB_NONE) return buttonres;
2448 bb->startedshot = *rb->current_tick;
2449 }
2450 break;
2451
2452 case BUBBLES_PAUSE: /* pause the game */
2453 start = *rb->current_tick;
2454 rb->splash(0, "Paused");
2455
2456 while(pluginlib_getaction(TIMEOUT_BLOCK,plugin_contexts,
2457 ARRAYLEN(plugin_contexts))
2458 != BUBBLES_PAUSE);
2459 bb->startedshot += *rb->current_tick-start;
2460 bubbles_drawboard(bb);
2461 rb->lcd_update();
2462 break;
2463
2464 case BUBBLES_QUIT1:
2465 case BUBBLES_QUIT2: /* end the game */
2466 if(!animblock) {
2467 resume = true;
2468 return BB_END;
2469 }
2470 break;
2471
2472 case ACTION_UNKNOWN:
2473 case ACTION_NONE: /* no button pressed */
2474 break;
2475
2476 default:
2477 if(rb->default_event_handler_ex(button, bubbles_callback,
2478 (void*) bb) == SYS_USB_CONNECTED)
2479 return BB_USB;
2480 break;
2481 }
2482
2483 return BB_NONE;
2484}
2485
2486static int bubbles_menu_cb(int action,
2487 const struct menu_item_ex *this_item,
2488 struct gui_synclist *this_list)
2489{
2490 (void)this_list;
2491 int i = ((intptr_t)this_item);
2492 if(action == ACTION_REQUEST_MENUITEM
2493 && !resume && (i==0))
2494 return ACTION_EXIT_MENUITEM;
2495 return action;
2496}
2497
2498/*****************************************************************************
2499* bubbles_menu() is the initial menu at the start of the game.
2500******************************************************************************/
2501static int bubbles_menu(struct game_context* bb) {
2502 static unsigned int startlevel = 0;
2503 int selected = 0;
2504 bool startgame = false;
2505
2506 MENUITEM_STRINGLIST(menu,"Bubbles Menu",bubbles_menu_cb,
2507 "Resume Game", "Start New Game",
2508 "Level", "High Scores", "Playback Control",
2509 "Quit without Saving", "Quit");
2510
2511 while(!startgame){
2512 switch (rb->do_menu(&menu, &selected, NULL, false))
2513 {
2514 case 0: /* resume game */
2515 startgame = true;
2516 if(resume_file)
2517 rb->remove(SAVE_FILE);
2518 resume_file = false;
2519 break;
2520 case 1: /* new game */
2521 bb->level = startlevel;
2522 startgame = true;
2523 resume = false;
2524 resume_file = false;
2525 break;
2526 case 2: /* choose level */
2527 startlevel++;
2528 rb->set_int("Choose start level", "", UNIT_INT, &startlevel,
2529 NULL, 1, 1, highlevel+1, NULL);
2530 startlevel--;
2531 break;
2532 case 3: /* High scores */
2533 highscore_show(-1, highscores, NUM_SCORES, true);
2534 break;
2535 case 4: /* Playback Control */
2536 playback_control(NULL);
2537 break;
2538 case 5: /* quit but don't save */
2539 return BB_QUIT_WITHOUT_SAVING;
2540 case 6: /* save and quit */
2541 return BB_QUIT;
2542 case MENU_ATTACHED_USB:
2543 bubbles_callback(bb);
2544 return BB_USB;
2545 }
2546 }
2547 return 0;
2548}
2549
2550/*****************************************************************************
2551* bubbles() is the main game subroutine, it returns the final game status.
2552******************************************************************************/
2553static int bubbles(struct game_context* bb) {
2554 int buttonres;
2555 long timeout;
2556
2557 /********************
2558 * menu *
2559 ********************/
2560 buttonres = bubbles_menu(bb);
2561 if(buttonres != 0)
2562 return buttonres;
2563
2564 /********************
2565 * init *
2566 ********************/
2567 bubbles_init(bb);
2568 bubbles_drawboard(bb);
2569 rb->lcd_update();
2570
2571 /**********************
2572 * play *
2573 **********************/
2574 bb->startedshot = *rb->current_tick;
2575
2576 while(true) {
2577 /* refresh the board */
2578 bubbles_drawboard(bb);
2579 rb->lcd_update();
2580
2581 /* manange idle framerate */
2582 bb->elapsedshot = *rb->current_tick-bb->startedshot;
2583
2584 if(MAX_SHOTTIME-bb->elapsedshot < HZ/2) {
2585 timeout = MAX_SHOTTIME-bb->elapsedshot;
2586 } else {
2587 timeout = HZ/2;
2588 }
2589
2590 /* handle button events */
2591 buttonres = bubbles_handlebuttons(bb, false, timeout);
2592 if(buttonres != BB_NONE) return buttonres;
2593
2594 /* handle timing */
2595 bb->elapsedshot = *rb->current_tick-bb->startedshot;
2596
2597 if(bb->elapsedshot > MAX_SHOTTIME) {
2598 bb->elapsedlvl += bb->elapsedshot;
2599 bb->elapsedshot = 0;
2600 buttonres = bubbles_fire(bb);
2601 if(buttonres != BB_NONE) return buttonres;
2602 buttonres = bubbles_checklevel(bb);
2603 if(buttonres != BB_NONE) return buttonres;
2604 bb->startedshot = *rb->current_tick;
2605 }
2606 }
2607}
2608
2609/*****************************************************************************
2610* plugin entry point.
2611******************************************************************************/
2612enum plugin_status plugin_start(const void* parameter) {
2613 static struct game_context bb;
2614 bool exit = false;
2615 enum plugin_status ret = PLUGIN_OK;
2616
2617 (void)parameter;
2618
2619 /* load files */
2620 resume = bubbles_loadgame(&bb);
2621 resume_file = resume;
2622 bubbles_loaddata();
2623 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
2624 rb->lcd_clear_display();
2625
2626 /* start app */
2627#if LCD_DEPTH > 1
2628 rb->lcd_set_backdrop(NULL);
2629#endif
2630 rb->lcd_setfont(FONT_SYSFIXED);
2631
2632 while(!exit) {
2633 switch(bubbles(&bb)){
2634 case BB_WIN:
2635 rb->splash(HZ*2, "You Win!");
2636 /* record high level */
2637 highlevel = NUM_LEVELS-1;
2638 /* record high score */
2639 bubbles_recordscore(&bb);
2640 break;
2641
2642 case BB_LOSE:
2643 resume = false;
2644 rb->splash(HZ*2, "Game Over");
2645 /* record high score */
2646 bubbles_recordscore(&bb);
2647 /* fall through to BB_END */
2648
2649 case BB_END:
2650 break;
2651
2652 case BB_USB:
2653 ret = PLUGIN_USB_CONNECTED;
2654 exit = true;
2655 break;
2656
2657 case BB_QUIT:
2658 rb->splash(HZ/3, "Saving game data ...");
2659 bubbles_savegame(&bb);
2660 bubbles_savedata();
2661 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
2662 /* fall through */
2663
2664 case BB_QUIT_WITHOUT_SAVING:
2665 exit = true;
2666 break;
2667
2668 default:
2669 break;
2670 }
2671 }
2672 rb->lcd_setfont(FONT_UI);
2673 return ret;
2674}