Adapt the remaining plugins to put the greyscale isr on cop. Now they can be used...
[Rockbox.git] / apps / plugins / pong.c
blobb1e53d3dccaa2816c0b01a7e971f3d0b0b48e0cf
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Daniel Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
21 #ifdef HAVE_LCD_BITMAP
23 PLUGIN_HEADER
25 #define PAD_HEIGHT LCD_HEIGHT / 6 /* Recorder: 10 iRiver: 21 */
26 #define PAD_WIDTH LCD_WIDTH / 50 /* Recorder: 2 iRiver: 2 */
28 #define BALL_HEIGHT LCD_HEIGHT / 32 /* Recorder: 2 iRiver: 4 */
29 #define BALL_WIDTH LCD_HEIGHT / 32 /* We want a square ball */
31 #define SPEEDX ( LCD_WIDTH * 3 ) / 2 /* Recorder: 168 iRiver: 240 */
32 #define SPEEDY LCD_HEIGHT * 2 /* Recorder: 128 iRiver: 256 */
34 #define RES 100
36 #define MOVE_STEP LCD_HEIGHT / 32 /* move pad this many steps up/down each move */
38 /* variable button definitions */
39 #if CONFIG_KEYPAD == RECORDER_PAD
40 #define PONG_QUIT BUTTON_OFF
41 #define PONG_PAUSE BUTTON_ON
42 #define PONG_LEFT_UP BUTTON_F1
43 #define PONG_LEFT_DOWN BUTTON_LEFT
44 #define PONG_RIGHT_UP BUTTON_F3
45 #define PONG_RIGHT_DOWN BUTTON_RIGHT
47 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
48 #define PONG_QUIT BUTTON_OFF
49 #define PONG_PAUSE BUTTON_ON
50 #define PONG_LEFT_UP BUTTON_F1
51 #define PONG_LEFT_DOWN BUTTON_LEFT
52 #define PONG_RIGHT_UP BUTTON_F3
53 #define PONG_RIGHT_DOWN BUTTON_RIGHT
55 #elif CONFIG_KEYPAD == ONDIO_PAD
56 #define PONG_QUIT BUTTON_OFF
57 #define PONG_PAUSE BUTTON_RIGHT
58 #define PONG_LEFT_UP BUTTON_LEFT
59 #define PONG_LEFT_DOWN BUTTON_MENU
60 #define PONG_RIGHT_UP BUTTON_UP
61 #define PONG_RIGHT_DOWN BUTTON_DOWN
63 #elif CONFIG_KEYPAD == IRIVER_H100_PAD
64 #define PONG_QUIT BUTTON_OFF
65 #define PONG_LEFT_UP BUTTON_UP
66 #define PONG_LEFT_DOWN BUTTON_DOWN
67 #define PONG_RIGHT_UP BUTTON_ON
68 #define PONG_RIGHT_DOWN BUTTON_MODE
69 #define PONG_RC_QUIT BUTTON_RC_STOP
71 #elif CONFIG_KEYPAD == IRIVER_H300_PAD
72 #define PONG_QUIT BUTTON_OFF
73 #define PONG_LEFT_UP BUTTON_UP
74 #define PONG_LEFT_DOWN BUTTON_DOWN
75 #define PONG_RIGHT_UP BUTTON_REC
76 #define PONG_RIGHT_DOWN BUTTON_MODE
77 #define PONG_RC_QUIT BUTTON_RC_STOP
79 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
80 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
81 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
82 #define PONG_QUIT BUTTON_SELECT
83 #define PONG_LEFT_UP BUTTON_MENU
84 #define PONG_LEFT_DOWN BUTTON_LEFT
85 #define PONG_RIGHT_UP BUTTON_RIGHT
86 #define PONG_RIGHT_DOWN BUTTON_PLAY
88 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
89 #define PONG_QUIT BUTTON_POWER
90 #define PONG_LEFT_UP BUTTON_UP
91 #define PONG_LEFT_DOWN BUTTON_DOWN
92 #define PONG_RIGHT_UP BUTTON_REC
93 #define PONG_RIGHT_DOWN BUTTON_PLAY
95 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
96 #define PONG_QUIT BUTTON_POWER
97 #define PONG_PAUSE BUTTON_SELECT
98 #define PONG_LEFT_UP BUTTON_UP
99 #define PONG_LEFT_DOWN BUTTON_DOWN
100 #define PONG_RIGHT_UP BUTTON_VOL_UP
101 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
103 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
104 #define PONG_QUIT BUTTON_POWER
105 #define PONG_PAUSE BUTTON_SELECT
106 #define PONG_LEFT_UP BUTTON_LEFT
107 #define PONG_LEFT_DOWN BUTTON_DOWN
108 #define PONG_RIGHT_UP BUTTON_UP
109 #define PONG_RIGHT_DOWN BUTTON_RIGHT
111 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
112 #define PONG_QUIT BUTTON_POWER
113 #define PONG_PAUSE BUTTON_SELECT
114 #define PONG_LEFT_UP BUTTON_VOL_UP
115 #define PONG_LEFT_DOWN BUTTON_VOL_DOWN
116 #define PONG_RIGHT_UP BUTTON_UP
117 #define PONG_RIGHT_DOWN BUTTON_DOWN
119 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
120 #define PONG_QUIT BUTTON_POWER
121 #define PONG_LEFT_UP BUTTON_SCROLL_UP
122 #define PONG_LEFT_DOWN BUTTON_SCROLL_DOWN
123 #define PONG_RIGHT_UP BUTTON_REW
124 #define PONG_RIGHT_DOWN BUTTON_FF
126 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
127 #define PONG_QUIT BUTTON_BACK
128 #define PONG_LEFT_UP BUTTON_UP
129 #define PONG_LEFT_DOWN BUTTON_DOWN
130 #define PONG_RIGHT_UP BUTTON_VOL_UP
131 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
133 #elif (CONFIG_KEYPAD == MROBE100_PAD)
134 #define PONG_QUIT BUTTON_POWER
135 #define PONG_PAUSE BUTTON_SELECT
136 #define PONG_LEFT_UP BUTTON_MENU
137 #define PONG_LEFT_DOWN BUTTON_LEFT
138 #define PONG_RIGHT_UP BUTTON_PLAY
139 #define PONG_RIGHT_DOWN BUTTON_RIGHT
141 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
142 #define PONG_QUIT BUTTON_RC_REC
143 #define PONG_PAUSE BUTTON_RC_PLAY
144 #define PONG_LEFT_UP BUTTON_RC_VOL_UP
145 #define PONG_LEFT_DOWN BUTTON_RC_VOL_DOWN
146 #define PONG_RIGHT_UP BUTTON_VOL_UP
147 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
149 #elif (CONFIG_KEYPAD == COWOND2_PAD)
150 #define PONG_QUIT BUTTON_POWER
151 #define PONG_LEFT_UP BUTTON_UP
152 #define PONG_LEFT_DOWN BUTTON_DOWN
153 #define PONG_RIGHT_UP BUTTON_LEFT
154 #define PONG_RIGHT_DOWN BUTTON_RIGHT
156 #else
157 #error No keymap defined!
158 #endif
160 static struct plugin_api* rb;
162 struct pong {
163 int ballx; /* current X*RES position of the ball */
164 int bally; /* current Y*RES position of the ball */
165 int w_pad[2]; /* wanted current Y positions of pads */
166 int e_pad[2]; /* existing current Y positions of pads */
167 int ballspeedx; /* */
168 int ballspeedy; /* */
170 int score[2];
173 void singlepad(int x, int y, int set)
175 if(set) {
176 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
178 else {
179 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
180 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
181 rb->lcd_set_drawmode(DRMODE_SOLID);
185 void pad(struct pong *p, int pad)
187 static int xpos[2]={0, LCD_WIDTH-PAD_WIDTH};
189 /* clear existing pad */
190 singlepad(xpos[pad], p->e_pad[pad], 0);
192 /* draw wanted pad */
193 singlepad(xpos[pad], p->w_pad[pad], 1);
195 /* existing is now the wanted */
196 p->e_pad[pad] = p->w_pad[pad];
199 bool wallcollide(struct pong *p, int pad)
201 /* we have already checked for pad-collision, just check if this hits
202 the wall */
203 if(pad) {
204 /* right-side */
205 if(p->ballx > LCD_WIDTH*RES)
206 return true;
208 else {
209 if(p->ballx < 0)
210 return true;
212 return false;
215 /* returns true if the ball has hit a pad, and then the info variable
216 will have extra angle info */
218 bool padcollide(struct pong *p, int pad, int *info)
220 int x = p->ballx/RES;
221 int y = p->bally/RES;
223 if((y < (p->e_pad[pad]+PAD_HEIGHT)) &&
224 (y + BALL_HEIGHT > p->e_pad[pad])) {
225 /* Y seems likely right */
227 /* store the delta between ball-middle MINUS pad-middle, so
228 it returns:
229 0 when the ball hits exactly the middle of the pad
230 positive numbers when the ball is below the middle of the pad
231 negative numbers when the ball is above the middle of the pad
233 max number is +- PAD_HEIGHT/2
236 *info = (y+BALL_HEIGHT/2) - (p->e_pad[pad] + PAD_HEIGHT/2);
238 if(pad) {
239 /* right-side */
240 if((x + BALL_WIDTH) >= (LCD_WIDTH - PAD_WIDTH))
241 return true; /* phump */
243 else {
244 if(x <= PAD_WIDTH)
245 return true;
248 return false; /* nah */
251 void bounce(struct pong *p, int pad, int info)
253 (void)pad; /* not used right now */
254 p->ballspeedx = -p->ballspeedx;
256 /* info is the hit-angle into the pad */
257 if(p->ballspeedy > 0) {
258 /* downwards */
259 if(info > 0) {
260 /* below the middle of the pad */
261 p->ballspeedy += info * RES/3;
263 else if(info < 0) {
264 /* above the middle */
265 p->ballspeedy = info * RES/2;
268 else {
269 /* upwards */
270 if(info > 0) {
271 /* below the middle of the pad */
272 p->ballspeedy = info * RES/2;
274 else if(info < 0) {
275 /* above the middle */
276 p->ballspeedy -= info * RES/3;
280 p->ballspeedy += rb->rand()%21-10;
282 #if 0
283 fprintf(stderr, "INFO: %d YSPEED: %d\n", info, p->ballspeedy);
284 #endif
287 void score(struct pong *p, int pad)
289 if(pad)
290 rb->splash(HZ/4, "right scores!");
291 else
292 rb->splash(HZ/4, "left scores!");
293 rb->lcd_clear_display();
294 p->score[pad]++;
296 /* then move the X-speed of the ball and give it a random Y position */
297 p->ballspeedx = -p->ballspeedx;
298 p->bally = rb->rand()%(LCD_HEIGHT*RES - BALL_HEIGHT);
300 /* avoid hitting the pad with the new ball */
301 p->ballx = (p->ballx < 0) ?
302 (RES * PAD_WIDTH) : (RES * (LCD_WIDTH - PAD_WIDTH - BALL_WIDTH));
304 /* restore Y-speed to default */
305 p->ballspeedy = (p->ballspeedy > 0) ? SPEEDY : -SPEEDY;
307 /* set the existing pad positions to something weird to force pad
308 updates */
309 p->e_pad[0] = -1;
310 p->e_pad[1] = -1;
313 void ball(struct pong *p)
315 int x = p->ballx/RES;
316 int y = p->bally/RES;
318 int newx;
319 int newy;
321 int info;
323 /* movement */
324 p->ballx += p->ballspeedx;
325 p->bally += p->ballspeedy;
327 newx = p->ballx/RES;
328 newy = p->bally/RES;
330 /* detect if ball hits a wall */
331 if(newy + BALL_HEIGHT > LCD_HEIGHT) {
332 /* hit floor, bounce */
333 p->ballspeedy = -p->ballspeedy;
334 newy = LCD_HEIGHT - BALL_HEIGHT;
335 p->bally = newy * RES;
337 else if(newy < 0) {
338 /* hit ceiling, bounce */
339 p->ballspeedy = -p->ballspeedy;
340 p->bally = 0;
341 newy = 0;
344 /* detect if ball hit pads */
345 if(padcollide(p, 0, &info))
346 bounce(p, 0, info);
347 else if(padcollide(p, 1, &info))
348 bounce(p, 1, info);
349 else if(wallcollide(p, 0))
350 score(p, 1);
351 else if(wallcollide(p, 1))
352 score(p, 0);
354 newx = p->ballx/RES;
355 newy = p->bally/RES;
357 /* clear old position */
358 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
359 rb->lcd_fillrect(x, y, BALL_WIDTH, BALL_HEIGHT);
360 rb->lcd_set_drawmode(DRMODE_SOLID);
362 /* draw the new ball position */
363 rb->lcd_fillrect(newx, newy, BALL_WIDTH, BALL_HEIGHT);
366 void padmove(int *pos, int dir)
368 *pos += dir;
369 if(*pos > (LCD_HEIGHT-PAD_HEIGHT))
370 *pos = (LCD_HEIGHT-PAD_HEIGHT);
371 else if(*pos < 0)
372 *pos = 0;
375 int keys(struct pong *p)
377 int key;
378 #ifdef PONG_PAUSE
379 static bool pause = false;
380 #endif
382 int time = 4; /* number of ticks this function will loop reading keys */
383 int start = *rb->current_tick;
384 int end = start + time;
386 while(end > *rb->current_tick) {
387 key = rb->button_get_w_tmo(end - *rb->current_tick);
389 #ifdef HAS_BUTTON_HOLD
390 if (rb->button_hold())
391 return 2; /* Pause game */
392 #endif
394 if(key & PONG_QUIT
395 #ifdef PONG_RC_QUIT
396 || key & PONG_RC_QUIT
397 #endif
399 return 0; /* exit game NOW */
401 #ifdef PONG_PAUSE
402 if(key == PONG_PAUSE)
403 pause = !pause;
404 if(pause)
405 return 2; /* Pause game */
406 #endif
408 key = rb->button_status(); /* ignore BUTTON_REPEAT */
410 if(key & PONG_LEFT_DOWN) /* player left goes down */
411 padmove(&p->w_pad[0], MOVE_STEP);
413 if(key & PONG_LEFT_UP) /* player left goes up */
414 padmove(&p->w_pad[0], -MOVE_STEP);
416 if(key & PONG_RIGHT_DOWN) /* player right goes down */
417 padmove(&p->w_pad[1], MOVE_STEP);
419 if(key & PONG_RIGHT_UP) /* player right goes up */
420 padmove(&p->w_pad[1], -MOVE_STEP);
422 if(rb->default_event_handler(key) == SYS_USB_CONNECTED)
423 return -1; /* exit game because of USB */
425 return 1; /* return 0 to exit game */
428 void showscore(struct pong *p)
430 static char buffer[20];
431 int w;
433 rb->snprintf(buffer, sizeof(buffer), "%d - %d", p->score[0], p->score[1]);
434 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
435 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), 0, (unsigned char *)buffer);
438 /* this is the plugin entry point */
439 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
441 struct pong pong;
442 int game = 1;
444 /* init the struct with some silly values to start with */
446 pong.ballx = 20*RES;
447 pong.bally = 20*RES;
449 pong.e_pad[0] = 0;
450 pong.w_pad[0] = 7;
451 pong.e_pad[1] = 0;
452 pong.w_pad[1] = 40;
454 pong.ballspeedx = SPEEDX;
455 pong.ballspeedy = SPEEDY;
457 pong.score[0] = pong.score[1] = 0; /* lets start at 0 - 0 ;-) */
459 /* if you don't use the parameter, you can do like
460 this to avoid the compiler warning about it */
461 (void)parameter;
463 rb = api; /* use the "standard" rb pointer */
465 /* Clear screen */
466 rb->lcd_clear_display();
468 /* go go go */
469 while(game > 0) {
470 if (game == 2) { /* Game Paused */
471 rb->splash(0, "PAUSED");
472 while(game == 2)
473 game = keys(&pong); /* short circuit */
474 rb->lcd_clear_display();
476 showscore(&pong);
477 pad(&pong, 0); /* draw left pad */
478 pad(&pong, 1); /* draw right pad */
479 ball(&pong); /* move and draw ball */
481 rb->lcd_update();
483 game = keys(&pong); /* deal with keys */
486 return (game == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
489 #endif /* HAVE_LCD_BITMAP */