More iPod 3G work from Seven Le Mesle
[Rockbox.git] / apps / plugins / rockblox.c
blobb4caaf38f24a2fddec3571d2a9ea2eb0fa465fb4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 1999 Mattis Wadman (nappe@sudac.org)
12 * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se)
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
23 #ifdef HAVE_LCD_BITMAP
25 PLUGIN_HEADER
27 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
28 (CONFIG_KEYPAD == IPOD_3G_PAD)
29 #define ROCKBLOX_OFF BUTTON_MENU
30 #define ROCKBLOX_UP BUTTON_SCROLL_BACK
31 #define ROCKBLOX_DOWN BUTTON_SCROLL_FWD
32 #define ROCKBLOX_LEFT BUTTON_LEFT
33 #define ROCKBLOX_RIGHT BUTTON_RIGHT
34 #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
35 #define ROCKBLOX_OFF BUTTON_POWER
36 #define ROCKBLOX_UP BUTTON_UP
37 #define ROCKBLOX_DOWN BUTTON_DOWN
38 #define ROCKBLOX_LEFT BUTTON_LEFT
39 #define ROCKBLOX_RIGHT BUTTON_RIGHT
40 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
41 #define ROCKBLOX_OFF BUTTON_A
42 #define ROCKBLOX_UP BUTTON_UP
43 #define ROCKBLOX_DOWN BUTTON_DOWN
44 #define ROCKBLOX_LEFT BUTTON_LEFT
45 #define ROCKBLOX_RIGHT BUTTON_RIGHT
46 #else
47 #define ROCKBLOX_OFF BUTTON_OFF
48 #define ROCKBLOX_UP BUTTON_UP
49 #define ROCKBLOX_DOWN BUTTON_DOWN
50 #define ROCKBLOX_LEFT BUTTON_LEFT
51 #define ROCKBLOX_RIGHT BUTTON_RIGHT
52 #endif
54 static const int start_x = 5;
55 static const int start_y = 5;
56 static const int max_x = 4 * 17;
57 static const int max_y = 3 * 10;
58 static const short level_speeds[10] = {
59 1000, 900, 800, 700, 600, 500, 400, 300, 250, 200
61 static const int blocks = 7;
62 static const int block_frames[7] = {1,2,2,2,4,4,4};
64 static int current_x, current_y, current_f, current_b;
65 static int level, score;
66 static int next_b, next_f;
67 static short lines;
68 static char virtual[LCD_WIDTH * LCD_HEIGHT];
69 static struct plugin_api* rb;
72 block_data is built up the following way
74 first array index specifies the block number
75 second array index specifies the rotation of the block
76 third array index specifies:
77 0: x-coordinates of pixels
78 1: y-coordinates of pixels
79 fourth array index specifies the coordinate of a pixel
81 each block consists of four pixels whose relative coordinates are given
82 with block_data
85 static const char block_data[7][4][2][4] =
88 {{0,1,0,1},{0,0,1,1}}
91 {{0,1,1,2},{1,1,0,0}},
92 {{0,0,1,1},{0,1,1,2}}
95 {{0,1,1,2},{0,0,1,1}},
96 {{1,1,0,0},{0,1,1,2}}
99 {{1,1,1,1},{0,1,2,3}},
100 {{0,1,2,3},{2,2,2,2}}
103 {{1,1,1,2},{2,1,0,0}},
104 {{0,1,2,2},{1,1,1,2}},
105 {{0,1,1,1},{2,2,1,0}},
106 {{0,0,1,2},{0,1,1,1}}
109 {{0,1,1,1},{0,0,1,2}},
110 {{0,1,2,2},{1,1,1,0}},
111 {{1,1,1,2},{0,1,2,2}},
112 {{0,0,1,2},{2,1,1,1}}
115 {{1,0,1,2},{0,1,1,1}},
116 {{2,1,1,1},{1,0,1,2}},
117 {{1,0,1,2},{2,1,1,1}},
118 {{0,1,1,1},{1,0,1,2}}
122 static int t_rand(int range)
124 return *rb->current_tick % range;
127 static void draw_frame(int fstart_x,int fstop_x,int fstart_y,int fstop_y)
129 rb->lcd_drawline(fstart_x, fstart_y, fstop_x, fstart_y);
130 rb->lcd_drawline(fstart_x, fstop_y, fstop_x, fstop_y);
132 rb->lcd_drawline(fstart_x, fstart_y, fstart_x, fstop_y);
133 rb->lcd_drawline(fstop_x, fstart_y, fstop_x, fstop_y);
135 rb->lcd_drawline(fstart_x - 1, fstart_y + 1, fstart_x - 1, fstop_y + 1);
136 rb->lcd_drawline(fstart_x - 1, fstop_y + 1, fstop_x - 1, fstop_y + 1);
139 static void draw_block(int x, int y, int block, int frame, bool clear)
141 int i, a, b;
143 for(i=0;i < 4;i++) {
144 if (clear)
146 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
147 for (a = 0; a < 3; a++)
148 for (b = 0; b < 4; b++)
149 rb->lcd_drawpixel(start_x + x + block_data[block][frame][1][i] * 4 - b,
150 start_y + y + block_data[block][frame][0][i] * 3 + a);
151 rb->lcd_set_drawmode(DRMODE_SOLID);
153 else
155 for (a = 0; a < 3; a++)
156 for (b = 0; b < 4; b++)
157 rb->lcd_drawpixel(start_x+x+block_data[block][frame][1][i] * 4 - b,
158 start_y+y+block_data[block][frame][0][i] * 3 + a);
163 static void to_virtual(void)
165 int i, a, b;
167 for(i = 0; i < 4; i++)
168 for (a = 0; a < 3; a++)
169 for (b = 0; b < 4; b++)
170 *(virtual +
171 (current_y + block_data[current_b][current_f][0][i] * 3 + a) *
172 max_x + current_x + block_data[current_b][current_f][1][i] *
173 4 - b) = current_b + 1;
176 static bool block_touch (int x, int y)
178 int a,b;
179 for (a = 0; a < 4; a++)
180 for (b = 0; b < 3; b++)
181 if (*(virtual + (y + b) * max_x + (x - a)) != 0)
182 return true;
183 return false;
186 static bool gameover(void)
188 int i;
189 int frame, block, y, x;
191 x = current_x;
192 y = current_y;
193 block = current_b;
194 frame = current_f;
196 for(i = 0; i < 4; i++){
197 /* Do we have blocks touching? */
198 if(block_touch(x + block_data[block][frame][1][i] * 4,
199 y + block_data[block][frame][0][i] * 3))
201 /* Are we at the top of the frame? */
202 if(x + block_data[block][frame][1][i] * 4 >= max_x - 16)
204 /* Game over ;) */
205 return true;
209 return false;
212 static bool valid_position(int x, int y, int block, int frame)
214 int i;
215 for(i=0;i < 4;i++)
216 if ((y + block_data[block][frame][0][i] * 3 > max_y - 3) ||
217 (x + block_data[block][frame][1][i] * 4 > max_x - 4) ||
218 (y + block_data[block][frame][0][i] * 3 < 0) ||
219 (x + block_data[block][frame][1][i] * 4 < 4) ||
220 block_touch (x + block_data[block][frame][1][i] * 4,
221 y + block_data[block][frame][0][i] * 3))
223 return false;
225 return true;
228 static void from_virtual(void)
230 int x,y;
232 for(y = 0; y < max_y; y++)
233 for(x = 1; x < max_x - 1; x++)
234 if(*(virtual + (y * max_x) + x) != 0)
236 rb->lcd_drawpixel(start_x + x, start_y + y);
238 else
240 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
241 rb->lcd_drawpixel(start_x + x, start_y + y);
242 rb->lcd_set_drawmode(DRMODE_SOLID);
246 static void move_block(int x,int y,int f)
248 int last_frame = current_f;
249 if(f != 0)
251 current_f += f;
252 if(current_f > block_frames[current_b]-1)
253 current_f = 0;
254 if(current_f < 0)
255 current_f = block_frames[current_b]-1;
258 if(valid_position(current_x + x, current_y + y, current_b, current_f))
260 draw_block(current_x,current_y,current_b,last_frame,true);
261 current_x += x;
262 current_y += y;
263 draw_block(current_x,current_y,current_b,current_f,false);
264 rb->lcd_update();
266 else
267 current_f = last_frame;
270 static void new_block(void)
272 current_b = next_b;
273 current_f = next_f;
274 current_x = max_x - 16;
275 current_y = (int)12;
276 next_b = t_rand(blocks);
277 next_f = t_rand(block_frames[next_b]);
279 rb->lcd_drawline (max_x + 7, start_y - 1, max_x + 29, start_y - 1);
280 rb->lcd_drawline (max_x + 29, start_y, max_x + 29, start_y + 14);
281 rb->lcd_drawline (max_x + 29, start_y + 14, max_x + 7, start_y + 14);
282 rb->lcd_drawline (max_x + 7, start_y + 14, max_x + 7, start_y - 1);
283 rb->lcd_drawline (max_x + 6, start_y + 15, max_x + 6, start_y);
284 rb->lcd_drawline (max_x + 6, start_y + 15, max_x + 28, start_y + 15);
286 draw_block(max_x + 9, start_y - 4, current_b, current_f, true);
287 draw_block(max_x + 9, start_y - 4, next_b, next_f, false);
288 if(!valid_position(current_x, current_y, current_b, current_f))
290 draw_block(current_x, current_y, current_b, current_f, false);
291 rb->lcd_update();
293 else
294 draw_block(current_x, current_y, current_b, current_f, false);
297 static int check_lines(void)
299 int x,y,i,j;
300 bool line;
301 int lines = 0;
302 for(x = 0; x < max_x; x++)
304 line = true;
305 for(y = 0; y < max_y; y++)
307 if(*(virtual + y * max_x + x) == 0)
309 line = false;
310 break;
314 if(line)
316 lines++;
317 /* move rows down */
318 for(i = x; i < max_x - 1; i++)
319 for (j = 0; j < max_y; j++)
320 *(virtual + j * max_x + i)=*(virtual + j * max_x + (i + 1));
322 x--; /* re-check this line */
326 return lines / 4;
329 static void move_down(void)
331 int l;
332 char s[25];
334 if(!valid_position(current_x - 4, current_y, current_b, current_f))
336 to_virtual();
337 l = check_lines();
338 if(l)
340 lines += l;
341 level = (int)lines/10;
342 if(level > 9)
343 level = 9;
344 from_virtual();
345 score += l*l;
348 rb->snprintf(s, sizeof(s), "%d Rows - Level %d", lines, level);
349 rb->lcd_putsxy(2, 42, s);
351 new_block();
352 move_block(0,0,0);
354 else
355 move_block(-4,0,0);
358 static int game_loop(void)
360 int button;
362 while(1)
364 int count = 0;
365 while(count * 300 < level_speeds[level])
367 button = rb->button_get_w_tmo(HZ/10);
368 switch(button)
370 case ROCKBLOX_OFF:
371 return PLUGIN_OK;
373 case ROCKBLOX_UP:
374 case ROCKBLOX_UP | BUTTON_REPEAT:
375 move_block(0,-3,0);
376 break;
378 case ROCKBLOX_DOWN:
379 case ROCKBLOX_DOWN | BUTTON_REPEAT:
380 move_block(0,3,0);
381 break;
383 case ROCKBLOX_RIGHT:
384 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
385 move_block(0,0,1);
386 break;
388 case ROCKBLOX_LEFT:
389 case ROCKBLOX_LEFT | BUTTON_REPEAT:
390 move_down();
391 break;
393 default:
394 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
395 return PLUGIN_USB_CONNECTED;
396 break;
399 count++;
402 if(gameover())
404 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
405 rb->lcd_fillrect(0, 52, LCD_WIDTH, LCD_HEIGHT - 52);
406 rb->lcd_set_drawmode(DRMODE_SOLID);
407 rb->lcd_putsxy(2, 52, "You lose!");
408 rb->lcd_update();
409 rb->sleep(HZ * 3);
410 return false;
413 move_down();
416 return false;
419 static void init_rockblox(void)
421 rb->memset(&virtual, 0, sizeof(virtual));
423 current_x = 0;
424 current_y = 0;
425 current_f = 0;
426 current_b = 0;
427 level = 0;
428 lines = 0;
429 score = 0;
430 next_b = 0;
431 next_f = 0;
434 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
436 int ret;
438 (void)parameter;
439 rb = api;
441 /* Lets use the default font */
442 rb->lcd_setfont(FONT_SYSFIXED);
444 init_rockblox();
446 draw_frame(start_x, start_x + max_x - 1, start_y - 1, start_y + max_y);
447 rb->lcd_putsxy(2, 42, "0 Rows - Level 0");
448 rb->lcd_update();
450 next_b = t_rand(blocks);
451 next_f = t_rand(block_frames[next_b]);
452 new_block();
453 ret = game_loop();
455 rb->lcd_setfont(FONT_UI);
457 return ret;
460 #endif