Added MP3::Info.pm inside script to make it standalone.
[kugel-rb.git] / apps / plugins / rockblox.c
blobeac65636013cf8bc154982aee77548c53b5763b4
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 static const int start_x = 5;
26 static const int start_y = 5;
27 static const int max_x = 4 * 17;
28 static const int max_y = 3 * 10;
29 static const short level_speeds[10] = {
30 1000, 900, 800, 700, 600, 500, 400, 300, 250, 200
32 static const int blocks = 7;
33 static const int block_frames[7] = {1,2,2,2,4,4,4};
35 static int current_x, current_y, current_f, current_b;
36 static int level, score;
37 static int next_b, next_f;
38 static short lines;
39 static char virtual[LCD_WIDTH * LCD_HEIGHT];
40 static struct plugin_api* rb;
43 block_data is built up the following way
45 first array index specifies the block number
46 second array index specifies the rotation of the block
47 third array index specifies:
48 0: x-coordinates of pixels
49 1: y-coordinates of pixels
50 fourth array index specifies the coordinate of a pixel
52 each block consists of four pixels whose relative coordinates are given
53 with block_data
56 static const char block_data[7][4][2][4] =
59 {{0,1,0,1},{0,0,1,1}}
62 {{0,1,1,2},{1,1,0,0}},
63 {{0,0,1,1},{0,1,1,2}}
66 {{0,1,1,2},{0,0,1,1}},
67 {{1,1,0,0},{0,1,1,2}}
70 {{1,1,1,1},{0,1,2,3}},
71 {{0,1,2,3},{2,2,2,2}}
74 {{1,1,1,2},{2,1,0,0}},
75 {{0,1,2,2},{1,1,1,2}},
76 {{0,1,1,1},{2,2,1,0}},
77 {{0,0,1,2},{0,1,1,1}}
80 {{0,1,1,1},{0,0,1,2}},
81 {{0,1,2,2},{1,1,1,0}},
82 {{1,1,1,2},{0,1,2,2}},
83 {{0,0,1,2},{2,1,1,1}}
86 {{1,0,1,2},{0,1,1,1}},
87 {{2,1,1,1},{1,0,1,2}},
88 {{1,0,1,2},{2,1,1,1}},
89 {{0,1,1,1},{1,0,1,2}}
93 static int t_rand(int range)
95 return *rb->current_tick % range;
98 static void draw_frame(int fstart_x,int fstop_x,int fstart_y,int fstop_y)
100 rb->lcd_drawline(fstart_x, fstart_y, fstop_x, fstart_y);
101 rb->lcd_drawline(fstart_x, fstop_y, fstop_x, fstop_y);
103 rb->lcd_drawline(fstart_x, fstart_y, fstart_x, fstop_y);
104 rb->lcd_drawline(fstop_x, fstart_y, fstop_x, fstop_y);
106 rb->lcd_drawline(fstart_x - 1, fstart_y + 1, fstart_x - 1, fstop_y + 1);
107 rb->lcd_drawline(fstart_x - 1, fstop_y + 1, fstop_x - 1, fstop_y + 1);
110 static void draw_block(int x, int y, int block, int frame, bool clear)
112 int i, a, b;
113 for(i=0;i < 4;i++) {
114 if (clear)
116 for (a = 0; a < 3; a++)
117 for (b = 0; b < 4; b++)
118 rb->lcd_clearpixel(start_x + x + block_data[block][frame][1][i] * 4 - b,
119 start_y + y + block_data[block][frame][0][i] * 3 + a);
121 else
123 for (a = 0; a < 3; a++)
124 for (b = 0; b < 4; b++)
125 rb->lcd_drawpixel(start_x+x+block_data[block][frame][1][i] * 4 - b,
126 start_y+y+block_data[block][frame][0][i] * 3 + a);
131 static void to_virtual(void)
133 int i, a, b;
135 for(i = 0; i < 4; i++)
136 for (a = 0; a < 3; a++)
137 for (b = 0; b < 4; b++)
138 *(virtual +
139 (current_y + block_data[current_b][current_f][0][i] * 3 + a) *
140 max_x + current_x + block_data[current_b][current_f][1][i] *
141 4 - b) = current_b + 1;
144 static bool block_touch (int x, int y)
146 int a,b;
147 for (a = 0; a < 4; a++)
148 for (b = 0; b < 3; b++)
149 if (*(virtual + (y + b) * max_x + (x - a)) != 0)
150 return true;
151 return false;
154 static bool gameover(void)
156 int i;
157 int frame, block, y, x;
159 x = current_x;
160 y = current_y;
161 block = current_b;
162 frame = current_f;
164 for(i = 0; i < 4; i++){
165 /* Do we have blocks touching? */
166 if(block_touch(x + block_data[block][frame][1][i] * 4,
167 y + block_data[block][frame][0][i] * 3))
169 /* Are we at the top of the frame? */
170 if(x + block_data[block][frame][1][i] * 4 >= max_x - 16)
172 /* Game over ;) */
173 return true;
177 return false;
180 static bool valid_position(int x, int y, int block, int frame)
182 int i;
183 for(i=0;i < 4;i++)
184 if ((y + block_data[block][frame][0][i] * 3 > max_y - 3) ||
185 (x + block_data[block][frame][1][i] * 4 > max_x - 4) ||
186 (y + block_data[block][frame][0][i] * 3 < 0) ||
187 (x + block_data[block][frame][1][i] * 4 < 4) ||
188 block_touch (x + block_data[block][frame][1][i] * 4,
189 y + block_data[block][frame][0][i] * 3))
191 return false;
193 return true;
196 static void from_virtual(void)
198 int x,y;
199 for(y = 0; y < max_y; y++)
200 for(x = 1; x < max_x - 1; x++)
201 if(*(virtual + (y * max_x) + x) != 0)
202 rb->lcd_drawpixel(start_x + x, start_y + y);
203 else
204 rb->lcd_clearpixel(start_x + x, start_y + y);
207 static void move_block(int x,int y,int f)
209 int last_frame = current_f;
210 if(f != 0)
212 current_f += f;
213 if(current_f > block_frames[current_b]-1)
214 current_f = 0;
215 if(current_f < 0)
216 current_f = block_frames[current_b]-1;
219 if(valid_position(current_x + x, current_y + y, current_b, current_f))
221 draw_block(current_x,current_y,current_b,last_frame,true);
222 current_x += x;
223 current_y += y;
224 draw_block(current_x,current_y,current_b,current_f,false);
225 rb->lcd_update();
227 else
228 current_f = last_frame;
231 static void new_block(void)
233 current_b = next_b;
234 current_f = next_f;
235 current_x = max_x - 16;
236 current_y = (int)12;
237 next_b = t_rand(blocks);
238 next_f = t_rand(block_frames[next_b]);
240 rb->lcd_drawline (max_x + 7, start_y - 1, max_x + 29, start_y - 1);
241 rb->lcd_drawline (max_x + 29, start_y, max_x + 29, start_y + 14);
242 rb->lcd_drawline (max_x + 29, start_y + 14, max_x + 7, start_y + 14);
243 rb->lcd_drawline (max_x + 7, start_y + 14, max_x + 7, start_y - 1);
244 rb->lcd_drawline (max_x + 6, start_y + 15, max_x + 6, start_y);
245 rb->lcd_drawline (max_x + 6, start_y + 15, max_x + 28, start_y + 15);
247 draw_block(max_x + 9, start_y - 4, current_b, current_f, true);
248 draw_block(max_x + 9, start_y - 4, next_b, next_f, false);
249 if(!valid_position(current_x, current_y, current_b, current_f))
251 draw_block(current_x, current_y, current_b, current_f, false);
252 rb->lcd_update();
254 else
255 draw_block(current_x, current_y, current_b, current_f, false);
258 static int check_lines(void)
260 int x,y,i,j;
261 bool line;
262 int lines = 0;
263 for(x = 0; x < max_x; x++)
265 line = true;
266 for(y = 0; y < max_y; y++)
268 if(*(virtual + y * max_x + x) == 0)
270 line = false;
271 break;
275 if(line)
277 lines++;
278 /* move rows down */
279 for(i = x; i < max_x - 1; i++)
280 for (j = 0; j < max_y; j++)
281 *(virtual + j * max_x + i)=*(virtual + j * max_x + (i + 1));
283 x--; /* re-check this line */
287 return lines / 4;
290 static void move_down(void)
292 int l;
293 char s[25];
295 if(!valid_position(current_x - 4, current_y, current_b, current_f))
297 to_virtual();
298 l = check_lines();
299 if(l)
301 lines += l;
302 level = (int)lines/10;
303 if(level > 9)
304 level = 9;
305 from_virtual();
306 score += l*l;
309 rb->snprintf(s, sizeof(s), "%d Rows - Level %d", lines, level);
310 rb->lcd_putsxy(2, 42, s);
312 new_block();
313 move_block(0,0,0);
315 else
316 move_block(-4,0,0);
319 static int game_loop(void)
321 int button;
323 while(1)
325 int count = 0;
326 while(count * 300 < level_speeds[level])
328 button = rb->button_get_w_tmo(HZ/10);
329 switch(button)
331 case BUTTON_OFF:
332 return PLUGIN_OK;
334 case BUTTON_UP:
335 case BUTTON_UP | BUTTON_REPEAT:
336 move_block(0,-3,0);
337 break;
339 case BUTTON_DOWN:
340 case BUTTON_DOWN | BUTTON_REPEAT:
341 move_block(0,3,0);
342 break;
344 case BUTTON_RIGHT:
345 case BUTTON_RIGHT | BUTTON_REPEAT:
346 move_block(0,0,1);
347 break;
349 case BUTTON_LEFT:
350 case BUTTON_LEFT | BUTTON_REPEAT:
351 move_down();
352 break;
354 default:
355 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
356 return PLUGIN_USB_CONNECTED;
357 break;
360 count++;
363 if(gameover())
365 rb->lcd_clearrect(0, 52, LCD_WIDTH, LCD_HEIGHT - 52);
366 rb->lcd_putsxy(2, 52, "You lose!");
367 rb->lcd_update();
368 rb->sleep(HZ * 3);
369 return false;
372 move_down();
375 return false;
378 static void init_rockblox(void)
380 rb->memset(&virtual, 0, sizeof(virtual));
382 current_x = 0;
383 current_y = 0;
384 current_f = 0;
385 current_b = 0;
386 level = 0;
387 lines = 0;
388 score = 0;
389 next_b = 0;
390 next_f = 0;
393 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
395 int ret;
397 TEST_PLUGIN_API(api);
399 (void)parameter;
400 rb = api;
402 /* Lets use the default font */
403 rb->lcd_setfont(FONT_SYSFIXED);
405 init_rockblox();
407 draw_frame(start_x, start_x + max_x - 1, start_y - 1, start_y + max_y);
408 rb->lcd_putsxy(2, 42, "0 Rows - Level 0");
409 rb->lcd_update();
411 next_b = t_rand(blocks);
412 next_f = t_rand(block_frames[next_b]);
413 new_block();
414 ret = game_loop();
416 rb->lcd_setfont(FONT_UI);
418 return ret;
421 #endif