Add AI to the pong plugin, to allow single-player operation.
[kugel-rb.git] / apps / plugins / credits.c
blob8f86c7626ba8daacf0b4cadcefe020fdc48facac
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Robert Hak <rhak at ramapo.edu>
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "lib/helper.h"
26 static const char* const credits[] = {
27 #include "credits.raw" /* generated list of names from docs/CREDITS */
30 #ifdef HAVE_LCD_CHARCELLS
32 static void roll_credits(void)
34 int numnames = sizeof(credits)/sizeof(char*);
35 int curr_name = 0;
36 int curr_len = rb->utf8length(credits[0]);
37 int curr_index = 0;
38 int curr_line = 0;
39 int name, len, new_len, line, x;
41 while (1)
43 rb->lcd_clear_display();
45 name = curr_name;
46 x = -curr_index;
47 len = curr_len;
48 line = curr_line;
50 while (x < 11)
52 int x2;
54 if (x < 0)
55 rb->lcd_puts(0, line,
56 credits[name] + rb->utf8seek(credits[name], -x));
57 else
58 rb->lcd_puts(x, line, credits[name]);
60 if (++name >= numnames)
61 break;
63 line ^= 1;
65 x2 = x + len/2;
66 if ((unsigned)x2 < 11)
67 rb->lcd_putc(x2, line, '*');
69 new_len = rb->utf8length(credits[name]);
70 x += MAX(len/2 + 2, len - new_len/2 + 1);
71 len = new_len;
73 rb->lcd_update();
75 /* abort on keypress */
76 if(rb->action_userabort(HZ/8))
77 return;
79 if (++curr_index >= curr_len)
81 if (++curr_name >= numnames)
82 break;
83 new_len = rb->utf8length(credits[curr_name]);
84 curr_index -= MAX(curr_len/2 + 2, curr_len - new_len/2 + 1);
85 curr_len = new_len;
86 curr_line ^= 1;
91 #else
93 static bool stop_autoscroll(int action)
95 switch (action)
97 case ACTION_STD_CANCEL:
98 case ACTION_STD_OK:
99 case ACTION_STD_NEXT:
100 case ACTION_STD_NEXTREPEAT:
101 case ACTION_STD_PREV:
102 case ACTION_STD_PREVREPEAT:
103 return true;
104 default:
105 return false;
107 return false;
110 static int update_rowpos(int action, int cur_pos, int rows_per_screen, int tot_rows)
112 switch(action)
114 case ACTION_STD_PREV:
115 case ACTION_STD_PREVREPEAT:
116 cur_pos--;
117 break;
118 case ACTION_STD_NEXT:
119 case ACTION_STD_NEXTREPEAT:
120 cur_pos++;
121 break;
124 if(cur_pos > tot_rows - rows_per_screen)
125 cur_pos = 0;
126 if(cur_pos < 0)
127 cur_pos = tot_rows - rows_per_screen;
129 return cur_pos;
132 static void roll_credits(void)
134 /* to do: use target defines iso keypads to set animation timings */
135 #if (CONFIG_KEYPAD == RECORDER_PAD)
136 #define PAUSE_TIME 1.2
137 #define ANIM_SPEED 35
138 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
139 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
140 #define PAUSE_TIME 0
141 #define ANIM_SPEED 100
142 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
143 #define PAUSE_TIME 0
144 #define ANIM_SPEED 35
145 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
146 #define PAUSE_TIME 0
147 #define ANIM_SPEED 100
148 #else
149 #define PAUSE_TIME 1
150 #define ANIM_SPEED 40
151 #endif
153 #define NUM_VISIBLE_LINES (LCD_HEIGHT/font_h - 1)
154 #define CREDITS_TARGETPOS ((LCD_WIDTH/2)-(credits_w/2))
156 int i=0, j=0, namepos=0, offset_dummy;
157 int name_w, name_h, name_targetpos=1, font_h;
158 int credits_w, credits_pos;
159 int numnames = (sizeof(credits)/sizeof(char*));
160 char name[40], elapsednames[32];
161 int action = ACTION_NONE;
163 /* control if scrolling is automatic (with animation) or manual */
164 bool manual_scroll = false;
166 rb->lcd_setfont(FONT_UI);
167 rb->lcd_clear_display();
168 rb->lcd_update();
170 rb->lcd_getstringsize("A", NULL, &font_h);
172 /* snprintf "credits" text, and save the width and height */
173 rb->snprintf(elapsednames, sizeof(elapsednames), "[Credits] %d/%d",
174 j+1, numnames);
175 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
177 /* fly in "credits" text from the left */
178 for(credits_pos = 0 - credits_w; credits_pos <= CREDITS_TARGETPOS;
179 credits_pos += (CREDITS_TARGETPOS-credits_pos + 14) / 7)
181 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
182 rb->lcd_fillrect(0, 0, LCD_WIDTH, font_h);
183 rb->lcd_set_drawmode(DRMODE_SOLID);
184 rb->lcd_putsxy(credits_pos, 0, elapsednames);
185 rb->lcd_update_rect(0, 0, LCD_WIDTH, font_h);
186 rb->sleep(HZ/ANIM_SPEED);
189 /* first screen's worth of lines fly in */
190 for(i=0; i<NUM_VISIBLE_LINES; i++)
192 rb->snprintf(name, sizeof(name), "%s", credits[i]);
193 rb->lcd_getstringsize(name, &name_w, &name_h);
195 rb->snprintf(elapsednames, sizeof(elapsednames), "[Credits] %d/%d",
196 i+1, numnames);
197 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
198 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
199 rb->lcd_update_rect(CREDITS_TARGETPOS, 0, credits_w, font_h);
201 for(namepos = 0-name_w; namepos <= name_targetpos;
202 namepos += (name_targetpos - namepos + 14) / 7)
204 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
205 /* clear any trails left behind */
206 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
207 rb->lcd_set_drawmode(DRMODE_SOLID);
208 rb->lcd_putsxy(namepos, font_h*(i+1), name);
209 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
211 /* exit on abort, switch to manual on up/down */
212 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
213 if(stop_autoscroll(action))
214 break;
216 if(stop_autoscroll(action))
217 break;
220 /* process user actions (if any) */
221 if(ACTION_STD_CANCEL == action)
222 return;
223 if(stop_autoscroll(action))
224 manual_scroll = true; /* up/down - abort was catched above */
226 if(!manual_scroll)
228 j+= i;
230 /* pause for a bit if needed */
231 action = rb->get_action(CONTEXT_LIST, HZ*PAUSE_TIME);
232 if(ACTION_STD_CANCEL == action)
233 return;
234 if(stop_autoscroll(action))
235 manual_scroll = true;
238 if(!manual_scroll)
240 while(j < numnames)
242 /* just a screen's worth at a time */
243 for(i=0; i<NUM_VISIBLE_LINES; i++)
245 if(j+i >= numnames)
246 break;
247 offset_dummy=1;
249 rb->snprintf(name, sizeof(name), "%s",
250 credits[j+i-NUM_VISIBLE_LINES]);
251 rb->lcd_getstringsize(name, &name_w, &name_h);
253 /* fly out an existing line.. */
254 while(namepos<LCD_WIDTH+offset_dummy)
256 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
257 /* clear trails */
258 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
259 rb->lcd_set_drawmode(DRMODE_SOLID);
260 rb->lcd_putsxy(namepos, font_h*(i+1), name);
261 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
263 /* exit on keypress, react to scrolling */
264 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
265 if(stop_autoscroll(action))
266 break;
268 namepos += offset_dummy;
269 offset_dummy++;
270 } /* while(namepos<LCD_WIDTH+offset_dummy) */
271 if(stop_autoscroll(action))
272 break;
274 rb->snprintf(name, sizeof(name), "%s", credits[j+i]);
275 rb->lcd_getstringsize(name, &name_w, &name_h);
277 rb->snprintf(elapsednames, sizeof(elapsednames),
278 "[Credits] %d/%d", j+i+1, numnames);
279 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
280 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
281 if (j+i < NUM_VISIBLE_LINES) /* takes care of trail on loop */
282 rb->lcd_update_rect(0, 0, LCD_WIDTH, font_h);
284 for(namepos = 0-name_w; namepos <= name_targetpos;
285 namepos += (name_targetpos - namepos + 14) / 7)
287 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
288 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
289 rb->lcd_set_drawmode(DRMODE_SOLID);
290 rb->lcd_putsxy(namepos, font_h*(i+1), name);
291 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
292 rb->lcd_update_rect(CREDITS_TARGETPOS, 0, credits_w,font_h);
294 /* stop on keypress */
295 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
296 if(stop_autoscroll(action))
297 break;
299 if(stop_autoscroll(action))
300 break;
301 namepos = name_targetpos;
302 } /* for(i=0; i<NUM_VISIBLE_LINES; i++) */
303 if(stop_autoscroll(action))
304 break;
306 action = rb->get_action(CONTEXT_LIST, HZ*PAUSE_TIME);
307 if(stop_autoscroll(action))
308 break;
310 j+=i; /* no user intervention, draw the next screen-full */
311 } /* while(j < numnames) */
313 /* handle the keypress that we intercepted during autoscroll */
314 if(ACTION_STD_CANCEL == action)
315 return;
316 if(stop_autoscroll(action))
317 manual_scroll = true;
318 } /* if(!manual_scroll) */
320 if(manual_scroll)
322 /* user went into manual scrolling, handle it here */
323 rb->lcd_set_drawmode(DRMODE_SOLID);
324 while(ACTION_STD_CANCEL != action)
326 rb->lcd_clear_display();
327 rb->snprintf(elapsednames, sizeof(elapsednames),
328 "[Credits] %d-%d/%d", j+1,
329 j+NUM_VISIBLE_LINES, numnames);
330 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
331 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
333 for(i=0; i<NUM_VISIBLE_LINES; i++)
334 rb->lcd_putsxyf(0, font_h*(i+1), "%s", credits[j+i]);
336 rb->lcd_update();
338 rb->yield();
340 /* wait for user action */
341 action = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK);
342 if(ACTION_STD_CANCEL == action)
343 return;
344 j = update_rowpos(action, j, NUM_VISIBLE_LINES, numnames);
346 return; /* exit without animation */
349 action = rb->get_action(CONTEXT_LIST, HZ*3);
350 if(ACTION_STD_CANCEL == action)
351 return;
353 offset_dummy = 1;
355 /* now make the text exit to the right */
356 for(credits_pos = (LCD_WIDTH/2)-(credits_w/2);
357 credits_pos <= LCD_WIDTH+offset_dummy;
358 credits_pos += offset_dummy, offset_dummy++)
360 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
361 rb->lcd_fillrect(0, 0, LCD_WIDTH, font_h);
362 rb->lcd_set_drawmode(DRMODE_SOLID);
363 rb->lcd_putsxy(credits_pos, 0, elapsednames);
364 rb->lcd_update();
368 #endif
370 enum plugin_status plugin_start(const void* parameter)
372 (void)parameter;
374 /* Turn off backlight timeout */
375 backlight_force_on(); /* backlight control in lib/helper.c */
377 rb->show_logo();
378 #ifdef HAVE_LCD_CHARCELLS
379 rb->lcd_double_height(false);
380 #endif
382 /* Show the logo for about 3 secs allowing the user to stop */
383 if(!rb->action_userabort(3*HZ))
384 roll_credits();
386 /* Turn on backlight timeout (revert to settings) */
387 backlight_use_settings(); /* backlight control in lib/helper.c */
389 return PLUGIN_OK;