1 #include "intro.h"
2 #include "datafun.h"
3 #include "guru_meditation.h"
4 #include "random_gen.h"
5 #include "SFont.h"
6 #include <assert.h>
7 #include <fcntl.h>
8 #include <math.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include "sparkles.h"
15 #include "blubats.h"
16 #include "display_subsystem.h"
17 #include "engine_exhaust.h"
18 #include "greeblies.h"
19 #include "globals.h"
20 #include "ship.h"
21 #include "sound.h"
22 
23 /*
24  * FORM.ROCK FORM.INTR is a FORM chunk with further data for the intro.
25  *
26  * . . TEXT	Chunk with further text for the scroller.
27  *
28  */
29 
30 
31 static struct {
32   SDL_Color min;
33   SDL_Color max;
34 } minmaxcolors[NUM_COPPERBARS] = {
35   { { 0x30, 0, 0 }, { 0xcf, 0x40, 0x4f } }, //Red
36   { { 0, 0x10, 0 }, { 0x11, 0xc0, 0xa } }, //Green
37   { { 0, 0, 0x40 }, { 0x7, 0x8, 0xaf } }, //Blue
38   { { 0xa, 0x1a, 0x13 }, { 0x12, 0xcd, 0xad } }, //Cyan
39   { { 1, 1, 1 }, { 0xc0, 0xc1, 0xc0 } }, //Gray
40   { { 0x10, 0x10, 0 }, { 0xc0, 0xbf, 0xa } } //Yellow
41 };
42 
43 char intro_default_text[] = "Exploding Rock Productions presents \"Rock Dodger\" V"VERSION".    "
44   "Press any key to continue!    "
45   "       %s        "
46   "Credits: Coding by Paul Holt, RPK. Music by Jack Beatmaster, Roz, Strobo, zake. Gfx: Paul Holt, RPK. Font: ripped from lib-sge.   "
47   "  A little bit of history: In 1984 Paul Holt programmed the first version of the game in his computer science class. The game was later (in 2001) ported to Linux and SDL. In December 2010 I (RPK) joined the project and started cleaning up the code and added the eye blink to the greeblies. In 2015 we moved the main development site to https://bitbucket.org/rpkrawczyk/rockdodger. And here we are... Enjoy!       "
48   ;
49 static char txtbuf[8001];
50 
51 
init_intro(SDL_Surface * target,uiff_ctx_t * iff)52 struct rockintro *init_intro(SDL_Surface *target, uiff_ctx_t *iff) {
53   int i, j, x, y;
54   int32_t chunksize;
55   SDL_Color colors[16];
56   SDL_Surface *surf;
57   char readbuf[sizeof(txtbuf) - sizeof(intro_default_text) - 3];
58   int xsize = target->w;
59   struct rockintro *rockiptr = calloc(sizeof(struct rockintro), 1);
60 
61   if(rockiptr) {
62     strcpy(txtbuf, "Intro data is kaputt...    Game may be borked...           ");
63     chunksize = uiff_find_group_ctx(iff, IFF_FIND_REWIND, FORM, MakeID('I', 'N', 'T', 'R'));
64     assert(printf("FORM.ROCK FORM.INTR size = $%08lX\n", (long)chunksize));
65     if(chunksize <= 0) {
66       guru_meditation(GM_FLAGS_RECOVERY | GM_FLAGS_CHOICE | GM_FLAGS_ABORTIFY, GM_SS_BootStrap | GM_GE_OpenRes | GURU_SEC_intro, &init_intro);
67     } else {
68       chunksize = uiff_find_chunk_wflags(iff, MakeID('T', 'E', 'X', 'T'), IFF_FIND_REWIND);
69       assert(printf(". . TEXT size = $%08lX\n", (long)chunksize));
70       if(chunksize > 0) {
71 	i = fread(readbuf, chunksize, 1, iff->f);
72 	if(i > 0 && i < sizeof(readbuf))
73 	  snprintf(txtbuf, sizeof(txtbuf), intro_default_text, readbuf);
74       } else guru_meditation(GM_FLAGS_RECOVERY | GM_FLAGS_CHOICE | GM_FLAGS_ABORTIFY, GM_SS_BootStrap | GM_GE_IOError | GURU_SEC_intro, &init_intro);
75     }
76 
77     if((surf = load_image("exploding_rock.png", 0, 0xff, 0)) != NULL) {
78       rockiptr->intro_image = SDL_DisplayFormat(surf);
79       SDL_FreeSurface(surf);
80     } else return NULL;
81 
82     rockiptr->scroller = init_scroller(txtbuf, 440, 3.141, target->w);
83     if(rockiptr->scroller == NULL) return NULL;
84     for(i = 0; i < NUM_COPPERBARS; ++i) {
85       rockiptr->positions[i] = 2 * M_PI / NUM_COPPERBARS * i;
86       rockiptr->speeds[i] = 1.9 / 30.0;
87 
88       for(j = 0; j < 8; ++j) {
89 	SDL_Color col;
90 	unsigned u;
91 
92 	u = (8 - j) * minmaxcolors[i].min.r;
93 	u += j * minmaxcolors[i].max.r;
94 	col.r = u / 8;
95 	u = (8 - j ) * minmaxcolors[i].min.g;
96 	u += j * minmaxcolors[i].max.g;
97 	col.g = u / 8;
98 	u = (8 - j ) * minmaxcolors[i].min.b;
99 	u += j * minmaxcolors[i].max.b;
100 	u /= 8;
101 	col.b = u;
102 	colors[j] = col;
103       }
104 
105       surf = SDL_CreateRGBSurface(SDL_HWSURFACE, xsize, 16, 8, 0, 0, 0, 0);
106       if(surf == NULL) return NULL;
107       SDL_LockSurface(surf);
108       SDL_SetColors(surf, colors, 0, 16);
109       for(y = 0; y < 8; ++y) {
110 	for(x = 0; x < xsize; ++x) {
111 	  Uint8 *pixels = surf->pixels;
112 
113 	  pixels[y * surf->w + x] = y;
114 	  pixels[(15 - y) * surf->w + x] = y;
115 	}
116       }
117       SDL_UnlockSurface(surf);
118       rockiptr->copperbars[i] = SDL_DisplayFormat(surf);
119       SDL_SetAlpha(rockiptr->copperbars[i], SDL_SRCALPHA|SDL_RLEACCEL, 141);
120       SDL_FreeSurface(surf);
121     }
122   } else { // No memory...
123     guru_alert(GM_FLAGS_DEADEND, GM_SS_BootStrap | GM_GE_NoMemory | GURU_SEC_intro, &init_intro);
124   }
125   return rockiptr;
126 }
127 
128 
fld_logo(struct rockintro * intro,SDL_Surface * target,float movementrate)129 void fld_logo(struct rockintro *intro, SDL_Surface *target, float movementrate) {
130   int rastline;
131   SDL_Surface *lsurf = intro->intro_image;
132   SDL_Rect r = { (target->w - 640) / 2, 0, 0, 0 };
133   SDL_Rect s = { 0, 0, lsurf->w, 1};
134 
135   if(intro->fld_amplitude <= 0) {
136     s.h = lsurf->h;
137     SDL_BlitSurface(intro->intro_image, NULL, target, &r);
138   } else {
139     float phi = intro->fld_logophase;
140     float tline = intro->fld_logo_wagging_amplitude * sinf(phi);
141     float camp = intro->fld_amplitude; // cosine amplitude
142 
143     intro->fld_last_topline = (int)tline;
144     for(rastline = 0; rastline < lsurf->h; ++rastline) {
145       s.y = rastline;
146       r.y = tline;
147       SDL_BlitSurface(intro->intro_image, &s, target, &r);
148       tline += 1 + camp + cosf(phi) * camp;
149       phi += 1.0 / 200.0 * M_PI;
150     }
151     intro->fld_logophase += movementrate / 11;
152   }
153 }
154 
155 
update_and_draw_intro(struct rockintro * intro,SDL_Surface * target,float movementrate)156 void update_and_draw_intro(struct rockintro *intro, SDL_Surface *target, float movementrate) {
157   int i, j;
158   float z_positions[NUM_COPPERBARS];
159   Sint16 y_positions[NUM_COPPERBARS];
160   int minimum = 0;
161   SDL_Rect r = { 0, 0, 0, 0 };
162 
163   for(i = 0; i < NUM_COPPERBARS; ++i) {
164     y_positions[i] = sinf(intro->positions[i]) * 40 + 440;
165     z_positions[i] = cosf(intro->positions[i]);
166     intro->positions[i] += intro->speeds[i] * movementrate;
167   }
168   for(i = 0; i < NUM_COPPERBARS; ++i) {
169     minimum = 0;
170     for(j = 1; j < NUM_COPPERBARS; ++j) if(z_positions[j] < z_positions[minimum]) minimum = j;
171     r.y = y_positions[minimum];
172     SDL_BlitSurface(intro->copperbars[minimum], NULL, target, &r);
173     z_positions[minimum] = 666;
174   }
175   fld_logo(intro, target, movementrate);
176   update_and_draw_scroller(intro->scroller, target, movementrate * 1.412);
177   draw_sparkles(target);
178   update_sparkles(target);
179 }
180 
shutdown_intro(struct rockintro * intro)181 void shutdown_intro(struct rockintro *intro) {
182   int i;
183 
184   for(i = 0; i < NUM_COPPERBARS; ++i) {
185     SDL_FreeSurface(i[intro->copperbars]);
186   }
187   destroy_scroller(intro->scroller);
188   SDL_FreeSurface(intro->intro_image);
189   reset_sparkles();
190   free(intro);
191 }
192 
193 
play_intro(int force,int oss_sound_flag,uiff_ctx_t iff)194 void play_intro(int force, int oss_sound_flag, uiff_ctx_t iff) {
195   SDL_Event event;
196   int state;
197   register int i;
198   int last_state = -1;
199   int running = 1;
200   SDL_Surface *surf_screen = SDL_GetVideoSurface();
201   short deltah, heading = 0;
202   float *fp;
203 
204   if(force == 0) {
205     switch(opt_intro) {
206     case 3:
207     case 2:
208       //Do not bug user again...
209       opt_intro = 0;
210       save_setup();
211     case 1:
212       break;
213     case 0:
214       return;
215     default:
216       assert(0);
217       return;
218     }
219   }
220 
221   struct rockintro *intro = init_intro(surf_screen, &iff);
222   if(intro == NULL) {
223     fprintf(stderr, "Can not initialise intro!\n");
224     return;
225   }
226   if(oss_sound_flag) play_tune(3);
227 
228   while(running) {
229     while(SDL_PollEvent(&event) != 0) {
230       if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_KEYDOWN) running = 0;
231     }
232     ticks_since_last = SDL_GetTicks() - last_ticks;
233     last_ticks = SDL_GetTicks();
234     if(ticks_since_last > 200) {
235       movementrate = 0;
236     } else {
237       movementrate = ticks_since_last / 50.0;
238     }
239     SDL_FillRect(surf_screen, NULL, SDL_MapRGB(surf_screen->format, 0, 0, 0));
240     update_and_draw_intro(intro, surf_screen, movementrate);
241     state = (last_ticks / 0x1BC6) % 10;
242     if(state != last_state) {
243       switch(state) {
244       case 6:
245 	shipdata.xship = -37;
246 	shipdata.yship = 225;
247 	break;
248       case 5:
249 	shipdata.xship = -37;
250 	shipdata.yship = 370;
251 	break;
252       case 1:
253 	shipdata.xship = -37;
254 	shipdata.yship = 80;
255 	break;
256       case 3:
257 	while(activate_one_blubat());
258 	shipdata.xship = xsize / 2;
259 	shipdata.yship = ysize + 42;
260 	break;
261       }
262       last_state = state;
263     }
264     SDL_LockSurface(surf_screen);
265     draw_engine_dots(surf_screen);
266     SDL_UnlockSurface(surf_screen);
267     switch(state) {
268     case 5:
269     case 1:
270     case 6:
271       draw_ship(surf_screen);
272       create_engine_dots(220);
273       shipdata.xship += movementrate * 6.08 * surf_screen->w / 800.0; //Ship should have the same speed, regardless of the screen size.
274       if(shipdata.xship > xsize + 40) shipdata.xship = -40;
275       break;
276     case 2:
277       draw_ghostly_rock_dodger(surf_t_rock, surf_t_dodger);
278       fadetimer += movementrate / 1.92;
279       break;
280     case 3:
281       display_blubats(surf_screen);
282       move_all_blubats();
283       break;
284     case 4:
285       draw_ghostly_rock_dodger(surf_t_rock, surf_t_dodger);
286       fadetimer += movementrate / 1.41;
287       break;
288     case 7:
289     case 8:
290       deltah = (surf_screen->w - 640) / 2;
291       i = intro->fld_last_topline;
292       create_plumedots(7, 168 + deltah, i + 47, -heading, 4, 8);
293       create_plumedots(7, surf_screen->w - 158 - deltah, i + 47, heading, 4, 8);
294       heading += 2;
295       break;
296     case 9:
297       fp = &intro->fld_logo_wagging_amplitude;
298       if(*fp < 20) *fp += movementrate / 61.51;
299       fp = &intro->fld_amplitude;
300       if(*fp < 1.0 / 5.014847583) *fp += movementrate / 77.8111472142;
301       break;
302     }
303     SDL_Flip(surf_screen);
304   }
305   init_engine_dots();
306   deactivate_all_blubats();
307   shutdown_intro(intro);
308   fadetimer = 0; //Reset the fade timer as the title page will otherwise not begin correctly. See display_version_n_text().
309 }
310