FS#10075 - FUZE: QUIT Plugin by selecting BUTTON_HOME by Johannes Schwarz. Updates...
[kugel-rb/myfork.git] / apps / plugins / pong.c
blobe2b4befe825009109124e1bf47dfd51076e190f6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
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 #define PAD_HEIGHT LCD_HEIGHT / 6 /* Recorder: 10 iRiver: 21 */
28 #define PAD_WIDTH LCD_WIDTH / 50 /* Recorder: 2 iRiver: 2 */
30 #define BALL_HEIGHT LCD_HEIGHT / 32 /* Recorder: 2 iRiver: 4 */
31 #define BALL_WIDTH LCD_HEIGHT / 32 /* We want a square ball */
33 #define SPEEDX ( LCD_WIDTH * 3 ) / 2 /* Recorder: 168 iRiver: 240 */
34 #define SPEEDY LCD_HEIGHT * 2 /* Recorder: 128 iRiver: 256 */
36 #define RES 100
38 #define MOVE_STEP LCD_HEIGHT / 32 /* move pad this many steps up/down each move */
40 /* variable button definitions */
41 #if CONFIG_KEYPAD == RECORDER_PAD
42 #define PONG_QUIT BUTTON_OFF
43 #define PONG_PAUSE BUTTON_ON
44 #define PONG_LEFT_UP BUTTON_F1
45 #define PONG_LEFT_DOWN BUTTON_LEFT
46 #define PONG_RIGHT_UP BUTTON_F3
47 #define PONG_RIGHT_DOWN BUTTON_RIGHT
49 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
50 #define PONG_QUIT BUTTON_OFF
51 #define PONG_PAUSE BUTTON_ON
52 #define PONG_LEFT_UP BUTTON_F1
53 #define PONG_LEFT_DOWN BUTTON_LEFT
54 #define PONG_RIGHT_UP BUTTON_F3
55 #define PONG_RIGHT_DOWN BUTTON_RIGHT
57 #elif CONFIG_KEYPAD == ONDIO_PAD
58 #define PONG_QUIT BUTTON_OFF
59 #define PONG_PAUSE BUTTON_RIGHT
60 #define PONG_LEFT_UP BUTTON_LEFT
61 #define PONG_LEFT_DOWN BUTTON_MENU
62 #define PONG_RIGHT_UP BUTTON_UP
63 #define PONG_RIGHT_DOWN BUTTON_DOWN
65 #elif CONFIG_KEYPAD == IRIVER_H100_PAD
66 #define PONG_QUIT BUTTON_OFF
67 #define PONG_LEFT_UP BUTTON_UP
68 #define PONG_LEFT_DOWN BUTTON_DOWN
69 #define PONG_RIGHT_UP BUTTON_ON
70 #define PONG_RIGHT_DOWN BUTTON_MODE
71 #define PONG_RC_QUIT BUTTON_RC_STOP
73 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
74 #define PONG_QUIT BUTTON_OFF
75 #define PONG_LEFT_UP BUTTON_UP
76 #define PONG_LEFT_DOWN BUTTON_DOWN
77 #define PONG_RIGHT_UP BUTTON_REC
78 #define PONG_RIGHT_DOWN BUTTON_MODE
79 #define PONG_RC_QUIT BUTTON_RC_STOP
81 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
82 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
83 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
84 #define PONG_QUIT BUTTON_SELECT
85 #define PONG_LEFT_UP BUTTON_MENU
86 #define PONG_LEFT_DOWN BUTTON_LEFT
87 #define PONG_RIGHT_UP BUTTON_RIGHT
88 #define PONG_RIGHT_DOWN BUTTON_PLAY
90 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
91 #define PONG_QUIT BUTTON_POWER
92 #define PONG_LEFT_UP BUTTON_UP
93 #define PONG_LEFT_DOWN BUTTON_DOWN
94 #define PONG_RIGHT_UP BUTTON_REC
95 #define PONG_RIGHT_DOWN BUTTON_PLAY
97 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
98 #define PONG_QUIT BUTTON_POWER
99 #define PONG_PAUSE BUTTON_SELECT
100 #define PONG_LEFT_UP BUTTON_UP
101 #define PONG_LEFT_DOWN BUTTON_DOWN
102 #define PONG_RIGHT_UP BUTTON_VOL_UP
103 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
105 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
106 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
107 (CONFIG_KEYPAD == SANSA_M200_PAD)
108 #define PONG_QUIT BUTTON_POWER
109 #define PONG_PAUSE BUTTON_SELECT
110 #define PONG_LEFT_UP BUTTON_LEFT
111 #define PONG_LEFT_DOWN BUTTON_DOWN
112 #define PONG_RIGHT_UP BUTTON_UP
113 #define PONG_RIGHT_DOWN BUTTON_RIGHT
115 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
116 #define PONG_QUIT (BUTTON_HOME|BUTTON_REPEAT)
117 #define PONG_PAUSE BUTTON_SELECT
118 #define PONG_LEFT_UP BUTTON_LEFT
119 #define PONG_LEFT_DOWN BUTTON_DOWN
120 #define PONG_RIGHT_UP BUTTON_UP
121 #define PONG_RIGHT_DOWN BUTTON_RIGHT
123 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
124 #define PONG_QUIT BUTTON_POWER
125 #define PONG_PAUSE BUTTON_SELECT
126 #define PONG_LEFT_UP BUTTON_VOL_UP
127 #define PONG_LEFT_DOWN BUTTON_VOL_DOWN
128 #define PONG_RIGHT_UP BUTTON_UP
129 #define PONG_RIGHT_DOWN BUTTON_DOWN
131 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
132 #define PONG_QUIT BUTTON_POWER
133 #define PONG_LEFT_UP BUTTON_SCROLL_UP
134 #define PONG_LEFT_DOWN BUTTON_SCROLL_DOWN
135 #define PONG_RIGHT_UP BUTTON_REW
136 #define PONG_RIGHT_DOWN BUTTON_FF
138 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
139 #define PONG_QUIT BUTTON_BACK
140 #define PONG_LEFT_UP BUTTON_UP
141 #define PONG_LEFT_DOWN BUTTON_DOWN
142 #define PONG_RIGHT_UP BUTTON_VOL_UP
143 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
145 #elif (CONFIG_KEYPAD == MROBE100_PAD)
146 #define PONG_QUIT BUTTON_POWER
147 #define PONG_PAUSE BUTTON_SELECT
148 #define PONG_LEFT_UP BUTTON_MENU
149 #define PONG_LEFT_DOWN BUTTON_LEFT
150 #define PONG_RIGHT_UP BUTTON_PLAY
151 #define PONG_RIGHT_DOWN BUTTON_RIGHT
153 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
154 #define PONG_QUIT BUTTON_RC_REC
155 #define PONG_PAUSE BUTTON_RC_PLAY
156 #define PONG_LEFT_UP BUTTON_RC_VOL_UP
157 #define PONG_LEFT_DOWN BUTTON_RC_VOL_DOWN
158 #define PONG_RIGHT_UP BUTTON_VOL_UP
159 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
161 #elif (CONFIG_KEYPAD == COWOND2_PAD)
162 #define PONG_QUIT BUTTON_POWER
164 #elif CONFIG_KEYPAD == IAUDIO67_PAD
165 #define PONG_QUIT BUTTON_POWER
166 #define PONG_PAUSE BUTTON_MENU
167 #define PONG_LEFT_UP BUTTON_VOLUP
168 #define PONG_LEFT_DOWN BUTTON_VOLDOWN
169 #define PONG_RIGHT_UP BUTTON_RIGHT
170 #define PONG_RIGHT_DOWN BUTTON_LEFT
172 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
173 #define PONG_QUIT BUTTON_BACK
174 #define PONG_LEFT_UP BUTTON_UP
175 #define PONG_LEFT_DOWN BUTTON_DOWN
176 #define PONG_RIGHT_UP BUTTON_PLAY
177 #define PONG_RIGHT_DOWN BUTTON_MENU
179 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
180 #define PONG_QUIT BUTTON_POWER
181 #define PONG_PAUSE BUTTON_MENU
182 #define PONG_LEFT_UP BUTTON_UP
183 #define PONG_LEFT_DOWN BUTTON_DOWN
184 #define PONG_RIGHT_UP BUTTON_VOL_UP
185 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
187 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
188 #define PONG_QUIT BUTTON_POWER
190 #else
191 #error No keymap defined!
192 #endif
194 #ifdef HAVE_TOUCHSCREEN
195 #ifndef PONG_QUIT
196 #define PONG_QUIT BUTTON_TOPMIDDLE
197 #endif
198 #ifndef PONG_LEFT_UP
199 #define PONG_LEFT_UP BUTTON_TOPLEFT
200 #endif
201 #ifndef PONG_LEFT_DOWN
202 #define PONG_LEFT_DOWN BUTTON_BOTTOMLEFT
203 #endif
204 #ifndef PONG_RIGHT_UP
205 #define PONG_RIGHT_UP BUTTON_TOPRIGHT
206 #endif
207 #ifndef PONG_RIGHT_DOWN
208 #define PONG_RIGHT_DOWN BUTTON_BOTTOMRIGHT
209 #endif
210 #ifndef PONG_PAUSE
211 #define PONG_PAUSE BUTTON_CENTER
212 #endif
213 #endif
215 struct pong {
216 int ballx; /* current X*RES position of the ball */
217 int bally; /* current Y*RES position of the ball */
218 int w_pad[2]; /* wanted current Y positions of pads */
219 int e_pad[2]; /* existing current Y positions of pads */
220 int ballspeedx; /* */
221 int ballspeedy; /* */
223 int score[2];
226 void singlepad(int x, int y, int set)
228 if(set) {
229 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
231 else {
232 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
233 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
234 rb->lcd_set_drawmode(DRMODE_SOLID);
238 static int xpos[2]={0, LCD_WIDTH-PAD_WIDTH};
239 void pad(struct pong *p, int pad)
241 /* clear existing pad */
242 singlepad(xpos[pad], p->e_pad[pad], 0);
244 /* draw wanted pad */
245 singlepad(xpos[pad], p->w_pad[pad], 1);
247 /* existing is now the wanted */
248 p->e_pad[pad] = p->w_pad[pad];
251 bool wallcollide(struct pong *p, int pad)
253 /* we have already checked for pad-collision, just check if this hits
254 the wall */
255 if(pad) {
256 /* right-side */
257 if(p->ballx > LCD_WIDTH*RES)
258 return true;
260 else {
261 if(p->ballx < 0)
262 return true;
264 return false;
267 /* returns true if the ball has hit a pad, and then the info variable
268 will have extra angle info */
270 bool padcollide(struct pong *p, int pad, int *info)
272 int x = p->ballx/RES;
273 int y = p->bally/RES;
275 if((y < (p->e_pad[pad]+PAD_HEIGHT)) &&
276 (y + BALL_HEIGHT > p->e_pad[pad])) {
277 /* Y seems likely right */
279 /* store the delta between ball-middle MINUS pad-middle, so
280 it returns:
281 0 when the ball hits exactly the middle of the pad
282 positive numbers when the ball is below the middle of the pad
283 negative numbers when the ball is above the middle of the pad
285 max number is +- PAD_HEIGHT/2
288 *info = (y+BALL_HEIGHT/2) - (p->e_pad[pad] + PAD_HEIGHT/2);
290 if(pad) {
291 /* right-side */
292 if((x + BALL_WIDTH) >= (LCD_WIDTH - PAD_WIDTH))
293 return true; /* phump */
295 else {
296 if(x <= PAD_WIDTH)
297 return true;
300 return false; /* nah */
303 void bounce(struct pong *p, int pad, int info)
305 (void)pad; /* not used right now */
306 p->ballspeedx = -p->ballspeedx;
308 /* info is the hit-angle into the pad */
309 if(p->ballspeedy > 0) {
310 /* downwards */
311 if(info > 0) {
312 /* below the middle of the pad */
313 p->ballspeedy += info * RES/3;
315 else if(info < 0) {
316 /* above the middle */
317 p->ballspeedy = info * RES/2;
320 else {
321 /* upwards */
322 if(info > 0) {
323 /* below the middle of the pad */
324 p->ballspeedy = info * RES/2;
326 else if(info < 0) {
327 /* above the middle */
328 p->ballspeedy -= info * RES/3;
332 p->ballspeedy += rb->rand()%21-10;
334 #if 0
335 fprintf(stderr, "INFO: %d YSPEED: %d\n", info, p->ballspeedy);
336 #endif
339 void score(struct pong *p, int pad)
341 if(pad)
342 rb->splash(HZ/4, "right scores!");
343 else
344 rb->splash(HZ/4, "left scores!");
345 rb->lcd_clear_display();
346 p->score[pad]++;
348 /* then move the X-speed of the ball and give it a random Y position */
349 p->ballspeedx = -p->ballspeedx;
350 p->bally = rb->rand()%(LCD_HEIGHT*RES - BALL_HEIGHT);
352 /* avoid hitting the pad with the new ball */
353 p->ballx = (p->ballx < 0) ?
354 (RES * PAD_WIDTH) : (RES * (LCD_WIDTH - PAD_WIDTH - BALL_WIDTH));
356 /* restore Y-speed to default */
357 p->ballspeedy = (p->ballspeedy > 0) ? SPEEDY : -SPEEDY;
359 /* set the existing pad positions to something weird to force pad
360 updates */
361 p->e_pad[0] = -1;
362 p->e_pad[1] = -1;
365 void ball(struct pong *p)
367 int x = p->ballx/RES;
368 int y = p->bally/RES;
370 int newx;
371 int newy;
373 int info;
375 /* movement */
376 p->ballx += p->ballspeedx;
377 p->bally += p->ballspeedy;
379 newx = p->ballx/RES;
380 newy = p->bally/RES;
382 /* detect if ball hits a wall */
383 if(newy + BALL_HEIGHT > LCD_HEIGHT) {
384 /* hit floor, bounce */
385 p->ballspeedy = -p->ballspeedy;
386 newy = LCD_HEIGHT - BALL_HEIGHT;
387 p->bally = newy * RES;
389 else if(newy < 0) {
390 /* hit ceiling, bounce */
391 p->ballspeedy = -p->ballspeedy;
392 p->bally = 0;
393 newy = 0;
396 /* detect if ball hit pads */
397 if(padcollide(p, 0, &info))
398 bounce(p, 0, info);
399 else if(padcollide(p, 1, &info))
400 bounce(p, 1, info);
401 else if(wallcollide(p, 0))
402 score(p, 1);
403 else if(wallcollide(p, 1))
404 score(p, 0);
406 newx = p->ballx/RES;
407 newy = p->bally/RES;
409 /* clear old position */
410 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
411 rb->lcd_fillrect(x, y, BALL_WIDTH, BALL_HEIGHT);
412 rb->lcd_set_drawmode(DRMODE_SOLID);
414 /* draw the new ball position */
415 rb->lcd_fillrect(newx, newy, BALL_WIDTH, BALL_HEIGHT);
418 void padmove(int *pos, int dir)
420 *pos += dir;
421 if(*pos > (LCD_HEIGHT-PAD_HEIGHT))
422 *pos = (LCD_HEIGHT-PAD_HEIGHT);
423 else if(*pos < 0)
424 *pos = 0;
427 int keys(struct pong *p)
429 int key;
430 #ifdef PONG_PAUSE
431 static bool pause = false;
432 #endif
434 /* number of ticks this function will loop reading keys */
435 #ifndef HAVE_TOUCHSCREEN
436 int time = 4;
437 #else
438 int time = 1;
439 #endif
440 int start = *rb->current_tick;
441 int end = start + time;
443 while(end > *rb->current_tick) {
444 key = rb->button_get_w_tmo(end - *rb->current_tick);
446 #ifdef HAVE_TOUCHSCREEN
447 short touch_x, touch_y;
448 if(key & BUTTON_TOUCHSCREEN)
450 touch_x = rb->button_get_data() >> 16;
451 touch_y = rb->button_get_data() & 0xFFFF;
452 if(touch_x >= xpos[0] && touch_x <= xpos[0]+(PAD_WIDTH*4))
453 padmove(&p->w_pad[0], touch_y-(p->e_pad[0]*2+PAD_HEIGHT)/2);
455 if(touch_x >= xpos[1]-(PAD_WIDTH*4) && touch_x <= xpos[1])
456 padmove(&p->w_pad[1], touch_y-(p->e_pad[1]*2+PAD_HEIGHT)/2);
458 #endif
460 #ifdef HAS_BUTTON_HOLD
461 if (rb->button_hold())
462 return 2; /* Pause game */
463 #endif
465 if(key & PONG_QUIT
466 #ifdef PONG_RC_QUIT
467 || key & PONG_RC_QUIT
468 #endif
470 return 0; /* exit game NOW */
472 #ifdef PONG_PAUSE
473 if(key == PONG_PAUSE)
474 pause = !pause;
475 if(pause)
476 return 2; /* Pause game */
477 #endif
479 key = rb->button_status(); /* ignore BUTTON_REPEAT */
481 if(key & PONG_LEFT_DOWN) /* player left goes down */
482 padmove(&p->w_pad[0], MOVE_STEP);
484 if(key & PONG_LEFT_UP) /* player left goes up */
485 padmove(&p->w_pad[0], -MOVE_STEP);
487 if(key & PONG_RIGHT_DOWN) /* player right goes down */
488 padmove(&p->w_pad[1], MOVE_STEP);
490 if(key & PONG_RIGHT_UP) /* player right goes up */
491 padmove(&p->w_pad[1], -MOVE_STEP);
493 if(rb->default_event_handler(key) == SYS_USB_CONNECTED)
494 return -1; /* exit game because of USB */
496 return 1; /* return 0 to exit game */
499 void showscore(struct pong *p)
501 static char buffer[20];
502 int w;
504 rb->snprintf(buffer, sizeof(buffer), "%d - %d", p->score[0], p->score[1]);
505 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
506 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), 0, (unsigned char *)buffer);
509 /* this is the plugin entry point */
510 enum plugin_status plugin_start(const void* parameter)
512 struct pong pong;
513 int game = 1;
515 /* init the struct with some silly values to start with */
517 pong.ballx = 20*RES;
518 pong.bally = 20*RES;
520 pong.e_pad[0] = 0;
521 pong.w_pad[0] = 7;
522 pong.e_pad[1] = 0;
523 pong.w_pad[1] = 40;
525 pong.ballspeedx = SPEEDX;
526 pong.ballspeedy = SPEEDY;
528 pong.score[0] = pong.score[1] = 0; /* lets start at 0 - 0 ;-) */
530 /* if you don't use the parameter, you can do like
531 this to avoid the compiler warning about it */
532 (void)parameter;
534 /* Clear screen */
535 rb->lcd_clear_display();
537 /* go go go */
538 while(game > 0) {
539 if (game == 2) { /* Game Paused */
540 rb->splash(0, "PAUSED");
541 while(game == 2)
542 game = keys(&pong); /* short circuit */
543 rb->lcd_clear_display();
545 showscore(&pong);
546 pad(&pong, 0); /* draw left pad */
547 pad(&pong, 1); /* draw right pad */
548 ball(&pong); /* move and draw ball */
550 rb->lcd_update();
552 game = keys(&pong); /* deal with keys */
555 return (game == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
558 #endif /* HAVE_LCD_BITMAP */