1 #include "globals.h"
2 #include <assert.h>
3 #include <math.h>
4 #include "display_subsystem.h"
5 #include "game_state.h"
6 #include "highscore_io.h"
7 #include "input_functions.h"
8 #include "SFont.h"
9 #include "scroller.h"
10 #include "ship.h"
11 #include "sound.h"
12 
13 struct Setup_Data {
14   Scroller_t *scroller;
15   short current;
16   const char *entry_name;
17   const char *description; //!< will be in the scroller on the bottom of the screen
18   char *values[12];
19 };
20 
21 char *edition_name;
22 int xsize = 800;
23 int ysize = 600;
24 SDL_Surface *surf_screen = NULL;
25 SDL_Surface *surf_green_block = NULL;
26 SDL_Surface *surf_t_rock = NULL;	// Title element "rock"
27 SDL_Surface *surf_t_dodger = NULL;	// Title element "dodgers"
28 spacedots_t *current_spacedot_engine = NULL;
29 unsigned short opt_fullscreen = 1;
30 unsigned short opt_cicada_spacedots = 0;
31 unsigned short opt_intro = 2;
32 float movementrate;
33 float level = 0;
34 float shieldlevel, laserlevel, shieldpulse = 0;
35 int initialshield, gameover = 0;
36 
37 RD_VIDEO_TYPE heatcolor[W * 3];
38 
39 enum states state = TITLE_PAGE;	//!< current game state
40 float state_timeout = 600.0;	//!< timeout before next game state switch
41 float fadetimer = 0;
42 Uint32 initticks = 0;
43 Uint32 last_ticks = 0;
44 Uint32 ticks_since_last = 0;
45 Uint32 ign_k_utl_ticks = 0;
46 int music_volume = 128; //See sound.c...
47 int nships;
48 int last_levelup_snd;
49 uiff_ctx_t *iff_ctx;
50 
51 static const char resolution_format[] = "resolution = ( %d, %d )\n";
52 static const char spacedots_format[] = "spacedots = %31s\n";
53 static const char fullscreen_format[] = "fullscreen = %31s\n";
54 static const char intro_format[] = "intro = %31s\n";
55 static const char version_format[] = "version = %13s\n";
56 static const char music_volume_format[] = "musvol = %13s\n";
57 static char configuration_file_version[14];
58 
59 struct Setup_Data setup[] = {
60   { NULL, 0, "", "Use cursor keys to select and change options, press enter or F1 to quit the screen.", { "", NULL } },
61   { NULL, 0, "resolution", "Select the screen resolution!", { "", "640x480", "800x480", "800x600", "1024x768", "1152x864", "1280x1024", "1440x900", "1600x900", NULL } },
62   { NULL, 0, "fullscreen", "Use the full-screen display or windowed mode for rockdodger?", { "fullscreen", "windowed", NULL } },
63   { NULL, 0, "spacedots", "How are the spacedots (the little stars in the background) drawn? The classic version draws them directly into the surface, the cicada version uses surfaces (may be faster).", { "classic", "cicada", NULL } },
64   { NULL, 8, "music volume", "Set the volume for the background music.", { "0", "16", "32", "48", "64", "80", "96", "112", "128", "144", "160" } },
65   { NULL, 0, "intro", "Should the intro be displayed? The intro is usually only displayed for the first time after a version change.", { "no", "yes", NULL } },
66   { NULL, 0, "", "Rockdoger V"VERSION" compiled on "COMPILEDATE".", { "", NULL } },
67   { NULL, 0, "activate config?", "Set this to yes and press ENTER to activate the current configuration. Valid options are: 'no' keep old configuration, 'yes' activate configuration, 'yes and save' activate and save the configuration.", { "no", "yes", "yes and save", NULL } },
68   { NULL, 0, NULL }
69 };
70 #define SETUP_SIZE (sizeof(setup) / sizeof(struct Setup_Data))
71 
update_movement_rate()72 void update_movement_rate() {
73   ticks_since_last = SDL_GetTicks() - last_ticks;
74   last_ticks = SDL_GetTicks();
75   if(ticks_since_last > 200) {
76     movementrate = 0;
77   } else {
78     movementrate = ticks_since_last / 50.0;
79   }
80 }
81 
82 
cleanup_globals()83 void cleanup_globals() {
84   struct Setup_Data *setupptr;
85 
86   initticks = SDL_GetTicks();
87   for(setupptr = setup; setupptr->entry_name; ++setupptr) {
88     if(setupptr->scroller) {
89       destroy_scroller(setupptr->scroller);
90       setupptr->scroller = NULL;
91     }
92   }
93 }
94 
95 
find_setup_entry(const char * name)96 struct Setup_Data *find_setup_entry(const char *name) {
97   struct Setup_Data *setupptr;
98 
99   for(setupptr = setup; setupptr->entry_name; ++setupptr) {
100     if(strcmp(name, setupptr->entry_name) == 0) return setupptr;
101   }
102   return NULL;
103 }
104 
save_setup()105 void save_setup() {
106   FILE *f;
107   char buf[256];
108   struct Setup_Data *setupptr;
109 
110   snprintf(buf, sizeof(buf) - 1, "%s/.rockdodger", getenv("HOME"));
111   if((f = fopen(buf, "w")) == NULL) return;
112 #ifdef DEBUG
113   fprintf(stderr, "Writing config to '%s'.\n", buf);
114 #endif
115   fprintf(f, "#rockdodger configuration\n");
116   fprintf(f, version_format, VERSION);
117   fprintf(f, resolution_format, xsize, ysize);
118   //
119   setupptr = find_setup_entry("spacedots");
120   assert(setupptr);
121   fprintf(f, spacedots_format, setupptr->values[setupptr->current]);
122   //
123   setupptr = find_setup_entry("fullscreen");
124   assert(setupptr);
125   fprintf(f, fullscreen_format, setupptr->values[setupptr->current]);
126   //
127   setupptr = find_setup_entry("intro");
128   assert(setupptr);
129   fprintf(f, intro_format, setupptr->values[setupptr->current]);
130   //
131   setupptr = find_setup_entry("music volume");
132   assert(setupptr);
133   fprintf(f, music_volume_format, setupptr->values[setupptr->current]);
134   fclose(f);
135 }
136 
137 
load_setup()138 int load_setup() {
139   FILE *f;
140   char buf[256];
141   char inpbuf[32];
142   int x0, x1;
143 
144   snprintf(buf, sizeof(buf) - 1, "%s/.rockdodger", getenv("HOME"));
145   if(!(f = fopen(buf, "r"))) return 0;
146   while(fgets(buf, sizeof(buf), f) != NULL) {
147     if(strlen(buf) == 0 || buf[0] == '#') continue;
148     if(sscanf(buf, resolution_format, &x0, &x1) == 2) {
149       if(x0 > 0 && x1 > 0) {
150 	xsize = x0;
151 	ysize = x1;
152       }
153     } else if(sscanf(buf, spacedots_format, inpbuf) == 1) {
154       if(strcmp(inpbuf, "cicada") == 0)
155 	opt_cicada_spacedots = 1;
156       else
157 	opt_cicada_spacedots = 0;
158     } else if(sscanf(buf, fullscreen_format, inpbuf) == 1) {
159       if(strcmp(inpbuf, "fullscreen") == 0)
160 	opt_fullscreen = 1;
161       else
162 	opt_fullscreen = 0;
163     } else if(sscanf(buf, intro_format, inpbuf) == 1) {
164       if(opt_intro != 3) opt_intro = (strcmp(inpbuf, "yes") == 0) ? 1 : 0;
165     } else if(sscanf(buf, version_format, configuration_file_version) == 1) {
166       if(strcmp(configuration_file_version, VERSION) != 0) opt_intro = 3;
167     } else if(sscanf(buf, music_volume_format, inpbuf) == 1) {
168       music_volume = atoi(inpbuf);
169       //Check for illegal values. Oh boy, I am sooo lazy.
170       if(music_volume < 0) music_volume = 0;
171       else if(music_volume > 160) music_volume = 160;
172     } else {
173       printf("Unknown setup line '%s'.\n", buf);
174     }
175   }
176   fclose(f);
177   return 1;
178 }
179 
180 
setuploop()181 void setuploop() {
182   int i;
183   short old_config[SETUP_SIZE];
184   inputstate_t inputstate;
185   char txtbuf[181];
186   int crsrpos = 0;
187   struct Setup_Data *setupptr;
188   char resolution_buf[10];
189   short activate_config;
190   SDL_Rect drect = { 16, 0, 0, 0 };
191   SDL_Rect srect = { 0, 0, surf_screen->w - 32, 20 };
192 
193   play_tune(4);
194   for(i = 0; i < SETUP_SIZE; ++i) old_config[i] = setup[i].current;
195   state_timeout = 69105;
196   setupptr = find_setup_entry("music volume");
197   assert(setupptr);
198   setupptr->current = music_volume >> 4;
199   assert(setupptr->current < 11);
200   setupptr = find_setup_entry("fullscreen");
201   assert(setupptr);
202   setupptr->current = opt_fullscreen == 0 ? 1 : 0;
203   setupptr = find_setup_entry("intro");
204   assert(setupptr);
205   setupptr->current = opt_intro == 1 ? 1 : 0;
206   setupptr = find_setup_entry("spacedots");
207   assert(setupptr);
208   setupptr->current = opt_cicada_spacedots;
209   setupptr = find_setup_entry("resolution");
210   assert(setupptr);
211   sprintf(resolution_buf, "%dx%d", xsize, ysize);
212   setupptr->values[0] = resolution_buf;
213   while(state == SETUP) {
214     update_movement_rate();
215     (void) input_subsystem(&inputstate);
216     /* TODO: really not possible in setup? */
217     handle_state_timeout(0);
218     if(inputstate.inputstate[UP]) {
219       --crsrpos;
220       temporary_disable_key_input();
221     } else if(inputstate.inputstate[DOWN]) {
222       ++crsrpos;
223       temporary_disable_key_input();
224     } else if(inputstate.inputstate[RIGHT]) {
225       setupptr = setup + crsrpos;
226       if(setupptr->values[++setupptr->current] == NULL) setupptr->current = 0;
227       temporary_disable_key_input();
228     } else if(inputstate.inputstate[LEFT]) {
229       setupptr = setup + crsrpos;
230       if(--setupptr->current < 0) {
231 	while(setupptr->values[++setupptr->current]); //This will find the null pointer.
232 	--setupptr->current; //Now last entry.
233       }
234       temporary_disable_key_input();
235     } else if(inputstate.inputstate[INPUT_SELECT]) {
236       state = TITLE_PAGE;
237     }
238     /*
239      * If the cursor positon is less then zero set it to zero or if
240      * the position would be pointing to NULL which is the end of
241      * available options also ignore the keystroke. If the first
242      * character is less then a space then ignore it, too. We will use
243      * control characters for special use cases...
244      */
245     if(crsrpos < 0) crsrpos = 0;
246     else if(setup[crsrpos].entry_name == NULL || (setup[crsrpos].entry_name[0] < ' ' && setup[crsrpos].entry_name[0] != 0)) --crsrpos;
247     if(setup[crsrpos].scroller == NULL) {
248       setup[crsrpos].scroller = init_scroller(setup[crsrpos].description, surf_screen->h - 30, 4.62384, surf_screen->w);
249     }
250     //display subsystem
251     draw_background_objects();
252     XCenteredString(surf_screen, 20, "SETUP");
253     for(setupptr = setup, i = 0; setupptr->entry_name; ++setupptr, ++i) {
254       sprintf(txtbuf, "%-70s %12s", setupptr->entry_name, setupptr->values[setupptr->current]);
255       PutString(surf_screen, 20, 60 + i * 22, setupptr->entry_name);
256       PutString(surf_screen, surf_screen->w - 20 - SFont_wide(setupptr->values[setupptr->current]), 60 + i * 22, setupptr->values[setupptr->current]);
257       SDL_SetAlpha(surf_green_block, SDL_SRCALPHA, (int) (51.0 + 30.0 * sinf(fadetimer)));
258       drect.y = 60 + crsrpos * 22;
259       SDL_BlitSurface(surf_green_block, &srect, surf_screen, &drect);
260     }
261     assert(setup[crsrpos].scroller);
262     if(setup[crsrpos].scroller) update_and_draw_scroller(setup[crsrpos].scroller, surf_screen, movementrate);
263     // Update the surface
264     SDL_Flip(surf_screen);
265     fadetimer += movementrate / 8.2;
266   }
267   //We are leaving... check if activated
268   setupptr = find_setup_entry("activate config?");
269   assert(setupptr);
270   activate_config = setupptr->current;
271   assert(activate_config >= 0 && activate_config <= 2);
272   if(activate_config > 0) {
273     setupptr->current = 0;
274     //Activate
275     setupptr = find_setup_entry("resolution");
276     assert(setupptr);
277     if(setupptr->current > 0) {
278       i = sscanf(setupptr->values[setupptr->current], "%dx%d", &xsize, &ysize);
279       assert(i == 2);
280     }
281     setupptr = find_setup_entry("fullscreen");
282     assert(setupptr);
283     opt_fullscreen = setupptr->current == 0 ? 1 : 0; //0=fullscreen, 1=no fullscrenn, qed.
284     setupptr = find_setup_entry("spacedots");
285     assert(setupptr);
286     opt_cicada_spacedots = setupptr->current;
287     setupptr = find_setup_entry("music volume");
288     assert(setupptr);
289     music_volume = atoi(setupptr->values[setupptr->current]);
290     state = RESTART_GAME;
291   }
292   if(activate_config == 2) {
293     save_setup();
294   }
295   if(activate_config == 0)
296     for(i = 0; i < SETUP_SIZE; ++i) setup[i].current = old_config[i];
297   play_tune(0);
298   state_timeout = 496.69105;
299 }
300 
get_iff_rock(const char * fname)301 uiff_ctx_t *get_iff_rock(const char *fname) {
302   FILE *f = NULL;
303   uiff_ctx_t *ctx = NULL;
304 
305   printf("Rockdodger data file is '%s'.\n", fname);
306   if(!(f = fopen(fname, "r"))) {
307     perror("Can not open rockdodger data-file");
308   } else if((ctx = uiff_from_file(f, FORM, MakeID('R', 'O', 'C', 'K'))) == NULL) {
309     perror("No context");
310     fclose(f);
311   }
312   return ctx;
313 }
314 
load_edition_name(uiff_ctx_t iff)315 char *load_edition_name(uiff_ctx_t iff) {
316   int32_t chunksize;
317   char buf[33];
318   size_t bread;
319 
320   uiff_rewind_group(&iff);
321   chunksize = uiff_find_chunk_ctx(&iff, MakeID('E', 'D', 'T', 'N'));
322   assert(printf("FORM.ROCK EDTN size = %d\n", (int)chunksize));
323   if(chunksize < 0) {
324     edition_name = strcpy(buf, "#UNKNOWN#");
325   } else {
326     bread = fread(buf, 1, chunksize < sizeof(buf) - 1 ? chunksize : sizeof(buf) - 1, iff.f);
327     assert(bread < sizeof(buf) - 1);
328     buf[bread] = 0;
329   }
330   return strdup(buf);
331 }
332