1 /*
2 * Tux Racer
3 * Copyright (C) 1999-2001 Jasmin F. Patry
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /* This file is complex. However, the ultimate purpose is to make
21 adding new configuration parameters easy. Here's what you need to
22 do to add a new parameter:
23
24 1. Choose a name and type for the parameter. By convention,
25 parameters have lower case names and words_are_separated_like_this.
26 Possible types are bool, int, char, and string. (Nothing is ruling
27 out floating point types; I just haven't needed them.) As an
28 example in the subsequent steps, suppose we wish to add a parameter
29 foo_bar of type string.
30
31 2. Add a field for the parameter to the 'params' struct defined
32 below. In our example, we would add the line
33 struct param foo_bar;
34 to the definition of struct params.
35
36 Note that the order of the entries in this struct determines the
37 order that the parameters will appear in the configuration file.
38
39 3. Initialize and assign a default value to the parameter in the
40 init_game_configuration() function. The INIT_PARAM_<TYPE> macros
41 will do this for you. In our example, we would add the line
42 INIT_PARAM_STRING( foo_bar, "baz" )
43 to assign a default value of "baz" to the parameter foo_bar.
44
45 4. Create the getparam/setparam functions for the parameter. This
46 is done using the FN_PARAM_<TYPE> macros. In our example, we would
47 add the line
48 FN_PARAM_STRING( foo_bar )
49 somewhere in the top-level scope of this file (to keep things neat
50 group it with the other definitions). The will create
51 getparam_foo_bar() and setparam_foo_bar() functions that can be
52 used to query the value of the parameter.
53
54 5. Create the prototypes for the getparam/setparam functions. This
55 is done in game_config.h using the PROTO_PARAM_<TYPE> macros. In
56 our example, we would add the line
57 PROTO_PARAM_STRING( foo_bar );
58 to game_config.h.
59
60 6. You're done! */
61
62 #include "tuxracer.h"
63
64 #if defined( WIN32 )
65 # define OLD_CONFIG_FILE "tuxracer.cfg"
66 #else
67 # define OLD_CONFIG_FILE ".tuxracer"
68 #endif /* defined( WIN32 ) */
69
70 #if defined( WIN32 )
71 # define CONFIG_DIR "config"
72 # define CONFIG_FILE "options.txt"
73 #else
74 # define CONFIG_DIR ".tuxracer"
75 # define CONFIG_FILE "options"
76 #endif /* defined( WIN32 ) */
77
78 #ifndef DATA_DIR
79 # if defined( WIN32 )
80 # define DATA_DIR "."
81 # else
82 # define DATA_DIR "/usr/local/share/tuxracer"
83 # endif /* defined( WIN32 ) */
84 #endif
85
86 /* Identifies the parameter type */
87 typedef enum {
88 PARAM_STRING,
89 PARAM_CHAR,
90 PARAM_INT,
91 PARAM_BOOL
92 } param_type;
93
94 /* Stores the value for all types */
95 typedef union {
96 char* string_val;
97 char char_val;
98 int int_val;
99 bool_t bool_val;
100 } param_val;
101
102 /* Stores state for each parameter */
103 struct param {
104 int loaded;
105 char *name;
106 param_type type;
107 param_val val;
108 param_val deflt;
109 char *comment;
110 };
111
112 /*
113 * These macros are used to initialize parameter values
114 */
115
116 #define INIT_PARAM( nam, val, typename, commnt ) \
117 Params.nam.loaded = False; \
118 Params.nam.name = #nam; \
119 Params.nam.deflt.typename ## _val = val; \
120 Params.nam.comment = commnt;
121
122 #define INIT_PARAM_STRING( nam, val, commnt ) \
123 INIT_PARAM( nam, val, string, commnt ); \
124 Params.nam.type = PARAM_STRING;
125
126 #define INIT_PARAM_CHAR( nam, val, commnt ) \
127 INIT_PARAM( nam, val, char, commnt ); \
128 Params.nam.type = PARAM_CHAR;
129
130 #define INIT_PARAM_INT( nam, val, commnt ) \
131 INIT_PARAM( nam, val, int, commnt ); \
132 Params.nam.type = PARAM_INT;
133
134 #define INIT_PARAM_BOOL( nam, val, commnt ) \
135 INIT_PARAM( nam, val, bool, commnt ); \
136 Params.nam.type = PARAM_BOOL;
137
138
139 /*
140 * These functions are used to get and set parameter values
141 */
142
fetch_param_string(struct param * p)143 void fetch_param_string( struct param *p )
144 {
145 char *val;
146
147 check_assertion( p->type == PARAM_STRING,
148 "configuration parameter type mismatch" );
149
150 val = Tcl_GetVar( g_game.tcl_interp, p->name, TCL_GLOBAL_ONLY );
151 if ( val == NULL ) {
152 p->val.string_val = string_copy( p->deflt.string_val );
153 } else {
154 p->val.string_val = string_copy( val );
155 }
156 p->loaded = True;
157
158 }
159
set_param_string(struct param * p,char * new_val)160 void set_param_string( struct param *p, char *new_val )
161 {
162 char *ret;
163
164 check_assertion( p->type == PARAM_STRING,
165 "configuration parameter type mismatch" );
166
167 if ( p->loaded ) {
168 free( p->val.string_val );
169 }
170 ret = Tcl_SetVar( g_game.tcl_interp, p->name, new_val, TCL_GLOBAL_ONLY );
171 if ( ret == NULL ) {
172 p->val.string_val = string_copy( p->deflt.string_val );
173 } else {
174 p->val.string_val = string_copy( new_val );
175 }
176 p->loaded = True;
177
178 }
179
fetch_param_char(struct param * p)180 void fetch_param_char( struct param *p )
181 {
182 char *str_val;
183
184 check_assertion( p->type == PARAM_CHAR,
185 "configuration parameter type mismatch" );
186
187 str_val = Tcl_GetVar( g_game.tcl_interp, p->name, TCL_GLOBAL_ONLY );
188
189 if ( str_val == NULL || str_val[0] == '\0' ) {
190 p->val.char_val = p->deflt.char_val;
191 } else {
192 p->val.char_val = str_val[0];
193 }
194 p->loaded = True;
195 }
196
set_param_char(struct param * p,char new_val)197 void set_param_char( struct param *p, char new_val )
198 {
199 char buff[2];
200 char *ret;
201
202 check_assertion( p->type == PARAM_CHAR,
203 "configuration parameter type mismatch" );
204
205 buff[0] = new_val;
206 buff[1] = '\0';
207
208 ret = Tcl_SetVar( g_game.tcl_interp, p->name, buff, TCL_GLOBAL_ONLY );
209 if ( ret == NULL ) {
210 p->val.char_val = p->deflt.char_val;
211 } else {
212 p->val.char_val = new_val;
213 }
214 p->loaded = True;
215
216 }
217
fetch_param_int(struct param * p)218 void fetch_param_int( struct param *p )
219 {
220 char *str_val;
221 int val;
222
223 check_assertion( p->type == PARAM_INT,
224 "configuration parameter type mismatch" );
225
226 str_val = Tcl_GetVar( g_game.tcl_interp, p->name, TCL_GLOBAL_ONLY );
227
228 if ( str_val == NULL
229 || Tcl_GetInt( g_game.tcl_interp, str_val, &val) == TCL_ERROR )
230 {
231 p->val.int_val = p->deflt.int_val;
232 } else {
233 p->val.int_val = val;
234 }
235 p->loaded = True;
236 }
237
set_param_int(struct param * p,int new_val)238 void set_param_int( struct param *p, int new_val )
239 {
240 char buff[30];
241 char *ret;
242
243 check_assertion( p->type == PARAM_INT,
244 "configuration parameter type mismatch" );
245
246 sprintf( buff, "%d", new_val );
247
248 ret = Tcl_SetVar( g_game.tcl_interp, p->name, buff, TCL_GLOBAL_ONLY );
249 if ( ret == NULL ) {
250 p->val.int_val = p->deflt.int_val;
251 } else {
252 p->val.int_val = new_val;
253 }
254 p->loaded = True;
255
256 }
257
fetch_param_bool(struct param * p)258 void fetch_param_bool( struct param *p )
259 {
260 char *str_val;
261 int val;
262 bool_t no_val = False;
263
264 check_assertion( p->type == PARAM_BOOL,
265 "configuration parameter type mismatch" );
266
267 str_val = Tcl_GetVar( g_game.tcl_interp, p->name, TCL_GLOBAL_ONLY );
268
269 if ( str_val == NULL ) {
270 no_val = True;
271 } else if ( string_cmp_no_case( str_val, "false" ) == 0 ) {
272 p->val.bool_val = False;
273 } else if ( string_cmp_no_case( str_val, "true" ) == 0 ) {
274 p->val.bool_val = True;
275 } else if ( Tcl_GetInt( g_game.tcl_interp, str_val, &val) == TCL_ERROR ) {
276 no_val = True;
277 } else {
278 p->val.bool_val = (val == 0) ? False : True ;
279 }
280
281 if ( no_val ) {
282 p->val.bool_val = p->deflt.bool_val;
283 }
284
285 p->loaded = True;
286 }
287
set_param_bool(struct param * p,bool_t new_val)288 void set_param_bool( struct param *p, bool_t new_val )
289 {
290 char buff[2];
291 char *ret;
292
293 check_assertion( p->type == PARAM_BOOL,
294 "configuration parameter type mismatch" );
295
296 sprintf( buff, "%d", new_val ? 1 : 0 );
297
298 ret = Tcl_SetVar( g_game.tcl_interp, p->name, buff, TCL_GLOBAL_ONLY );
299 if ( ret == NULL ) {
300 p->val.bool_val = p->deflt.bool_val;
301 } else {
302 p->val.bool_val = new_val;
303 }
304 p->loaded = True;
305 }
306
307
308 /*
309 * Creates set/get functions for each parameter
310 */
311 #define FN_PARAM( name, typename, type ) \
312 type getparam_ ## name() { \
313 if ( !Params.name.loaded ) { \
314 fetch_param_ ## typename( &( Params.name ) ); \
315 } \
316 return Params.name.val.typename ## _val; \
317 } \
318 void setparam_ ## name( type val) { \
319 set_param_ ## typename( &( Params.name ), val ); }
320
321 #define FN_PARAM_STRING( name ) \
322 FN_PARAM( name, string, char* )
323
324 #define FN_PARAM_CHAR( name ) \
325 FN_PARAM( name, char, char )
326
327 #define FN_PARAM_INT( name ) \
328 FN_PARAM( name, int, int )
329
330 #define FN_PARAM_BOOL( name ) \
331 FN_PARAM( name, bool, bool_t )
332
333
334 /*
335 * Main parameter struct
336 */
337 struct params {
338 struct param data_dir;
339 struct param fullscreen;
340 struct param x_resolution;
341 struct param y_resolution;
342 struct param bpp_mode;
343 struct param capture_mouse;
344 struct param force_window_position;
345 struct param quit_key;
346 struct param turn_left_key;
347 struct param turn_right_key;
348 struct param trick_modifier_key;
349 struct param brake_key;
350 struct param paddle_key;
351 struct param jump_key;
352 struct param reset_key;
353 struct param follow_view_key;
354 struct param behind_view_key;
355 struct param above_view_key;
356 struct param view_mode; /* coresponds to view_mode_t */
357 struct param screenshot_key;
358 struct param pause_key;
359
360 struct param joystick_paddle_button;
361 struct param joystick_brake_button;
362 struct param joystick_jump_button;
363 struct param joystick_trick_button;
364 struct param joystick_continue_button;
365 struct param joystick_x_axis;
366 struct param joystick_y_axis;
367
368 struct param no_audio;
369 struct param sound_enabled;
370 struct param music_enabled;
371 struct param sound_volume; /* 0-128 */
372 struct param music_volume; /* 0-128 */
373 struct param audio_freq_mode; /* 0 = 11025,
374 1 = 22050,
375 2 = 44100 */
376 struct param audio_format_mode; /* 0 = 8 bits,
377 1 = 16 bits */
378 struct param audio_stereo;
379 struct param audio_buffer_size;
380
381 struct param display_fps;
382 struct param course_detail_level;
383 struct param forward_clip_distance;
384 struct param backward_clip_distance;
385 struct param tree_detail_distance;
386 struct param terrain_blending;
387 struct param perfect_terrain_blending;
388 struct param terrain_envmap;
389 struct param disable_fog;
390 struct param draw_tux_shadow;
391 struct param tux_sphere_divisions;
392 struct param tux_shadow_sphere_divisions;
393 struct param draw_particles;
394 struct param track_marks;
395 struct param ui_snow;
396 struct param nice_fog;
397 struct param use_cva;
398 struct param cva_hack;
399 struct param use_sphere_display_list;
400 struct param do_intro_animation;
401 struct param mipmap_type; /* 0 = GL_NEAREST,
402 1 = GL_LINEAR,
403 2 = GL_NEAREST_MIPMAP_NEAREST,
404 3 = GL_LINEAR_MIPMAP_NEAREST,
405 4 = GL_NEAREST_MIPMAP_LINEAR,
406 5 = GL_LINEAR_MIPMAP_LINEAR
407 */
408 struct param ode_solver; /* 0 = Euler,
409 1 = ODE23,
410 2 = ODE45
411 */
412 struct param fov;
413 struct param debug;
414 struct param warning_level;
415 struct param write_diagnostic_log;
416 };
417
418 static struct params Params;
419
420
421 /*
422 * Initialize parameter data
423 */
424
init_game_configuration()425 void init_game_configuration()
426 {
427 INIT_PARAM_STRING(
428 data_dir, DATA_DIR,
429 "# The location of the Tux Racer data files" );
430
431 INIT_PARAM_BOOL(
432 draw_tux_shadow, False,
433 "# Set this to true to display Tux's shadow. Note that this is a \n"
434 "# hack and is quite expensive in terms of framerate.\n"
435 "# [EXPERT] This looks better if your card has a stencil buffer; \n"
436 "# if compiling use the --enable-stencil-buffer configure option \n"
437 "# to enable the use of the stencil buffer" );
438
439 INIT_PARAM_BOOL(
440 draw_particles, True,
441 "# Controls the drawing of snow particles that are kicked up as Tux\n"
442 "# turns and brakes. Setting this to false should help improve \n"
443 "# performance." );
444
445 INIT_PARAM_INT(
446 tux_sphere_divisions, 6,
447 "# [EXPERT] Higher values result in a more finely subdivided mesh \n"
448 "# for Tux, and vice versa. If you're experiencing low framerates,\n"
449 "# try lowering this value." );
450
451 INIT_PARAM_INT(
452 tux_shadow_sphere_divisions, 3,
453 "# [EXPERT] The level of subdivision of Tux's shadow." );
454
455 INIT_PARAM_BOOL(
456 nice_fog, True,
457 "# [EXPERT] If true, then the GL_NICEST hint will be used when\n"
458 "# rendering fog. On some cards, setting this to false may improve\n"
459 "# performance.");
460
461 INIT_PARAM_BOOL(
462 use_sphere_display_list, True,
463 "# [EXPERT] Mesa 3.1 sometimes renders Tux strangely when display \n"
464 "# lists are used. Setting this to false should solve the problem \n"
465 "# at the cost of a few Hz." );
466
467 INIT_PARAM_BOOL(
468 display_fps, False,
469 "# Set this to true to display the current framerate in Hz." );
470
471 INIT_PARAM_INT(
472 x_resolution, 640,
473 "# The horizontal size of the Tux Racer window" );
474
475 INIT_PARAM_INT(
476 y_resolution, 480,
477 "# The vertical size of the Tux Racer window" );
478
479 INIT_PARAM_BOOL(
480 capture_mouse, False,
481 "# If true, then the mouse will not be able to leave the \n"
482 "# Tux Racer window.\n"
483 "# If you lose keyboard focus while running Tux Racer, try setting\n"
484 "# this to true." );
485
486 INIT_PARAM_BOOL(
487 do_intro_animation, True,
488 "# If false, then the introductory animation sequence will be skipped."
489 );
490
491 INIT_PARAM_INT(
492 mipmap_type, 3,
493 "# [EXPERT] Allows you to control which type of texture\n"
494 "# interpolation/mipmapping is used when rendering textures. The\n"
495 "# values correspond to the following OpenGL settings:\n"
496 "#\n"
497 "# 0: GL_NEAREST\n"
498 "# 1: GL_LINEAR\n"
499 "# 2: GL_NEAREST_MIPMAP_NEAREST\n"
500 "# 3: GL_LINEAR_MIPMAP_NEAREST\n"
501 "# 4: GL_NEAREST_MIPMAP_LINEAR\n"
502 "# 5: GL_LINEAR_MIPMAP_LINEAR\n"
503 "#\n"
504 "# On some cards, you may be able to improve performance by\n"
505 "# decreasing this number, at the cost of lower image quality." );
506
507 INIT_PARAM_BOOL(
508 fullscreen, True,
509 "# If true then the game will run in full-screen mode." );
510
511 INIT_PARAM_INT(
512 bpp_mode, 0,
513 "# Controls how many bits per pixel are used in the game.\n"
514 "# Valid values are:\n"
515 "#\n"
516 "# 0: Use current bpp setting of operating system\n"
517 "# 1: 16 bpp\n"
518 "# 2: 32 bpp\n"
519 "# Note that some cards (e.g., Voodoo1, Voodoo2, Voodoo3) only support\n"
520 "# 16 bits per pixel." );
521
522 INIT_PARAM_BOOL(
523 force_window_position, False ,
524 "# If true, then the Tux Racer window will automatically be\n"
525 "# placed at (0,0)" );
526
527 INIT_PARAM_INT(
528 ode_solver, 1 ,
529 "# Selects the ODE (ordinary differential equation) solver. \n"
530 "# Possible values are:\n"
531 "#\n"
532 "# 0: Modified Euler (fastest but least accurate)\n"
533 "# 1: Runge-Kutta (2,3)\n"
534 "# 2: Runge-Kutta (4,5) (slowest but most accurate)" );
535
536 INIT_PARAM_STRING(
537 quit_key, "q escape" ,
538 "# Key binding for quitting a race" );
539 INIT_PARAM_STRING(
540 turn_left_key, "j left" ,
541 "# Key binding for turning left" );
542 INIT_PARAM_STRING(
543 turn_right_key, "l right" ,
544 "# Key binding for turning right" );
545 INIT_PARAM_STRING(
546 trick_modifier_key, "d" ,
547 "# Key binding for doing tricks" );
548 INIT_PARAM_STRING(
549 brake_key, "k space down" ,
550 "# Key binding for braking" );
551 INIT_PARAM_STRING(
552 paddle_key, "i up" ,
553 "# Key binding for paddling (on the ground) and flapping (in the air)"
554 );
555 INIT_PARAM_STRING(
556 follow_view_key, "1" ,
557 "# Key binding for the \"Follow\" camera mode" );
558 INIT_PARAM_STRING(
559 behind_view_key, "2" ,
560 "# Key binding for the \"Behind\" camera mode" );
561 INIT_PARAM_STRING(
562 above_view_key, "3" ,
563 "# Key binding for the \"Above\" camera mode" );
564 INIT_PARAM_INT(
565 view_mode, 1 ,
566 "# Default view mode. Possible values are\n"
567 "#\n"
568 "# 0: Behind\n"
569 "# 1: Follow\n"
570 "# 2: Above" );
571 INIT_PARAM_STRING(
572 screenshot_key, "=" ,
573 "# Key binding for taking a screenshot" );
574 INIT_PARAM_STRING(
575 pause_key, "p" ,
576 "# Key binding for pausing the game" );
577 INIT_PARAM_STRING(
578 reset_key, "backspace" ,
579 "# Key binding for resetting the player position" );
580 INIT_PARAM_STRING(
581 jump_key, "e" ,
582 "# Key binding for jumping" );
583
584 INIT_PARAM_INT(
585 joystick_paddle_button, 0 ,
586 "# Joystick button for paddling (numbering starts at 0).\n"
587 "# Set to -1 to disable." );
588
589 INIT_PARAM_INT(
590 joystick_brake_button, 2 ,
591 "# Joystick button for braking (numbering starts at 0).\n"
592 "# Set to -1 to disable." );
593
594 INIT_PARAM_INT(
595 joystick_jump_button, 3 ,
596 "# Joystick button for jumping (numbering starts at 0)" );
597
598 INIT_PARAM_INT(
599 joystick_trick_button, 1 ,
600 "# Joystick button for doing tricks (numbering starts at 0)" );
601
602 INIT_PARAM_INT(
603 joystick_continue_button, 0 ,
604 "# Joystick button for moving past intro, paused, and \n"
605 "# game over screens (numbering starts at 0)" );
606
607 INIT_PARAM_INT(
608 joystick_x_axis, 0 ,
609 "# Joystick axis to use for turning (numbering starts at 0)" );
610
611 INIT_PARAM_INT(
612 joystick_y_axis, 1 ,
613 "# Joystick axis to use for paddling/braking (numbering starts at 0)" );
614
615 INIT_PARAM_INT(
616 fov, 60 ,
617 "# [EXPERT] Sets the camera field-of-view" );
618 INIT_PARAM_STRING(
619 debug, "" ,
620 "# [EXPERT] Controls the Tux Racer debugging modes" );
621 INIT_PARAM_INT(
622 warning_level, 100 ,
623 "# [EXPERT] Controls the Tux Racer warning messages" );
624 INIT_PARAM_INT(
625 forward_clip_distance, 75 ,
626 "# Controls how far ahead of the camera the course\n"
627 "# is rendered. Larger values mean that more of the course is\n"
628 "# rendered, resulting in slower performance. Decreasing this \n"
629 "# value is an effective way to improve framerates." );
630 INIT_PARAM_INT(
631 backward_clip_distance, 10 ,
632 "# [EXPERT] Some objects aren't yet clipped to the view frustum, \n"
633 "# so this value is used to control how far up the course these \n"
634 "# objects are drawn." );
635 INIT_PARAM_INT(
636 tree_detail_distance, 20 ,
637 "# [EXPERT] Controls the distance at which trees are drawn with \n"
638 "# two rectangles instead of one." );
639 INIT_PARAM_BOOL(
640 terrain_blending, True ,
641 "# Controls the blending of the terrain textures. Setting this\n"
642 "# to false will help improve performance." );
643 INIT_PARAM_BOOL(
644 perfect_terrain_blending, False ,
645 "# [EXPERT] If true, then terrain triangles with three different\n"
646 "# terrain types at the vertices will be blended correctly\n"
647 "# (instead of using a faster but imperfect approximation)." );
648 INIT_PARAM_BOOL(
649 terrain_envmap, True ,
650 "# If true, then the ice will be drawn with an \"environment map\",\n"
651 "# which gives the ice a shiny appearance. Setting this to false\n"
652 "# will help improve performance." );
653 INIT_PARAM_BOOL(
654 disable_fog, False ,
655 "# If true, then fog will be turned off. Some Linux drivers for the\n"
656 "# ATI Rage128 seem to have a bug in their fog implementation which\n"
657 "# makes the screen nearly pure white when racing; if you experience\n"
658 "# this problem then set this variable to true." );
659 INIT_PARAM_BOOL(
660 use_cva, True ,
661 "# [EXPERT] If true, then compiled vertex arrays will be used when\n"
662 "# drawing the terrain. Whether or not this helps performance\n"
663 "# is driver- and card-dependent." );
664 INIT_PARAM_BOOL(
665 cva_hack, True ,
666 "# Some card/driver combinations render the terrrain incorrectly\n"
667 "# when using compiled vertex arrays. This activates a hack \n"
668 "# to work around that problem." );
669 INIT_PARAM_INT(
670 course_detail_level, 75 ,
671 "# [EXPERT] This controls how accurately the course terrain is \n"
672 "# rendered. A high value results in greater accuracy at the cost of \n"
673 "# performance, and vice versa. This value can be decreased and \n"
674 "# increased in 10% increments at runtime using the F9 and F10 keys.\n"
675 "# To better see the effect, activate wireframe mode using the F11 \n"
676 "# key (this is a toggle)." );
677 INIT_PARAM_BOOL(
678 no_audio, False ,
679 "# If True, then audio in the game is completely disabled." );
680 INIT_PARAM_BOOL(
681 sound_enabled, True ,
682 "# Use this to turn sound effects on and off." );
683 INIT_PARAM_BOOL(
684 music_enabled, True ,
685 "# Use this to turn music on and off." );
686 INIT_PARAM_INT(
687 sound_volume, 127 ,
688 "# This controls the sound volume (valid range is 0-127)." );
689 INIT_PARAM_INT(
690 music_volume, 64 ,
691 "# This controls the music volume (valid range is 0-127)." );
692 INIT_PARAM_INT(
693 audio_freq_mode, 1 ,
694 "# The controls the frequency of the audio. Valid values are:\n"
695 "# \n"
696 "# 0: 11025 Hz\n"
697 "# 1: 22050 Hz\n"
698 "# 2: 44100 Hz" );
699 INIT_PARAM_INT(
700 audio_format_mode, 1 ,
701 "# This controls the number of bits per sample for the audio.\n"
702 "# Valid values are:\n"
703 "#\n"
704 "# 0: 8 bits\n"
705 "# 1: 16 bits" );
706 INIT_PARAM_BOOL(
707 audio_stereo, True ,
708 "# Audio will be played in stereo of true, and mono if false" );
709 INIT_PARAM_INT(
710 audio_buffer_size, 2048 ,
711 "# [EXPERT] Controls the size of the audio buffer. \n"
712 "# Increase the buffer size if you experience choppy audio\n"
713 "# (at the cost of greater audio latency)" );
714 INIT_PARAM_BOOL(
715 track_marks, True ,
716 "# If true, then the players will leave track marks in the snow." );
717 INIT_PARAM_BOOL(
718 ui_snow, True ,
719 "# If true, then the ui screens will have falling snow." );
720
721 INIT_PARAM_BOOL(
722 write_diagnostic_log, False ,
723 "# If true, then a file called diagnostic_log.txt will be generated\n"
724 "# which you should attach to any bug reports you make.\n"
725 "# To generate the file, set this variable to \"true\", and\n"
726 "# then run the game so that you reproduce the bug, if possible."
727 );
728 }
729
730
731 /*
732 * Create the set/get functions for parameters
733 */
734
735 FN_PARAM_STRING( data_dir )
FN_PARAM_BOOL(draw_tux_shadow)736 FN_PARAM_BOOL( draw_tux_shadow )
737 FN_PARAM_BOOL( draw_particles )
738 FN_PARAM_INT( tux_sphere_divisions )
739 FN_PARAM_INT( tux_shadow_sphere_divisions )
740 FN_PARAM_BOOL( nice_fog )
741 FN_PARAM_BOOL( use_sphere_display_list )
742 FN_PARAM_BOOL( display_fps )
743 FN_PARAM_INT( x_resolution )
744 FN_PARAM_INT( y_resolution )
745 FN_PARAM_BOOL( capture_mouse )
746 FN_PARAM_BOOL( do_intro_animation )
747 FN_PARAM_INT( mipmap_type )
748 FN_PARAM_BOOL( fullscreen )
749 FN_PARAM_INT( bpp_mode )
750 FN_PARAM_BOOL( force_window_position )
751 FN_PARAM_INT( ode_solver )
752 FN_PARAM_STRING( quit_key )
753 FN_PARAM_STRING( turn_left_key )
754 FN_PARAM_STRING( turn_right_key )
755 FN_PARAM_STRING( trick_modifier_key )
756 FN_PARAM_STRING( brake_key )
757 FN_PARAM_STRING( paddle_key )
758 FN_PARAM_STRING( above_view_key )
759 FN_PARAM_STRING( behind_view_key )
760 FN_PARAM_STRING( follow_view_key )
761 FN_PARAM_INT( view_mode )
762 FN_PARAM_STRING( screenshot_key )
763 FN_PARAM_STRING( pause_key )
764 FN_PARAM_STRING( reset_key )
765 FN_PARAM_STRING( jump_key )
766 FN_PARAM_INT( joystick_jump_button )
767 FN_PARAM_INT( joystick_brake_button )
768 FN_PARAM_INT( joystick_paddle_button )
769 FN_PARAM_INT( joystick_trick_button )
770 FN_PARAM_INT( joystick_continue_button )
771 FN_PARAM_INT( joystick_x_axis )
772 FN_PARAM_INT( joystick_y_axis )
773 FN_PARAM_INT( fov )
774 FN_PARAM_STRING( debug )
775 FN_PARAM_INT( warning_level )
776 FN_PARAM_INT( forward_clip_distance )
777 FN_PARAM_INT( backward_clip_distance )
778 FN_PARAM_INT( tree_detail_distance )
779 FN_PARAM_INT( course_detail_level )
780 FN_PARAM_BOOL( terrain_blending )
781 FN_PARAM_BOOL( perfect_terrain_blending )
782 FN_PARAM_BOOL( terrain_envmap )
783 FN_PARAM_BOOL( disable_fog )
784 FN_PARAM_BOOL( use_cva )
785 FN_PARAM_BOOL( cva_hack )
786 FN_PARAM_BOOL( track_marks )
787 FN_PARAM_BOOL( ui_snow )
788
789 FN_PARAM_BOOL( no_audio )
790 FN_PARAM_BOOL( sound_enabled )
791 FN_PARAM_BOOL( music_enabled )
792 FN_PARAM_INT( sound_volume )
793 FN_PARAM_INT( music_volume )
794 FN_PARAM_INT( audio_freq_mode )
795 FN_PARAM_INT( audio_format_mode )
796 FN_PARAM_BOOL( audio_stereo )
797 FN_PARAM_INT( audio_buffer_size )
798 FN_PARAM_BOOL( write_diagnostic_log )
799
800
801
802 /*
803 * Functions to read and write the configuration file
804 */
805
806 int get_old_config_file_name( char *buff, int len )
807 {
808 #if defined( WIN32 )
809 if ( strlen( OLD_CONFIG_FILE ) +1 > len ) {
810 return 1;
811 }
812 strcpy( buff, OLD_CONFIG_FILE );
813 return 0;
814 #else
815 struct passwd *pwent;
816
817 pwent = getpwuid( getuid() );
818 if ( pwent == NULL ) {
819 perror( "getpwuid" );
820 return 1;
821 }
822
823 if ( strlen( pwent->pw_dir ) + strlen( OLD_CONFIG_FILE ) + 2 > len ) {
824 return 1;
825 }
826
827 sprintf( buff, "%s/%s", pwent->pw_dir, OLD_CONFIG_FILE );
828 return 0;
829 #endif /* defined( WIN32 ) */
830 }
831
get_config_dir_name(char * buff,int len)832 int get_config_dir_name( char *buff, int len )
833 {
834 #if defined( WIN32 )
835 if ( strlen( CONFIG_DIR ) +1 > len ) {
836 return 1;
837 }
838 strcpy( buff, CONFIG_DIR );
839 return 0;
840 #else
841 struct passwd *pwent;
842
843 pwent = getpwuid( getuid() );
844 if ( pwent == NULL ) {
845 perror( "getpwuid" );
846 return 1;
847 }
848
849 if ( strlen( pwent->pw_dir ) + strlen( CONFIG_DIR) + 2 > len ) {
850 return 1;
851 }
852
853 sprintf( buff, "%s/%s", pwent->pw_dir, CONFIG_DIR );
854 return 0;
855 #endif /* defined( WIN32 ) */
856 }
857
get_config_file_name(char * buff,int len)858 int get_config_file_name( char *buff, int len )
859 {
860 if (get_config_dir_name( buff, len ) != 0) {
861 return 1;
862 }
863 if ( strlen( buff ) + strlen( CONFIG_FILE ) +2 > len ) {
864 return 1;
865 }
866
867 #if defined( WIN32 )
868 strcat( buff, "\\" );
869 #else
870 strcat( buff, "/" );
871 #endif /* defined( WIN32 ) */
872
873 strcat( buff, CONFIG_FILE);
874 return 0;
875 }
876
clear_config_cache()877 void clear_config_cache()
878 {
879 struct param *parm;
880 int i;
881
882 for (i=0; i<sizeof(Params)/sizeof(struct param); i++) {
883 parm = (struct param*)&Params + i;
884 parm->loaded = False;
885 }
886 }
887
read_config_file()888 void read_config_file()
889 {
890 char config_file[BUFF_LEN];
891 char config_dir[BUFF_LEN];
892
893 clear_config_cache();
894
895 if ( get_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
896 return;
897 }
898 if ( get_config_dir_name( config_dir, sizeof( config_dir ) ) != 0 ) {
899 return;
900 }
901
902
903 if ( dir_exists( config_dir ) ) {
904 if ( file_exists( config_file ) ) {
905 /* File exists -- let's try to evaluate it. */
906 if ( Tcl_EvalFile( g_game.tcl_interp, config_file ) != TCL_OK ) {
907 handle_error( 1, "error evalating %s: %s", config_file,
908 Tcl_GetStringResult( g_game.tcl_interp ) );
909 }
910 }
911 return;
912 }
913
914 /* File does not exist -- look for old version */
915 if ( get_old_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
916 return;
917 }
918 if ( !file_exists( config_file ) ) {
919 return;
920 }
921 /* Old file exists -- let's try to evaluate it. */
922 if ( Tcl_EvalFile( g_game.tcl_interp, config_file ) != TCL_OK ) {
923 handle_error( 1, "error evalating deprecated %s: %s", config_file,
924 Tcl_GetStringResult( g_game.tcl_interp ) );
925 } else {
926 /* Remove old file and save info in new file location */
927 remove(config_file);
928 write_config_file();
929 }
930 }
931
write_config_file()932 void write_config_file()
933 {
934 FILE *config_stream;
935 char config_file[BUFF_LEN];
936 char config_dir[BUFF_LEN];
937 struct param *parm;
938 int i;
939
940 if ( get_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
941 return;
942 }
943 if ( get_config_dir_name( config_dir, sizeof( config_dir ) ) != 0 ) {
944 return;
945 }
946
947 if ( !dir_exists( config_dir ) ) {
948
949 #if defined(WIN32) && !defined(__CYGWIN__)
950 if (mkdir( config_dir ) != 0) {
951 return;
952 }
953 #else
954 if (mkdir( config_dir, 0775) != 0) {
955 return;
956 }
957 #endif
958
959 }
960
961 config_stream = fopen( config_file, "w" );
962
963 if ( config_stream == NULL ) {
964 print_warning( CRITICAL_WARNING,
965 "couldn't open %s for writing: %s",
966 config_file, strerror(errno) );
967 return;
968 }
969
970 fprintf( config_stream,
971 "# Tux Racer " VERSION " configuration file\n"
972 "#\n"
973 );
974
975 for (i=0; i<sizeof(Params)/sizeof(struct param); i++) {
976 parm = (struct param*)&Params + i;
977 if ( parm->comment != NULL ) {
978 fprintf( config_stream, "\n# %s\n#\n%s\n#\n",
979 parm->name, parm->comment );
980 }
981 switch ( parm->type ) {
982 case PARAM_STRING:
983 fetch_param_string( parm );
984 fprintf( config_stream, "set %s \"%s\"\n",
985 parm->name, parm->val.string_val );
986 break;
987 case PARAM_CHAR:
988 fetch_param_char( parm );
989 fprintf( config_stream, "set %s %c\n",
990 parm->name, parm->val.char_val );
991 break;
992 case PARAM_INT:
993 fetch_param_int( parm );
994 fprintf( config_stream, "set %s %d\n",
995 parm->name, parm->val.int_val );
996 break;
997 case PARAM_BOOL:
998 fetch_param_bool( parm );
999 fprintf( config_stream, "set %s %s\n",
1000 parm->name, parm->val.bool_val ? "true" : "false" );
1001 break;
1002 default:
1003 code_not_reached();
1004 }
1005 }
1006
1007 if ( fclose( config_stream ) != 0 ) {
1008 perror( "fclose" );
1009 }
1010 }
1011
1012 /*
1013 * Tcl callback to allow reading of game configuration variables from Tcl.
1014 */
get_param_cb(ClientData cd,Tcl_Interp * ip,int argc,char * argv[])1015 static int get_param_cb ( ClientData cd, Tcl_Interp *ip,
1016 int argc, char *argv[])
1017 {
1018 int i;
1019 int num_params;
1020 struct param *parm;
1021
1022 if ( argc != 2 ) {
1023 Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n",
1024 "Usage: ", argv[0], " <parameter name>",
1025 (char *)0 );
1026 return TCL_ERROR;
1027 }
1028
1029 /* Search for parameter */
1030 parm = NULL;
1031 num_params = sizeof(Params)/sizeof(struct param);
1032 for (i=0; i<num_params; i++) {
1033 parm = (struct param*)&Params + i;
1034
1035 if ( strcmp( parm->name, argv[1] ) == 0 ) {
1036 break;
1037 }
1038 }
1039
1040 /* If can't find parameter, report error */
1041 if ( parm == NULL || i == num_params ) {
1042 Tcl_AppendResult(ip, argv[0], ": invalid parameter `",
1043 argv[1], "'", (char *)0 );
1044 return TCL_ERROR;
1045 }
1046
1047 /* Get value of parameter */
1048 switch ( parm->type ) {
1049 case PARAM_STRING:
1050 fetch_param_string( parm );
1051 Tcl_SetObjResult( ip, Tcl_NewStringObj( parm->val.string_val, -1 ) );
1052 break;
1053
1054 case PARAM_CHAR:
1055 fetch_param_char( parm );
1056 Tcl_SetObjResult( ip, Tcl_NewStringObj( &parm->val.char_val, 1 ) );
1057 break;
1058
1059 case PARAM_INT:
1060 fetch_param_int( parm );
1061 Tcl_SetObjResult( ip, Tcl_NewIntObj( parm->val.int_val ) );
1062 break;
1063
1064 case PARAM_BOOL:
1065 fetch_param_bool( parm );
1066 Tcl_SetObjResult( ip, Tcl_NewBooleanObj( parm->val.bool_val ) );
1067 break;
1068
1069 default:
1070 code_not_reached();
1071 }
1072
1073 return TCL_OK;
1074 }
1075
1076 /*
1077 * Tcl callback to allow setting of game configuration variables from Tcl.
1078 */
set_param_cb(ClientData cd,Tcl_Interp * ip,int argc,char * argv[])1079 static int set_param_cb ( ClientData cd, Tcl_Interp *ip,
1080 int argc, char *argv[])
1081 {
1082 int i;
1083 int tmp_int;
1084 int num_params;
1085 struct param *parm;
1086
1087 if ( argc != 3 ) {
1088 Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n",
1089 "Usage: ", argv[0], " <parameter name> <value>",
1090 (char *)0 );
1091 return TCL_ERROR;
1092 }
1093
1094 /* Search for parameter */
1095 parm = NULL;
1096 num_params = sizeof(Params)/sizeof(struct param);
1097 for (i=0; i<num_params; i++) {
1098 parm = (struct param*)&Params + i;
1099
1100 if ( strcmp( parm->name, argv[1] ) == 0 ) {
1101 break;
1102 }
1103 }
1104
1105 /* If can't find parameter, report error */
1106 if ( parm == NULL || i == num_params ) {
1107 Tcl_AppendResult(ip, argv[0], ": invalid parameter `",
1108 argv[1], "'", (char *)0 );
1109 return TCL_ERROR;
1110 }
1111
1112 /* Set value of parameter */
1113 switch ( parm->type ) {
1114 case PARAM_STRING:
1115 set_param_string( parm, argv[2] );
1116 break;
1117
1118 case PARAM_CHAR:
1119 if ( strlen( argv[2] ) > 1 ) {
1120 Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
1121 argv[1], "' must be a single character",
1122 (char *)0 );
1123 return TCL_ERROR;
1124 }
1125 set_param_char( parm, argv[2][0] );
1126 break;
1127
1128 case PARAM_INT:
1129 if ( Tcl_GetInt( ip, argv[2], &tmp_int ) != TCL_OK ) {
1130 Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
1131 argv[1], "' must be an integer",
1132 (char *)0 );
1133 return TCL_ERROR;
1134 }
1135 set_param_int( parm, tmp_int );
1136 break;
1137
1138 case PARAM_BOOL:
1139 if ( Tcl_GetBoolean( ip, argv[2], &tmp_int ) != TCL_OK ) {
1140 Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
1141 argv[1], "' must be a boolean",
1142 (char *)0 );
1143 return TCL_ERROR;
1144 }
1145 check_assertion( tmp_int == 0 || tmp_int == 1,
1146 "invalid boolean value" );
1147 set_param_bool( parm, (bool_t) tmp_int );
1148 break;
1149
1150 default:
1151 code_not_reached();
1152 }
1153
1154 return TCL_OK;
1155 }
1156
register_game_config_callbacks(Tcl_Interp * ip)1157 void register_game_config_callbacks( Tcl_Interp *ip )
1158 {
1159 Tcl_CreateCommand (ip, "tux_get_param", get_param_cb, 0,0);
1160 Tcl_CreateCommand (ip, "tux_set_param", set_param_cb, 0,0);
1161 }
1162
1163