1 #include "title.h"
2 #include "data.h"
3 #include "star.h"
4 #include "display.h"
5 #include "dirty.h"
6
7 /* for parsing readme.txt */
8 typedef struct TEXT_LIST {
9 char *text;
10 struct TEXT_LIST *next;
11 } TEXT_LIST;
12
13 typedef struct README_SECTION {
14 TEXT_LIST *head;
15 TEXT_LIST *tail;
16 char *flat;
17 char *desc;
18 } README_SECTION;
19
20 /* for parsing thanks._tx and the various source files */
21 typedef struct CREDIT_NAME {
22 char *name;
23 char *text;
24 TEXT_LIST *files;
25 struct CREDIT_NAME *next;
26 } CREDIT_NAME;
27
28 /* text messages (loaded from readme.txt) */
29 static char *title_text;
30 static int title_size;
31 static int title_alloced;
32
33 static char *end_text;
34
35 static PALETTE title_palette;
36
37 /* author credits scroller */
38 static int credit_width = 0;
39 static int credit_scroll = 0;
40 static int credit_offset = 0;
41 static int credit_age = 0;
42 static int credit_speed = 32;
43 static int credit_skip = 1;
44
45 /* text scroller at the bottom */
46 static int text_scroll = 0;
47 static BITMAP *text_bmp;
48 static int text_char;
49 static int text_pix;
50 static int text_width;
51
52 CREDIT_NAME *credit_name = NULL;
53
54 static CREDIT_NAME *credits = NULL;
55
56 /* timer callback for controlling the speed of the scrolling text */
57 static volatile int scroll_count;
58
59
60
scroll_counter(void)61 static void scroll_counter(void)
62 {
63 scroll_count++;
64 }
65 END_OF_STATIC_FUNCTION(scroll_counter);
66
67
68
69 /* helper to find a file or directory in the Allegro tree */
find_relative_path(char buf[],size_t bufsize,const char * name)70 static int find_relative_path(char buf[], size_t bufsize, const char *name)
71 {
72 static const char *locations[] = {
73 "",
74 "../",
75 "../../", /* Allegro root, no build directory */
76 "../../../", /* Allegro root, with build directory */
77 "../../../../", /* Allegro root, MSVC build configuration directory */
78 NULL
79 };
80 char exe[256];
81 char dir[256];
82 int i;
83
84 get_executable_name(exe, sizeof(exe));
85 for (i = 0; locations[i] != NULL; i++) {
86 replace_filename(dir, exe, locations[i], sizeof(dir));
87 append_filename(buf, dir, name, bufsize);
88 if (file_exists(buf, FA_ALL, NULL)) {
89 return 1;
90 }
91 }
92
93 return 0;
94 }
95
96
97
98 /* helper to open readme.txt and thanks._tx */
open_relative_file(char buf[],size_t size,const char * name)99 static PACKFILE *open_relative_file(char buf[], size_t size, const char *name)
100 {
101 if (find_relative_path(buf, size, name))
102 return pack_fopen(buf, F_READ);
103
104 return NULL;
105 }
106
107
108
109 /* formats a list of TEXT_LIST structure into a single string */
format_text(TEXT_LIST * head,char * eol,char * gap)110 static char *format_text(TEXT_LIST * head, char *eol, char *gap)
111 {
112 TEXT_LIST *l;
113 int size = 0;
114 char *s;
115
116 l = head;
117 while (l) {
118 if (l->text[0])
119 size += strlen(l->text) + strlen(eol);
120 else
121 size += strlen(gap) + strlen(eol);
122 l = l->next;
123 }
124
125 s = malloc(size + 1);
126 s[0] = 0;
127
128 l = head;
129 while (l) {
130 if (l->text[0])
131 strcat(s, l->text);
132 else
133 strcat(s, gap);
134 strcat(s, eol);
135 l = l->next;
136 }
137
138 return s;
139 }
140
141
142
143 /* loads the scroller message from readme.txt */
load_text(void)144 static void load_text(void)
145 {
146 README_SECTION sect[] = {
147 {NULL, NULL, NULL, "Introduction"},
148 {NULL, NULL, NULL, "Features"},
149 {NULL, NULL, NULL, "Copyright"},
150 {NULL, NULL, NULL, "Contact info"}
151 };
152
153 #define SPLITTER " "
154
155 static char intro_msg[] =
156 "Welcome to the Allegro demonstration game, by Shawn Hargreaves."
157 SPLITTER
158 "Your mission: to go where no man has gone before, to seek out strange new life, and to boldly blast it to smithereens."
159 SPLITTER
160 "Your controls: the arrow keys to move left and right, the up arrow to accelerate (the faster you go, the more score you get), and the space bar to fire."
161 SPLITTER
162 "What complexity!"
163 SPLITTER
164 "What subtlety."
165 SPLITTER
166 "What originality."
167 SPLITTER "But enough of that. On to the serious stuff..." SPLITTER;
168
169 static char splitter[] = SPLITTER;
170 static char marker[] = "--------";
171 char buf[256];
172 README_SECTION *sec = NULL;
173 TEXT_LIST *l, *p;
174 PACKFILE *f;
175 int inblank = TRUE;
176 char *s;
177 int i;
178
179 f = open_relative_file(buf, sizeof(buf), "docs/txt/readme.txt");
180 if (!f) {
181 title_text =
182 "Can't find readme.txt, so this scroller is empty. ";
183 title_size = strlen(title_text);
184 title_alloced = FALSE;
185 end_text = NULL;
186 return;
187 }
188
189 while (pack_fgets(buf, sizeof(buf) - 1, f) != 0) {
190 if (buf[0] == '=') {
191 s = strchr(buf, ' ');
192 if (s) {
193 for (i = strlen(s) - 1; (uisspace(s[i])) || (s[i] == '='); i--)
194 s[i] = 0;
195
196 s++;
197
198 sec = NULL;
199 inblank = TRUE;
200
201 for (i = 0; i < (int)(sizeof(sect) / sizeof(sect[0])); i++) {
202 if (stricmp(s, sect[i].desc) == 0) {
203 sec = §[i];
204 break;
205 }
206 }
207 }
208 }
209 else if (sec) {
210 s = buf;
211
212 while ((*s) && (uisspace(*s)))
213 s++;
214
215 for (i = strlen(s) - 1; (i >= 0) && (uisspace(s[i])); i--)
216 s[i] = 0;
217
218 if ((s[0]) || (!inblank)) {
219 l = malloc(sizeof(TEXT_LIST));
220 l->next = NULL;
221 l->text = malloc(strlen(s) + 1);
222 strcpy(l->text, s);
223
224 if (sec->tail)
225 sec->tail->next = l;
226 else
227 sec->head = l;
228
229 sec->tail = l;
230 }
231
232 inblank = (s[0] == 0);
233 }
234 }
235
236 pack_fclose(f);
237
238 if (sect[2].head)
239 end_text = format_text(sect[2].head, "\n", "");
240 else
241 end_text = NULL;
242
243 title_size = strlen(intro_msg);
244
245 for (i = 0; i < (int)(sizeof(sect) / sizeof(sect[0])); i++) {
246 if (sect[i].head) {
247 sect[i].flat = format_text(sect[i].head, " ", splitter);
248 title_size += strlen(sect[i].flat) + strlen(sect[i].desc) +
249 strlen(splitter) + strlen(marker) * 2 + 2;
250 }
251 }
252
253 title_text = malloc(title_size + 1);
254 title_alloced = TRUE;
255
256 strcpy(title_text, intro_msg);
257
258 for (i = 0; i < (int)(sizeof(sect) / sizeof(sect[0])); i++) {
259 if (sect[i].flat) {
260 strcat(title_text, marker);
261 strcat(title_text, " ");
262 strcat(title_text, sect[i].desc);
263 strcat(title_text, " ");
264 strcat(title_text, marker);
265 strcat(title_text, splitter);
266 strcat(title_text, sect[i].flat);
267 }
268 }
269
270 for (i = 0; i < (int)(sizeof(sect) / sizeof(sect[0])); i++) {
271 l = sect[i].head;
272 while (l) {
273 free(l->text);
274 p = l;
275 l = l->next;
276 free(p);
277 }
278 if (sect[i].flat)
279 free(sect[i].flat);
280 }
281 }
282
283
284
285 /* reads credit info from a source file */
parse_source(AL_CONST char * filename,int attrib,void * param)286 static int parse_source(AL_CONST char *filename, int attrib, void *param)
287 {
288 char buf[256];
289 PACKFILE *f;
290 CREDIT_NAME *c;
291 TEXT_LIST *d;
292 char *p;
293
294 if (attrib & FA_DIREC) {
295 p = get_filename(filename);
296
297 if ((stricmp(p, ".") != 0) && (stricmp(p, "..") != 0) &&
298 (stricmp(p, "lib") != 0) && (stricmp(p, "obj") != 0)) {
299
300 /* recurse inside a directory */
301 strcpy(buf, filename);
302 put_backslash(buf);
303 strcat(buf, "*.*");
304
305 for_each_file_ex(buf, 0, ~(FA_ARCH | FA_RDONLY | FA_DIREC),
306 parse_source, param);
307 }
308 }
309 else {
310 p = get_extension(filename);
311
312 if ((stricmp(p, "c") == 0) || (stricmp(p, "cpp") == 0) ||
313 (stricmp(p, "h") == 0) || (stricmp(p, "inc") == 0) ||
314 (stricmp(p, "s") == 0) || (stricmp(p, "asm") == 0)) {
315
316 /* parse a source file */
317 f = pack_fopen(filename, F_READ);
318 if (!f)
319 return -1;
320
321 textprintf_centre_ex(screen, font, SCREEN_W / 2, SCREEN_H / 2 + 8,
322 makecol(160, 160, 160), 0,
323 " %s ",
324 filename + (int)(unsigned long)param);
325
326 while (pack_fgets(buf, sizeof(buf) - 1, f) != 0) {
327 if (strstr(buf, "*/"))
328 break;
329
330 c = credits;
331
332 while (c) {
333 if (strstr(buf, c->name)) {
334 for (d = c->files; d; d = d->next) {
335 if (strcmp
336 (d->text,
337 filename + (int)(unsigned long)param) == 0)
338 break;
339 }
340
341 if (!d) {
342 d = malloc(sizeof(TEXT_LIST));
343 d->text =
344 malloc(strlen
345 (filename + (int)(unsigned long)param) +
346 1);
347 strcpy(d->text, filename + (int)(unsigned long)param);
348 d->next = c->files;
349 c->files = d;
350 }
351 }
352
353 c = c->next;
354 }
355 }
356
357 pack_fclose(f);
358 }
359 }
360
361 return 0;
362 }
363
364
365
366 /* sorts a list of text strings */
sort_text_list(TEXT_LIST ** head)367 static void sort_text_list(TEXT_LIST ** head)
368 {
369 TEXT_LIST **prev, *p;
370 int done;
371
372 do {
373 done = TRUE;
374
375 prev = head;
376 p = *head;
377
378 while ((p) && (p->next)) {
379 if (stricmp(p->text, p->next->text) > 0) {
380 *prev = p->next;
381 p->next = p->next->next;
382 (*prev)->next = p;
383 p = *prev;
384
385 done = FALSE;
386 }
387
388 prev = &p->next;
389 p = p->next;
390 }
391
392 } while (!done);
393 }
394
395
396
397 /* sorts a list of credit strings */
sort_credit_list(void)398 static void sort_credit_list(void)
399 {
400 CREDIT_NAME **prev, *p;
401 TEXT_LIST *t;
402 int n, done;
403
404 do {
405 done = TRUE;
406
407 prev = &credits;
408 p = credits;
409
410 while ((p) && (p->next)) {
411 n = 0;
412
413 for (t = p->files; t; t = t->next)
414 n--;
415
416 for (t = p->next->files; t; t = t->next)
417 n++;
418
419 if (n == 0)
420 n = stricmp(p->name, p->next->name);
421
422 if (n > 0) {
423 *prev = p->next;
424 p->next = p->next->next;
425 (*prev)->next = p;
426 p = *prev;
427
428 done = FALSE;
429 }
430
431 prev = &p->next;
432 p = p->next;
433 }
434
435 } while (!done);
436 }
437
438
439
440 /* reads credit info from various places */
load_credits(void)441 static void load_credits(void)
442 {
443 static int once = FALSE;
444 char buf[256], buf2[256], *p, *p2;
445 CREDIT_NAME *c = NULL;
446 PACKFILE *f;
447
448 if (once)
449 return;
450 once = TRUE;
451
452 textout_centre_ex(screen, font, "Scanning for author credits...",
453 SCREEN_W / 2, SCREEN_H / 2 - 16, makecol(160, 160,
454 160), 0);
455
456 load_text();
457
458 /* Don't load top scroller with small screens. */
459 if (SCREEN_W < 640)
460 return;
461
462 /* parse thanks._tx */
463 f = open_relative_file(buf, sizeof(buf), "docs/src/thanks._tx");
464 if (!f)
465 return;
466
467 while (pack_fgets(buf, sizeof(buf) - 1, f) != 0) {
468 if (stricmp(buf, "Thanks!") == 0)
469 break;
470
471 while ((p = strstr(buf, "<")) != NULL) {
472 *p = '<';
473 memmove(p + 1, p + 3, strlen(p + 2));
474 }
475
476 while ((p = strstr(buf, ">")) != NULL) {
477 *p = '>';
478 memmove(p + 1, p + 3, strlen(p + 2));
479 }
480
481 p = buf;
482
483 while ((*p) && (uisspace(*p)))
484 p++;
485
486 p2 = p;
487
488 while ((*p2) && ((!uisspace(*p2)) || (*(p2 + 1) != '(')))
489 p2++;
490
491 if ((strncmp(p2, " (<email>", 9) == 0) ||
492 (strncmp(p2, " (email", 7) == 0)) {
493 *p2 = 0;
494
495 c = malloc(sizeof(CREDIT_NAME));
496
497 c->name = malloc(strlen(p) + 1);
498 strcpy(c->name, p);
499
500 c->text = NULL;
501 c->files = NULL;
502
503 c->next = credits;
504 credits = c;
505 }
506 else if (*p) {
507 if (c) {
508 p2 = p + strlen(p) - 1;
509 while ((p2 > p) && (uisspace(*p2)))
510 *(p2--) = 0;
511
512 if (c->text) {
513 c->text = realloc(c->text, strlen(c->text) + strlen(p) + 2);
514 strcat(c->text, " ");
515 strcat(c->text, p);
516 }
517 else {
518 c->text = malloc(strlen(p) + 1);
519 strcpy(c->text, p);
520 }
521 }
522 }
523 else
524 c = NULL;
525 }
526
527 pack_fclose(f);
528
529 /* parse source files from root of Allegro directory down */
530 if (find_relative_path(buf2, sizeof(buf2), "src")) {
531 replace_filename(buf, buf2, "*.*", sizeof(buf));
532 for_each_file_ex(buf, 0, ~(FA_ARCH | FA_RDONLY | FA_DIREC),
533 parse_source,
534 (void *)(unsigned long)(strlen(buf2) - 3));
535 }
536
537 /* sort the lists */
538 sort_credit_list();
539
540 for (c = credits; c; c = c->next) {
541 sort_text_list(&c->files);
542 }
543 }
544
545
546
scroller(void)547 static void scroller(void)
548 {
549 int c, n;
550 TEXT_LIST *tl;
551
552 starfield_3d();
553
554 /* move the scroller at the bottom */
555 text_scroll++;
556
557 /* update the credits position */
558 if (credit_scroll <= 0) {
559 if (credit_name)
560 credit_name = credit_name->next;
561
562 if (!credit_name)
563 credit_name = credits;
564
565 if (credit_name) {
566 credit_width =
567 text_length(data[TITLE_FONT].dat, credit_name->name) + 24;
568
569 if (credit_name->text)
570 credit_scroll = strlen(credit_name->text) * 8 + SCREEN_W -
571 credit_width + 64;
572 else
573 credit_scroll = 256;
574
575 tl = credit_name->files;
576 n = 0;
577
578 while (tl) {
579 n++;
580 tl = tl->next;
581 }
582
583 credit_offset = 0;
584
585 if (n) {
586 credit_skip = 1 + n / 50;
587 credit_speed =
588 8 + fixtoi(fixdiv(itofix(512), itofix(n)));
589 if (credit_speed > 200)
590 credit_speed = 200;
591 c = 1024 + (n - 1) * credit_speed;
592 if (credit_scroll < c) {
593 credit_offset = credit_scroll - c;
594 credit_scroll = c;
595 }
596 }
597
598 credit_age = 0;
599 }
600 }
601 else {
602 credit_scroll--;
603 credit_age++;
604 }
605 }
606
607
608
draw_scroller(BITMAP * bmp)609 static void draw_scroller(BITMAP *bmp)
610 {
611 /* for the text scroller */
612 char buf[2] = " ";
613 TEXT_LIST *tl;
614 int n, n2, c, c2, c3;
615 char *p;
616 char cbuf[2] = " ";
617 FONT *bigfont = data[TITLE_FONT].dat;
618 int th = text_height(bigfont);
619
620 /* draw the text scroller at the bottom */
621 blit(text_bmp, text_bmp, text_scroll, 0, 0, 0, SCREEN_W, th);
622 rectfill(text_bmp, SCREEN_W - text_scroll, 0, SCREEN_W, th, 0);
623
624 while (text_scroll > 0) {
625 text_pix += text_scroll;
626 if (text_char >= 0)
627 buf[0] = title_text[text_char];
628 textout_ex(text_bmp, bigfont, buf,
629 SCREEN_W - text_pix, 0, -1, 0);
630 if (text_pix >= text_width) {
631 text_scroll = text_pix - text_width;
632 text_char++;
633 if (text_char >= title_size)
634 text_char = 0;
635 buf[0] = title_text[text_char];
636 text_pix = 0;
637 text_width = text_length(data[TITLE_FONT].dat, buf);
638 }
639 else
640 text_scroll = 0;
641 }
642
643 blit(text_bmp, bmp, 0, 0, 0, SCREEN_H - th, SCREEN_W, th);
644 if (animation_type == DIRTY_RECTANGLE)
645 dirty_rectangle(0, SCREEN_H - th, SCREEN_W, th);
646
647 /* draw author file credits */
648 if (credit_name) {
649 int x, y, z;
650 int ix, iy;
651 tl = credit_name->files;
652 n = credit_width;
653 n2 = 0;
654
655 while (tl) {
656 c = 1024 + n2 * credit_speed - credit_age;
657
658 if ((c > 0) && (c < 1024) && ((n2 % credit_skip) == 0)) {
659 x = itofix(SCREEN_W / 2);
660 y = itofix(SCREEN_H / 2 - 32);
661
662 c2 = c * ((n / 13) % 17 + 1) / 32;
663 if (n & 1)
664 c2 = -c2;
665
666 c2 -= 96;
667
668 c3 = (32 +
669 fixtoi(ABS(fixsin(itofix(c / (15 + n % 42) + n))) *
670 128)) * SCREEN_W / 640;
671
672 x += fixsin(itofix(c2)) * c3;
673 y += fixcos(itofix(c2)) * c3;
674
675 if (c < 512) {
676 z = fixsqrt(itofix(c) / 512);
677
678 x = fixmul(itofix(32), itofix(1) - z) + fixmul(x, z);
679 y = fixmul(itofix(16), itofix(1) - z) + fixmul(y, z);
680 }
681 else if (c > 768) {
682 z = fixsqrt(itofix(1024 - c) / 256);
683
684 if (n & 2)
685 x = fixmul(itofix(128), itofix(1) - z) + fixmul(x, z);
686 else
687 x = fixmul(itofix(SCREEN_W - 128),
688 itofix(1) - z) + fixmul(x, z);
689
690 y = fixmul(itofix(SCREEN_H - 128),
691 itofix(1) - z) + fixmul(y, z);
692 }
693
694 c = 128 + (512 - ABS(512 - c)) / 24;
695 c = MIN(255, c * 1.25);
696
697 ix = fixtoi(x);
698 iy = fixtoi(y);
699
700 c2 = strlen(tl->text);
701 ix -= c2 * 4;
702
703 textout_ex(bmp, font, tl->text, ix, iy, c, 0);
704 if (animation_type == DIRTY_RECTANGLE)
705 dirty_rectangle(ix, iy, c2 * 8, 8);
706 }
707
708 tl = tl->next;
709 n += 1234567;
710 n2++;
711 }
712 }
713
714 draw_starfield_3d(bmp);
715
716 /* draw author name/desc credits */
717 if (credit_name) {
718 if (credit_name->text) {
719 c = credit_scroll + credit_offset;
720 p = credit_name->text;
721 c2 = strlen(p);
722
723 if (c > 0) {
724 if (c2 > c / 8) {
725 p += c2 - c / 8;
726 c &= 7;
727 }
728 else {
729 c -= c2 * 8;
730 }
731
732 c += credit_width;
733
734 while ((*p) && (c < SCREEN_W - 32)) {
735 if (c < credit_width + 96)
736 c2 = 128 + (c - credit_width - 32) * 127 / 64;
737 else if (c > SCREEN_W - 96)
738 c2 = 128 + (SCREEN_W - 32 - c) * 127 / 64;
739 else
740 c2 = 255;
741
742 if ((c2 > 128) && (c2 <= 255)) {
743 cbuf[0] = *p;
744 textout_ex(bmp, font, cbuf, c, 16, c2, 0);
745 }
746
747 p++;
748 c += 8;
749 }
750 }
751 }
752
753 c = 4;
754
755 if (credit_age < 100)
756 c -= (100 - credit_age) * (100 -
757 credit_age) * credit_width / 10000;
758
759 if (credit_scroll < 150)
760 c += (150 - credit_scroll) * (150 -
761 credit_scroll) * SCREEN_W /
762 22500;
763
764 textprintf_ex(bmp, data[TITLE_FONT].dat, c, 4, -1, 0, "%s:",
765 credit_name->name);
766 if (animation_type == DIRTY_RECTANGLE)
767 dirty_rectangle(0, 4, SCREEN_W, text_height(data[TITLE_FONT].dat));
768 }
769
770 /* draw the Allegro logo over the top */
771 draw_sprite(bmp, data[TITLE_BMP].dat, SCREEN_W / 2 - 160,
772 SCREEN_H / 2 - 96);
773 }
774
775
776
777 /* displays the title screen */
title_screen(void)778 int title_screen(void)
779 {
780 static int color = 0;
781 int c;
782 BITMAP *bmp;
783 RGB rgb;
784 int updated;
785 int scroll_pos = 0;
786
787 text_scroll = 0;
788 credit_width = 0;
789 credit_scroll = 0;
790 credit_offset = 0;
791 credit_age = 0;
792 credit_speed = 32;
793 credit_skip = 1;
794
795 text_char = -1;
796 text_pix = 0;
797 text_width = 0;
798 text_bmp = create_bitmap(SCREEN_W, 24);
799 clear_bitmap(text_bmp);
800
801 play_midi(data[TITLE_MUSIC].dat, TRUE);
802 play_sample(data[WELCOME_SPL].dat, 255, 127, 1000, FALSE);
803
804 load_credits();
805
806 init_starfield_3d();
807
808 for (c = 0; c < 8; c++)
809 title_palette[c] = ((RGB *) data[TITLE_PAL].dat)[c];
810
811 /* set up the colors differently each time we display the title screen */
812 for (c = 8; c < PAL_SIZE / 2; c++) {
813 rgb = ((RGB *) data[TITLE_PAL].dat)[c];
814 switch (color) {
815 case 0:
816 rgb.b = rgb.r;
817 rgb.r = 0;
818 break;
819 case 1:
820 rgb.g = rgb.r;
821 rgb.r = 0;
822 break;
823 case 3:
824 rgb.g = rgb.r;
825 break;
826 }
827 title_palette[c] = rgb;
828 }
829
830 for (c = PAL_SIZE / 2; c < PAL_SIZE; c++)
831 title_palette[c] = ((RGB *) data[TITLE_PAL].dat)[c];
832
833 color++;
834 if (color > 3)
835 color = 0;
836
837 clear_display();
838
839 set_palette(title_palette);
840
841 LOCK_VARIABLE(scroll_count);
842 LOCK_FUNCTION(scroll_counter);
843 scroll_count = 1;
844 install_int(scroll_counter, 5);
845
846 while ((c = scroll_count) < 160)
847 stretch_blit(data[TITLE_BMP].dat, screen, 0, 0, 320, 128,
848 SCREEN_W / 2 - c, SCREEN_H / 2 - c * 64 / 160 - 32,
849 c * 2, c * 128 / 160);
850
851 remove_int(scroll_counter);
852
853 blit(data[TITLE_BMP].dat, screen, 0, 0, SCREEN_W / 2 - 160,
854 SCREEN_H / 2 - 96, 320, 128);
855
856 clear_keybuf();
857
858 scroll_count = 0;
859
860 install_int(scroll_counter, 6);
861
862 do {
863 updated = 0;
864 while (scroll_pos <= scroll_count) {
865 scroller();
866 scroll_pos++;
867 updated = 1;
868 }
869
870 if (max_fps || updated) {
871 bmp = prepare_display();
872 draw_scroller(bmp);
873 flip_display();
874 }
875
876 /* rest for a short while if we're not in CPU-hog mode and too fast */
877 if (!max_fps && !updated) {
878 rest(1);
879 }
880
881 poll_joystick();
882
883 } while ((!keypressed()) && (!joy[0].button[0].b)
884 && (!joy[0].button[1].b));
885
886 remove_int(scroll_counter);
887
888 fade_out(5);
889
890 destroy_bitmap(text_bmp);
891
892 while (keypressed())
893 if ((readkey() & 0xff) == 27)
894 return FALSE;
895
896 return TRUE;
897 }
898
899
900
end_title(void)901 void end_title(void)
902 {
903 CREDIT_NAME *cred;
904 TEXT_LIST *tl;
905
906 if (end_text) {
907 allegro_message("%shttp://alleg.sourceforge.net/\n\n", end_text);
908 free(end_text);
909 }
910
911 if ((title_text) && (title_alloced))
912 free(title_text);
913
914 while (credits) {
915 cred = credits;
916 credits = cred->next;
917
918 if (cred->name)
919 free(cred->name);
920
921 if (cred->text)
922 free(cred->text);
923
924 while (cred->files) {
925 tl = cred->files;
926 cred->files = tl->next;
927
928 if (tl->text)
929 free(tl->text);
930
931 free(tl);
932 }
933
934 free(cred);
935 }
936 }
937
938