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 #define PONG_QUIT BUTTON_SELECT
82 #define PONG_LEFT_UP BUTTON_MENU
83 #define PONG_LEFT_DOWN BUTTON_LEFT
84 #define PONG_RIGHT_UP BUTTON_RIGHT
85 #define PONG_RIGHT_DOWN BUTTON_PLAY
87 #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
88 #define PONG_QUIT BUTTON_POWER
89 #define PONG_LEFT_UP BUTTON_UP
90 #define PONG_LEFT_DOWN BUTTON_DOWN
91 #define PONG_RIGHT_UP BUTTON_REC
92 #define PONG_RIGHT_DOWN BUTTON_PLAY
94 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
95 #define PONG_QUIT BUTTON_A
96 #define PONG_PAUSE BUTTON_MENU
97 #define PONG_LEFT_UP BUTTON_UP
98 #define PONG_LEFT_DOWN BUTTON_DOWN
99 #define PONG_RIGHT_UP BUTTON_POWER
100 #define PONG_RIGHT_DOWN BUTTON_MENU
102 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
103 #define PONG_QUIT BUTTON_POWER
104 #define PONG_PAUSE BUTTON_SELECT
105 #define PONG_LEFT_UP BUTTON_LEFT
106 #define PONG_LEFT_DOWN BUTTON_DOWN
107 #define PONG_RIGHT_UP BUTTON_UP
108 #define PONG_RIGHT_DOWN BUTTON_RIGHT
110 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
111 #define PONG_QUIT BUTTON_POWER
112 #define PONG_LEFT_UP BUTTON_SCROLL_UP
113 #define PONG_LEFT_DOWN BUTTON_SCROLL_DOWN
114 #define PONG_RIGHT_UP BUTTON_REW
115 #define PONG_RIGHT_DOWN BUTTON_FF
119 static struct plugin_api
* rb
;
122 int ballx
; /* current X*RES position of the ball */
123 int bally
; /* current Y*RES position of the ball */
124 int w_pad
[2]; /* wanted current Y positions of pads */
125 int e_pad
[2]; /* existing current Y positions of pads */
126 int ballspeedx
; /* */
127 int ballspeedy
; /* */
132 void singlepad(int x
, int y
, int set
)
135 rb
->lcd_fillrect(x
, y
, PAD_WIDTH
, PAD_HEIGHT
);
138 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
139 rb
->lcd_fillrect(x
, y
, PAD_WIDTH
, PAD_HEIGHT
);
140 rb
->lcd_set_drawmode(DRMODE_SOLID
);
144 void pad(struct pong
*p
, int pad
)
146 static int xpos
[2]={0, LCD_WIDTH
-PAD_WIDTH
};
148 /* clear existing pad */
149 singlepad(xpos
[pad
], p
->e_pad
[pad
], 0);
151 /* draw wanted pad */
152 singlepad(xpos
[pad
], p
->w_pad
[pad
], 1);
154 /* existing is now the wanted */
155 p
->e_pad
[pad
] = p
->w_pad
[pad
];
158 bool wallcollide(struct pong
*p
, int pad
)
160 /* we have already checked for pad-collision, just check if this hits
164 if(p
->ballx
> LCD_WIDTH
*RES
)
174 /* returns true if the ball has hit a pad, and then the info variable
175 will have extra angle info */
177 bool padcollide(struct pong
*p
, int pad
, int *info
)
179 int x
= p
->ballx
/RES
;
180 int y
= p
->bally
/RES
;
182 if((y
< (p
->e_pad
[pad
]+PAD_HEIGHT
)) &&
183 (y
+ BALL_HEIGHT
> p
->e_pad
[pad
])) {
184 /* Y seems likely right */
186 /* store the delta between ball-middle MINUS pad-middle, so
188 0 when the ball hits exactly the middle of the pad
189 positive numbers when the ball is below the middle of the pad
190 negative numbers when the ball is above the middle of the pad
192 max number is +- PAD_HEIGHT/2
195 *info
= (y
+BALL_HEIGHT
/2) - (p
->e_pad
[pad
] + PAD_HEIGHT
/2);
199 if((x
+ BALL_WIDTH
) >= (LCD_WIDTH
- PAD_WIDTH
))
200 return true; /* phump */
207 return false; /* nah */
210 void bounce(struct pong
*p
, int pad
, int info
)
212 (void)pad
; /* not used right now */
213 p
->ballspeedx
= -p
->ballspeedx
;
215 /* info is the hit-angle into the pad */
216 if(p
->ballspeedy
> 0) {
219 /* below the middle of the pad */
220 p
->ballspeedy
+= info
* RES
/3;
223 /* above the middle */
224 p
->ballspeedy
= info
* RES
/2;
230 /* below the middle of the pad */
231 p
->ballspeedy
= info
* RES
/2;
234 /* above the middle */
235 p
->ballspeedy
-= info
* RES
/3;
239 p
->ballspeedy
+= rb
->rand()%21-10;
242 fprintf(stderr
, "INFO: %d YSPEED: %d\n", info
, p
->ballspeedy
);
246 void score(struct pong
*p
, int pad
)
248 rb
->splash(HZ
/4, true, "%s scores!", pad
?"right":"left");
249 rb
->lcd_clear_display();
252 /* then move the X-speed of the ball and give it a random Y position */
253 p
->ballspeedx
= -p
->ballspeedx
;
254 p
->bally
= rb
->rand()%(LCD_HEIGHT
*RES
- BALL_HEIGHT
);
256 /* avoid hitting the pad with the new ball */
257 p
->ballx
= (p
->ballx
< 0) ?
258 (RES
* PAD_WIDTH
) : (RES
* (LCD_WIDTH
- PAD_WIDTH
- BALL_WIDTH
));
260 /* restore Y-speed to default */
261 p
->ballspeedy
= (p
->ballspeedy
> 0) ? SPEEDY
: -SPEEDY
;
263 /* set the existing pad positions to something weird to force pad
269 void ball(struct pong
*p
)
271 int x
= p
->ballx
/RES
;
272 int y
= p
->bally
/RES
;
280 p
->ballx
+= p
->ballspeedx
;
281 p
->bally
+= p
->ballspeedy
;
286 /* detect if ball hits a wall */
287 if(newy
+ BALL_HEIGHT
> LCD_HEIGHT
) {
288 /* hit floor, bounce */
289 p
->ballspeedy
= -p
->ballspeedy
;
290 newy
= LCD_HEIGHT
- BALL_HEIGHT
;
291 p
->bally
= newy
* RES
;
294 /* hit ceiling, bounce */
295 p
->ballspeedy
= -p
->ballspeedy
;
300 /* detect if ball hit pads */
301 if(padcollide(p
, 0, &info
))
303 else if(padcollide(p
, 1, &info
))
305 else if(wallcollide(p
, 0))
307 else if(wallcollide(p
, 1))
313 /* clear old position */
314 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
315 rb
->lcd_fillrect(x
, y
, BALL_WIDTH
, BALL_HEIGHT
);
316 rb
->lcd_set_drawmode(DRMODE_SOLID
);
318 /* draw the new ball position */
319 rb
->lcd_fillrect(newx
, newy
, BALL_WIDTH
, BALL_HEIGHT
);
322 void padmove(int *pos
, int dir
)
325 if(*pos
> (LCD_HEIGHT
-PAD_HEIGHT
))
326 *pos
= (LCD_HEIGHT
-PAD_HEIGHT
);
331 int keys(struct pong
*p
)
335 static bool pause
= false;
338 int time
= 4; /* number of ticks this function will loop reading keys */
339 int start
= *rb
->current_tick
;
340 int end
= start
+ time
;
342 while(end
> *rb
->current_tick
) {
343 key
= rb
->button_get_w_tmo(end
- *rb
->current_tick
);
345 #ifdef HAS_BUTTON_HOLD
346 if (rb
->button_hold())
347 return 2; /* Pause game */
352 || key
& PONG_RC_QUIT
355 return 0; /* exit game NOW */
358 if(key
== PONG_PAUSE
)
361 return 2; /* Pause game */
364 key
= rb
->button_status(); /* ignore BUTTON_REPEAT */
366 if(key
& PONG_LEFT_DOWN
) /* player left goes down */
367 padmove(&p
->w_pad
[0], MOVE_STEP
);
369 if(key
& PONG_LEFT_UP
) /* player left goes up */
370 padmove(&p
->w_pad
[0], -MOVE_STEP
);
372 if(key
& PONG_RIGHT_DOWN
) /* player right goes down */
373 padmove(&p
->w_pad
[1], MOVE_STEP
);
375 if(key
& PONG_RIGHT_UP
) /* player right goes up */
376 padmove(&p
->w_pad
[1], -MOVE_STEP
);
378 if(rb
->default_event_handler(key
) == SYS_USB_CONNECTED
)
379 return -1; /* exit game because of USB */
381 return 1; /* return 0 to exit game */
384 void showscore(struct pong
*p
)
386 static char buffer
[20];
389 rb
->snprintf(buffer
, sizeof(buffer
), "%d - %d", p
->score
[0], p
->score
[1]);
390 w
= rb
->lcd_getstringsize((unsigned char *)buffer
, NULL
, NULL
);
391 rb
->lcd_putsxy( (LCD_WIDTH
/ 2) - (w
/ 2), 0, (unsigned char *)buffer
);
394 /* this is the plugin entry point */
395 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
400 /* init the struct with some silly values to start with */
410 pong
.ballspeedx
= SPEEDX
;
411 pong
.ballspeedy
= SPEEDY
;
413 pong
.score
[0] = pong
.score
[1] = 0; /* lets start at 0 - 0 ;-) */
415 /* if you don't use the parameter, you can do like
416 this to avoid the compiler warning about it */
419 rb
= api
; /* use the "standard" rb pointer */
422 rb
->lcd_clear_display();
426 if (game
== 2) { /* Game Paused */
427 rb
->splash(0, true, "PAUSED");
429 game
= keys(&pong
); /* short circuit */
430 rb
->lcd_clear_display();
433 pad(&pong
, 0); /* draw left pad */
434 pad(&pong
, 1); /* draw right pad */
435 ball(&pong
); /* move and draw ball */
439 game
= keys(&pong
); /* deal with keys */
442 return (game
== 0) ? PLUGIN_OK
: PLUGIN_USB_CONNECTED
;
445 #endif /* HAVE_LCD_BITMAP */