naev 0.12.5
conf.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
5#include <getopt.h> /* getopt_long */
6#include <stdlib.h> /* atoi */
7#include <unistd.h> /* getopt */
8
9#include "naev.h"
11
12#include "physfs.h"
13
14#include "conf.h"
15
16#include "background.h"
17#include "env.h"
18#include "input.h"
19#include "log.h"
20#include "music.h"
21#include "nfile.h"
22#include "nlua.h"
23#include "nstring.h"
24#include "sound.h"
25#include "space.h"
26#include "utf8.h"
27
28#define conf_loadInt( env, n, i ) \
29 { \
30 nlua_getenv( naevL, env, n ); \
31 if ( lua_isnumber( naevL, -1 ) ) { \
32 i = (int)lua_tonumber( naevL, -1 ); \
33 } \
34 lua_pop( naevL, 1 ); \
35 }
36
37#define conf_loadFloat( env, n, f ) \
38 { \
39 nlua_getenv( naevL, env, n ); \
40 if ( lua_isnumber( naevL, -1 ) ) { \
41 f = (double)lua_tonumber( naevL, -1 ); \
42 } \
43 lua_pop( naevL, 1 ); \
44 }
45
46#define conf_loadTime( env, n, i ) \
47 { \
48 nlua_getenv( naevL, env, n ); \
49 if ( lua_isnumber( naevL, -1 ) ) { \
50 i = (time_t)lua_tonumber( naevL, -1 ); \
51 } \
52 lua_pop( naevL, 1 ); \
53 }
54
55#define conf_loadBool( env, n, b ) \
56 { \
57 nlua_getenv( naevL, env, n ); \
58 if ( lua_isnumber( naevL, -1 ) ) \
59 b = ( lua_tonumber( naevL, -1 ) != 0. ); \
60 else if ( !lua_isnil( naevL, -1 ) ) \
61 b = lua_toboolean( naevL, -1 ); \
62 lua_pop( naevL, 1 ); \
63 }
64
65#define conf_loadString( env, n, s ) \
66 { \
67 nlua_getenv( naevL, env, n ); \
68 if ( lua_isstring( naevL, -1 ) ) { \
69 free( s ); \
70 s = strdup( lua_tostring( naevL, -1 ) ); \
71 } \
72 lua_pop( naevL, 1 ); \
73 }
74
75/* Global configuration. */
76PlayerConf_t conf = {
77 .loaded = 0, .ndata = NULL, .language = NULL, .joystick_nam = NULL };
78
79/* from main.c */
80extern int show_fps;
81extern int max_fps;
82extern int indjoystick;
83extern char *namjoystick;
84
85/*
86 * prototypes
87 */
88static void print_usage( void );
89
90/*
91 * prints usage
92 */
93static void print_usage( void )
94{
95 LOG( _( "Usage: %s [OPTIONS]" ), env.argv0 );
96 LOG( _( "Options are:" ) );
97 LOG( _( " -f, --fullscreen activate fullscreen" ) );
98 LOG( _( " -F n, --fps n limit frames per second to n" ) );
99 LOG( _( " -V, --vsync enable vsync" ) );
100 LOG( _( " -W n set width to n" ) );
101 LOG( _( " -H n set height to n" ) );
102 LOG( _( " -j n, --joystick n use joystick n" ) );
103 LOG( _( " -J s, --Joystick s use joystick whose name contains s" ) );
104 LOG( _( " -M, --mute disables sound" ) );
105 LOG( _( " -S, --sound forces sound" ) );
106 LOG( _( " -m f, --mvol f sets the music volume to f" ) );
107 LOG( _( " -s f, --svol f sets the sound volume to f" ) );
108 LOG( _( " -d, --datapath adds a new datapath to be mounted (i.e., "
109 "appends it to the search path for game assets)" ) );
110 LOG( _( " -X, --scale defines the scale factor" ) );
111 LOG(
112 _( " --devmode enables dev mode perks like the editors" ) );
113 LOG( _( " -h, --help display this message and exit" ) );
114 LOG( _( " -v, --version print the version and exit" ) );
115}
116
120void conf_setDefaults( void )
121{
122 conf_cleanup();
123
124 /* Joystick. */
125 conf.joystick_ind = -1;
126
127 /* GUI. */
128 conf.mesg_visible = 5;
129 conf.map_overlay_opacity = MAP_OVERLAY_OPACITY_DEFAULT;
130 conf.big_icons = BIG_ICONS_DEFAULT;
131 conf.always_radar = 0;
132
133 /* Repeat. */
134 conf.repeat_delay = 500;
135 conf.repeat_freq = 30;
136
137 /* Dynamic zoom. */
138 conf.zoom_manual = MANUAL_ZOOM_DEFAULT;
139 conf.zoom_far = ZOOM_FAR_DEFAULT;
140 conf.zoom_near = ZOOM_NEAR_DEFAULT;
141 conf.zoom_speed = ZOOM_SPEED_DEFAULT;
142
143 /* Font sizes. */
144 conf.font_size_console = FONT_SIZE_CONSOLE_DEFAULT;
145 conf.font_size_intro = FONT_SIZE_INTRO_DEFAULT;
146 conf.font_size_def = FONT_SIZE_DEF_DEFAULT;
147 conf.font_size_small = FONT_SIZE_SMALL_DEFAULT;
148
149 /* Misc. */
150 conf.redirect_file = 1;
151 conf.nosave = 0;
152 conf.devmode = 0;
153 conf.devautosave = 0;
154 conf.lua_enet = 0;
155 conf.lua_repl = 0;
156 conf.lastversion = strdup( "" );
157 conf.translation_warning_seen = 0;
158 memset( &conf.last_played, 0, sizeof( time_t ) );
159
160 /* Accessibility. */
161 conf.puzzle_skip = PUZZLE_SKIP_DEFAULT;
162
163 /* Gameplay. */
164 conf_setGameplayDefaults();
165
166 /* Audio. */
167 conf_setAudioDefaults();
168
169 /* Video. */
170 conf_setVideoDefaults();
171
172 /* Input */
173 input_setDefault( 1 );
174
175 /* Debugging. */
176 conf.fpu_except = 0; /* Causes many issues. */
177
178 /* Editor. */
179 if ( nfile_dirExists( "../dat/" ) )
180 conf.dev_data_dir = strdup( "../dat/" );
181 else
182 conf.dev_data_dir = NULL;
183}
184
188void conf_setGameplayDefaults( void )
189{
190 conf.difficulty = DIFFICULTY_DEFAULT;
191 conf.doubletap_sens = DOUBLETAP_SENSITIVITY_DEFAULT;
192 conf.mouse_hide = MOUSE_HIDE_DEFAULT;
193 conf.mouse_accel = MOUSE_ACCEL_DEFAULT;
194 conf.mouse_doubleclick = MOUSE_DOUBLECLICK_TIME;
195 conf.mouse_fly = MOUSE_FLY_DEFAULT;
196 conf.zoom_manual = MANUAL_ZOOM_DEFAULT;
197}
198
202void conf_setAudioDefaults( void )
203{
204 /* Sound. */
205 conf.al_efx = USE_EFX_DEFAULT;
206 conf.nosound = MUTE_SOUND_DEFAULT;
207 conf.sound = SOUND_VOLUME_DEFAULT;
208 conf.music = MUSIC_VOLUME_DEFAULT;
209 conf.engine_vol = ENGINE_VOLUME_DEFAULT;
210}
211
215void conf_setVideoDefaults( void )
216{
217 int w, h, f;
218 SDL_DisplayMode resolution;
219
220 /* More complex resolution handling. */
221 f = 0;
222 if ( SDL_GetCurrentDisplayMode( 0, &resolution ) == 0 ) {
223 /* Try higher resolution. */
224 w = RESOLUTION_W_DEFAULT;
225 h = RESOLUTION_H_DEFAULT;
226
227 /* Fullscreen and fit everything onscreen. */
228 if ( ( resolution.w <= w ) || ( resolution.h <= h ) ) {
229 w = resolution.w;
230 h = resolution.h;
231 f = FULLSCREEN_DEFAULT;
232 }
233 } else {
234 w = 800;
235 h = 600;
236 }
237
238 /* OpenGL. */
239 conf.fsaa = FSAA_DEFAULT;
240 conf.vsync = VSYNC_DEFAULT;
241
242 /* Window. */
243 conf.fullscreen = f;
244 conf.width = w;
245 conf.height = h;
246 conf.explicit_dim =
247 0; /* No need for a define, this is only for first-run. */
248 conf.scalefactor = SCALE_FACTOR_DEFAULT;
249 conf.nebu_scale = NEBULA_SCALE_FACTOR_DEFAULT;
250 conf.minimize = MINIMIZE_DEFAULT;
251 conf.colourblind_sim = COLOURBLIND_SIM_DEFAULT;
252 conf.colourblind_correct = COLOURBLIND_CORRECT_DEFAULT;
253 conf.colourblind_type = COLOURBLIND_TYPE_DEFAULT;
254 conf.game_speed = GAME_SPEED_DEFAULT;
255 conf.healthbars = HEALTHBARS_DEFAULT;
256 conf.bg_brightness = BG_BRIGHTNESS_DEFAULT;
257 conf.nebu_nonuniformity = NEBU_NONUNIFORMITY_DEFAULT;
258 conf.nebu_saturation = NEBU_SATURATION_DEFAULT;
259 conf.jump_brightness = JUMP_BRIGHTNESS_DEFAULT;
260 conf.gamma_correction = GAMMA_CORRECTION_DEFAULT;
261 conf.low_memory = LOW_MEMORY_DEFAULT;
262 conf.max_3d_tex_size = MAX_3D_TEX_SIZE;
263
264 if ( cur_system )
265 background_load( cur_system->background );
266
267 /* FPS. */
268 conf.fps_show = SHOW_FPS_DEFAULT;
269 conf.fps_max = FPS_MAX_DEFAULT;
270
271 /* Pause. */
272 conf.pause_show = SHOW_PAUSE_DEFAULT;
273}
274
275/*
276 * Frees some memory the conf allocated.
277 */
278void conf_cleanup( void )
279{
280 conf_free( &conf );
281}
282
283/*
284 * @brief Parses the local conf that dictates where user data goes.
285 */
286void conf_loadConfigPath( void )
287{
288 const char *file = "datapath.lua";
289
290 if ( !nfile_fileExists( file ) )
291 return;
292
293 nlua_env lEnv = nlua_newEnv( file );
294 if ( nlua_dofileenv( lEnv, file ) == 0 )
295 conf_loadString( lEnv, "datapath", conf.datapath );
296
297 nlua_freeEnv( lEnv );
298}
299
300/*
301 * parses the config file
302 */
303int conf_loadConfig( const char *file )
304{
305 int t, cb;
306 SDL_Keycode key;
307 int type;
308 int w, h;
309 SDL_Keymod m;
310
311 /* Check to see if file exists. */
312 if ( !nfile_fileExists( file ) ) {
313 conf.loaded = 1;
314 return nfile_touch( file );
315 }
316
317 /* Load the configuration. */
318 nlua_env lEnv = nlua_newEnv( file );
319 if ( nlua_dofileenv( lEnv, file ) == 0 ) {
320
321 /* ndata. */
322 conf_loadString( lEnv, "data", conf.ndata );
323
324 /* Language. */
325 conf_loadString( lEnv, "language", conf.language );
326
327 /* OpenGL. */
328 conf_loadInt( lEnv, "fsaa", conf.fsaa );
329 conf_loadBool( lEnv, "vsync", conf.vsync );
330
331 /* Window. */
332 w = h = 0;
333 conf_loadInt( lEnv, "width", w );
334 conf_loadInt( lEnv, "height", h );
335 if ( w != 0 ) {
336 conf.explicit_dim = 1;
337 conf.width = w;
338 }
339 if ( h != 0 ) {
340 conf.explicit_dim = 1;
341 conf.height = h;
342 }
343 conf_loadFloat( lEnv, "scalefactor", conf.scalefactor );
344 conf_loadFloat( lEnv, "nebu_scale", conf.nebu_scale );
345 conf_loadBool( lEnv, "fullscreen", conf.fullscreen );
346 conf_loadBool( lEnv, "modesetting", conf.modesetting );
347 conf_loadBool( lEnv, "notresizable", conf.notresizable );
348 conf_loadBool( lEnv, "borderless", conf.borderless );
349 conf_loadBool( lEnv, "minimize", conf.minimize );
350 cb = 0;
351 conf_loadBool( lEnv, "colourblind",
352 cb ); /* TODO remove in 0.13.0 or so. */
353 if ( cb ) {
354 /* Old colourblind used Rod Monochromancy, so we'll restore that in
355 * this case. TODO Remove in 0.13.0 or so. */
356 conf.colourblind_type = 3;
357 conf.colourblind_sim = 1.; /* Turn on at max. */
358 }
359 conf_loadFloat( lEnv, "colourblind_sim", conf.colourblind_sim );
360 conf_loadFloat( lEnv, "colourblind_correct", conf.colourblind_correct );
361 conf_loadInt( lEnv, "colourblind_type", conf.colourblind_type );
362 conf_loadFloat( lEnv, "game_speed", conf.game_speed );
363 conf_loadBool( lEnv, "healthbars", conf.healthbars );
364 conf_loadFloat( lEnv, "bg_brightness", conf.bg_brightness );
365 conf_loadBool( lEnv, "puzzle_skip", conf.puzzle_skip );
366 /* TODO leave only nebu_nonuniformity for 0.13.0 */
367 conf_loadFloat( lEnv, "nebu_uniformity", conf.nebu_nonuniformity );
368 conf_loadFloat( lEnv, "nebu_nonuniformity", conf.nebu_nonuniformity );
369 /* end todo */
370 conf_loadFloat( lEnv, "nebu_saturation", conf.nebu_saturation );
371 conf_loadFloat( lEnv, "jump_brightness", conf.jump_brightness );
372 conf_loadFloat( lEnv, "gamma_correction", conf.gamma_correction );
373 conf_loadBool( lEnv, "low_memory", conf.low_memory );
374 conf_loadInt( lEnv, "max_3d_tex_size", conf.max_3d_tex_size );
375
376 /* FPS */
377 conf_loadBool( lEnv, "showfps", conf.fps_show );
378 conf_loadInt( lEnv, "maxfps", conf.fps_max );
379
380 /* Pause */
381 conf_loadBool( lEnv, "showpause", conf.pause_show );
382
383 /* Sound. */
384 conf_loadBool( lEnv, "al_efx", conf.al_efx );
385 conf_loadBool( lEnv, "nosound", conf.nosound );
386 conf_loadFloat( lEnv, "sound", conf.sound );
387 conf_loadFloat( lEnv, "music", conf.music );
388 conf_loadFloat( lEnv, "engine_vol", conf.engine_vol );
389
390 /* Joystick. */
391 nlua_getenv( naevL, lEnv, "joystick" );
392 if ( lua_isnumber( naevL, -1 ) )
393 conf.joystick_ind = (int)lua_tonumber( naevL, -1 );
394 else if ( lua_isstring( naevL, -1 ) )
395 conf.joystick_nam = strdup( lua_tostring( naevL, -1 ) );
396 lua_pop( naevL, 1 );
397
398 /* GUI. */
399 conf_loadInt( lEnv, "mesg_visible", conf.mesg_visible );
400 if ( conf.mesg_visible <= 0 )
401 conf.mesg_visible = 5;
402 conf_loadFloat( lEnv, "map_overlay_opacity", conf.map_overlay_opacity );
403 conf.map_overlay_opacity = CLAMP( 0, 1, conf.map_overlay_opacity );
404 conf_loadBool( lEnv, "big_icons", conf.big_icons );
405 conf_loadBool( lEnv, "always_radar", conf.always_radar );
406
407 /* Key repeat. */
408 conf_loadInt( lEnv, "repeat_delay", conf.repeat_delay );
409 conf_loadInt( lEnv, "repeat_freq", conf.repeat_freq );
410
411 /* Zoom. */
412 conf_loadBool( lEnv, "zoom_manual", conf.zoom_manual );
413 conf_loadFloat( lEnv, "zoom_far", conf.zoom_far );
414 conf_loadFloat( lEnv, "zoom_near", conf.zoom_near );
415 conf_loadFloat( lEnv, "zoom_speed", conf.zoom_speed );
416
417 /* Font size. */
418 conf_loadInt( lEnv, "font_size_console", conf.font_size_console );
419 conf_loadInt( lEnv, "font_size_intro", conf.font_size_intro );
420 conf_loadInt( lEnv, "font_size_def", conf.font_size_def );
421 conf_loadInt( lEnv, "font_size_small", conf.font_size_small );
422
423 /* Misc. */
424 conf_loadString( lEnv, "difficulty", conf.difficulty );
425 conf_loadFloat( lEnv, "compression_velocity", conf.compression_velocity );
426 conf_loadFloat( lEnv, "compression_mult", conf.compression_mult );
427 conf_loadBool( lEnv, "redirect_file", conf.redirect_file );
428 conf_loadInt( lEnv, "doubletap_sensitivity", conf.doubletap_sens );
429 conf_loadFloat( lEnv, "mouse_hide", conf.mouse_hide );
430 conf_loadBool( lEnv, "mouse_fly", conf.mouse_fly );
431 conf_loadInt( lEnv, "mouse_accel", conf.mouse_accel );
432 conf_loadFloat( lEnv, "mouse_doubleclick", conf.mouse_doubleclick );
433 conf_loadFloat( lEnv, "autonav_reset_dist", conf.autonav_reset_dist );
434 conf_loadFloat( lEnv, "autonav_reset_shield", conf.autonav_reset_shield );
435 conf_loadBool( lEnv, "devmode", conf.devmode );
436 conf_loadBool( lEnv, "devautosave", conf.devautosave );
437 conf_loadBool( lEnv, "lua_enet", conf.lua_enet );
438 conf_loadBool( lEnv, "lua_repl", conf.lua_repl );
439 conf_loadBool( lEnv, "conf_nosave", conf.nosave );
440 conf_loadString( lEnv, "lastversion", conf.lastversion );
441 conf_loadBool( lEnv, "translation_warning_seen",
442 conf.translation_warning_seen );
443 conf_loadTime( lEnv, "last_played", conf.last_played );
444
445 /* Debugging. */
446 conf_loadBool( lEnv, "fpu_except", conf.fpu_except );
447
448 /* Editor. */
449 conf_loadString( lEnv, "dev_data_dir", conf.dev_data_dir );
450
451 /*
452 * Keybindings.
453 */
454 for ( int i = 0; i <= KST_PASTE; i++ ) {
455 nlua_getenv( naevL, lEnv, input_getKeybindBrief( i ) );
456
457 /* Use 'none' to differentiate between not instantiated and disabled
458 * bindings. */
459 if ( lua_isstring( naevL, -1 ) ) {
460 const char *str = lua_tostring( naevL, -1 );
461 if ( strcmp( str, "none" ) == 0 ) {
462 input_setKeybind( i, KEYBIND_NULL, SDLK_UNKNOWN, NMOD_NONE );
463 }
464 } else if ( lua_istable( naevL, -1 ) ) { /* it's a table */
465 const char *str, *mod;
466 /* gets the event type */
467 lua_getfield( naevL, -1, "type" );
468 if ( lua_isstring( naevL, -1 ) )
469 str = lua_tostring( naevL, -1 );
470 else if ( lua_isnil( naevL, -1 ) ) {
471 WARN( _( "Found keybind with no type field!" ) );
472 str = "null";
473 } else {
474 WARN( _( "Found keybind with invalid type field!" ) );
475 str = "null";
476 }
477 lua_pop( naevL, 1 );
478
479 /* gets the key */
480 lua_getfield( naevL, -1, "key" );
481 t = lua_type( naevL, -1 );
482 if ( t == LUA_TNUMBER )
483 key = (int)lua_tonumber( naevL, -1 );
484 else if ( t == LUA_TSTRING )
485 key = input_keyConv( lua_tostring( naevL, -1 ) );
486 else if ( t == LUA_TNIL ) {
487 WARN( _( "Found keybind with no key field!" ) );
488 key = SDLK_UNKNOWN;
489 } else {
490 WARN( _( "Found keybind with invalid key field!" ) );
491 key = SDLK_UNKNOWN;
492 }
493 lua_pop( naevL, 1 );
494
495 /* Get the modifier. */
496 lua_getfield( naevL, -1, "mod" );
497 if ( lua_isstring( naevL, -1 ) )
498 mod = lua_tostring( naevL, -1 );
499 else
500 mod = NULL;
501 lua_pop( naevL, 1 );
502
503 if ( str != NULL ) { /* keybind is valid */
504 /* get type */
505 if ( strcmp( str, "null" ) == 0 )
506 type = KEYBIND_NULL;
507 else if ( strcmp( str, "keyboard" ) == 0 )
508 type = KEYBIND_KEYBOARD;
509 else if ( strcmp( str, "jaxispos" ) == 0 )
510 type = KEYBIND_JAXISPOS;
511 else if ( strcmp( str, "jaxisneg" ) == 0 )
512 type = KEYBIND_JAXISNEG;
513 else if ( strcmp( str, "jbutton" ) == 0 )
514 type = KEYBIND_JBUTTON;
515 else if ( strcmp( str, "jhat_up" ) == 0 )
516 type = KEYBIND_JHAT_UP;
517 else if ( strcmp( str, "jhat_down" ) == 0 )
518 type = KEYBIND_JHAT_DOWN;
519 else if ( strcmp( str, "jhat_left" ) == 0 )
520 type = KEYBIND_JHAT_LEFT;
521 else if ( strcmp( str, "jhat_right" ) == 0 )
522 type = KEYBIND_JHAT_RIGHT;
523 else {
524 WARN( _( "Unknown keybinding of type %s" ), str );
525 continue;
526 }
527
528 /* Check to see if it is valid. */
529 if ( ( key == SDLK_UNKNOWN ) && ( type == KEYBIND_KEYBOARD ) ) {
530 WARN( _( "Keybind for '%s' is invalid" ),
532 continue;
533 }
534
535 /* Set modifier, probably should be able to handle two at a time.
536 */
537 if ( mod != NULL ) {
538 if ( strcmp( mod, "ctrl" ) == 0 )
539 m = NMOD_CTRL;
540 else if ( strcmp( mod, "shift" ) == 0 )
541 m = NMOD_SHIFT;
542 else if ( strcmp( mod, "alt" ) == 0 )
543 m = NMOD_ALT;
544 else if ( strcmp( mod, "meta" ) == 0 )
545 m = NMOD_META;
546 else if ( strcmp( mod, "any" ) == 0 )
547 m = NMOD_ANY;
548 else if ( strcmp( mod, "none" ) == 0 )
549 m = NMOD_NONE;
550 else {
551 WARN( _( "Unknown keybinding mod of type %s" ), mod );
552 m = NMOD_NONE;
553 }
554 } else
555 m = NMOD_NONE;
556
557 /* set the keybind */
558 input_setKeybind( i, type, key, m );
559 } else
560 WARN( _( "Malformed keybind for '%s' in '%s'." ),
561 input_getKeybindName( i ), file );
562 }
563 /* clean up after table stuff */
564 lua_pop( naevL, 1 );
565 }
566 lua_pop( naevL, 1 );
567 } else { /* failed to load the config file */
568 WARN( _( "Config file '%s' has invalid syntax:" ), file );
569 WARN( " %s", lua_tostring( naevL, -1 ) );
570 nlua_freeEnv( lEnv );
571 return 1;
572 }
573
574 conf.loaded = 1;
575 nlua_freeEnv( lEnv );
576 return 0;
577}
578
579/*
580 * parses the CLI options
581 */
582int conf_parseCLI( int argc, char **argv )
583{
584 static struct option long_options[] = {
585 { "datapath", required_argument, 0, 'd' },
586 { "fullscreen", no_argument, 0, 'f' },
587 { "fps", required_argument, 0, 'F' },
588 { "vsync", no_argument, 0, 'V' },
589 { "joystick", required_argument, 0, 'j' },
590 { "Joystick", required_argument, 0, 'J' },
591 { "width", required_argument, 0, 'W' },
592 { "height", required_argument, 0, 'H' },
593 { "mute", no_argument, 0, 'M' },
594 { "sound", no_argument, 0, 'S' },
595 { "mvol", required_argument, 0, 'm' },
596 { "svol", required_argument, 0, 's' },
597 { "scale", required_argument, 0, 'X' },
598 { "devmode", no_argument, 0, 'D' },
599 { "help", no_argument, 0, 'h' },
600 { "version", no_argument, 0, 'v' },
601 { NULL, 0, 0, 0 } };
602 int option_index = 1;
603 int c = 0;
604
605 /* man 3 getopt says optind should be initialized to 1, but that seems to
606 * cause all options to get parsed, i.e. we cannot detect a trailing ndata
607 * option.
608 */
609 optind = 0;
610 while ( ( c = getopt_long( argc, argv, "fF:Vd:j:J:W:H:MSm:s:X:Nhv",
611 long_options, &option_index ) ) != -1 ) {
612 switch ( c ) {
613 case 'd':
614 PHYSFS_mount( optarg, NULL, 1 );
615 break;
616 case 'f':
617 conf.fullscreen = 1;
618 break;
619 case 'F':
620 conf.fps_max = atoi( optarg );
621 break;
622 case 'V':
623 conf.vsync = 1;
624 break;
625 case 'j':
626 conf.joystick_ind = atoi( optarg );
627 break;
628 case 'J':
629 conf.joystick_nam = strdup( optarg );
630 break;
631 case 'W':
632 conf.width = atoi( optarg );
633 conf.explicit_dim = 1;
634 break;
635 case 'H':
636 conf.height = atoi( optarg );
637 conf.explicit_dim = 1;
638 break;
639 case 'M':
640 conf.nosound = 1;
641 break;
642 case 'S':
643 conf.nosound = 0;
644 break;
645 case 'm':
646 conf.music = atof( optarg );
647 break;
648 case 's':
649 conf.sound = atof( optarg );
650 break;
651 case 'N':
652 free( conf.ndata );
653 conf.ndata = NULL;
654 break;
655 case 'X':
656 conf.scalefactor = atof( optarg );
657 break;
658 case 'D':
659 conf.devmode = 1;
660 LOG( _( "Enabling developer mode." ) );
661 break;
662
663 case 'v':
664 /* by now it has already displayed the version */
665 exit( EXIT_SUCCESS );
666 case 'h':
667 print_usage();
668 exit( EXIT_SUCCESS );
669 }
670 }
671
672 return optind;
673}
674
684static size_t quoteLuaString( char *str, size_t size, const char *text )
685{
686 char slashescape;
687 size_t count, i;
688 uint32_t ch;
689
690 if ( size == 0 )
691 return 0;
692
693 /* Write a Lua nil if we are given a NULL pointer */
694 if ( text == NULL )
695 return scnprintf( str, size, "nil" );
696
697 count = 0;
698
699 /* Quote start */
700 str[count++] = '\"';
701 if ( count == size )
702 return count;
703
704 /* Iterate over the characters in text */
705 i = 0;
706 while ( ( ch = u8_nextchar( text, &i ) ) ) {
707 /* Check if we can print this as a friendly backslash-escape */
708 switch ( ch ) {
709 case '#':
710 slashescape = 'a';
711 break;
712 case '\b':
713 slashescape = 'b';
714 break;
715 case '\f':
716 slashescape = 'f';
717 break;
718 case '\n':
719 slashescape = 'n';
720 break;
721 case '\r':
722 slashescape = 'r';
723 break;
724 case '\t':
725 slashescape = 't';
726 break;
727 case '\v':
728 slashescape = 'v';
729 break;
730 case '\\':
731 slashescape = '\\';
732 break;
733 case '\"':
734 slashescape = '\"';
735 break;
736 case '\'':
737 slashescape = '\'';
738 break;
739 /* Technically, Lua can also represent \0, but we can't in our input */
740 default:
741 slashescape = 0;
742 break;
743 }
744 if ( slashescape != 0 ) {
745 /* Yes, we can use a backslash-escape! */
746 str[count++] = '\\';
747 if ( count == size )
748 return count;
749
750 str[count++] = slashescape;
751 if ( count == size )
752 return count;
753
754 continue;
755 }
756
757 /* Render UTF8. */
758 count += u8_toutf8( &str[count], size - count, &ch, 1 );
759 if ( count >= size )
760 return count;
761 }
762
763 /* Quote end */
764 str[count++] = '\"';
765 if ( count == size )
766 return count;
767
768 /* zero-terminate, if possible */
769 str[count] = '\0'; /* don't increase count, like snprintf */
770
771 /* return the amount of characters written */
772 return count;
773}
774
775#define conf_saveComment( t ) \
776 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "-- %s\n", t );
777
778#define conf_saveEmptyLine() \
779 if ( sizeof( buf ) != pos ) \
780 buf[pos++] = '\n';
781
782#define conf_saveInt( n, i ) \
783 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = %d\n", n, i );
784
785#define conf_saveULong( n, i ) \
786 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = %lu\n", n, i );
787
788#define conf_saveTime( n, i ) \
789 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = %llu\n", n, \
790 (unsigned long long)i );
791
792#define conf_saveFloat( n, f ) \
793 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = %f\n", n, f );
794
795#define conf_saveBool( n, b ) \
796 if ( b ) \
797 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = true\n", n ); \
798 else \
799 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = false\n", n );
800
801#define conf_saveString( n, s ) \
802 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = ", n ); \
803 pos += quoteLuaString( &buf[pos], sizeof( buf ) - pos, s ); \
804 if ( sizeof( buf ) != pos ) \
805 buf[pos++] = '\n';
806
807#define GENERATED_START_COMMENT "START GENERATED SECTION"
808#define GENERATED_END_COMMENT "END GENERATED SECTION"
809
810/*
811 * saves the current configuration
812 */
813int conf_saveConfig( const char *file )
814{
815 char *old;
816 const char *oldfooter;
817 size_t oldsize;
818 char buf[32 * 1024];
819 size_t pos;
820
821 pos = 0;
822 oldfooter = NULL;
823
824 /* User doesn't want to save the config. */
825 if ( conf.nosave )
826 return 0;
827
828 /* Read the old configuration, if possible */
829 if ( nfile_fileExists( file ) &&
830 ( old = nfile_readFile( &oldsize, file ) ) != NULL ) {
831 /* See if we can find the generated section and preserve
832 * whatever the user wrote before it */
833 const char *tmp =
834 strnstr( old, "-- " GENERATED_START_COMMENT "\n", oldsize );
835 if ( tmp != NULL ) {
836 /* Copy over the user content */
837 pos = MIN( sizeof( buf ), (size_t)( tmp - old ) );
838 memcpy( buf, old, pos );
839
840 /* See if we can find the end of the section */
841 tmp = strnstr( tmp, "-- " GENERATED_END_COMMENT "\n", oldsize - pos );
842 if ( tmp != NULL ) {
843 /* Everything after this should also be preserved */
844 oldfooter = tmp + strlen( "-- " GENERATED_END_COMMENT "\n" );
845 oldsize -= ( oldfooter - old );
846 }
847 } else {
848 /* Treat the contents of the old file as a footer. */
849 oldfooter = old;
850 }
851 } else {
852 old = NULL;
853
854 /* Write a nice header for new configuration files */
855 conf_saveComment( _( "Naev configuration file" ) );
856 conf_saveEmptyLine();
857 }
858
859 /* Back up old configuration. */
860 if ( nfile_backupIfExists( file ) < 0 ) {
861 WARN( _( "Not saving configuration." ) );
862 return -1;
863 }
864
865 /* Header. */
866 conf_saveComment( GENERATED_START_COMMENT );
867 conf_saveComment(
868 _( "The contents of this section will be rewritten by Naev!" ) );
869 conf_saveEmptyLine();
870
871 /* ndata. */
872 conf_saveComment(
873 _( "The location of Naev's data pack, usually called 'ndata'" ) );
874 conf_saveString( "data", conf.ndata );
875 conf_saveEmptyLine();
876
877 /* Language. */
878 conf_saveComment(
879 _( "Language to use. Set to the two character identifier to the language "
880 "(e.g., \"en\" for English), and nil for autodetect." ) );
881 conf_saveString( "language", conf.language );
882 conf_saveEmptyLine();
883
884 /* Difficulty. */
885 conf_saveComment(
886 _( "Global difficulty to set the game to. Can be overwritten by saved "
887 "game settings. Has to match one of the difficulties defined in "
888 "\"difficulty.xml\" in the data files." ) );
889 if ( conf.difficulty == NULL ) {
890 conf_saveComment( "difficulty = nil" );
891 } else {
892 conf_saveString( "difficulty", conf.difficulty );
893 }
894 conf_saveEmptyLine();
895
896 /* OpenGL. */
897 conf_saveComment( _( "The factor to use in Full-Scene Anti-Aliasing" ) );
898 conf_saveComment( _( "Anything lower than 2 will simply disable FSAA" ) );
899 conf_saveInt( "fsaa", conf.fsaa );
900 conf_saveEmptyLine();
901
902 conf_saveComment( _(
903 "Synchronize framebuffer updates with the vertical blanking interval" ) );
904 conf_saveBool( "vsync", conf.vsync );
905 conf_saveEmptyLine();
906
907 /* Window. */
908 conf_saveComment( _( "The window size or screen resolution" ) );
909 conf_saveComment(
910 _( "Set both of these to 0 to make Naev try the desktop resolution" ) );
911 if ( conf.explicit_dim ) {
912 conf_saveInt( "width", conf.width );
913 conf_saveInt( "height", conf.height );
914 } else {
915 conf_saveInt( "width", 0 );
916 conf_saveInt( "height", 0 );
917 }
918 conf_saveEmptyLine();
919
920 conf_saveComment( _( "Factor used to divide the above resolution with" ) );
921 conf_saveComment( _( "This is used to lower the rendering resolution, and "
922 "scale to the above" ) );
923 conf_saveFloat( "scalefactor", conf.scalefactor );
924 conf_saveEmptyLine();
925
926 conf_saveComment( _( "Scale factor for rendered nebula backgrounds." ) );
927 conf_saveComment(
928 _( "Larger values can save time but lead to a blurrier appearance." ) );
929 conf_saveFloat( "nebu_scale", conf.nebu_scale );
930 conf_saveEmptyLine();
931
932 conf_saveComment( _( "Run Naev in full-screen mode" ) );
933 conf_saveBool( "fullscreen", conf.fullscreen );
934 conf_saveEmptyLine();
935
936 conf_saveComment( _( "Use video modesetting when fullscreen is enabled" ) );
937 conf_saveBool( "modesetting", conf.modesetting );
938 conf_saveEmptyLine();
939
940 conf_saveComment( _( "Disable allowing resizing the window." ) );
941 conf_saveBool( "notresizable", conf.notresizable );
942 conf_saveEmptyLine();
943
944 conf_saveComment(
945 _( "Disable window decorations. Use with care and know the keyboard "
946 "controls to quit and toggle fullscreen." ) );
947 conf_saveBool( "borderless", conf.borderless );
948 conf_saveEmptyLine();
949
950 conf_saveComment( _( "Minimize the game on focus loss." ) );
951 conf_saveBool( "minimize", conf.minimize );
952 conf_saveEmptyLine();
953
954 conf_saveComment(
955 _( "Enables colourblind simulation. A value of 0. disables." ) );
956 conf_saveFloat( "colourblind_sim", conf.colourblind_sim );
957 conf_saveEmptyLine();
958
959 conf_saveComment( _( "Type of colourblindness to simulate or correct." ) );
960 conf_saveComment( _( "0 is Protanopia" ) );
961 conf_saveComment( _( "1 is Deuteranopia" ) );
962 conf_saveComment( _( "2 is Tritanapia" ) );
963 conf_saveComment( _( "3 is Rod Monochromacy" ) );
964 conf_saveComment( _( "4 is Cone Monochromacy" ) );
965 conf_saveInt( "colourblind_type", conf.colourblind_type );
966 conf_saveEmptyLine();
967
968 conf_saveComment( _( "Intensity of the colour blindness correction. A value "
969 "of 0. disables." ) );
970 conf_saveFloat( "colourblind_correct", conf.colourblind_correct );
971 conf_saveEmptyLine();
972
973 conf_saveComment( _( "Slows down the game to improve accessibility." ) );
974 conf_saveFloat( "game_speed", conf.game_speed );
975 conf_saveEmptyLine();
976
977 conf_saveComment( _( "Enable health bars. These show hostility/friendliness "
978 "and health of pilots on screen." ) );
979 conf_saveBool( "healthbars", conf.healthbars );
980 conf_saveEmptyLine();
981
982 conf_saveComment(
983 _( "Background brightness. 1 is normal brightness while setting it to 0 "
984 "would make the backgrounds pitch black." ) );
985 conf_saveFloat( "bg_brightness", conf.bg_brightness );
986 conf_saveEmptyLine();
987
988 conf_saveComment(
989 _( "Nebula non-uniformity. 1 is normal nebula while setting it to 0 "
990 "would make the nebula a solid colour." ) );
991 conf_saveFloat( "nebu_nonuniformity", conf.nebu_nonuniformity );
992 conf_saveEmptyLine();
993
994 conf_saveComment( _(
995 "Nebula saturation. Modifies the base saturation of the nebula colour. "
996 "Lower values desaturate the nebulas to make them easier to view." ) );
997 conf_saveFloat( "nebu_saturation", conf.nebu_saturation );
998 conf_saveEmptyLine();
999
1000 conf_saveComment(
1001 _( "Controls the intensity to which the screen fades when jumping. 1.0 "
1002 "would be pure white, while 0.0 would be pure black." ) );
1003 conf_saveFloat( "jump_brightness", conf.jump_brightness );
1004 conf_saveEmptyLine();
1005
1006 conf_saveComment(
1007 _( "Gamma correction parameter. A value of 1 disables it (no curve)." ) );
1008 conf_saveFloat( "gamma_correction", conf.gamma_correction );
1009 conf_saveEmptyLine();
1010
1011 conf_saveComment( _( "Enables low memory mode which foregoes using normal "
1012 "textures and ambient occlusion. Useful when you want "
1013 "to run Naev or more limited hardware." ) );
1014 conf_saveBool( "low_memory", conf.low_memory );
1015 conf_saveEmptyLine();
1016
1017 conf_saveComment( _( "Provide an in-game option to skip puzzles that appear "
1018 "throughout the game." ) );
1019 conf_saveBool( "puzzle_skip", conf.puzzle_skip );
1020 conf_saveEmptyLine();
1021
1022 conf_saveComment(
1023 _( "Maximum texture size to use for 3D models when in low memory mode. A "
1024 "value of less than or equal to 0 disables texture resizing." ) );
1025 conf_saveInt( "max_3d_tex_size", conf.max_3d_tex_size );
1026 conf_saveEmptyLine();
1027
1028 /* FPS */
1029 conf_saveComment( _( "Display a frame rate counter" ) );
1030 conf_saveBool( "showfps", conf.fps_show );
1031 conf_saveEmptyLine();
1032
1033 conf_saveComment( _( "Limit the rendering frame rate" ) );
1034 conf_saveInt( "maxfps", conf.fps_max );
1035 conf_saveEmptyLine();
1036
1037 /* Pause */
1038 conf_saveComment( _( "Show 'PAUSED' on screen while paused" ) );
1039 conf_saveBool( "showpause", conf.pause_show );
1040 conf_saveEmptyLine();
1041
1042 /* Sound. */
1043 conf_saveComment( _( "Enables EFX extension for OpenAL backend." ) );
1044 conf_saveBool( "al_efx", conf.al_efx );
1045 conf_saveEmptyLine();
1046
1047 conf_saveComment( _( "Disable all sound" ) );
1048 conf_saveBool( "nosound", conf.nosound );
1049 conf_saveEmptyLine();
1050
1051 conf_saveComment(
1052 _( "Volume of sound effects and music, between 0.0 and 1.0" ) );
1053 conf_saveFloat( "sound",
1054 ( sound_disabled ) ? conf.sound : sound_getVolume() );
1055 conf_saveFloat( "music",
1056 ( music_disabled ) ? conf.music : music_getVolume() );
1057 conf_saveComment(
1058 _( "Relative engine sound volume. Should be between 0.0 and 1.0" ) );
1059 conf_saveFloat( "engine_vol", conf.engine_vol );
1060 conf_saveEmptyLine();
1061
1062 /* Joystick. */
1063 conf_saveComment( _( "The name or numeric index of the joystick to use" ) );
1064 conf_saveComment( _( "Setting this to nil disables the joystick support" ) );
1065 if ( conf.joystick_nam != NULL ) {
1066 conf_saveString( "joystick", conf.joystick_nam );
1067 } else if ( conf.joystick_ind >= 0 ) {
1068 conf_saveInt( "joystick", conf.joystick_ind );
1069 } else {
1070 conf_saveString( "joystick", NULL );
1071 }
1072 conf_saveEmptyLine();
1073
1074 /* GUI. */
1075 conf_saveComment( _( "Number of lines visible in the comm window." ) );
1076 conf_saveInt( "mesg_visible", conf.mesg_visible );
1077 conf_saveComment( _( "Opacity fraction (0-1) for the overlay map." ) );
1078 conf_saveFloat( "map_overlay_opacity", conf.map_overlay_opacity );
1079 conf_saveComment(
1080 _( "Use bigger icons in the outfit, shipyard, and other lists." ) );
1081 conf_saveBool( "big_icons", conf.big_icons );
1082 conf_saveComment( _(
1083 "Always show the radar and don't hide it when the overlay is active." ) );
1084 conf_saveBool( "always_radar", conf.always_radar );
1085 conf_saveEmptyLine();
1086
1087 /* Key repeat. */
1088 conf_saveComment(
1089 _( "Delay in ms before starting to repeat (0 disables)" ) );
1090 conf_saveInt( "repeat_delay", conf.repeat_delay );
1091 conf_saveComment(
1092 _( "Delay in ms between repeats once it starts to repeat" ) );
1093 conf_saveInt( "repeat_freq", conf.repeat_freq );
1094 conf_saveEmptyLine();
1095
1096 /* Zoom. */
1097 conf_saveComment( _( "Minimum and maximum zoom factor to use in-game" ) );
1098 conf_saveComment( _( "At 1.0, no sprites are scaled" ) );
1099 conf_saveComment( _( "zoom_far should be less then zoom_near" ) );
1100 conf_saveBool( "zoom_manual", conf.zoom_manual );
1101 conf_saveFloat( "zoom_far", conf.zoom_far );
1102 conf_saveFloat( "zoom_near", conf.zoom_near );
1103 conf_saveEmptyLine();
1104
1105 conf_saveComment( _( "Zooming speed in factor increments per second" ) );
1106 conf_saveFloat( "zoom_speed", conf.zoom_speed );
1107 conf_saveEmptyLine();
1108
1109 /* Fonts. */
1110 conf_saveComment( _( "Font sizes (in pixels) for Naev" ) );
1111 conf_saveComment( _( "Warning, setting to other than the default can cause "
1112 "visual glitches!" ) );
1113 pos +=
1114 scnprintf( &buf[pos], sizeof( buf ) - pos,
1115 _( "-- Console default: %d\n" ), FONT_SIZE_CONSOLE_DEFAULT );
1116 conf_saveInt( "font_size_console", conf.font_size_console );
1117 pos += scnprintf( &buf[pos], sizeof( buf ) - pos,
1118 _( "-- Intro default: %d\n" ), FONT_SIZE_INTRO_DEFAULT );
1119 conf_saveInt( "font_size_intro", conf.font_size_intro );
1120 pos += scnprintf( &buf[pos], sizeof( buf ) - pos,
1121 _( "-- Default size: %d\n" ), FONT_SIZE_DEF_DEFAULT );
1122 conf_saveInt( "font_size_def", conf.font_size_def );
1123 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, _( "-- Small size: %d\n" ),
1124 FONT_SIZE_SMALL_DEFAULT );
1125 conf_saveInt( "font_size_small", conf.font_size_small );
1126
1127 /* Misc. */
1128 conf_saveComment( _( "Redirects log and error output to files" ) );
1129 conf_saveBool( "redirect_file", conf.redirect_file );
1130 conf_saveEmptyLine();
1131
1132 conf_saveComment( _( "Doubletap sensitivity (used for double tap accel for "
1133 "afterburner or double tap reverse for cooldown)" ) );
1134 conf_saveInt( "doubletap_sensitivity", conf.doubletap_sens );
1135 conf_saveEmptyLine();
1136
1137 conf_saveComment(
1138 _( "Time (in seconds) to wait until hiding mouse when not used." ) );
1139 conf_saveBool( "mouse_hide", conf.mouse_hide );
1140 conf_saveEmptyLine();
1141
1142 conf_saveComment( _( "Whether or not clicking the middle mouse button "
1143 "toggles mouse flying mode." ) );
1144 conf_saveBool( "mouse_fly", conf.mouse_fly );
1145 conf_saveEmptyLine();
1146
1147 conf_saveComment( _( "Mouse-flying accel control" ) );
1148 conf_saveInt( "mouse_accel", conf.mouse_accel );
1149 conf_saveEmptyLine();
1150
1151 conf_saveComment(
1152 _( "Maximum interval to count as a double-click (0 disables)." ) );
1153 conf_saveFloat( "mouse_doubleclick", conf.mouse_doubleclick );
1154 conf_saveEmptyLine();
1155
1156 conf_saveComment(
1157 _( "Enables developer mode (universe editor and the likes)" ) );
1158 conf_saveBool( "devmode", conf.devmode );
1159 conf_saveEmptyLine();
1160
1161 conf_saveComment( _( "Automatic saving for when using the universe editor "
1162 "whenever an edit is done" ) );
1163 conf_saveBool( "devautosave", conf.devautosave );
1164 conf_saveEmptyLine();
1165
1166 conf_saveComment(
1167 _( "Enable the lua-enet library, for use by online/multiplayer mods "
1168 "(CAUTION: online Lua scripts may have security vulnerabilities!)" ) );
1169 conf_saveBool( "lua_enet", conf.lua_enet );
1170 conf_saveComment( _( "Enable the experimental CLI based on lua-repl." ) );
1171 conf_saveBool( "lua_repl", conf.lua_repl );
1172 conf_saveEmptyLine();
1173
1174 conf_saveComment(
1175 _( "Save the config every time game exits (rewriting this bit)" ) );
1176 conf_saveInt( "conf_nosave", conf.nosave );
1177 conf_saveEmptyLine();
1178
1179 conf_saveComment(
1180 _( "Indicates the last version the game has run in before" ) );
1181 conf_saveString( "lastversion", conf.lastversion );
1182 conf_saveEmptyLine();
1183
1184 conf_saveComment( _( "Indicates whether we've already warned about "
1185 "incomplete game translations." ) );
1186 conf_saveBool( "translation_warning_seen", conf.translation_warning_seen );
1187 conf_saveEmptyLine();
1188
1189 conf_saveComment( _( "Time Naev was last played. This gets refreshed each "
1190 "time you exit Naev." ) );
1191 conf_saveTime( "last_played", time( NULL ) );
1192 conf_saveEmptyLine();
1193
1194 /* Debugging. */
1195 conf_saveComment(
1196 _( "Enables FPU exceptions - only works on DEBUG builds" ) );
1197 conf_saveBool( "fpu_except", conf.fpu_except );
1198 conf_saveEmptyLine();
1199
1200 /* Editor. */
1201 conf_saveComment( _( "Path where the main data is stored at" ) );
1202 conf_saveString( "dev_data_dir", conf.dev_data_dir );
1203 conf_saveEmptyLine();
1204
1205 /*
1206 * Keybindings.
1207 */
1208 conf_saveEmptyLine();
1209 conf_saveComment( _( "Keybindings" ) );
1210 conf_saveEmptyLine();
1211
1212 /* Iterate over the keybinding. */
1213 for ( int i = 0; i <= KST_PASTE; i++ ) {
1214 SDL_Keycode key;
1215 KeybindType type;
1216 const char *typename;
1217 SDL_Keymod mod;
1218 const char *modname;
1219 char keyname[17];
1220
1221 /* Use an extra character in keyname to make sure it's always
1222 * zero-terminated */
1223 keyname[sizeof( keyname ) - 1] = '\0';
1224
1225 /* Save a comment line containing the description */
1226 conf_saveComment( input_getKeybindDescription( i ) );
1227
1228 /* Get the keybind */
1229 key = input_getKeybind( i, &type, &mod );
1230
1231 /* Determine the textual name for the keybind type */
1232 switch ( type ) {
1233 case KEYBIND_KEYBOARD:
1234 typename = "keyboard";
1235 break;
1236 case KEYBIND_JAXISPOS:
1237 typename = "jaxispos";
1238 break;
1239 case KEYBIND_JAXISNEG:
1240 typename = "jaxisneg";
1241 break;
1242 case KEYBIND_JBUTTON:
1243 typename = "jbutton";
1244 break;
1245 case KEYBIND_JHAT_UP:
1246 typename = "jhat_up";
1247 break;
1248 case KEYBIND_JHAT_DOWN:
1249 typename = "jhat_down";
1250 break;
1251 case KEYBIND_JHAT_LEFT:
1252 typename = "jhat_left";
1253 break;
1254 case KEYBIND_JHAT_RIGHT:
1255 typename = "jhat_right";
1256 break;
1257 default:
1258 typename = NULL;
1259 break;
1260 }
1261 /* Write a nil if an unknown type */
1262 if ( ( typename == NULL ) ||
1263 ( key == SDLK_UNKNOWN && type == KEYBIND_KEYBOARD ) ) {
1264 pos += scnprintf( &buf[pos], sizeof( buf ) - pos, "%s = \"none\"\n",
1265 input_getKeybindBrief( i ) );
1266 continue;
1267 }
1268
1269 /* Determine the textual name for the modifier */
1270 switch ( (int)mod ) {
1271 case NMOD_CTRL:
1272 modname = "ctrl";
1273 break;
1274 case NMOD_SHIFT:
1275 modname = "shift";
1276 break;
1277 case NMOD_ALT:
1278 modname = "alt";
1279 break;
1280 case NMOD_META:
1281 modname = "meta";
1282 break;
1283 case NMOD_ANY:
1284 modname = "any";
1285 break;
1286 default:
1287 modname = "none";
1288 break;
1289 }
1290
1291 /* Determine the textual name for the key, if a keyboard keybind */
1292 if ( type == KEYBIND_KEYBOARD )
1293 quoteLuaString( keyname, sizeof( keyname ) - 1,
1294 SDL_GetKeyName( key ) );
1295 /* If SDL can't describe the key, store it as an integer */
1296 if ( type != KEYBIND_KEYBOARD ||
1297 strcmp( keyname, "\"unknown key\"" ) == 0 )
1298 scnprintf( keyname, sizeof( keyname ) - 1, "%d", key );
1299
1300 /* Write out a simple Lua table containing the keybind info */
1301 pos +=
1302 scnprintf( &buf[pos], sizeof( buf ) - pos,
1303 "%s = { type = \"%s\", mod = \"%s\", key = %s }\n",
1304 input_getKeybindBrief( i ), typename, modname, keyname );
1305 }
1306 conf_saveEmptyLine();
1307
1308 /* Footer. */
1309 conf_saveComment( GENERATED_END_COMMENT );
1310
1311 if ( old != NULL ) {
1312 if ( oldfooter != NULL ) {
1313 /* oldfooter and oldsize now reference the old content past the footer
1314 */
1315 oldsize = MIN( (size_t)oldsize, sizeof( buf ) - pos );
1316 memcpy( &buf[pos], oldfooter, oldsize );
1317 pos += oldsize;
1318 }
1319 free( old );
1320 }
1321
1322 if ( nfile_writeFile( buf, pos, file ) < 0 ) {
1323 WARN( _( "Failed to write configuration! You'll most likely have to "
1324 "restore it by copying your backup configuration over your "
1325 "current configuration." ) );
1326 return -1;
1327 }
1328
1329 return 0;
1330}
1331
1335void conf_copy( PlayerConf_t *dest, const PlayerConf_t *src )
1336{
1337 conf_free( dest );
1338 memcpy( dest, src, sizeof( PlayerConf_t ) );
1339#define STRDUP( s ) dest->s = ( ( src->s == NULL ) ? NULL : strdup( src->s ) )
1340 STRDUP( ndata );
1341 STRDUP( datapath );
1342 STRDUP( language );
1343 STRDUP( joystick_nam );
1344 STRDUP( lastversion );
1345 STRDUP( dev_data_dir );
1346 if ( src->difficulty != NULL )
1347 STRDUP( difficulty );
1348#undef STRDUP
1349}
1350
1354void conf_free( PlayerConf_t *config )
1355{
1356 free( config->ndata );
1357 free( config->datapath );
1358 free( config->language );
1359 free( config->joystick_nam );
1360 free( config->lastversion );
1361 free( config->dev_data_dir );
1362 free( config->difficulty );
1363
1364 /* Clear memory. */
1365 memset( config, 0, sizeof( PlayerConf_t ) );
1366}
int background_load(const char *name)
Loads a background script by name.
Definition background.c:502
const char * input_getKeybindBrief(KeySemanticType keybind)
Gets the brief descirption of the keybinding.
Definition input.c:681
SDL_Keycode input_getKeybind(KeySemanticType keybind, KeybindType *type, SDL_Keymod *mod)
Gets the value of a keybind.
Definition input.c:525
SDL_Keycode input_keyConv(const char *name)
Gets the key id from its name.
Definition input.c:485
void input_setDefault(int wasd)
Sets the default input keys.
Definition input.c:267
const char * input_getKeybindName(KeySemanticType keybind)
Gets the name of the keybinding.
Definition input.c:693
void input_setKeybind(KeySemanticType keybind, KeybindType type, SDL_Keycode key, SDL_Keymod mod)
Binds key of type type to action keybind.
Definition input.c:502
const char * input_getKeybindDescription(KeySemanticType keybind)
Gets the description of the keybinding.
Definition input.c:708
int music_disabled
Definition music.c:29
double music_getVolume(void)
Gets the current music volume (linear).
Definition music.c:223
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define CLAMP(a, b, x)
Definition naev.h:41
int nfile_writeFile(const char *data, size_t len, const char *path)
Tries to write a file.
Definition nfile.c:559
char * nfile_readFile(size_t *filesize, const char *path)
Tries to read a file.
Definition nfile.c:442
int nfile_backupIfExists(const char *path)
Backup a file, if it exists.
Definition nfile.c:356
int nfile_fileExists(const char *path)
Checks to see if a file exists.
Definition nfile.c:329
int nfile_touch(const char *path)
Tries to create the file if it doesn't exist.
Definition nfile.c:533
int nfile_dirExists(const char *path)
Checks to see if a directory exists.
Definition nfile.c:309
lua_State * naevL
Definition nlua.c:54
char * strnstr(const char *haystack, const char *needle, size_t size)
A bounded version of strstr. Conforms to BSD semantics.
Definition nstring.c:26
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
static const double c[]
Definition rng.c:256
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1291
int sound_disabled
Definition sound.c:130
StarSystem * cur_system
Definition space.c:110
Struct containing player options.
Definition conf.h:94
char * datapath
Definition conf.h:100
char * language
Definition conf.h:103
char * ndata
Definition conf.h:99
char * difficulty
Definition conf.h:181
char * dev_data_dir
Definition conf.h:209
char * lastversion
Definition conf.h:200
char * joystick_nam
Definition conf.h:154