2009050
[gdash.git] / src / sdlmain.c
blobec20c75c440fbf51a6275e16273e47769e24948f
1 /*
2 * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include <SDL/SDL.h>
17 #include <glib.h>
18 #include <glib/gi18n.h>
19 #include "config.h"
20 #include "cave.h"
21 #include "caveobject.h"
22 #include "caveengine.h"
23 #include "cavesound.h"
24 #include "cavedb.h"
25 #include "caveset.h"
26 #include "c64import.h"
27 #include "settings.h"
28 #include "util.h"
29 #include "gameplay.h"
30 #include "sdlgfx.h"
31 #include "sdlui.h"
32 #include "sound.h"
33 #include "about.h"
36 static int cavenum;
37 static int levelnum;
39 static char *username;
43 static void
44 game_help()
46 const char* strings_menu[]={
47 gd_key_name(gd_sdl_key_left), "MOVE LEFT",
48 gd_key_name(gd_sdl_key_right), "MOVE RIGHT",
49 gd_key_name(gd_sdl_key_up), "MOVE UP",
50 gd_key_name(gd_sdl_key_down), "MOVE DOWN",
51 gd_key_name(gd_sdl_key_fire_1), "FIRE (SNAP)",
52 gd_key_name(gd_sdl_key_suicide), "SUICIDE",
53 "", "",
54 "F", "FAST FORWARD (HOLD)",
55 "SHIFT", "STATUS BAR (HOLD)",
56 "", "",
57 "SPACE", "PAUSE",
58 "ESC", "RESTART LEVEL",
59 "I", "CAVE INFO",
60 "", "",
61 "F1", "MAIN MENU",
62 "CTRL-Q", "QUIT PROGRAM",
63 NULL
66 gd_help(strings_menu);
73 static void
74 showheader_pause(GdStatusBarColors *cols)
76 gd_clear_header(cols->background);
77 gd_blittext(gd_screen, -1, gd_statusbar_mid, cols->default_color, "SPACEBAR TO RESUME");
80 static void
81 showheader_gameover(GdStatusBarColors *cols)
83 gd_clear_header(cols->background);
84 gd_blittext(gd_screen, -1, gd_statusbar_mid, cols->default_color, "G A M E O V E R");
88 /* generate an user event */
89 static Uint32
90 timer_callback(Uint32 interval, void *param)
92 SDL_Event ev;
94 ev.type=SDL_USEREVENT;
95 SDL_PushEvent(&ev);
97 return interval;
101 /* the game itself */
102 static void
103 play_game_func(GdGame *game)
105 gboolean toggle=FALSE; /* this is used to divide the rate of the user interrupt by 2, if no fine scrolling requested */
106 gboolean exit_game;
107 gboolean show_highscore;
108 int statusbar_since=0; /* count number of frames from when the outoftime or paused event happened. */
109 gboolean paused;
110 SDL_TimerID tim;
111 SDL_Event event;
112 gboolean restart, suicide; /* for sdl key_downs */
113 GdStatusBarColors cols_struct;
114 GdStatusBarColors *cols=&cols_struct;
115 char *wrapped;
117 /* install the sdl timer which will generate events to control the speed of the game and drawing, at an 50hz rate; 1/50hz=20ms */
118 tim=SDL_AddTimer(20, timer_callback, NULL);
120 suicide=FALSE; /* detected suicide and restart level keys */
121 restart=FALSE;
122 exit_game=FALSE;
123 show_highscore=FALSE;
124 paused=FALSE;
125 while (!exit_game && SDL_WaitEvent(&event)) {
126 GdGameState state;
127 GdDirection player_move;
129 switch(event.type) {
130 case SDL_QUIT: /* application closed by window manager */
131 gd_quit=TRUE;
132 exit_game=TRUE;
133 break;
135 case SDL_KEYDOWN:
136 switch(event.key.keysym.sym) {
137 case SDLK_ESCAPE:
138 restart=TRUE;
139 break;
140 case SDLK_F1:
141 exit_game=TRUE;
142 break;
143 case SDLK_q:
144 if (gd_keystate[SDLK_LCTRL]||gd_keystate[SDLK_RCTRL]) {
145 gd_quit=TRUE;
146 exit_game=TRUE;
148 break;
149 case SDLK_i:
150 gd_show_cave_info(game->original_cave);
151 break;
152 case SDLK_SPACE:
153 paused=!paused;
154 if (paused) {
155 statusbar_since=0; /* count frames "paused" */
156 gd_sound_off(); /* if paused, no sound. */
158 break;
159 case SDLK_F2:
160 suicide=TRUE;
161 break;
162 case SDLK_h:
163 gd_sound_off(); /* switch off sounds when showing help. */
164 game_help();
165 /* no need to turn on sounds; next cave iteration will restore them. */
166 /* also, do not worry about 25hz user events, as the help function will simply drop them. */
167 break;
168 default:
169 break;
171 break;
173 case SDL_USEREVENT:
174 /* get movement */
175 player_move=gd_direction_from_keypress(gd_up(), gd_down(), gd_left(), gd_right());
176 /* tell the interrupt "20ms has passed" */
177 state=gd_game_main_int(game, 20, player_move, gd_fire(), suicide, restart, !paused && !game->out_of_window, FALSE, gd_keystate[SDLK_f]);
179 /* state of game, returned by gd_game_main_int */
180 switch (state) {
181 case GD_GAME_INVALID_STATE:
182 g_assert_not_reached();
183 break;
185 case GD_GAME_SHOW_STORY:
186 gd_dark_screen();
187 gd_title_line(game->cave->name);
188 gd_status_line("FIRE: CONTINUE");
189 wrapped=gd_wrap_text(game->cave->story->str, gd_screen->w/gd_font_width()-2);
190 gd_blittext_n(gd_screen, gd_font_width(), gd_line_height()*2, GD_GDASH_LIGHTBLUE, wrapped);
191 g_free(wrapped);
192 break;
194 case GD_GAME_CAVE_LOADED:
195 /* select colors, prepare drawing etc. */
196 gd_select_pixbuf_colors(game->cave->color0, game->cave->color1, game->cave->color2, game->cave->color3, game->cave->color4, game->cave->color5);
197 gd_scroll_to_origin();
198 SDL_FillRect(gd_screen, NULL, SDL_MapRGB(gd_screen->format, 0, 0, 0)); /* fill whole gd_screen with black - cave might be smaller than previous! */
199 /* select status bar colors here, as some depend on actual cave colors */
200 gd_play_game_select_status_bar_colors(cols, game->cave);
201 gd_showheader_uncover(game, cols, TRUE); /* true = show "playing replay" if necessary */
202 suicide=FALSE; /* clear detected keypresses, so we do not "remember" them from previous cave runs */
203 restart=FALSE;
204 break;
206 case GD_GAME_NOTHING:
207 /* normally continue. */
208 break;
210 case GD_GAME_LABELS_CHANGED:
211 gd_showheader_game(game, statusbar_since, cols, TRUE); /* true = show "playing replay" if necessary */
212 suicide=FALSE; /* clear detected keypresses, as cave was iterated and they were processed */
213 break;
215 case GD_GAME_TIMEOUT_NOW:
216 statusbar_since=0;
217 gd_showheader_game(game, statusbar_since, cols, TRUE); /* also update the status bar here. */ /* true = show "playing replay" if necessary */
218 suicide=FALSE; /* clear detected keypresses, as cave was iterated and they were processed */
219 break;
221 case GD_GAME_NO_MORE_LIVES:
222 showheader_gameover(cols);
223 break;
225 case GD_GAME_STOP:
226 exit_game=TRUE; /* game stopped, this could be a replay or a snapshot */
227 break;
229 case GD_GAME_GAME_OVER:
230 exit_game=TRUE;
231 show_highscore=TRUE; /* normal game stopped, may jump to highscore later. */
232 break;
235 statusbar_since++;
237 /* for the sdl version, it seems nicer if we first scroll, and then draw. */
238 /* scrolling for the sdl version will merely invalidate the whole gfx buffer. */
239 /* if drawcave was before scrolling, it would draw, scroll would invalidate, and then it should be drawn again */
240 /* only do the drawing if the cave already exists. */
241 toggle=!toggle;
242 if (game->gfx_buffer) {
243 /* if fine scrolling, scroll at 50hz. if not, only scroll at every second call, so 25hz. */
244 if (game->cave && (toggle || gd_fine_scroll))
245 game->out_of_window=gd_scroll(game, game->cave->player_state==GD_PL_NOT_YET); /* do the scrolling. scroll exactly, if player is not yet alive */
247 gd_drawcave(gd_screen, game); /* draw the cave. */
249 /* may show pause header. but only if the cave already exists in a gfx buffer - or else we are seeing a story at the moment */
250 if (paused) {
251 if (statusbar_since/50%4==0)
252 showheader_pause(cols);
253 else
254 gd_showheader_game(game, statusbar_since, cols, TRUE); /* true = show "playing replay" if necessary */
258 SDL_Flip(gd_screen); /* can always be called, as it keeps track of dirty regions of the screen */
261 SDL_RemoveTimer(tim);
262 gd_sound_off(); /* we stop sounds. gd_game_free would do it, but we need the game struct for highscore */
264 /* (if stopped because of a quit event, do not bother highscore at all) */
265 if (!gd_quit && show_highscore && gd_is_highscore(gd_caveset_data->highscore, game->player_score)) {
266 int rank;
268 /* enter to highscore table */
269 rank=gd_add_highscore(gd_caveset_data->highscore, game->player_name, game->player_score);
270 gd_show_highscore(NULL, rank);
272 else {
273 /* no high score */
278 static void
279 play_game(int start_cave, int start_level)
281 char *name;
282 GdGame *game;
284 /* ask name of player. */
285 name=gd_input_string("ENTER YOUR NAME", username);
286 if (!name)
287 return;
288 g_free(username);
289 username=name;
291 gd_music_stop();
293 game=gd_game_new(username, start_cave, start_level);
294 play_game_func(game);
295 gd_game_free(game);
298 static void
299 play_replay(GdCave *cave, GdReplay *replay)
301 GdGame *game;
303 gd_music_stop();
305 game=gd_game_new_replay(cave, replay);
306 play_game_func(game);
307 gd_game_free(game);
308 /* wait for keys, as for example escape may be pressed at this time */
309 gd_wait_for_key_releases();
311 gd_music_play_random();
314 static int
315 previous_selectable_cave(int cavenum)
317 int cn=cavenum;
319 while (cn>0) {
320 GdCave *cave;
322 cn--;
323 cave=gd_return_nth_cave(cn);
324 if (gd_all_caves_selectable || cave->selectable)
325 return cn;
328 /* if not found any suitable, return current */
329 return cavenum;
332 static int
333 next_selectable_cave(int cavenum)
335 int cn=cavenum;
337 while (cn<gd_caveset_count()-1) {
338 GdCave *cave;
340 cn++;
341 cave=gd_return_nth_cave(cn);
342 if (gd_all_caves_selectable || cave->selectable)
343 return cn;
346 /* if not found any suitable, return current */
347 return cavenum;
358 static GdMainMenuSelected
359 main_menu()
361 const int image_centered_threshold=164*gd_scale;
362 SDL_Surface **animation;
363 int animcycle;
364 int count;
365 GdMainMenuSelected s;
366 int x;
367 int waitcycle=0;
368 int y_gameline, y_caveline;
369 int image_h;
370 gboolean show_status;
371 gboolean title_image_shown;
373 animation=gd_get_title_animation(FALSE);
374 animcycle=0;
375 /* count number of frames */
376 count=0;
377 while(animation[count]!=NULL)
378 count++;
380 /* start playing after creating title animation above */
381 gd_music_play_random();
383 /* height of title screen, then decide which lines to show and where */
384 image_h=animation[0]->h;
385 if (gd_screen->h-image_h < 2*gd_font_height()) {
386 /* less than 2 lines - place for only one line of text. */
387 y_gameline=-1;
388 y_caveline=image_h + (gd_screen->h-image_h-gd_font_height())/2; /* centered in the small place */
389 show_status=FALSE;
390 } else
391 if (gd_screen->h-image_h < 3*gd_font_height()) {
392 /* more than 2, less than 3 - place for status bar. game name is not shown, as this will */
393 /* only be true for a game with its own title screen, and i decided that in that case it */
394 /* would make more sense. */
395 y_gameline=-1;
396 y_caveline=image_h + (gd_screen->h-image_h-gd_font_height()*2)/2; /* centered there */
397 show_status=TRUE;
398 } else {
399 image_h=image_centered_threshold; /* "minimum" height for the image, and it will be centered */
400 /* more than 3, less than 4 - place for everything. */
401 y_gameline=image_h + (gd_screen->h-image_h-gd_font_height()-gd_font_height()*2)/2; /* centered with cave name */
402 y_caveline=y_gameline+gd_font_height();
403 /* if there is some place, move the cave line one pixel lower. */
404 if (y_caveline+2*gd_font_height()<gd_screen->h)
405 y_caveline+=1*gd_scale;
406 show_status=TRUE;
409 /* fill whole gd_screen with black */
410 SDL_FillRect(gd_screen, NULL, SDL_MapRGB(gd_screen->format, 0, 0, 0));
411 /* then fill with the tile, so if the title image is very small, there is no black border */
412 /* only do that if the image is significantly smaller */
413 if (animation[0]->w < gd_screen->w*9/10 || animation[0]->h < image_centered_threshold*9/10) {
414 SDL_Rect rect;
416 rect.x=0;
417 rect.y=0;
418 rect.w=gd_screen->w;
419 rect.h=image_centered_threshold;
420 SDL_SetClipRect(gd_screen, &rect);
421 gd_dark_screen();
422 SDL_SetClipRect(gd_screen, NULL);
425 if (y_gameline!=-1) {
426 x=gd_blittext_n(gd_screen, 0, y_gameline, GD_GDASH_WHITE, "GAME: ");
427 x=gd_blittext_n(gd_screen, x, y_gameline, GD_GDASH_YELLOW, gd_caveset_data->name);
428 if (gd_caveset_edited) /* if edited (new replays), draw a sign XXX */
429 x=gd_blittext_n(gd_screen, x, y_gameline, GD_GDASH_RED, " *");
431 if (show_status) {
432 if (gd_caveset_has_replays())
433 gd_status_line("CRSR: SELECT SPC: PLAY R: REPLAYS");
434 else
435 gd_status_line("CRSR: SELECT SPC: PLAY F1: HELP");
438 if (gd_has_new_error())
439 /* show error flag */
440 gd_blittext_n(gd_screen, gd_screen->w-gd_font_width(), gd_screen->h-gd_font_height(), GD_GDASH_RED, "E");
442 s=M_NONE;
443 cavenum=gd_caveset_last_selected;
444 levelnum=gd_caveset_last_selected_level;
446 /* here we process the keys and joystick in an ugly way, so wait for releases first. */
447 gd_wait_for_key_releases();
449 title_image_shown=FALSE;
450 while(!gd_quit && s==M_NONE) {
451 SDL_Event event;
452 SDL_Rect dest_pos;
453 static int i=0; /* used to slow down cave selection, as this function must run at 25hz for animation */
455 /* play animation */
456 if (!title_image_shown || count>1) {
457 animcycle=(animcycle+1)%count;
458 dest_pos.x=(gd_screen->w-animation[animcycle]->w)/2; /* centered horizontally */
459 if (animation[animcycle]->h<image_centered_threshold)
460 dest_pos.y=(image_centered_threshold-animation[animcycle]->h)/2; /* centered vertically */
461 else
462 dest_pos.y=0; /* top of screen, as not too much space left for info lines */
463 SDL_BlitSurface(animation[animcycle], 0, gd_screen, &dest_pos);
464 title_image_shown=TRUE; /* shown at least once, so if not animated, we do not waste cpu */
467 /* selected cave */
468 gd_clear_line(gd_screen, y_caveline);
469 x=gd_blittext_n(gd_screen, 0, y_caveline, GD_GDASH_WHITE, "CAVE: ");
470 x=gd_blittext_n(gd_screen, 0, y_caveline, GD_GDASH_WHITE, "CAVE: ");
471 x=gd_blittext_n(gd_screen, x, y_caveline, GD_GDASH_YELLOW, gd_return_nth_cave(cavenum)->name);
472 x=gd_blittext_n(gd_screen, x, y_caveline, GD_GDASH_WHITE, "/");
473 x=gd_blittext_printf_n(gd_screen, x, y_caveline, GD_GDASH_YELLOW, "%d", levelnum+1);
475 SDL_Flip(gd_screen);
477 i=(i+1)%3;
479 while (SDL_PollEvent(&event)) {
480 switch(event.type) {
481 case SDL_QUIT: /* application closed by window manager */
482 gd_quit=TRUE;
483 s=M_QUIT;
484 break;
486 case SDL_KEYDOWN:
487 switch(event.key.keysym.sym) {
488 case SDLK_ESCAPE: /* escape: quit app */
489 case SDLK_q:
490 s=M_EXIT;
491 break;
493 case SDLK_RETURN: /* enter: start playing */
494 s=M_PLAY;
495 break;
497 case SDLK_l: /* load file */
498 s=M_LOAD;
499 break;
501 case SDLK_s: /* save file */
502 s=M_SAVE;
503 break;
505 case SDLK_i: /* caveset info */
506 s=M_INFO;
507 break;
509 case SDLK_n: /* save file with new filename */
510 s=M_SAVE_AS_NEW;
511 break;
513 case SDLK_c:
514 s=M_LOAD_FROM_INSTALLED;
515 break;
517 case SDLK_r:
518 s=M_REPLAYS;
519 break;
521 case SDLK_a:
522 s=M_ABOUT;
523 break;
525 case SDLK_b:
526 s=M_LICENSE;
527 break;
529 case SDLK_o: /* s: settings */
530 s=M_OPTIONS;
531 break;
533 case SDLK_t: /* t: install theme */
534 s=M_INSTALL_THEME;
535 break;
537 case SDLK_e: /* show error console */
538 s=M_ERRORS;
539 break;
541 case SDLK_h: /* h: highscore */
542 s=M_HIGHSCORE;
543 break;
545 case SDLK_F1: /* f1: help */
546 s=M_HELP;
547 break;
549 default: /* other keys do nothing */
550 break;
552 default: /* other events we don't care */
553 break;
557 /* not all frames process the joystick - otherwise it would be too fast. */
558 waitcycle=(waitcycle+1)%2;
560 /* we use gd_down() and functions like that, so the joystick also works */
561 if (waitcycle==0) {
562 /* joystick or keyboard up */
563 if (gd_up() && i==0) {
564 levelnum++;
565 if (levelnum>4)
566 levelnum=4;
569 /* joystick or keyboard down */
570 if (gd_down() && i==0) {
571 levelnum--;
572 if (levelnum<0)
573 levelnum=0;
576 /* joystick or keyboard left */
577 if (gd_left() && i==0)
578 cavenum=previous_selectable_cave(cavenum);
580 /* joystick or keyboard right */
581 if (gd_right() && i==0)
582 cavenum=next_selectable_cave(cavenum);
585 if (gd_space_or_enter_or_fire())
586 s=M_PLAY;
588 SDL_Delay(40); /* 25 fps - we need exactly this for the animation */
591 gd_wait_for_key_releases();
593 /* forget animation */
594 for (x=0; x<count; x++)
595 SDL_FreeSurface(animation[x]);
596 g_free(animation);
598 return s;
601 static void
602 main_help()
604 const char* strings_menu[]={
605 "CURSOR", "SELECT CAVE&LEVEL",
606 "SPACE, RETURN", "PLAY GAME",
607 "I", "SHOW CAVESET INFO",
608 "H", "SHOW HALL OF FAME",
609 "R", "SHOW REPLAYS",
610 "", "",
611 "L", "LOAD CAVESET",
612 "C", "LOAD FROM INSTALLED CAVES",
613 "S", "SAVE CAVESET (REPLAYS)",
614 "N", "SAVE AS NEW FILE",
615 "", "",
616 "O", "OPTIONS",
617 "T", "INSTALL THEME",
618 "E", "ERROR CONSOLE",
619 "A", "ABOUT GDASH",
620 "B", "LICENSE",
621 "", "",
622 "ESCAPE", "QUIT",
623 NULL
626 gd_help(strings_menu);
631 /* save caveset to specified directory, and pop up error message if failed */
632 /* if not, call function to remember file name. */
633 static void
634 caveset_save(const gchar *filename)
636 gboolean saved;
638 saved=gd_caveset_save(filename);
639 if (!saved)
640 gd_error_console();
641 else
642 gd_caveset_file_operation_successful(filename);
645 /* ask for new filename to save file to. then do the save. */
646 static void
647 save_file_as(const char *directory)
649 char *filename;
650 char *filter;
652 if (!gd_last_folder)
653 gd_last_folder=g_strdup(g_get_home_dir());
655 filter=g_strjoinv(";", gd_caveset_extensions);
656 filename=gd_select_file("SAVE CAVESET AS", directory?directory:gd_last_folder, filter, TRUE);
657 g_free(filter);
659 /* if file selected */
660 if (filename) {
661 /* remember last directory */
662 g_free(gd_last_folder);
663 gd_last_folder=g_path_get_dirname(filename);
665 caveset_save(filename);
668 g_free(filename);
671 /* if the caveset has a valid bdcff file name, save caves into that. if not, call the "save file as" function */
672 static void
673 save_file()
675 if (!gd_caveset_filename)
676 /* if no filename remembered, rather start the save_as function, which asks for one. */
677 save_file_as(NULL);
678 else
679 /* if given, save. */
680 gd_caveset_save(gd_caveset_filename);
685 main(int argc, char *argv[])
687 GOptionContext *context;
688 GError *error=NULL;
690 /* command line parsing */
691 context=gd_option_context_new();
692 g_option_context_parse (context, &argc, &argv, &error);
693 g_option_context_free (context);
694 if (error) {
695 g_warning("%s", error->message);
696 g_error_free(error);
699 /* show license? */
700 if (gd_param_license) {
701 char *wrapped=gd_wrap_text(gd_about_license, 72);
703 /* print license and quit. */
704 g_print("%s", wrapped);
705 g_free(wrapped);
706 return 0;
709 gd_settings_init_dirs();
711 gd_install_log_handler();
713 gd_cave_init();
714 gd_cave_db_init();
715 gd_cave_sound_db_init();
716 gd_c64_import_init_tables();
718 gd_load_settings();
720 gd_caveset_clear();
722 gd_clear_error_flag();
724 gd_wait_before_game_over=TRUE;
726 /* LOAD A CAVESET FROM A FILE, OR AN INTERNAL ONE */
727 /* if remaining arguments, they are filenames */
728 if (gd_param_cavenames && gd_param_cavenames[0]) {
729 /* load caveset, "ignore" errors. */
730 if (!gd_caveset_load_from_file (gd_param_cavenames[0], gd_user_config_dir)) {
731 g_critical (_("Errors during loading caveset from file '%s'"), gd_param_cavenames[0]);
732 } else
733 gd_caveset_file_operation_successful(gd_param_cavenames[0]);
735 else if (gd_param_internal) {
736 /* if specified an internal caveset */
737 if (!gd_caveset_load_from_internal (gd_param_internal-1, gd_user_config_dir))
738 g_critical (_("%d: no such internal caveset"), gd_param_internal);
741 /* if failed or nothing requested, load default */
742 if (gd_caveset==NULL)
743 gd_caveset_load_from_internal (0, gd_user_config_dir);
745 /* if cave or level values given, check range */
746 if (gd_param_cave)
747 if (gd_param_cave<1 || gd_param_cave>=gd_caveset_count() || gd_param_level<1 || gd_param_level>5) {
748 g_critical (_("Invalid cave or level number!\n"));
749 gd_param_cave=0;
750 gd_param_level=0;
753 gd_sdl_init(gd_sdl_scale);
754 gd_create_dark_background();
755 gd_sound_init(0);
756 #ifdef GD_SOUND
757 gd_sound_set_music_volume(gd_sound_music_volume_percent);
758 gd_sound_set_chunk_volumes(gd_sound_chunks_volume_percent);
759 #endif
761 gd_loadfont_default();
762 gd_load_theme();
764 username=g_strdup(g_get_real_name());
766 while (!gd_quit) {
767 GdMainMenuSelected s;
769 /* if a cavenum was given on the command line */
770 if (gd_param_cave) {
771 /* do as if it was selected from the menu */
772 cavenum=gd_param_cave-1;
773 levelnum=gd_param_level-1;
774 s=M_PLAY;
776 gd_param_cave=0; /* and forget it */
778 else
779 s=main_menu();
781 switch(s) {
782 case M_NONE:
783 break;
785 /* PLAYING */
786 case M_PLAY:
787 /* get selected cave&level, then play */
788 gd_caveset_last_selected=cavenum;
789 gd_caveset_last_selected_level=levelnum;
790 play_game(cavenum, levelnum);
791 break;
792 case M_REPLAYS:
793 gd_replays_menu(play_replay, TRUE);
794 break;
795 case M_HIGHSCORE:
796 gd_show_highscore(NULL, 0);
797 break;
798 case M_INFO:
799 gd_show_cave_info(NULL);
800 break;
802 /* FILES */
803 case M_LOAD:
804 gd_open_caveset(NULL);
805 break;
806 case M_LOAD_FROM_INSTALLED:
807 gd_open_caveset(gd_system_caves_dir);
808 break;
809 case M_SAVE:
810 save_file(NULL);
811 break;
812 case M_SAVE_AS_NEW:
813 save_file_as(NULL);
814 break;
817 /* INFO */
818 case M_ABOUT:
819 gd_about();
820 break;
821 case M_LICENSE:
822 gd_show_license();
823 break;
824 case M_HELP:
825 main_help();
826 break;
828 /* SETUP */
829 case M_INSTALL_THEME:
830 gd_install_theme();
831 break;
832 case M_OPTIONS:
833 gd_settings_menu();
834 break;
835 case M_ERRORS:
836 gd_error_console();
837 break;
839 /* EXIT */
840 case M_EXIT:
841 case M_QUIT:
842 gd_quit=TRUE;
843 break;
846 /* if quit requested, check if the caveset is edited. */
847 /* and the user wants to save, ignore the quit request */
848 if (gd_quit) {
849 /* ugly hack. gd_ask_yes_no would not work if quit is true. so set to false */
850 gd_quit=FALSE;
851 /* and if discards, set to true */
852 if (gd_discard_changes())
853 gd_quit=TRUE;
857 SDL_Quit();
859 gd_save_highscore(gd_user_config_dir);
860 gd_save_settings();
862 return 0;