1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
21 #ifdef HAVE_LCD_BITMAP
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 */
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
135 static struct plugin_api
* rb
;
138 int ballx
; /* current X*RES position of the ball */
139 int bally
; /* current Y*RES position of the ball */
140 int w_pad
[2]; /* wanted current Y positions of pads */
141 int e_pad
[2]; /* existing current Y positions of pads */
142 int ballspeedx
; /* */
143 int ballspeedy
; /* */
148 void singlepad(int x
, int y
, int set
)
151 rb
->lcd_fillrect(x
, y
, PAD_WIDTH
, PAD_HEIGHT
);
154 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
155 rb
->lcd_fillrect(x
, y
, PAD_WIDTH
, PAD_HEIGHT
);
156 rb
->lcd_set_drawmode(DRMODE_SOLID
);
160 void pad(struct pong
*p
, int pad
)
162 static int xpos
[2]={0, LCD_WIDTH
-PAD_WIDTH
};
164 /* clear existing pad */
165 singlepad(xpos
[pad
], p
->e_pad
[pad
], 0);
167 /* draw wanted pad */
168 singlepad(xpos
[pad
], p
->w_pad
[pad
], 1);
170 /* existing is now the wanted */
171 p
->e_pad
[pad
] = p
->w_pad
[pad
];
174 bool wallcollide(struct pong
*p
, int pad
)
176 /* we have already checked for pad-collision, just check if this hits
180 if(p
->ballx
> LCD_WIDTH
*RES
)
190 /* returns true if the ball has hit a pad, and then the info variable
191 will have extra angle info */
193 bool padcollide(struct pong
*p
, int pad
, int *info
)
195 int x
= p
->ballx
/RES
;
196 int y
= p
->bally
/RES
;
198 if((y
< (p
->e_pad
[pad
]+PAD_HEIGHT
)) &&
199 (y
+ BALL_HEIGHT
> p
->e_pad
[pad
])) {
200 /* Y seems likely right */
202 /* store the delta between ball-middle MINUS pad-middle, so
204 0 when the ball hits exactly the middle of the pad
205 positive numbers when the ball is below the middle of the pad
206 negative numbers when the ball is above the middle of the pad
208 max number is +- PAD_HEIGHT/2
211 *info
= (y
+BALL_HEIGHT
/2) - (p
->e_pad
[pad
] + PAD_HEIGHT
/2);
215 if((x
+ BALL_WIDTH
) >= (LCD_WIDTH
- PAD_WIDTH
))
216 return true; /* phump */
223 return false; /* nah */
226 void bounce(struct pong
*p
, int pad
, int info
)
228 (void)pad
; /* not used right now */
229 p
->ballspeedx
= -p
->ballspeedx
;
231 /* info is the hit-angle into the pad */
232 if(p
->ballspeedy
> 0) {
235 /* below the middle of the pad */
236 p
->ballspeedy
+= info
* RES
/3;
239 /* above the middle */
240 p
->ballspeedy
= info
* RES
/2;
246 /* below the middle of the pad */
247 p
->ballspeedy
= info
* RES
/2;
250 /* above the middle */
251 p
->ballspeedy
-= info
* RES
/3;
255 p
->ballspeedy
+= rb
->rand()%21-10;
258 fprintf(stderr
, "INFO: %d YSPEED: %d\n", info
, p
->ballspeedy
);
262 void score(struct pong
*p
, int pad
)
265 rb
->splash(HZ
/4, "right scores!");
267 rb
->splash(HZ
/4, "left scores!");
268 rb
->lcd_clear_display();
271 /* then move the X-speed of the ball and give it a random Y position */
272 p
->ballspeedx
= -p
->ballspeedx
;
273 p
->bally
= rb
->rand()%(LCD_HEIGHT
*RES
- BALL_HEIGHT
);
275 /* avoid hitting the pad with the new ball */
276 p
->ballx
= (p
->ballx
< 0) ?
277 (RES
* PAD_WIDTH
) : (RES
* (LCD_WIDTH
- PAD_WIDTH
- BALL_WIDTH
));
279 /* restore Y-speed to default */
280 p
->ballspeedy
= (p
->ballspeedy
> 0) ? SPEEDY
: -SPEEDY
;
282 /* set the existing pad positions to something weird to force pad
288 void ball(struct pong
*p
)
290 int x
= p
->ballx
/RES
;
291 int y
= p
->bally
/RES
;
299 p
->ballx
+= p
->ballspeedx
;
300 p
->bally
+= p
->ballspeedy
;
305 /* detect if ball hits a wall */
306 if(newy
+ BALL_HEIGHT
> LCD_HEIGHT
) {
307 /* hit floor, bounce */
308 p
->ballspeedy
= -p
->ballspeedy
;
309 newy
= LCD_HEIGHT
- BALL_HEIGHT
;
310 p
->bally
= newy
* RES
;
313 /* hit ceiling, bounce */
314 p
->ballspeedy
= -p
->ballspeedy
;
319 /* detect if ball hit pads */
320 if(padcollide(p
, 0, &info
))
322 else if(padcollide(p
, 1, &info
))
324 else if(wallcollide(p
, 0))
326 else if(wallcollide(p
, 1))
332 /* clear old position */
333 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
334 rb
->lcd_fillrect(x
, y
, BALL_WIDTH
, BALL_HEIGHT
);
335 rb
->lcd_set_drawmode(DRMODE_SOLID
);
337 /* draw the new ball position */
338 rb
->lcd_fillrect(newx
, newy
, BALL_WIDTH
, BALL_HEIGHT
);
341 void padmove(int *pos
, int dir
)
344 if(*pos
> (LCD_HEIGHT
-PAD_HEIGHT
))
345 *pos
= (LCD_HEIGHT
-PAD_HEIGHT
);
350 int keys(struct pong
*p
)
354 static bool pause
= false;
357 int time
= 4; /* number of ticks this function will loop reading keys */
358 int start
= *rb
->current_tick
;
359 int end
= start
+ time
;
361 while(end
> *rb
->current_tick
) {
362 key
= rb
->button_get_w_tmo(end
- *rb
->current_tick
);
364 #ifdef HAS_BUTTON_HOLD
365 if (rb
->button_hold())
366 return 2; /* Pause game */
371 || key
& PONG_RC_QUIT
374 return 0; /* exit game NOW */
377 if(key
== PONG_PAUSE
)
380 return 2; /* Pause game */
383 key
= rb
->button_status(); /* ignore BUTTON_REPEAT */
385 if(key
& PONG_LEFT_DOWN
) /* player left goes down */
386 padmove(&p
->w_pad
[0], MOVE_STEP
);
388 if(key
& PONG_LEFT_UP
) /* player left goes up */
389 padmove(&p
->w_pad
[0], -MOVE_STEP
);
391 if(key
& PONG_RIGHT_DOWN
) /* player right goes down */
392 padmove(&p
->w_pad
[1], MOVE_STEP
);
394 if(key
& PONG_RIGHT_UP
) /* player right goes up */
395 padmove(&p
->w_pad
[1], -MOVE_STEP
);
397 if(rb
->default_event_handler(key
) == SYS_USB_CONNECTED
)
398 return -1; /* exit game because of USB */
400 return 1; /* return 0 to exit game */
403 void showscore(struct pong
*p
)
405 static char buffer
[20];
408 rb
->snprintf(buffer
, sizeof(buffer
), "%d - %d", p
->score
[0], p
->score
[1]);
409 w
= rb
->lcd_getstringsize((unsigned char *)buffer
, NULL
, NULL
);
410 rb
->lcd_putsxy( (LCD_WIDTH
/ 2) - (w
/ 2), 0, (unsigned char *)buffer
);
413 /* this is the plugin entry point */
414 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
419 /* init the struct with some silly values to start with */
429 pong
.ballspeedx
= SPEEDX
;
430 pong
.ballspeedy
= SPEEDY
;
432 pong
.score
[0] = pong
.score
[1] = 0; /* lets start at 0 - 0 ;-) */
434 /* if you don't use the parameter, you can do like
435 this to avoid the compiler warning about it */
438 rb
= api
; /* use the "standard" rb pointer */
441 rb
->lcd_clear_display();
445 if (game
== 2) { /* Game Paused */
446 rb
->splash(0, "PAUSED");
448 game
= keys(&pong
); /* short circuit */
449 rb
->lcd_clear_display();
452 pad(&pong
, 0); /* draw left pad */
453 pad(&pong
, 1); /* draw right pad */
454 ball(&pong
); /* move and draw ball */
458 game
= keys(&pong
); /* deal with keys */
461 return (game
== 0) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
;
464 #endif /* HAVE_LCD_BITMAP */