A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 822 lines 24 kB view raw
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}