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
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
157 #error No keymap defined!
160 static struct plugin_api
* rb
;
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
; /* */
173 void singlepad(int x
, int y
, int set
)
176 rb
->lcd_fillrect(x
, y
, PAD_WIDTH
, PAD_HEIGHT
);
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
205 if(p
->ballx
> LCD_WIDTH
*RES
)
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
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);
240 if((x
+ BALL_WIDTH
) >= (LCD_WIDTH
- PAD_WIDTH
))
241 return true; /* phump */
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) {
260 /* below the middle of the pad */
261 p
->ballspeedy
+= info
* RES
/3;
264 /* above the middle */
265 p
->ballspeedy
= info
* RES
/2;
271 /* below the middle of the pad */
272 p
->ballspeedy
= info
* RES
/2;
275 /* above the middle */
276 p
->ballspeedy
-= info
* RES
/3;
280 p
->ballspeedy
+= rb
->rand()%21-10;
283 fprintf(stderr
, "INFO: %d YSPEED: %d\n", info
, p
->ballspeedy
);
287 void score(struct pong
*p
, int pad
)
290 rb
->splash(HZ
/4, "right scores!");
292 rb
->splash(HZ
/4, "left scores!");
293 rb
->lcd_clear_display();
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
313 void ball(struct pong
*p
)
315 int x
= p
->ballx
/RES
;
316 int y
= p
->bally
/RES
;
324 p
->ballx
+= p
->ballspeedx
;
325 p
->bally
+= p
->ballspeedy
;
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
;
338 /* hit ceiling, bounce */
339 p
->ballspeedy
= -p
->ballspeedy
;
344 /* detect if ball hit pads */
345 if(padcollide(p
, 0, &info
))
347 else if(padcollide(p
, 1, &info
))
349 else if(wallcollide(p
, 0))
351 else if(wallcollide(p
, 1))
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
)
369 if(*pos
> (LCD_HEIGHT
-PAD_HEIGHT
))
370 *pos
= (LCD_HEIGHT
-PAD_HEIGHT
);
375 int keys(struct pong
*p
)
379 static bool pause
= false;
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 */
396 || key
& PONG_RC_QUIT
399 return 0; /* exit game NOW */
402 if(key
== PONG_PAUSE
)
405 return 2; /* Pause game */
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];
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
)
444 /* init the struct with some silly values to start with */
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 */
463 rb
= api
; /* use the "standard" rb pointer */
466 rb
->lcd_clear_display();
470 if (game
== 2) { /* Game Paused */
471 rb
->splash(0, "PAUSED");
473 game
= keys(&pong
); /* short circuit */
474 rb
->lcd_clear_display();
477 pad(&pong
, 0); /* draw left pad */
478 pad(&pong
, 1); /* draw right pad */
479 ball(&pong
); /* move and draw ball */
483 game
= keys(&pong
); /* deal with keys */
486 return (game
== 0) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
;
489 #endif /* HAVE_LCD_BITMAP */