A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Daniel Stenberg
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "plugin.h"
22#include "lib/helper.h"
23
24#define PAD_HEIGHT LCD_HEIGHT / 6 /* Recorder: 10 iRiver: 21 */
25#define PAD_WIDTH LCD_WIDTH / 50 /* Recorder: 2 iRiver: 2 */
26
27#define BALL_HEIGHT LCD_HEIGHT / 32 /* Recorder: 2 iRiver: 4 */
28#define BALL_WIDTH LCD_HEIGHT / 32 /* We want a square ball */
29
30#define SPEEDX ( LCD_WIDTH * 3 ) / 2 /* Recorder: 168 iRiver: 240 */
31#define SPEEDY LCD_HEIGHT * 2 /* Recorder: 128 iRiver: 256 */
32/* This is the width of the dead spot where the
33 * cpu player doesnt care about the ball -- 3/8 of the screen */
34#define CPU_PLAYER_RIGHT_DIST ( (LCD_WIDTH/8 ) * 5 )
35#define CPU_PLAYER_LEFT_DIST ( (LCD_WIDTH/8 ) * 3 )
36
37#define RES 100
38
39#define MOVE_STEP LCD_HEIGHT / 32 /* move pad this many steps up/down each move */
40
41/* variable button definitions */
42#if CONFIG_KEYPAD == IRIVER_H100_PAD
43#define PONG_QUIT BUTTON_OFF
44#define PONG_LEFT_UP BUTTON_UP
45#define PONG_LEFT_DOWN BUTTON_DOWN
46#define PONG_RIGHT_UP BUTTON_ON
47#define PONG_RIGHT_DOWN BUTTON_MODE
48#define PONG_RC_QUIT BUTTON_RC_STOP
49
50#elif CONFIG_KEYPAD == IRIVER_H300_PAD
51#define PONG_QUIT BUTTON_OFF
52#define PONG_LEFT_UP BUTTON_UP
53#define PONG_LEFT_DOWN BUTTON_DOWN
54#define PONG_RIGHT_UP BUTTON_REC
55#define PONG_RIGHT_DOWN BUTTON_MODE
56#define PONG_RC_QUIT BUTTON_RC_STOP
57
58#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
59 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
60 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
61#define PONG_QUIT BUTTON_SELECT
62#define PONG_LEFT_UP BUTTON_MENU
63#define PONG_LEFT_DOWN BUTTON_LEFT
64#define PONG_RIGHT_UP BUTTON_RIGHT
65#define PONG_RIGHT_DOWN BUTTON_PLAY
66
67#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
68#define PONG_QUIT BUTTON_POWER
69#define PONG_LEFT_UP BUTTON_UP
70#define PONG_LEFT_DOWN BUTTON_DOWN
71#define PONG_RIGHT_UP BUTTON_REC
72#define PONG_RIGHT_DOWN BUTTON_PLAY
73
74#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
75#define PONG_QUIT BUTTON_POWER
76#define PONG_PAUSE BUTTON_SELECT
77#define PONG_LEFT_UP BUTTON_UP
78#define PONG_LEFT_DOWN BUTTON_DOWN
79#define PONG_RIGHT_UP BUTTON_VOL_UP
80#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
81
82#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
83 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
84 (CONFIG_KEYPAD == SANSA_M200_PAD) || \
85 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
86#define PONG_QUIT BUTTON_POWER
87#define PONG_PAUSE BUTTON_SELECT
88#define PONG_LEFT_UP BUTTON_LEFT
89#define PONG_LEFT_DOWN BUTTON_DOWN
90#define PONG_RIGHT_UP BUTTON_UP
91#define PONG_RIGHT_DOWN BUTTON_RIGHT
92
93#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
94#define PONG_QUIT BUTTON_HOME
95#define PONG_PAUSE BUTTON_SELECT
96#define PONG_LEFT_UP BUTTON_LEFT
97#define PONG_LEFT_DOWN BUTTON_DOWN
98#define PONG_RIGHT_UP BUTTON_UP
99#define PONG_RIGHT_DOWN BUTTON_RIGHT
100
101#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
102#define PONG_QUIT BUTTON_POWER
103#define PONG_PAUSE BUTTON_SELECT
104#define PONG_LEFT_UP BUTTON_VOL_UP
105#define PONG_LEFT_DOWN BUTTON_VOL_DOWN
106#define PONG_RIGHT_UP BUTTON_UP
107#define PONG_RIGHT_DOWN BUTTON_DOWN
108
109#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
110#define PONG_QUIT BUTTON_POWER
111#define PONG_LEFT_UP BUTTON_SCROLL_UP
112#define PONG_LEFT_DOWN BUTTON_SCROLL_DOWN
113#define PONG_RIGHT_UP BUTTON_REW
114#define PONG_RIGHT_DOWN BUTTON_FF
115
116#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
117#define PONG_QUIT BUTTON_BACK
118#define PONG_LEFT_UP BUTTON_UP
119#define PONG_LEFT_DOWN BUTTON_DOWN
120#define PONG_RIGHT_UP BUTTON_VOL_UP
121#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
122
123#elif (CONFIG_KEYPAD == MROBE100_PAD)
124#define PONG_QUIT BUTTON_POWER
125#define PONG_PAUSE BUTTON_SELECT
126#define PONG_LEFT_UP BUTTON_MENU
127#define PONG_LEFT_DOWN BUTTON_LEFT
128#define PONG_RIGHT_UP BUTTON_PLAY
129#define PONG_RIGHT_DOWN BUTTON_RIGHT
130
131#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
132#define PONG_QUIT BUTTON_RC_REC
133#define PONG_PAUSE BUTTON_RC_PLAY
134#define PONG_LEFT_UP BUTTON_RC_VOL_UP
135#define PONG_LEFT_DOWN BUTTON_RC_VOL_DOWN
136#define PONG_RIGHT_UP BUTTON_VOL_UP
137#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
138
139#elif (CONFIG_KEYPAD == COWON_D2_PAD)
140#define PONG_QUIT BUTTON_POWER
141
142#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
143#define PONG_QUIT BUTTON_BACK
144#define PONG_LEFT_UP BUTTON_UP
145#define PONG_LEFT_DOWN BUTTON_DOWN
146#define PONG_RIGHT_UP BUTTON_PLAY
147#define PONG_RIGHT_DOWN BUTTON_MENU
148
149#elif (CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD)
150#define PONG_QUIT BUTTON_POWER
151#define PONG_PAUSE BUTTON_PLAY
152#define PONG_LEFT_UP BUTTON_BACK
153#define PONG_LEFT_DOWN BUTTON_MENU
154#define PONG_RIGHT_UP BUTTON_UP
155#define PONG_RIGHT_DOWN BUTTON_DOWN
156
157#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
158#define PONG_QUIT BUTTON_POWER
159#define PONG_PAUSE BUTTON_MENU
160#define PONG_LEFT_UP BUTTON_UP
161#define PONG_LEFT_DOWN BUTTON_DOWN
162#define PONG_RIGHT_UP BUTTON_VOL_UP
163#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
164
165#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
166#define PONG_QUIT BUTTON_POWER
167#define PONG_PAUSE BUTTON_MENU
168#define PONG_LEFT_UP BUTTON_UP
169#define PONG_LEFT_DOWN BUTTON_DOWN
170#define PONG_RIGHT_UP BUTTON_VOL_UP
171#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
172
173#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
174#define PONG_QUIT BUTTON_POWER
175#define PONG_PAUSE BUTTON_MENU
176#define PONG_LEFT_UP BUTTON_UP
177#define PONG_LEFT_DOWN BUTTON_DOWN
178#define PONG_RIGHT_UP BUTTON_VOL_UP
179#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
180
181#elif CONFIG_KEYPAD == ONDAVX747_PAD || \
182CONFIG_KEYPAD == ONDAVX777_PAD || \
183CONFIG_KEYPAD == MROBE500_PAD
184#define PONG_QUIT BUTTON_POWER
185
186#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD
187#define PONG_QUIT (BUTTON_PLAY|BUTTON_REPEAT)
188#define PONG_PAUSE (BUTTON_PLAY|BUTTON_REL)
189#define PONG_LEFT_UP BUTTON_UP
190#define PONG_LEFT_DOWN BUTTON_DOWN
191#define PONG_RIGHT_UP BUTTON_FFWD
192#define PONG_RIGHT_DOWN BUTTON_REW
193
194#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD
195#define PONG_QUIT BUTTON_REW
196#define PONG_PAUSE BUTTON_PLAY
197#define PONG_LEFT_UP BUTTON_UP
198#define PONG_LEFT_DOWN BUTTON_DOWN
199#define PONG_RIGHT_UP BUTTON_REC
200#define PONG_RIGHT_DOWN BUTTON_FFWD
201
202#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
203#define PONG_QUIT BUTTON_REC
204#define PONG_PAUSE BUTTON_OK
205#define PONG_LEFT_UP BUTTON_MENU
206#define PONG_LEFT_DOWN BUTTON_PREV
207#define PONG_RIGHT_UP BUTTON_PLAY
208#define PONG_RIGHT_DOWN BUTTON_NEXT
209
210#elif CONFIG_KEYPAD == MPIO_HD200_PAD
211#define PONG_QUIT (BUTTON_REC|BUTTON_PLAY)
212#define PONG_LEFT_UP BUTTON_REW
213#define PONG_LEFT_DOWN BUTTON_FF
214#define PONG_RIGHT_UP BUTTON_VOL_UP
215#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
216
217#elif CONFIG_KEYPAD == MPIO_HD300_PAD
218#define PONG_QUIT (BUTTON_MENU|BUTTON_REPEAT)
219#define PONG_LEFT_UP BUTTON_REW
220#define PONG_LEFT_DOWN BUTTON_REC
221#define PONG_RIGHT_UP BUTTON_FF
222#define PONG_RIGHT_DOWN BUTTON_PLAY
223
224#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
225#define PONG_QUIT BUTTON_POWER
226#define PONG_LEFT_UP BUTTON_BACK
227#define PONG_LEFT_DOWN BUTTON_BOTTOMLEFT
228#define PONG_RIGHT_UP BUTTON_PLAYPAUSE
229#define PONG_RIGHT_DOWN BUTTON_BOTTOMRIGHT
230#define PONG_PAUSE BUTTON_SELECT
231
232#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
233#define PONG_QUIT BUTTON_BACK
234#define PONG_PAUSE BUTTON_SELECT
235#define PONG_LEFT_UP BUTTON_UP
236#define PONG_LEFT_DOWN BUTTON_DOWN
237#define PONG_RIGHT_UP BUTTON_MENU
238#define PONG_RIGHT_DOWN BUTTON_POWER
239
240#elif (CONFIG_KEYPAD == HM60X_PAD) || \
241 (CONFIG_KEYPAD == HM801_PAD)
242#define PONG_QUIT BUTTON_POWER
243#define PONG_PAUSE BUTTON_SELECT
244#define PONG_LEFT_UP BUTTON_UP
245#define PONG_LEFT_DOWN BUTTON_DOWN
246#define PONG_RIGHT_UP BUTTON_RIGHT
247#define PONG_RIGHT_DOWN BUTTON_LEFT
248
249#elif CONFIG_KEYPAD == SONY_NWZ_PAD
250#define PONG_QUIT BUTTON_BACK
251#define PONG_PAUSE BUTTON_PLAY
252#define PONG_LEFT_UP BUTTON_UP
253#define PONG_LEFT_DOWN BUTTON_DOWN
254#define PONG_RIGHT_UP BUTTON_RIGHT
255#define PONG_RIGHT_DOWN BUTTON_LEFT
256
257#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
258#define PONG_QUIT BUTTON_BACK
259#define PONG_PAUSE BUTTON_PLAYPAUSE
260#define PONG_LEFT_UP BUTTON_UP
261#define PONG_LEFT_DOWN BUTTON_DOWN
262#define PONG_RIGHT_UP BUTTON_RIGHT
263#define PONG_RIGHT_DOWN BUTTON_LEFT
264
265#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
266#define PONG_QUIT BUTTON_POWER
267#define PONG_PAUSE BUTTON_SELECT
268#define PONG_LEFT_UP BUTTON_UP
269#define PONG_LEFT_DOWN BUTTON_DOWN
270#define PONG_RIGHT_UP BUTTON_RIGHT
271#define PONG_RIGHT_DOWN BUTTON_LEFT
272
273#elif (CONFIG_KEYPAD == DX50_PAD)
274#define PONG_QUIT (BUTTON_POWER|BUTTON_REL)
275
276#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
277#define PONG_QUIT BUTTON_POWER
278#define PONG_PAUSE BUTTON_MENU
279
280#elif CONFIG_KEYPAD == XDUOO_X3_PAD
281#define PONG_QUIT BUTTON_POWER
282#define PONG_PAUSE BUTTON_PLAY
283#define PONG_LEFT_UP BUTTON_PREV
284#define PONG_LEFT_DOWN BUTTON_OPTION
285#define PONG_RIGHT_UP BUTTON_HOME
286#define PONG_RIGHT_DOWN BUTTON_NEXT
287
288#elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
289#define PONG_QUIT BUTTON_POWER
290#define PONG_PAUSE BUTTON_PLAY
291#define PONG_LEFT_UP BUTTON_PREV
292#define PONG_LEFT_DOWN BUTTON_OPTION
293#define PONG_RIGHT_UP BUTTON_HOME
294#define PONG_RIGHT_DOWN BUTTON_NEXT
295
296#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
297#define PONG_QUIT BUTTON_POWER
298#define PONG_PAUSE BUTTON_PLAY
299#define PONG_LEFT_UP BUTTON_PREV
300#define PONG_LEFT_DOWN BUTTON_OPTION
301#define PONG_RIGHT_UP BUTTON_HOME
302#define PONG_RIGHT_DOWN BUTTON_NEXT
303
304#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
305#define PONG_QUIT BUTTON_POWER
306#define PONG_PAUSE BUTTON_PREV
307#define PONG_LEFT_UP BUTTON_PLAY
308#define PONG_LEFT_DOWN BUTTON_HOME
309#define PONG_RIGHT_UP BUTTON_VOL_UP
310#define PONG_RIGHT_DOWN BUTTON_VOL_DOWN
311
312#elif CONFIG_KEYPAD == EROSQ_PAD
313#define PONG_QUIT BUTTON_POWER
314#define PONG_PAUSE BUTTON_PLAY
315#define PONG_LEFT_UP BUTTON_SCROLL_BACK
316#define PONG_LEFT_DOWN BUTTON_SCROLL_FWD
317#define PONG_RIGHT_UP BUTTON_PREV
318#define PONG_RIGHT_DOWN BUTTON_NEXT
319
320#elif CONFIG_KEYPAD == FIIO_M3K_PAD
321#define PONG_QUIT BUTTON_POWER
322#define PONG_PAUSE BUTTON_PLAY
323#define PONG_LEFT_UP BUTTON_MENU
324#define PONG_LEFT_DOWN BUTTON_LEFT
325#define PONG_RIGHT_UP BUTTON_BACK
326#define PONG_RIGHT_DOWN BUTTON_RIGHT
327
328#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
329/* use touchscreen */
330
331#elif CONFIG_KEYPAD == SDL_PAD
332#define PONG_QUIT BUTTON_TOPLEFT
333#define PONG_PAUSE BUTTON_CENTER
334#define PONG_LEFT_UP BUTTON_TOPMIDDLE
335#define PONG_LEFT_DOWN BUTTON_BOTTOMMIDDLE
336#define PONG_RIGHT_UP BUTTON_MIDRIGHT
337#define PONG_RIGHT_DOWN BUTTON_MIDLEFT
338#elif CONFIG_KEYPAD == MA_PAD
339#define PONG_QUIT BUTTON_BACK
340#define PONG_PAUSE BUTTON_PLAY
341#define PONG_LEFT_UP BUTTON_MENU
342#define PONG_LEFT_DOWN BUTTON_LEFT
343#define PONG_RIGHT_UP BUTTON_BACK
344#define PONG_RIGHT_DOWN BUTTON_RIGHT
345
346#elif CONFIG_KEYPAD == RG_NANO_PAD
347#define PONG_QUIT BUTTON_START
348#define PONG_PAUSE BUTTON_A
349#define PONG_LEFT_UP BUTTON_UP
350#define PONG_LEFT_DOWN BUTTON_DOWN
351#define PONG_RIGHT_UP BUTTON_X
352#define PONG_RIGHT_DOWN BUTTON_Y
353
354#else
355#error No keymap defined!
356#endif
357
358#ifdef HAVE_TOUCHSCREEN
359#ifndef PONG_QUIT
360#define PONG_QUIT BUTTON_TOPMIDDLE
361#endif
362#ifndef PONG_LEFT_UP
363#define PONG_LEFT_UP BUTTON_TOPLEFT
364#endif
365#ifndef PONG_LEFT_DOWN
366#define PONG_LEFT_DOWN BUTTON_BOTTOMLEFT
367#endif
368#ifndef PONG_RIGHT_UP
369#define PONG_RIGHT_UP BUTTON_TOPRIGHT
370#endif
371#ifndef PONG_RIGHT_DOWN
372#define PONG_RIGHT_DOWN BUTTON_BOTTOMRIGHT
373#endif
374#ifndef PONG_PAUSE
375#define PONG_PAUSE BUTTON_CENTER
376#endif
377#endif
378
379struct player {
380 int xpos; /* X position of pad */
381 int w_pad; /* wanted current Y position of pad */
382 int e_pad; /* existing current Y position of pad */
383 int score;
384 bool iscpu; /* Status of AI player */
385};
386
387struct ball {
388 int x; /* current X*RES position of the ball */
389 int y; /* current Y*RES position of the ball */
390 int speedx; /* */
391 int speedy; /* */
392};
393
394struct pong {
395 struct ball ball;
396 struct player player[2];
397};
398
399static void singlepad(int x, int y, int set)
400{
401 if(set) {
402 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
403 }
404 else {
405 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
406 rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
407 rb->lcd_set_drawmode(DRMODE_SOLID);
408 }
409}
410
411static void pad(struct pong *p, int pad)
412{
413 struct player *player = &p->player[pad];
414 /* clear existing pad */
415 singlepad(player->xpos, player->e_pad, 0);
416
417 /* draw wanted pad */
418 singlepad(player->xpos, player->w_pad, 1);
419
420 /* existing is now the wanted */
421 player->e_pad = player->w_pad;
422}
423
424static bool wallcollide(struct pong *p, int pad)
425{
426 /* we have already checked for pad-collision, just check if this hits
427 the wall */
428 if(pad) {
429 /* right-side */
430 if(p->ball.x > ( LCD_WIDTH*RES ) - PAD_WIDTH )
431 return true;
432 }
433 else {
434 if(p->ball.x + ( BALL_WIDTH*RES ) < PAD_WIDTH )
435 return true;
436 }
437 return false;
438}
439
440/* returns true if the ball has hit a pad, and then the info variable
441 will have extra angle info */
442
443static bool padcollide(struct pong *p, int pad, int *info)
444{
445 struct player *player = &p->player[pad];
446 int x = p->ball.x/RES;
447 int y = p->ball.y/RES;
448
449 if((y < (player->e_pad+PAD_HEIGHT)) &&
450 (y + BALL_HEIGHT > player->e_pad)) {
451 /* Y seems likely right */
452
453 /* store the delta between ball-middle MINUS pad-middle, so
454 it returns:
455 0 when the ball hits exactly the middle of the pad
456 positive numbers when the ball is below the middle of the pad
457 negative numbers when the ball is above the middle of the pad
458
459 max number is +- PAD_HEIGHT/2
460 */
461
462 *info = (y+BALL_HEIGHT/2) - (player->e_pad + PAD_HEIGHT/2);
463
464 if(pad) {
465 /* right-side */
466 if((x + BALL_WIDTH) >= (LCD_WIDTH - PAD_WIDTH))
467 return true; /* phump */
468 }
469 else {
470 if(x <= PAD_WIDTH)
471 return true;
472 }
473 }
474 return false; /* nah */
475}
476
477static void bounce(struct pong *p, int pad, int info)
478{
479 p->ball.speedx = -p->ball.speedx;
480
481 /* Give ball a little push to keep it from getting stuck between wall and pad */
482 if(pad) {
483 /* right side */
484 p->ball.x -= PAD_WIDTH*RES/4;
485 }
486 else {
487 p->ball.x += PAD_WIDTH*RES/4;
488 }
489
490 /* info is the hit-angle into the pad */
491 if(p->ball.speedy > 0) {
492 /* downwards */
493 if(info > 0) {
494 /* below the middle of the pad */
495 p->ball.speedy += info * RES/3;
496 }
497 else if(info < 0) {
498 /* above the middle */
499 p->ball.speedy = info * RES/2;
500 }
501 }
502 else {
503 /* upwards */
504 if(info > 0) {
505 /* below the middle of the pad */
506 p->ball.speedy = info * RES/2;
507 }
508 else if(info < 0) {
509 /* above the middle */
510 p->ball.speedy += info * RES/3;
511 }
512 }
513
514 p->ball.speedy += rb->rand()%21-10;
515
516#if 0
517 fprintf(stderr, "INFO: %d YSPEED: %d\n", info, p->ball.speedy);
518#endif
519}
520
521static void score(struct pong *p, int pad)
522{
523 if(pad)
524 rb->splash(HZ/4, "right scores!");
525 else
526 rb->splash(HZ/4, "left scores!");
527 rb->lcd_clear_display();
528 p->player[pad].score++;
529
530 /* then move the X-speed of the ball and give it a random Y position */
531 p->ball.speedx = -p->ball.speedx;
532 p->ball.y = rb->rand()%((LCD_HEIGHT-BALL_HEIGHT)*RES);
533
534 /* avoid hitting the pad with the new ball */
535 p->ball.x = (p->ball.x < 0) ?
536 (RES * PAD_WIDTH) : (RES * (LCD_WIDTH - PAD_WIDTH - BALL_WIDTH));
537
538 /* restore Y-speed to default */
539 p->ball.speedy = (p->ball.speedy > 0) ? SPEEDY : -SPEEDY;
540
541 /* set the existing pad positions to something weird to force pad
542 updates */
543 p->player[0].e_pad = -1;
544 p->player[1].e_pad = -1;
545}
546
547static void ball(struct pong *p)
548{
549 int oldx = p->ball.x/RES;
550 int oldy = p->ball.y/RES;
551
552 int newx;
553 int newy;
554
555 int info;
556
557 /* movement */
558 p->ball.x += p->ball.speedx;
559 p->ball.y += p->ball.speedy;
560
561 /*newx = p->ball.x/RES;*/
562 newy = p->ball.y/RES;
563
564 /* detect if ball hits a wall */
565 if(newy + BALL_HEIGHT > LCD_HEIGHT) {
566 /* hit floor, bounce */
567 p->ball.speedy = -p->ball.speedy;
568 p->ball.y = (LCD_HEIGHT - BALL_HEIGHT) * RES;
569 }
570 else if(newy < 0) {
571 /* hit ceiling, bounce */
572 p->ball.speedy = -p->ball.speedy;
573 p->ball.y = 0;
574 }
575
576 /* detect if ball hit pads */
577 if(padcollide(p, 0, &info))
578 bounce(p, 0, info);
579 else if(padcollide(p, 1, &info))
580 bounce(p, 1, info);
581 else if(wallcollide(p, 0))
582 score(p, 1);
583 else if(wallcollide(p, 1))
584 score(p, 0);
585
586 newx = p->ball.x/RES;
587 newy = p->ball.y/RES;
588
589 /* clear old position */
590 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
591 rb->lcd_fillrect(oldx, oldy, BALL_WIDTH, BALL_HEIGHT);
592 rb->lcd_set_drawmode(DRMODE_SOLID);
593
594 /* draw the new ball position */
595 rb->lcd_fillrect(newx, newy, BALL_WIDTH, BALL_HEIGHT);
596}
597
598static void padmove(int *pos, int dir)
599{
600 *pos += dir;
601 if(*pos > (LCD_HEIGHT-PAD_HEIGHT))
602 *pos = (LCD_HEIGHT-PAD_HEIGHT);
603 else if(*pos < 0)
604 *pos = 0;
605}
606
607static void key_pad(struct pong *p, int pad, int up, int down)
608{
609 struct player *player = &p->player[pad];
610 if(player->iscpu) {
611 if((pad && (p->ball.x/RES > CPU_PLAYER_RIGHT_DIST)) /* cpu right */
612 || (!pad && (p->ball.x/RES < CPU_PLAYER_LEFT_DIST)) /* cpu left */)
613 {
614 if(p->ball.y/RES > player->w_pad) /* player goes down */
615 padmove(&player->w_pad, MOVE_STEP);
616
617 if(p->ball.y/RES < player->w_pad) /* player goes up */
618 padmove(&player->w_pad, -MOVE_STEP);
619 }
620
621 if(down || up) {
622 /* if player presses control keys stop cpu player */
623 player->iscpu = false;
624 p->player[0].score = p->player[1].score = 0; /* reset the score */
625 rb->lcd_clear_display(); /* get rid of the text */
626 }
627 }
628 else {
629 if(down) /* player goes down */
630 padmove(&player->w_pad, MOVE_STEP);
631
632 if(up) /* player goes up */
633 padmove(&player->w_pad, -MOVE_STEP);
634 }
635}
636
637static int keys(struct pong *p)
638{
639 int key;
640#ifdef PONG_PAUSE
641 static bool pause = false;
642#endif
643
644 /* number of ticks this function will loop reading keys */
645#ifndef HAVE_TOUCHSCREEN
646 int time = 4;
647#else
648 int time = 1;
649#endif
650 int start = *rb->current_tick;
651 int end = start + time;
652
653 while(TIME_BEFORE(*rb->current_tick, end)) {
654 key = rb->button_get_w_tmo(end - *rb->current_tick);
655
656#ifdef HAVE_TOUCHSCREEN
657 short touch_x, touch_y;
658 if(key & BUTTON_TOUCHSCREEN)
659 {
660 struct player *player;
661 touch_x = rb->button_get_data() >> 16;
662 touch_y = rb->button_get_data() & 0xFFFF;
663
664 player = &p->player[0];
665 if(touch_x >= player->xpos && touch_x <= player->xpos+(PAD_WIDTH*4))
666 {
667 padmove(&player->w_pad, touch_y-(player->e_pad*2+PAD_HEIGHT)/2);
668 if (player->iscpu) {
669 /* if left player presses control keys stop cpu player */
670 player->iscpu = false;
671 p->player[0].score = p->player[1].score = 0; /* reset the score */
672 rb->lcd_clear_display(); /* get rid of the text */
673 }
674 }
675
676 player = &p->player[1];
677 if(touch_x >= player->xpos-(PAD_WIDTH*4) && touch_x <= player->xpos)
678 {
679 padmove(&player->w_pad, touch_y-(player->e_pad*2+PAD_HEIGHT)/2);
680 if (player->iscpu) {
681 /* if right player presses control keys stop cpu player */
682 player->iscpu = false;
683 p->player[0].score = p->player[1].score = 0; /* reset the score */
684 rb->lcd_clear_display(); /* get rid of the text */
685 }
686 }
687 }
688#endif
689
690#ifdef HAS_BUTTON_HOLD
691 if (rb->button_hold())
692 return 2; /* Pause game */
693#endif
694
695 if(key == PONG_QUIT
696#ifdef PONG_RC_QUIT
697 || key == PONG_RC_QUIT
698#endif
699 )
700 return 0; /* exit game NOW */
701
702#ifdef PONG_PAUSE
703 if(key == PONG_PAUSE)
704 pause = !pause;
705 if(pause)
706 return 2; /* Pause game */
707#endif
708
709 key = rb->button_status(); /* ignore BUTTON_REPEAT */
710
711 key_pad(p, 0, (key & PONG_LEFT_UP), (key & PONG_LEFT_DOWN));
712 key_pad(p, 1, (key & PONG_RIGHT_UP), (key & PONG_RIGHT_DOWN));
713
714 if(rb->default_event_handler(key) == SYS_USB_CONNECTED)
715 return -1; /* exit game because of USB */
716 }
717 return 1; /* return 0 to exit game */
718}
719
720static void showscore(struct pong *p)
721{
722 static char buffer[20];
723 int w;
724
725 rb->snprintf(buffer, sizeof(buffer), "%d - %d",
726 p->player[0].score, p->player[1].score);
727 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
728 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), 0, (unsigned char *)buffer);
729}
730
731static void blink_demo(void)
732{
733 static char buffer[30];
734 int w;
735
736 rb->snprintf(buffer, sizeof(buffer), "Press Key To Play");
737 w = rb->lcd_getstringsize((unsigned char *)buffer, NULL, NULL);
738 if(LCD_WIDTH > ( (w/8)*7 ) ) /* make sure text isn't too long for screen */
739 rb->lcd_putsxy( (LCD_WIDTH / 2) - (w / 2), (LCD_HEIGHT / 2),
740 (unsigned char *)buffer);
741}
742
743/* this is the plugin entry point */
744enum plugin_status plugin_start(const void* parameter)
745{
746 struct pong pong;
747 int game = 1;
748
749 int blink_timer = 0;
750 int blink_rate = 20;
751 bool blink = true;
752
753 /* init the struct with some silly values to start with */
754
755 pong.ball.x = 20*RES;
756 pong.ball.y = 20*RES;
757 pong.ball.speedx = SPEEDX;
758 pong.ball.speedy = SPEEDY;
759
760 pong.player[0].xpos = 0;
761 pong.player[0].e_pad = 0;
762 pong.player[0].w_pad = 7;
763 pong.player[1].xpos = LCD_WIDTH-PAD_WIDTH;
764 pong.player[1].e_pad = 0;
765 pong.player[1].w_pad = 40;
766
767 /* start every game in demo mode */
768 pong.player[0].iscpu = pong.player[1].iscpu = true;
769
770 pong.player[0].score = pong.player[1].score = 0; /* lets start at 0 - 0 ;-) */
771
772 /* if you don't use the parameter, you can do like
773 this to avoid the compiler warning about it */
774 (void)parameter;
775
776 /* Turn off backlight timeout */
777 backlight_ignore_timeout();
778
779 /* Clear screen */
780 rb->lcd_clear_display();
781
782 /* go go go */
783 while(game > 0) {
784 if( pong.player[0].iscpu && pong.player[1].iscpu ) {
785 if(blink_timer<blink_rate) {
786 ++blink_timer;
787 }
788 else {
789 blink_timer=0;
790 blink = !blink;
791 }
792
793 if(blink==true) {
794 blink_demo();
795 }
796 else {
797 rb->lcd_clear_display();
798 }
799 }
800
801 showscore(&pong);
802 pad(&pong, 0); /* draw left pad */
803 pad(&pong, 1); /* draw right pad */
804 ball(&pong); /* move and draw ball */
805
806 rb->lcd_update();
807
808 game = keys(&pong); /* deal with keys */
809
810 if (game == 2) { /* Game Paused */
811 rb->splash(0, "PAUSED");
812 while(game == 2)
813 game = keys(&pong); /* short circuit */
814 rb->lcd_clear_display();
815 }
816 }
817
818 /* Turn on backlight timeout (revert to settings) */
819 backlight_use_settings();
820
821 return (game == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
822}