Add AI to the pong plugin, to allow single-player operation.
[kugel-rb.git] / apps / plugins / pong.c
blob49fc8e1468fcbc868a55edc11613b7d4621147f9
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 #define PAD_HEIGHT LCD_HEIGHT / 6 /* Recorder: 10 iRiver: 21 */
24 #define PAD_WIDTH LCD_WIDTH / 50 /* Recorder: 2 iRiver: 2 */
26 #define BALL_HEIGHT LCD_HEIGHT / 32 /* Recorder: 2 iRiver: 4 */
27 #define BALL_WIDTH LCD_HEIGHT / 32 /* We want a square ball */
29 #define SPEEDX ( LCD_WIDTH * 3 ) / 2 /* Recorder: 168 iRiver: 240 */
30 #define SPEEDY LCD_HEIGHT * 2 /* Recorder: 128 iRiver: 256 */
31 #define CPU_PLAYER_DIST ( (LCD_WIDTH/8 ) * 5 ) /* This is the width of the dead spot where the */
32 #define DEM_PLAYER_DIST ( (LCD_WIDTH/8 ) * 3 ) /* cpu player doesnt care about the ball -- 3/8 of the screen */
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 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
105 (CONFIG_KEYPAD == SANSA_M200_PAD)
106 #define PONG_QUIT BUTTON_POWER
107 #define PONG_PAUSE BUTTON_SELECT
108 #define PONG_LEFT_UP BUTTON_LEFT
109 #define PONG_LEFT_DOWN BUTTON_DOWN
110 #define PONG_RIGHT_UP BUTTON_UP
111 #define PONG_RIGHT_DOWN BUTTON_RIGHT
113 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
114 #define PONG_QUIT BUTTON_HOME
115 #define PONG_PAUSE BUTTON_SELECT
116 #define PONG_LEFT_UP BUTTON_LEFT
117 #define PONG_LEFT_DOWN BUTTON_DOWN
118 #define PONG_RIGHT_UP BUTTON_UP
119 #define PONG_RIGHT_DOWN BUTTON_RIGHT
121 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
122 #define PONG_QUIT BUTTON_POWER
123 #define PONG_PAUSE BUTTON_SELECT
124 #define PONG_LEFT_UP BUTTON_VOL_UP
125 #define PONG_LEFT_DOWN BUTTON_VOL_DOWN
126 #define PONG_RIGHT_UP BUTTON_UP
127 #define PONG_RIGHT_DOWN BUTTON_DOWN
129 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
130 #define PONG_QUIT BUTTON_POWER
131 #define PONG_LEFT_UP BUTTON_SCROLL_UP
132 #define PONG_LEFT_DOWN BUTTON_SCROLL_DOWN
133 #define PONG_RIGHT_UP BUTTON_REW
134 #define PONG_RIGHT_DOWN BUTTON_FF
136 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
137 #define PONG_QUIT BUTTON_BACK
138 #define PONG_LEFT_UP BUTTON_UP
139 #define PONG_LEFT_DOWN BUTTON_DOWN
140 #define PONG_RIGHT_UP BUTTON_VOL_UP
141 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
143 #elif (CONFIG_KEYPAD == MROBE100_PAD)
144 #define PONG_QUIT BUTTON_POWER
145 #define PONG_PAUSE BUTTON_SELECT
146 #define PONG_LEFT_UP BUTTON_MENU
147 #define PONG_LEFT_DOWN BUTTON_LEFT
148 #define PONG_RIGHT_UP BUTTON_PLAY
149 #define PONG_RIGHT_DOWN BUTTON_RIGHT
151 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
152 #define PONG_QUIT BUTTON_RC_REC
153 #define PONG_PAUSE BUTTON_RC_PLAY
154 #define PONG_LEFT_UP BUTTON_RC_VOL_UP
155 #define PONG_LEFT_DOWN BUTTON_RC_VOL_DOWN
156 #define PONG_RIGHT_UP BUTTON_VOL_UP
157 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
159 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
160 #define PONG_QUIT BUTTON_POWER
162 #elif CONFIG_KEYPAD == IAUDIO67_PAD
163 #define PONG_QUIT BUTTON_POWER
164 #define PONG_PAUSE BUTTON_MENU
165 #define PONG_LEFT_UP BUTTON_VOLUP
166 #define PONG_LEFT_DOWN BUTTON_VOLDOWN
167 #define PONG_RIGHT_UP BUTTON_RIGHT
168 #define PONG_RIGHT_DOWN BUTTON_LEFT
170 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
171 #define PONG_QUIT BUTTON_BACK
172 #define PONG_LEFT_UP BUTTON_UP
173 #define PONG_LEFT_DOWN BUTTON_DOWN
174 #define PONG_RIGHT_UP BUTTON_PLAY
175 #define PONG_RIGHT_DOWN BUTTON_MENU
177 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
178 #define PONG_QUIT BUTTON_POWER
179 #define PONG_PAUSE BUTTON_MENU
180 #define PONG_LEFT_UP BUTTON_UP
181 #define PONG_LEFT_DOWN BUTTON_DOWN
182 #define PONG_RIGHT_UP BUTTON_VOL_UP
183 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
185 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
186 #define PONG_QUIT BUTTON_POWER
187 #define PONG_PAUSE BUTTON_MENU
188 #define PONG_LEFT_UP BUTTON_UP
189 #define PONG_LEFT_DOWN BUTTON_DOWN
190 #define PONG_RIGHT_UP BUTTON_VOL_UP
191 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
193 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
194 #define PONG_QUIT BUTTON_POWER
195 #define PONG_PAUSE BUTTON_MENU
196 #define PONG_LEFT_UP BUTTON_UP
197 #define PONG_LEFT_DOWN BUTTON_DOWN
198 #define PONG_RIGHT_UP BUTTON_VOL_UP
199 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
201 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
202 CONFIG_KEYPAD == ONDAVX777_PAD || \
203 CONFIG_KEYPAD == MROBE500_PAD
204 #define PONG_QUIT BUTTON_POWER
206 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
207 #define PONG_QUIT BUTTON_REC
208 #define PONG_PAUSE BUTTON_PLAY
209 #define PONG_LEFT_UP BUTTON_UP
210 #define PONG_LEFT_DOWN BUTTON_DOWN
211 #define PONG_RIGHT_UP BUTTON_FFWD
212 #define PONG_RIGHT_DOWN BUTTON_REW
214 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
215 #define PONG_QUIT BUTTON_REC
216 #define PONG_PAUSE BUTTON_OK
217 #define PONG_LEFT_UP BUTTON_MENU
218 #define PONG_LEFT_DOWN BUTTON_PREV
219 #define PONG_RIGHT_UP BUTTON_PLAY
220 #define PONG_RIGHT_DOWN BUTTON_NEXT
222 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
223 #define PONG_QUIT (BUTTON_REC|BUTTON_PLAY)
224 #define PONG_LEFT_UP BUTTON_REW
225 #define PONG_LEFT_DOWN BUTTON_FF
226 #define PONG_RIGHT_UP BUTTON_VOL_UP
227 #define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
229 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
230 #define PONG_QUIT (BUTTON_REC|BUTTON_REPEAT)
231 #define PONG_LEFT_UP BUTTON_FF
232 #define PONG_LEFT_DOWN BUTTON_REW
233 #define PONG_RIGHT_UP BUTTON_UP
234 #define PONG_RIGHT_DOWN BUTTON_DOWN
236 #else
237 #error No keymap defined!
238 #endif
240 #ifdef HAVE_TOUCHSCREEN
241 #ifndef PONG_QUIT
242 #define PONG_QUIT BUTTON_TOPMIDDLE
243 #endif
244 #ifndef PONG_LEFT_UP
245 #define PONG_LEFT_UP BUTTON_TOPLEFT
246 #endif
247 #ifndef PONG_LEFT_DOWN
248 #define PONG_LEFT_DOWN BUTTON_BOTTOMLEFT
249 #endif
250 #ifndef PONG_RIGHT_UP
251 #define PONG_RIGHT_UP BUTTON_TOPRIGHT
252 #endif
253 #ifndef PONG_RIGHT_DOWN
254 #define PONG_RIGHT_DOWN BUTTON_BOTTOMRIGHT
255 #endif
256 #ifndef PONG_PAUSE
257 #define PONG_PAUSE BUTTON_CENTER
258 #endif
259 #endif
261 struct pong {
262 int ballx; /* current X*RES position of the ball */
263 int bally; /* current Y*RES position of the ball */
264 int w_pad[2]; /* wanted current Y positions of pads */
265 int e_pad[2]; /* existing current Y positions of pads */
266 int ballspeedx; /* */
267 int ballspeedy; /* */
268 int score[2];
269 bool cpu_player[2]; /* Status of AI players */
272 void singlepad(int x, int y, int set)
274 if(set) {
275 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
277 else {
278 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
279 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
280 rb->lcd_set_drawmode(DRMODE_SOLID);
284 static int xpos[2]={0, LCD_WIDTH-PAD_WIDTH};
285 void pad(struct pong *p, int pad)
287 /* clear existing pad */
288 singlepad(xpos[pad], p->e_pad[pad], 0);
290 /* draw wanted pad */
291 singlepad(xpos[pad], p->w_pad[pad], 1);
293 /* existing is now the wanted */
294 p->e_pad[pad] = p->w_pad[pad];
297 bool wallcollide(struct pong *p, int pad)
299 /* we have already checked for pad-collision, just check if this hits
300 the wall */
301 if(pad) {
302 /* right-side */
303 if(p->ballx > ( LCD_WIDTH*RES ) - PAD_WIDTH )
304 return true;
306 else {
307 if(p->ballx < PAD_WIDTH)
308 return true;
310 return false;
313 /* returns true if the ball has hit a pad, and then the info variable
314 will have extra angle info */
316 bool padcollide(struct pong *p, int pad, int *info)
318 int x = p->ballx/RES;
319 int y = p->bally/RES;
321 if((y < (p->e_pad[pad]+PAD_HEIGHT)) &&
322 (y + BALL_HEIGHT > p->e_pad[pad])) {
323 /* Y seems likely right */
325 /* store the delta between ball-middle MINUS pad-middle, so
326 it returns:
327 0 when the ball hits exactly the middle of the pad
328 positive numbers when the ball is below the middle of the pad
329 negative numbers when the ball is above the middle of the pad
331 max number is +- PAD_HEIGHT/2
334 *info = (y+BALL_HEIGHT/2) - (p->e_pad[pad] + PAD_HEIGHT/2);
336 if(pad) {
337 /* right-side */
338 if((x + BALL_WIDTH) >= (LCD_WIDTH - PAD_WIDTH))
339 return true; /* phump */
341 else {
342 if(x <= PAD_WIDTH)
343 return true;
346 return false; /* nah */
349 void bounce(struct pong *p, int pad, int info)
351 p->ballspeedx = -p->ballspeedx;
353 if(pad==0) { /* Give ball a little push to keep it from getting stuck between wall and pad */
354 p->ballx += PAD_WIDTH;
356 else {
357 p->ballx -= PAD_WIDTH;
360 /* info is the hit-angle into the pad */
361 if(p->ballspeedy > 0) {
362 /* downwards */
363 if(info > 0) {
364 /* below the middle of the pad */
365 p->ballspeedy += info * RES/3;
367 else if(info < 0) {
368 /* above the middle */
369 p->ballspeedy = info * RES/2;
372 else {
373 /* upwards */
374 if(info > 0) {
375 /* below the middle of the pad */
376 p->ballspeedy = info * RES/2;
378 else if(info < 0) {
379 /* above the middle */
380 p->ballspeedy -= info * RES/3;
384 p->ballspeedy += rb->rand()%21-10;
386 #if 0
387 fprintf(stderr, "INFO: %d YSPEED: %d\n", info, p->ballspeedy);
388 #endif
391 void score(struct pong *p, int pad)
393 if(pad)
394 rb->splash(HZ/4, "right scores!");
395 else
396 rb->splash(HZ/4, "left scores!");
397 rb->lcd_clear_display();
398 p->score[pad]++;
400 /* then move the X-speed of the ball and give it a random Y position */
401 p->ballspeedx = -p->ballspeedx;
402 p->bally = rb->rand()%(LCD_HEIGHT*RES - BALL_HEIGHT);
404 /* avoid hitting the pad with the new ball */
405 p->ballx = (p->ballx < 0) ?
406 (RES * PAD_WIDTH) : (RES * (LCD_WIDTH - PAD_WIDTH - BALL_WIDTH));
408 /* restore Y-speed to default */
409 p->ballspeedy = (p->ballspeedy > 0) ? SPEEDY : -SPEEDY;
411 /* set the existing pad positions to something weird to force pad
412 updates */
413 p->e_pad[0] = -1;
414 p->e_pad[1] = -1;
417 void ball(struct pong *p)
419 int x = p->ballx/RES;
420 int y = p->bally/RES;
422 int newx;
423 int newy;
425 int info;
427 /* movement */
428 p->ballx += p->ballspeedx;
429 p->bally += p->ballspeedy;
431 newx = p->ballx/RES;
432 newy = p->bally/RES;
434 /* detect if ball hits a wall */
435 if(newy + BALL_HEIGHT > LCD_HEIGHT) {
436 /* hit floor, bounce */
437 p->ballspeedy = -p->ballspeedy;
438 newy = LCD_HEIGHT - BALL_HEIGHT;
439 p->bally = newy * RES;
441 else if(newy < 0) {
442 /* hit ceiling, bounce */
443 p->ballspeedy = -p->ballspeedy;
444 p->bally = 0;
445 newy = 0;
448 /* detect if ball hit pads */
449 if(padcollide(p, 0, &info))
450 bounce(p, 0, info);
451 else if(padcollide(p, 1, &info))
452 bounce(p, 1, info);
453 else if(wallcollide(p, 0))
454 score(p, 1);
455 else if(wallcollide(p, 1))
456 score(p, 0);
458 newx = p->ballx/RES;
459 newy = p->bally/RES;
461 /* clear old position */
462 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
463 rb->lcd_fillrect(x, y, BALL_WIDTH, BALL_HEIGHT);
464 rb->lcd_set_drawmode(DRMODE_SOLID);
466 /* draw the new ball position */
467 rb->lcd_fillrect(newx, newy, BALL_WIDTH, BALL_HEIGHT);
470 void padmove(int *pos, int dir)
472 *pos += dir;
473 if(*pos > (LCD_HEIGHT-PAD_HEIGHT))
474 *pos = (LCD_HEIGHT-PAD_HEIGHT);
475 else if(*pos < 0)
476 *pos = 0;
479 int keys(struct pong *p)
481 int key;
482 #ifdef PONG_PAUSE
483 static bool pause = false;
484 #endif
486 /* number of ticks this function will loop reading keys */
487 #ifndef HAVE_TOUCHSCREEN
488 int time = 4;
489 #else
490 int time = 1;
491 #endif
492 int start = *rb->current_tick;
493 int end = start + time;
495 while(TIME_BEFORE(*rb->current_tick, end)) {
496 key = rb->button_get_w_tmo(end - *rb->current_tick);
498 #ifdef HAVE_TOUCHSCREEN
499 short touch_x, touch_y;
500 if(key & BUTTON_TOUCHSCREEN)
502 touch_x = rb->button_get_data() >> 16;
503 touch_y = rb->button_get_data() & 0xFFFF;
504 if(touch_x >= xpos[0] && touch_x <= xpos[0]+(PAD_WIDTH*4))
505 padmove(&p->w_pad[0], touch_y-(p->e_pad[0]*2+PAD_HEIGHT)/2);
507 if(touch_x >= xpos[1]-(PAD_WIDTH*4) && touch_x <= xpos[1])
508 padmove(&p->w_pad[1], touch_y-(p->e_pad[1]*2+PAD_HEIGHT)/2);
510 #endif
512 #ifdef HAS_BUTTON_HOLD
513 if (rb->button_hold())
514 return 2; /* Pause game */
515 #endif
517 if(key & PONG_QUIT
518 #ifdef PONG_RC_QUIT
519 || key & PONG_RC_QUIT
520 #endif
522 return 0; /* exit game NOW */
524 #ifdef PONG_PAUSE
525 if(key == PONG_PAUSE)
526 pause = !pause;
527 if(pause)
528 return 2; /* Pause game */
529 #endif
531 key = rb->button_status(); /* ignore BUTTON_REPEAT */
533 if(p->cpu_player[1] == true) {
534 if( (p->bally/RES > p->w_pad[0])
535 & (p->ballx/RES < DEM_PLAYER_DIST) ) /* player right goes down */
536 padmove(&p->w_pad[0], MOVE_STEP);
538 if( (p->bally/RES < p->w_pad[0])
539 & (p->ballx/RES < DEM_PLAYER_DIST) ) /* player right goes up */
540 padmove(&p->w_pad[0], -MOVE_STEP);
542 if( (key & PONG_LEFT_DOWN) || (key & PONG_LEFT_UP) ) {
543 /* if left player presses control keys stop cpu player */
544 p->cpu_player[1] = false;
545 p->score[0] = p->score[1] = 0; /* reset the score */
546 rb->lcd_clear_display(); /* get rid of the text */
549 else {
550 if(key & PONG_LEFT_DOWN) /* player left goes down */
551 padmove(&p->w_pad[0], MOVE_STEP);
553 if(key & PONG_LEFT_UP) /* player left goes up */
554 padmove(&p->w_pad[0], -MOVE_STEP);
557 if(p->cpu_player[2] == true) {
558 if( (p->bally/RES > p->w_pad[1])
559 & (p->ballx/RES > CPU_PLAYER_DIST) ) /* player right goes down */
560 padmove(&p->w_pad[1], MOVE_STEP);
562 if( (p->bally/RES < p->w_pad[1])
563 & (p->ballx/RES > CPU_PLAYER_DIST) ) /* player right goes up */
564 padmove(&p->w_pad[1], -MOVE_STEP);
566 if( (key & PONG_RIGHT_DOWN) || (key & PONG_RIGHT_UP) ) {
567 /* if right player presses control keys stop cpu player */
568 p->cpu_player[2] = false;
569 p->score[0] = p->score[1] = 0; /* reset the score */
570 rb->lcd_clear_display(); /* get rid of the text */
573 else {
574 if(key & PONG_RIGHT_DOWN) /* player right goes down */
575 padmove(&p->w_pad[1], MOVE_STEP);
577 if(key & PONG_RIGHT_UP) /* player right goes up */
578 padmove(&p->w_pad[1], -MOVE_STEP);
581 if(rb->default_event_handler(key) == SYS_USB_CONNECTED)
582 return -1; /* exit game because of USB */
584 return 1; /* return 0 to exit game */
587 void showscore(struct pong *p)
589 static char buffer[20];
590 int w;
592 rb->snprintf(buffer, sizeof(buffer), "%d - %d", p->score[0], p->score[1]);
593 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
594 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), 0, (unsigned char *)buffer);
597 void blink_demo(void)
599 static char buffer[30];
600 int w;
602 rb->snprintf(buffer, sizeof(buffer), "Press Key To Play");
603 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
604 if(LCD_WIDTH > ( (w/8)*7 ) ) /* make sure text isn't too long for screen */
605 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), (LCD_HEIGHT / 2),
606 (unsigned char *)buffer);
609 /* this is the plugin entry point */
610 enum plugin_status plugin_start(const void* parameter)
612 struct pong pong;
613 int game = 1;
615 int blink_timer = 0;
616 int blink_rate = 20;
617 bool blink = true;
619 /* init the struct with some silly values to start with */
621 pong.ballx = 20*RES;
622 pong.bally = 20*RES;
624 pong.e_pad[0] = 0;
625 pong.w_pad[0] = 7;
626 pong.e_pad[1] = 0;
627 pong.w_pad[1] = 40;
628 pong.cpu_player[1] = pong.cpu_player[2] = true; /* start every game in demo mode */
630 pong.ballspeedx = SPEEDX;
631 pong.ballspeedy = SPEEDY;
633 pong.score[0] = pong.score[1] = 0; /* lets start at 0 - 0 ;-) */
635 /* if you don't use the parameter, you can do like
636 this to avoid the compiler warning about it */
637 (void)parameter;
639 /* Clear screen */
640 rb->lcd_clear_display();
642 /* go go go */
643 while(game > 0) {
644 if (game == 2) { /* Game Paused */
645 rb->splash(0, "PAUSED");
646 while(game == 2)
647 game = keys(&pong); /* short circuit */
648 rb->lcd_clear_display();
651 if( (pong.cpu_player[1]==true) && (pong.cpu_player[2]==true) ) {
652 if(blink_timer<blink_rate) {
653 ++blink_timer;
655 else {
656 blink_timer=0;
657 blink = !blink;
660 if(blink==true) {
661 blink_demo();
663 else {
664 rb->lcd_clear_display();
668 showscore(&pong);
669 pad(&pong, 0); /* draw left pad */
670 pad(&pong, 1); /* draw right pad */
671 ball(&pong); /* move and draw ball */
673 rb->lcd_update();
675 game = keys(&pong); /* deal with keys */
678 return (game == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;