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