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