Back to index

extremetuxracer  0.5beta
game_config.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020  */
00021 
00022 /* This file is complex.  However, the ultimate purpose is to make
00023    adding new configuration parameters easy.  Here's what you need to
00024    do to add a new parameter:
00025 
00026    1. Choose a name and type for the parameter.  By convention,
00027    parameters have lower case names and words_are_separated_like_this.
00028    Possible types are bool, int, char, and string.  (Nothing is ruling
00029    out floating point types; I just haven't needed them.)  As an
00030    example in the subsequent steps, suppose we wish to add a parameter
00031    foo_bar of type string.
00032 
00033    2. Add a field for the parameter to the 'params' struct defined
00034    below.  In our example, we would add the line
00035        struct param foo_bar;
00036    to the definition of struct params.
00037 
00038    Note that the order of the entries in this struct determines the
00039    order that the parameters will appear in the configuration file.
00040 
00041    3. Initialize and assign a default value to the parameter in the
00042    init_game_configuration() function.  The INIT_PARAM_<TYPE> macros
00043    will do this for you.  In our example, we would add the line
00044        INIT_PARAM_STRING( foo_bar, "baz" )
00045    to assign a default value of "baz" to the parameter foo_bar.
00046 
00047    4. Create the getparam/setparam functions for the parameter.  This
00048    is done using the FN_PARAM_<TYPE> macros.  In our example, we would
00049    add the line 
00050        FN_PARAM_STRING( foo_bar )
00051    somewhere in the top-level scope of this file (to keep things neat
00052    group it with the other definitions).  The will create
00053    getparam_foo_bar() and setparam_foo_bar() functions that can be
00054    used to query the value of the parameter.
00055 
00056    5. Create the prototypes for the getparam/setparam functions.  This
00057    is done in game_config.h using the PROTO_PARAM_<TYPE> macros.  In
00058    our example, we would add the line
00059        PROTO_PARAM_STRING( foo_bar );
00060    to game_config.h.
00061 
00062    6. You're done!  */
00063 
00064 #include "file_util.h"
00065 #include "game_config.h"
00066 #include "string_util.h"
00067 #include "course_mgr.h"
00068 #include "winsys.h"
00069 #include "ppgltk/audio/audio.h"
00070 
00071 #ifdef __APPLE__
00072 #  include <CoreFoundation/CoreFoundation.h>
00073 static char osx_path[1024];
00074 static char* osx_path_ptr = NULL;
00075 
00076 static char* getMacPath()
00077 {
00078     if(!osx_path_ptr) {
00079         // on OS X we can't hard-code paths, it needs to be determined at runtime
00080         char path[1024];
00081         CFBundleRef mainBundle = CFBundleGetMainBundle(); assert(mainBundle);
00082         CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle); assert(mainBundleURL);
00083         CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle); assert(cfStringRef);
00084         CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
00085         CFRelease(mainBundleURL); CFRelease(cfStringRef);
00086         
00087         sprintf(osx_path,"%s%s",path,"/Contents/Resources");
00088         std::string contents = std::string(osx_path);
00089         if(contents.find(".app") != std::string::npos){
00090             osx_path_ptr = &osx_path[0];
00091         }
00092         else {
00093             sprintf(osx_path,"%s",PP_DATADIR);
00094             osx_path_ptr = &osx_path[0];
00095         }
00096     }
00097         return osx_path_ptr;
00098 }
00099 #endif
00100 
00101 #if defined( WIN32 )
00102 #  define OLD_CONFIG_FILE "etracer.cfg"
00103 #else
00104 #  define OLD_CONFIG_FILE ".etracer"
00105 #endif /* defined( WIN32 ) */
00106 
00107 #if defined( WIN32 )
00108 #  define CONFIG_DIR "config"
00109 #  define CONFIG_FILE "options.txt"
00110 #else
00111 #  define CONFIG_DIR ".etracer"
00112 #  define CONFIG_FILE "options"
00113 #endif /* defined( WIN32 ) */
00114 
00115 #ifndef DATA_DIR
00116 #  if defined( WIN32 )
00117 #    define DATA_DIR "."
00118 #  elif defined(__APPLE__)
00119 #    define DATA_DIR getMacPath()
00120 #  else
00121 #    define DATA_DIR PP_DATADIR
00122 #  endif
00123 #endif
00124 
00125 
00126 
00127 
00128 static const char* sp_config_file=NULL;
00129 
00130 
00131 /* Identifies the parameter type */
00132 typedef enum {
00133     PARAM_STRING,
00134     PARAM_CHAR,
00135     PARAM_INT,
00136     PARAM_BOOL
00137 } param_type;
00138 
00139 /* Stores the value for all types */
00140 typedef union {
00141     char* string_val;
00142     char  char_val;
00143     int   int_val;
00144     bool bool_val;
00145 } param_val;
00146 
00147 /* Stores state for each parameter */
00148 struct param {
00149     int loaded;
00150     char *name;
00151     param_type type;
00152     param_val val;
00153     param_val deflt;
00154     char *comment;
00155 };
00156 
00157 /*
00158  * These macros are used to initialize parameter values
00159  */
00160 
00161 #define INIT_PARAM( nam, val, typename, commnt ) \
00162    Params.nam.loaded = false; \
00163    Params.nam.name = #nam; \
00164    Params.nam.deflt.typename ## _val  = val; \
00165    Params.nam.comment = commnt;
00166 
00167 #define INIT_PARAM_STRING( nam, val, commnt ) \
00168    INIT_PARAM( nam, val, string, commnt ); \
00169    Params.nam.type = PARAM_STRING;
00170 
00171 #define INIT_PARAM_CHAR( nam, val, commnt ) \
00172    INIT_PARAM( nam, val, char, commnt ); \
00173    Params.nam.type = PARAM_CHAR;
00174 
00175 #define INIT_PARAM_INT( nam, val, commnt ) \
00176    INIT_PARAM( nam, val, int, commnt ); \
00177    Params.nam.type = PARAM_INT;
00178 
00179 #define INIT_PARAM_BOOL( nam, val, commnt ) \
00180    INIT_PARAM( nam, val, bool, commnt ); \
00181    Params.nam.type = PARAM_BOOL;
00182 
00183 
00184 /*
00185  * These functions are used to get and set parameter values
00186  */
00187 
00188 void fetch_param_string( struct param *p )
00189 {
00190     const char *val;
00191 
00192     check_assertion( p->type == PARAM_STRING, 
00193                    "configuration parameter type mismatch" );
00194 
00195     val = Tcl_GetVar( tclInterp, p->name, TCL_GLOBAL_ONLY );
00196     if ( val == NULL ) {
00197        p->val.string_val = string_copy( p->deflt.string_val );
00198     } else {
00199        p->val.string_val = string_copy( val );
00200     }
00201     p->loaded = true;
00202 
00203 }
00204 
00205 void set_param_string( struct param *p, CONST84 char *new_val )
00206 {
00207     const char *ret;
00208 
00209     check_assertion( p->type == PARAM_STRING, 
00210                    "configuration parameter type mismatch" );
00211 
00212     if ( p->loaded ) {
00213        free( p->val.string_val );
00214     }
00215     ret = Tcl_SetVar( tclInterp, p->name, new_val, TCL_GLOBAL_ONLY );
00216     if ( ret == NULL ) {
00217        p->val.string_val = string_copy( p->deflt.string_val );
00218     } else {
00219        p->val.string_val = string_copy( new_val );
00220     }
00221     p->loaded = true;
00222 
00223 }
00224 
00225 void fetch_param_char( struct param *p )
00226 {
00227     const char *str_val;
00228 
00229     check_assertion( p->type == PARAM_CHAR, 
00230                    "configuration parameter type mismatch" );
00231 
00232     str_val = Tcl_GetVar( tclInterp, p->name, TCL_GLOBAL_ONLY );
00233     
00234     if ( str_val == NULL || str_val[0] == '\0' ) {
00235        p->val.char_val = p->deflt.char_val;
00236     } else {
00237        p->val.char_val = str_val[0];
00238     }
00239     p->loaded = true;
00240 }
00241 
00242 void set_param_char( struct param *p, char new_val )
00243 {
00244     char buff[2];
00245     const char *ret;
00246 
00247     check_assertion( p->type == PARAM_CHAR, 
00248                    "configuration parameter type mismatch" );
00249 
00250     buff[0] = new_val;
00251     buff[1] = '\0';
00252 
00253     ret = Tcl_SetVar( tclInterp, p->name, buff, TCL_GLOBAL_ONLY );
00254     if ( ret == NULL ) {
00255        p->val.char_val = p->deflt.char_val;
00256     } else {
00257        p->val.char_val = new_val;
00258     }
00259     p->loaded = true;
00260 
00261 }
00262 
00263 void fetch_param_int( struct param *p )
00264 {
00265     CONST84 char *str_val;
00266     int val;
00267 
00268     check_assertion( p->type == PARAM_INT, 
00269                    "configuration parameter type mismatch" );
00270     
00271     str_val = Tcl_GetVar( tclInterp, p->name, TCL_GLOBAL_ONLY );
00272     
00273     if ( str_val == NULL 
00274         || Tcl_GetInt( tclInterp, str_val, &val) == TCL_ERROR  ) 
00275     {
00276        p->val.int_val = p->deflt.int_val;
00277     } else {
00278        p->val.int_val = val;
00279     }
00280     p->loaded = true;
00281 }
00282 
00283 void set_param_int( struct param *p, int new_val )
00284 {
00285     char buff[30];
00286     const char *ret;
00287 
00288     check_assertion( p->type == PARAM_INT, 
00289                    "configuration parameter type mismatch" );
00290 
00291     sprintf( buff, "%d", new_val );
00292 
00293     ret = Tcl_SetVar( tclInterp, p->name, buff, TCL_GLOBAL_ONLY );
00294     if ( ret == NULL ) {
00295        p->val.int_val = p->deflt.int_val;
00296     } else {
00297        p->val.int_val = new_val;
00298     }
00299     p->loaded = true;
00300 
00301 }
00302 
00303 void fetch_param_bool( struct param *p )
00304 {
00305     CONST84 char *str_val;
00306     int val;
00307     bool no_val = false;
00308 
00309     check_assertion( p->type == PARAM_BOOL, 
00310                    "configuration parameter type mismatch" );
00311 
00312     str_val = Tcl_GetVar( tclInterp, p->name, TCL_GLOBAL_ONLY );
00313     
00314     if ( str_val == NULL ) {
00315        no_val = true;
00316     } else if ( strcmp( str_val, "false" ) == 0 ) {
00317        p->val.bool_val = false;
00318     } else if ( strcmp( str_val, "true" ) == 0 ) {
00319        p->val.bool_val = true;
00320     } else if ( Tcl_GetInt( tclInterp, str_val, &val) == TCL_ERROR ) {
00321        no_val = true;
00322     } else {
00323        p->val.bool_val = (val == 0) ? false : true ;
00324     }
00325 
00326     if ( no_val ) {
00327        p->val.bool_val = p->deflt.bool_val;
00328     }
00329 
00330     p->loaded = true;
00331 }
00332 
00333 void set_param_bool( struct param *p, bool new_val )
00334 {
00335     char buff[2];
00336     const char *ret;
00337 
00338     check_assertion( p->type == PARAM_BOOL, 
00339                    "configuration parameter type mismatch" );
00340 
00341     sprintf( buff, "%d", new_val ? 1 : 0 );
00342 
00343     ret = Tcl_SetVar( tclInterp, p->name, buff, TCL_GLOBAL_ONLY );
00344     if ( ret == NULL ) {
00345        p->val.bool_val = p->deflt.bool_val;
00346     } else {
00347        p->val.bool_val = new_val;
00348     }
00349     p->loaded = true;
00350 }
00351 
00352 
00353 /*
00354  * Creates set/get functions for each parameter
00355  */
00356 #define FN_PARAM( name, typename, type ) \
00357     type getparam_ ## name() { \
00358         if ( !Params.name.loaded ) { \
00359             fetch_param_ ## typename( &( Params.name ) ); \
00360         } \
00361         return Params.name.val.typename ## _val; \
00362     } \
00363     void setparam_ ## name( type val) { \
00364         set_param_ ## typename( &( Params.name ), val ); } 
00365 
00366 #define FN_PARAM_STRING( name ) \
00367     FN_PARAM( name, string, char* )
00368 
00369 #define FN_PARAM_CHAR( name ) \
00370     FN_PARAM( name, char, char )
00371 
00372 #define FN_PARAM_INT( name ) \
00373     FN_PARAM( name, int, int )
00374 
00375 #define FN_PARAM_BOOL( name ) \
00376     FN_PARAM( name, bool, bool )
00377 
00378 
00379 /*
00380  * Main parameter struct
00381  */
00382 struct params {
00383     struct param data_dir;
00384     struct param fullscreen;
00385     struct param x_resolution;
00386     struct param y_resolution;
00387     struct param x_resolution_half_width;        
00388     struct param bpp_mode;
00389     struct param capture_mouse; 
00390     struct param force_window_position;
00391     struct param quit_key;
00392     struct param turn_left_key;
00393     struct param turn_right_key;
00394     struct param trick_modifier_key;
00395     struct param brake_key;
00396     struct param paddle_key;
00397     struct param jump_key;
00398     struct param reset_key;
00399     struct param follow_view_key;
00400     struct param behind_view_key;
00401     struct param above_view_key;
00402     struct param view_mode; /* coresponds to view_mode_t */
00403     struct param screenshot_key;
00404     struct param pause_key;
00405 
00406     struct param joystick_paddle_button;
00407     struct param joystick_brake_button;
00408     struct param joystick_jump_button;
00409     struct param joystick_trick_button;
00410     struct param joystick_continue_button;
00411     struct param joystick_x_axis;
00412     struct param joystick_y_axis;
00413        struct param disable_joystick;
00414 
00415     struct param no_audio;
00416     struct param sound_enabled;
00417     struct param music_enabled;
00418     struct param sound_volume; /* 0-128 */
00419     struct param music_volume; /* 0-128 */
00420     struct param audio_freq_mode; /* 0 = 11025, 
00421                                  1 = 22050, 
00422                                  2 = 44100 */
00423     struct param audio_format_mode; /* 0 = 8 bits, 
00424                                    1 = 16 bits */
00425     struct param audio_stereo; 
00426     struct param audio_buffer_size; 
00427 
00428     struct param display_fps;
00429        struct param display_course_percentage;   
00430        struct param course_detail_level;
00431     struct param forward_clip_distance;
00432     struct param backward_clip_distance;
00433     struct param tree_detail_distance;
00434     struct param terrain_blending;
00435     struct param perfect_terrain_blending;
00436     struct param terrain_envmap;
00437     struct param disable_fog;
00438               
00439     struct param stencil_buffer;
00440        struct param enable_fsaa;   
00441        struct param multisamples;
00442               
00443        struct param always_save_event_race_data;
00444               
00445        struct param draw_tux_shadow;      
00446     struct param tux_sphere_divisions;
00447     struct param tux_shadow_sphere_divisions;
00448     struct param draw_particles;
00449     struct param track_marks;
00450     struct param ui_snow;
00451     struct param nice_fog;
00452     struct param use_cva;
00453     struct param cva_hack;
00454     struct param use_sphere_display_list;
00455     struct param do_intro_animation;
00456     struct param mipmap_type; /* 0 = GL_NEAREST,
00457                              1 = GL_LINEAR,
00458                              2 = GL_NEAREST_MIPMAP_NEAREST,
00459                              3 = GL_LINEAR_MIPMAP_NEAREST,
00460                              4 = GL_NEAREST_MIPMAP_LINEAR,
00461                              5 = GL_LINEAR_MIPMAP_LINEAR
00462                            */
00463     struct param ode_solver; /* 0 = Euler,
00464                             1 = ODE23,
00465                             2 = ODE45
00466                           */
00467     struct param fov; 
00468     struct param debug; 
00469     struct param warning_level; 
00470     struct param write_diagnostic_log;
00471        struct param disable_collision_detection;
00472        struct param ui_language;
00473        struct param disable_videomode_autodetection;                  
00474        struct param disable_background;
00475 };
00476 
00477 static struct params Params;
00478 
00479 
00480 /*
00481  * Initialize parameter data
00482  */
00483 
00484 void init_game_configuration()
00485 {
00486     INIT_PARAM_STRING( 
00487        data_dir, DATA_DIR, 
00488        "# The location of the ET Racer data files" );
00489 
00490        INIT_PARAM_BOOL( 
00491        stencil_buffer, false, 
00492        "# Set this to true to activate the stencil buffer" );
00493        
00494        INIT_PARAM_BOOL( 
00495        enable_fsaa, false, 
00496        "# Set this to true to activate FSAA" );
00497 
00498        INIT_PARAM_INT( 
00499        multisamples, 2,
00500        "# Set multisamples for FSAA" );
00501        
00502     INIT_PARAM_BOOL( 
00503        draw_tux_shadow, false, 
00504        "# Set this to true to display Tux's shadow.  Note that this is a \n"
00505        "# hack and is quite expensive in terms of framerate.\n"
00506        "# [EXPERT] This looks better if your card has a stencil buffer; \n"
00507        "# if compiling use the --enable-stencil-buffer configure option \n"
00508        "# to enable the use of the stencil buffer" );
00509        
00510        
00511 
00512     INIT_PARAM_BOOL( 
00513        draw_particles, true,
00514        "# Controls the drawing of snow particles that are kicked up as Tux\n"
00515        "# turns and brakes.  Setting this to false should help improve \n"
00516        "# performance." );
00517 
00518     INIT_PARAM_INT( 
00519        tux_sphere_divisions, 15,
00520        "# [EXPERT] Higher values result in a more finely subdivided mesh \n"
00521        "# for Tux, and vice versa.  If you're experiencing low framerates,\n"
00522        "# try lowering this value." );
00523 
00524     INIT_PARAM_INT( 
00525        tux_shadow_sphere_divisions, 3,
00526        "# [EXPERT] The level of subdivision of Tux's shadow." );
00527 
00528     INIT_PARAM_BOOL( 
00529        nice_fog, false,
00530        "# [EXPERT] If true, then the GL_NICEST hint will be used when\n"
00531        "# rendering fog.  On some cards, setting this to false may improve\n"
00532        "# performance.");
00533 
00534     INIT_PARAM_BOOL( 
00535        use_sphere_display_list, true,
00536        "# [EXPERT]  Mesa 3.1 sometimes renders Tux strangely when display \n"
00537        "# lists are used.  Setting this to false should solve the problem \n"
00538        "# at the cost of a few Hz." );
00539 
00540     INIT_PARAM_BOOL( 
00541        display_fps, false,
00542        "# Set this to true to display the current framerate in Hz." );
00543 
00544     INIT_PARAM_BOOL( 
00545        display_course_percentage, true,
00546        "# Set this to true to display a progressbar of \n"
00547        "# the course percentage." );
00548 
00549     INIT_PARAM_INT( 
00550        x_resolution, 800,
00551        "# The horizontal size of the Tux Racer window" );
00552 
00553     INIT_PARAM_INT( 
00554        y_resolution, 600,
00555        "# The vertical size of the Tux Racer window" );
00556 
00557        INIT_PARAM_BOOL( 
00558        x_resolution_half_width, false, 
00559        "# Set this to true to use only half of the resolution width" );
00560 
00561     INIT_PARAM_BOOL( 
00562        capture_mouse, false,
00563        "# If true, then the mouse will not be able to leave the \n"
00564        "# Tux Racer window.\n"
00565        "# If you lose keyboard focus while running Tux Racer, try setting\n"
00566        "# this to true." );
00567 
00568     INIT_PARAM_BOOL( 
00569        do_intro_animation, true,
00570        "# If false, then the introductory animation sequence will be skipped." 
00571        );
00572 
00573     INIT_PARAM_INT( 
00574        mipmap_type, 5,
00575        "# [EXPERT] Allows you to control which type of texture\n"
00576        "# interpolation/mipmapping is used when rendering textures.  The\n"
00577        "# values correspond to the following OpenGL settings:\n"
00578        "#\n"
00579         "#  0: GL_NEAREST\n"
00580         "#  1: GL_LINEAR\n"
00581         "#  2: GL_NEAREST_MIPMAP_NEAREST\n"
00582        "#  3: GL_LINEAR_MIPMAP_NEAREST\n"
00583         "#  4: GL_NEAREST_MIPMAP_LINEAR\n"
00584         "#  5: GL_LINEAR_MIPMAP_LINEAR\n"
00585        "#\n"
00586        "# On some cards, you may be able to improve performance by\n"
00587         "# decreasing this number, at the cost of lower image quality." );
00588 
00589     INIT_PARAM_BOOL( 
00590        fullscreen, true,
00591        "# If true then the game will run in full-screen mode." );
00592 
00593     INIT_PARAM_INT( 
00594        bpp_mode, 0,
00595        "# Controls how many bits per pixel are used in the game.\n"
00596        "# Valid values are:\n"
00597        "#\n"
00598        "#  0: Use current bpp setting of operating system\n"
00599        "#  1: 16 bpp\n"
00600        "#  2: 32 bpp\n"
00601        "# Note that some cards (e.g., Voodoo1, Voodoo2, Voodoo3) only support\n"
00602        "# 16 bits per pixel." );
00603 
00604     INIT_PARAM_BOOL( 
00605        force_window_position, false ,
00606        "# If true, then the Tux Racer window will automatically be\n"
00607        "# placed at (0,0)" );
00608 
00609     INIT_PARAM_INT( 
00610        ode_solver, 2 ,
00611        "# Selects the ODE (ordinary differential equation) solver.  \n"
00612        "# Possible values are:\n"
00613        "#\n"
00614        "#   0: Modified Euler     (fastest but least accurate)\n"
00615         "#   1: Runge-Kutta (2,3)\n"
00616        "#   2: Runge-Kutta (4,5)  (slowest but most accurate)" );
00617 
00618     INIT_PARAM_STRING( 
00619        quit_key, "q escape" ,
00620        "# Key binding for quitting a race" );
00621     INIT_PARAM_INT( 
00622        turn_left_key, SDLK_LEFT ,
00623        "# Key binding for turning left" );
00624     INIT_PARAM_INT( 
00625        turn_right_key, SDLK_RIGHT ,
00626        "# Key binding for turning right" );
00627     INIT_PARAM_INT( 
00628        trick_modifier_key, 't' ,
00629        "# Key binding for doing tricks" );
00630     INIT_PARAM_INT( 
00631        brake_key, SDLK_DOWN ,
00632        "# Key binding for braking" );
00633     INIT_PARAM_INT( 
00634        paddle_key, SDLK_UP ,
00635        "# Key binding for paddling (on the ground) and flapping (in the air)" 
00636        );
00637     INIT_PARAM_STRING( 
00638        follow_view_key, "1" ,
00639        "# Key binding for the \"Follow\" camera mode" );
00640     INIT_PARAM_STRING( 
00641        behind_view_key, "2" ,
00642        "# Key binding for the \"Behind\" camera mode" );
00643     INIT_PARAM_STRING( 
00644        above_view_key, "3" ,
00645        "# Key binding for the \"Above\" camera mode" );
00646     INIT_PARAM_INT( 
00647        view_mode, 1 ,
00648        "# Default view mode. Possible values are\n" 
00649        "#\n"
00650        "#   0: Behind\n"
00651        "#   1: Follow\n"
00652        "#   2: Above" );
00653     INIT_PARAM_STRING( 
00654        screenshot_key, "=" ,
00655        "# Key binding for taking a screenshot" );
00656     INIT_PARAM_STRING( 
00657        pause_key, "p" ,
00658        "# Key binding for pausing the game" );
00659     INIT_PARAM_INT( 
00660        reset_key, 'r' ,
00661        "# Key binding for resetting the player position" );
00662     INIT_PARAM_INT( 
00663        jump_key, 'e' ,
00664        "# Key binding for jumping" );
00665 
00666     INIT_PARAM_INT( 
00667        joystick_paddle_button, 0 ,
00668        "# Joystick button for paddling (numbering starts at 0).\n" 
00669        "# Set to -1 to disable." );
00670 
00671     INIT_PARAM_INT( 
00672        joystick_brake_button, 2 ,
00673        "# Joystick button for braking (numbering starts at 0).\n" 
00674        "# Set to -1 to disable." );
00675 
00676     INIT_PARAM_INT( 
00677        joystick_jump_button, 3 ,
00678        "# Joystick button for jumping (numbering starts at 0)" );
00679 
00680     INIT_PARAM_INT( 
00681        joystick_trick_button, 1 ,
00682        "# Joystick button for doing tricks (numbering starts at 0)" );
00683 
00684     INIT_PARAM_INT( 
00685        joystick_continue_button, 0 ,
00686        "# Joystick button for moving past intro, paused, and \n"
00687        "# game over screens (numbering starts at 0)" );
00688     
00689     INIT_PARAM_INT(
00690        joystick_x_axis, 0 ,
00691        "# Joystick axis to use for turning (numbering starts at 0)" );
00692 
00693     INIT_PARAM_INT(
00694        joystick_y_axis, 1 ,
00695        "# Joystick axis to use for paddling/braking (numbering starts at 0)" );
00696    
00697        INIT_PARAM_BOOL(
00698        disable_joystick, false ,
00699        "# Disables the joystick support" );
00700 
00701     INIT_PARAM_INT( 
00702        fov, 60 ,
00703        "# [EXPERT] Sets the camera field-of-view" );
00704     INIT_PARAM_STRING( 
00705        debug, "" ,
00706        "# [EXPERT] Controls the Tux Racer debugging modes" );
00707     INIT_PARAM_INT( 
00708        warning_level, 100 ,
00709        "# [EXPERT] Controls the Tux Racer warning messages" );
00710     INIT_PARAM_INT( 
00711        forward_clip_distance, 100 ,
00712        "# Controls how far ahead of the camera the course\n"
00713        "# is rendered.  Larger values mean that more of the course is\n"
00714        "# rendered, resulting in slower performance. Decreasing this \n"
00715        "# value is an effective way to improve framerates." );
00716     INIT_PARAM_INT( 
00717        backward_clip_distance, 10 ,
00718        "# [EXPERT] Some objects aren't yet clipped to the view frustum, \n"
00719        "# so this value is used to control how far up the course these \n"
00720        "# objects are drawn." );
00721     INIT_PARAM_INT( 
00722        tree_detail_distance, 20 ,
00723        "# [EXPERT] Controls the distance at which trees are drawn with \n"
00724        "# two rectangles instead of one." );
00725     INIT_PARAM_BOOL( 
00726        terrain_blending, true ,
00727        "# Controls the blending of the terrain textures.  Setting this\n"
00728        "# to false will help improve performance." );
00729     INIT_PARAM_BOOL( 
00730        perfect_terrain_blending, false ,
00731        "# [EXPERT] If true, then terrain triangles with three different\n"
00732        "# terrain types at the vertices will be blended correctly\n"
00733        "# (instead of using a faster but imperfect approximation)." );
00734     INIT_PARAM_BOOL( 
00735        terrain_envmap, true ,
00736        "# If true, then the ice will be drawn with an \"environment map\",\n"
00737        "# which gives the ice a shiny appearance.  Setting this to false\n"
00738        "# will help improve performance." );
00739     INIT_PARAM_BOOL( 
00740        disable_fog, false ,
00741        "# If true, then fog will be turned off.  Some Linux drivers for the\n"
00742        "# ATI Rage128 seem to have a bug in their fog implementation which\n"
00743        "# makes the screen nearly pure white when racing; if you experience\n"
00744        "# this problem then set this variable to true." );
00745     INIT_PARAM_BOOL( 
00746        use_cva, true ,
00747        "# [EXPERT] If true, then compiled vertex arrays will be used when\n"
00748        "# drawing the terrain.  Whether or not this helps performance\n"
00749        "# is driver- and card-dependent." );
00750     INIT_PARAM_BOOL( 
00751        cva_hack, true ,
00752        "# Some card/driver combinations render the terrrain incorrectly\n"
00753        "# when using compiled vertex arrays.  This activates a hack \n"
00754        "# to work around that problem." );
00755     INIT_PARAM_INT( 
00756        course_detail_level, 75 ,
00757        "# [EXPERT] This controls how accurately the course terrain is \n"
00758        "# rendered. A high value results in greater accuracy at the cost of \n"
00759        "# performance, and vice versa.  This value can be decreased and \n"
00760        "# increased in 10% increments at runtime using the F9 and F10 keys.\n"
00761        "# To better see the effect, activate wireframe mode using the F11 \n"
00762        "# key (this is a toggle)." );
00763     INIT_PARAM_BOOL( 
00764        no_audio, false ,
00765        "# If true, then audio in the game is completely disabled." );
00766     INIT_PARAM_BOOL( 
00767        sound_enabled, true ,
00768        "# Use this to turn sound effects on and off." );
00769     INIT_PARAM_BOOL( 
00770        music_enabled, true ,
00771        "# Use this to turn music on and off." );
00772     INIT_PARAM_INT( 
00773        sound_volume, 64 ,
00774        "# This controls the sound volume (valid range is 0-127)." );
00775     INIT_PARAM_INT( 
00776        music_volume, 127 ,
00777        "# This controls the music volume (valid range is 0-127)." );
00778     INIT_PARAM_INT( 
00779        audio_freq_mode, 1 ,
00780        "# The controls the frequency of the audio.  Valid values are:\n"
00781        "# \n"
00782        "#   0: 11025 Hz\n"
00783        "#   1: 22050 Hz\n"
00784        "#   2: 44100 Hz" );
00785     INIT_PARAM_INT( 
00786        audio_format_mode, 1 ,
00787        "# This controls the number of bits per sample for the audio.\n"
00788        "# Valid values are:\n"
00789        "#\n"
00790        "#   0: 8 bits\n"
00791        "#   1: 16 bits" );
00792     INIT_PARAM_BOOL( 
00793        audio_stereo, true ,
00794        "# Audio will be played in stereo of true, and mono if false" );
00795     INIT_PARAM_INT( 
00796        audio_buffer_size, 2048 ,
00797        "# [EXPERT] Controls the size of the audio buffer.  \n"
00798        "# Increase the buffer size if you experience choppy audio\n" 
00799        "# (at the cost of greater audio latency)" );
00800     INIT_PARAM_BOOL( 
00801        track_marks, true ,
00802        "# If true, then the players will leave track marks in the snow." );
00803     INIT_PARAM_BOOL( 
00804        ui_snow, true ,
00805        "# If true, then the ui screens will have falling snow." );
00806 
00807     INIT_PARAM_BOOL( 
00808        write_diagnostic_log, false ,
00809        "# If true, then a file called diagnostic_log.txt will be generated\n" 
00810        "# which you should attach to any bug reports you make.\n"
00811        "# To generate the file, set this variable to \"true\", and\n"
00812        "# then run the game so that you reproduce the bug, if possible."
00813        );
00814        
00815     INIT_PARAM_BOOL( 
00816        always_save_event_race_data, false ,
00817        "# only for cheating purpose"
00818        );     
00819        
00820        INIT_PARAM_BOOL( 
00821        disable_collision_detection, false ,
00822        "# If true, collision detection with tree models is disabled"
00823        );
00824        
00825        INIT_PARAM_BOOL( 
00826        disable_videomode_autodetection, false, 
00827        "# Set this to true disable the autodetection\n"
00828        "# for available video modes." );
00829               
00830        INIT_PARAM_BOOL(
00831        disable_background, false,
00832        "# Set this to completely remove the background (skybox)\n"
00833        "# This option would improve the performance." );
00834        
00835        INIT_PARAM_STRING( 
00836        ui_language, "en_GB" ,
00837        "# set the language for the ui"
00838        );
00839        
00840 }
00841 
00842 
00843 /* 
00844  * Create the set/get functions for parameters
00845  */
00846 
00847 FN_PARAM_STRING( data_dir )
00848 FN_PARAM_BOOL( draw_tux_shadow )
00849 FN_PARAM_BOOL( draw_particles )
00850 FN_PARAM_INT( tux_sphere_divisions )
00851 FN_PARAM_INT( tux_shadow_sphere_divisions )
00852 FN_PARAM_BOOL( nice_fog )
00853 FN_PARAM_BOOL( use_sphere_display_list )
00854 FN_PARAM_BOOL( display_fps )
00855 FN_PARAM_BOOL( display_course_percentage )
00856 FN_PARAM_INT( x_resolution )
00857 FN_PARAM_INT( y_resolution )
00858 FN_PARAM_BOOL( x_resolution_half_width )
00859 FN_PARAM_BOOL( capture_mouse )
00860 FN_PARAM_BOOL( do_intro_animation )
00861 FN_PARAM_INT( mipmap_type )
00862 FN_PARAM_BOOL( fullscreen )
00863 FN_PARAM_INT( bpp_mode )
00864 FN_PARAM_BOOL( force_window_position )
00865 FN_PARAM_INT( ode_solver )
00866 FN_PARAM_STRING( quit_key )
00867 
00868 FN_PARAM_INT( turn_left_key )
00869 FN_PARAM_INT( turn_right_key )
00870 FN_PARAM_INT( trick_modifier_key )
00871 FN_PARAM_INT( brake_key )
00872 FN_PARAM_INT( paddle_key )
00873 FN_PARAM_STRING( above_view_key )
00874 FN_PARAM_STRING( behind_view_key )
00875 FN_PARAM_STRING( follow_view_key )
00876 FN_PARAM_INT( view_mode )
00877 FN_PARAM_STRING( screenshot_key )
00878 FN_PARAM_STRING( pause_key )
00879 FN_PARAM_INT( reset_key )
00880 FN_PARAM_INT( jump_key )
00881 FN_PARAM_INT( joystick_jump_button )
00882 FN_PARAM_INT( joystick_brake_button )
00883 FN_PARAM_INT( joystick_paddle_button )
00884 FN_PARAM_INT( joystick_trick_button )
00885 FN_PARAM_INT( joystick_continue_button )
00886 FN_PARAM_INT( joystick_x_axis )
00887 FN_PARAM_INT( joystick_y_axis )
00888 FN_PARAM_BOOL ( disable_joystick )
00889 FN_PARAM_INT( fov )
00890 FN_PARAM_STRING( debug )
00891 FN_PARAM_INT( warning_level )
00892 FN_PARAM_INT( forward_clip_distance )
00893 FN_PARAM_INT( backward_clip_distance )
00894 FN_PARAM_INT( tree_detail_distance )
00895 FN_PARAM_INT( course_detail_level )
00896 FN_PARAM_BOOL( terrain_blending )
00897 FN_PARAM_BOOL( perfect_terrain_blending )
00898 FN_PARAM_BOOL( terrain_envmap )
00899 FN_PARAM_BOOL( disable_fog )
00900 FN_PARAM_BOOL( use_cva )
00901 FN_PARAM_BOOL( cva_hack )
00902 FN_PARAM_BOOL( track_marks )
00903 FN_PARAM_BOOL( ui_snow )
00904 
00905 FN_PARAM_BOOL( no_audio )
00906 FN_PARAM_BOOL( sound_enabled )
00907 FN_PARAM_BOOL( music_enabled )
00908 FN_PARAM_INT( sound_volume )
00909 FN_PARAM_INT( music_volume )
00910 FN_PARAM_INT( audio_freq_mode )
00911 FN_PARAM_INT( audio_format_mode )
00912 FN_PARAM_BOOL( audio_stereo )
00913 FN_PARAM_INT( audio_buffer_size )
00914 FN_PARAM_BOOL( write_diagnostic_log )
00915 
00916 FN_PARAM_BOOL( stencil_buffer )
00917 FN_PARAM_BOOL( enable_fsaa )
00918 FN_PARAM_INT( multisamples )
00919 
00920 FN_PARAM_BOOL( always_save_event_race_data )
00921 FN_PARAM_BOOL( disable_collision_detection )
00922 FN_PARAM_BOOL( disable_videomode_autodetection )
00923 FN_PARAM_BOOL( disable_background )
00924 
00925 FN_PARAM_STRING( ui_language )
00926 
00927 
00928 /*
00929  * Functions to read and write the configuration file
00930  */
00931 
00932 int get_old_config_file_name( char *buff, unsigned int len )
00933 {
00934 #if defined( WIN32 ) 
00935     if ( strlen( OLD_CONFIG_FILE ) +1 > len ) {
00936        return 1;
00937     }
00938     strcpy( buff, OLD_CONFIG_FILE );
00939     return 0;
00940 #else
00941     struct passwd *pwent;
00942 
00943     pwent = getpwuid( getuid() );
00944     if ( pwent == NULL ) {
00945        perror( "getpwuid" );
00946        return 1;
00947     }
00948 
00949     if ( strlen( pwent->pw_dir ) + strlen( OLD_CONFIG_FILE ) + 2 > len ) {
00950        return 1;
00951     }
00952 
00953     sprintf( buff, "%s/%s", pwent->pw_dir, OLD_CONFIG_FILE );
00954     return 0;
00955 #endif /* defined( WIN32 ) */
00956 }
00957 
00958 int get_config_dir_name( char *buff, unsigned int len )
00959 {
00960 #if defined( WIN32 ) 
00961     if ( strlen( CONFIG_DIR ) +1 > len ) {
00962        return 1;
00963     }
00964     strcpy( buff, CONFIG_DIR );
00965     return 0;
00966 #else
00967     struct passwd *pwent;
00968 
00969     pwent = getpwuid( getuid() );
00970     if ( pwent == NULL ) {
00971        perror( "getpwuid" );
00972        return 1;
00973     }
00974 
00975     if ( strlen( pwent->pw_dir ) + strlen( CONFIG_DIR) + 2 > len ) {
00976        return 1;
00977     }
00978 
00979     sprintf( buff, "%s/%s", pwent->pw_dir, CONFIG_DIR );
00980     return 0;
00981 #endif /* defined( WIN32 ) */
00982 }
00983 
00984 int get_config_file_name( char *buff, unsigned int len )
00985 {
00986     if (get_config_dir_name( buff, len ) != 0) {
00987        return 1;
00988     }
00989     if ( strlen( buff ) + strlen( CONFIG_FILE ) +2 > len ) {
00990        return 1;
00991     }
00992 
00993 #if defined( WIN32 ) 
00994     strcat( buff, "\\" );
00995 #else
00996     strcat( buff, "/" );
00997 #endif /* defined( WIN32 ) */
00998 
00999     strcat( buff, CONFIG_FILE);
01000     return 0;
01001 }
01002 
01003 void clear_config_cache()
01004 {
01005     struct param *parm;
01006     unsigned int i;
01007 
01008     for (i=0; i<sizeof(Params)/sizeof(struct param); i++) {
01009        parm = (struct param*)&Params + i;
01010        parm->loaded = false;
01011     }
01012 }
01013 
01014 void read_config_file(std::string& file)
01015 {
01016     char config_file[BUFF_LEN];
01017     char config_dir[BUFF_LEN];
01018 
01019     clear_config_cache();
01020 
01021        if( !file.empty()){
01022               if ( Tcl_EvalFile( tclInterp, FUCKTCL file.c_str() ) != TCL_OK ) {
01023               handle_error( 1, "error evalating %s: %s", file.c_str(),
01024                            Tcl_GetStringResult( tclInterp ) );
01025            }  
01026               sp_config_file = file.c_str();     
01027               return;
01028        }else{
01029               sp_config_file = NULL;
01030        }
01031        
01032     if ( get_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
01033               return;
01034     }
01035     if ( get_config_dir_name( config_dir, sizeof( config_dir ) ) != 0 ) {
01036               return;
01037     }
01038 
01039        
01040 
01041     if ( dir_exists( config_dir ) ) {
01042        if ( file_exists( config_file ) ) {
01043            /* File exists -- let's try to evaluate it. */
01044            if ( Tcl_EvalFile( tclInterp, config_file ) != TCL_OK ) {
01045               handle_error( 1, "error evalating %s: %s", config_file,
01046                            Tcl_GetStringResult( tclInterp ) );
01047            }
01048        }
01049        return;
01050     }
01051 
01052     /* File does not exist -- look for old version */
01053     if ( get_old_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
01054        return;
01055     }
01056     if ( !file_exists( config_file ) ) {
01057        return;
01058     }
01059     /* Old file exists -- let's try to evaluate it. */
01060     if ( Tcl_EvalFile( tclInterp, config_file ) != TCL_OK ) {
01061        handle_error( 1, "error evalating deprecated %s: %s", config_file,
01062                     Tcl_GetStringResult( tclInterp ) );
01063     } else {
01064        /* Remove old file and save info in new file location */
01065        remove(config_file);
01066        write_config_file();
01067     }
01068 }
01069 
01070 void write_config_file()
01071 {
01072     FILE *config_stream;
01073     char config_file[BUFF_LEN];
01074     char config_dir[BUFF_LEN];
01075     struct param *parm;
01076     unsigned int i;
01077        
01078        if(sp_config_file==NULL){
01079 
01080     if ( get_config_file_name( config_file, sizeof( config_file ) ) != 0 ) {
01081        return;
01082     }
01083     if ( get_config_dir_name( config_dir, sizeof( config_dir ) ) != 0 ) {
01084        return;
01085     }
01086 
01087     if ( !dir_exists( config_dir ) ) {
01088 
01089 #if defined(WIN32) && !defined(__CYGWIN__)
01090        if (mkdir( config_dir ) != 0) {
01091            return;
01092        }
01093 #else
01094        if (mkdir( config_dir, 0775) != 0) {
01095            return;
01096        }
01097 #endif
01098 
01099     }
01100 
01101     config_stream = fopen( config_file, "w" );
01102        if ( config_stream == NULL ) {
01103        print_warning( CRITICAL_WARNING, 
01104                      "couldn't open %s for writing: %s", 
01105                      config_file, strerror(errno) );
01106        return;
01107     }
01108        
01109        }else{
01110               std::cout << "Writing to custom config file: "
01111                               << sp_config_file << std::endl;
01112               config_stream = fopen( sp_config_file, "w" );
01113               if ( config_stream == NULL ) {
01114                      print_warning( CRITICAL_WARNING, 
01115                      "couldn't open %s for writing: %s", 
01116                      sp_config_file, strerror(errno) );
01117                      return;
01118        }
01119        }
01120        
01121     fprintf( config_stream, 
01122             "# PP Racer " VERSION " configuration file\n"
01123             "#\n"
01124        );
01125 
01126     for (i=0; i<sizeof(Params)/sizeof(struct param); i++) {
01127        parm = (struct param*)&Params + i;
01128        if ( parm->comment != NULL ) {
01129 #ifdef __APPLE__
01130         // on mac, do not save data path, it's to be determined dynamically at runtime
01131         if( strcmp(parm->name, "data_dir") == 0) continue;
01132 #endif
01133            fprintf( config_stream, "\n# %s\n#\n%s\n#\n", 
01134                    parm->name, parm->comment );
01135        }
01136        switch ( parm->type ) {
01137        case PARAM_STRING:
01138            fetch_param_string( parm );
01139            fprintf( config_stream, "set %s \"%s\"\n",
01140                    parm->name, parm->val.string_val );
01141            break;
01142        case PARAM_CHAR:
01143            fetch_param_char( parm );
01144            fprintf( config_stream, "set %s %c\n",
01145                    parm->name, parm->val.char_val );
01146            break;
01147        case PARAM_INT:
01148            fetch_param_int( parm );
01149            fprintf( config_stream, "set %s %d\n",
01150                    parm->name, parm->val.int_val );
01151            break;
01152        case PARAM_BOOL:
01153            fetch_param_bool( parm );
01154            fprintf( config_stream, "set %s %s\n",
01155                    parm->name, parm->val.bool_val ? "true" : "false" );
01156            break;
01157        default:
01158            code_not_reached();
01159        }
01160     }
01161 
01162     if ( fclose( config_stream ) != 0 ) {
01163        perror( "fclose" );
01164     }
01165 }
01166 
01167 /*
01168  * Tcl callback to allow reading of game configuration variables from Tcl.
01169  */
01170 static int get_param_cb ( ClientData cd, Tcl_Interp *ip, 
01171                        int argc, CONST84 char *argv[]) 
01172 {
01173     int i;
01174     int num_params;
01175     struct param *parm;
01176 
01177     if ( argc != 2 ) {
01178         Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
01179                       "Usage: ", argv[0], " <parameter name>",
01180                       (char *)0 );
01181         return TCL_ERROR;
01182     } 
01183 
01184     /* Search for parameter */
01185     parm = NULL;
01186     num_params = sizeof(Params)/sizeof(struct param);
01187     for (i=0; i<num_params; i++) {
01188        parm = (struct param*)&Params + i;
01189 
01190        if ( strcmp( parm->name, argv[1] ) == 0 ) {
01191            break;
01192        }
01193     }
01194 
01195     /* If can't find parameter, report error */
01196     if ( parm == NULL || i == num_params ) {
01197        Tcl_AppendResult(ip, argv[0], ": invalid parameter `",
01198                       argv[1], "'", (char *)0 );
01199        return TCL_ERROR;
01200     }
01201 
01202     /* Get value of parameter */
01203     switch ( parm->type ) {
01204     case PARAM_STRING:
01205        fetch_param_string( parm );
01206        Tcl_SetObjResult( ip, Tcl_NewStringObj( parm->val.string_val, -1 ) );
01207        break;
01208 
01209     case PARAM_CHAR:
01210        fetch_param_char( parm );
01211        Tcl_SetObjResult( ip, Tcl_NewStringObj( &parm->val.char_val, 1 ) );
01212        break;
01213 
01214     case PARAM_INT:
01215        fetch_param_int( parm );
01216        Tcl_SetObjResult( ip, Tcl_NewIntObj( parm->val.int_val ) );
01217        break;
01218 
01219     case PARAM_BOOL:
01220        fetch_param_bool( parm );
01221        Tcl_SetObjResult( ip, Tcl_NewBooleanObj( parm->val.bool_val ) );
01222        break;
01223 
01224     default:
01225        code_not_reached();
01226     }
01227 
01228     return TCL_OK;
01229 } 
01230 
01231 /* 
01232  * Tcl callback to allow setting of game configuration variables from Tcl.
01233  */
01234 static int set_param_cb ( ClientData cd, Tcl_Interp *ip, 
01235                        int argc, CONST84 char *argv[]) 
01236 {
01237     int i;
01238     int tmp_int;
01239     int num_params;
01240     struct param *parm;
01241 
01242     if ( argc != 3 ) {
01243         Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
01244                       "Usage: ", argv[0], " <parameter name> <value>",
01245                       (char *)0 );
01246         return TCL_ERROR;
01247     } 
01248 
01249     /* Search for parameter */
01250     parm = NULL;
01251     num_params = sizeof(Params)/sizeof(struct param);
01252     for (i=0; i<num_params; i++) {
01253        parm = (struct param*)&Params + i;
01254 
01255        if ( strcmp( parm->name, argv[1] ) == 0 ) {
01256            break;
01257        }
01258     }
01259 
01260     /* If can't find parameter, report error */
01261     if ( parm == NULL || i == num_params ) {
01262        Tcl_AppendResult(ip, argv[0], ": invalid parameter `",
01263                       argv[1], "'", (char *)0 );
01264        return TCL_ERROR;
01265     }
01266 
01267     /* Set value of parameter */
01268     switch ( parm->type ) {
01269     case PARAM_STRING:
01270        set_param_string( parm, argv[2] ); 
01271        break;
01272 
01273     case PARAM_CHAR:
01274        if ( strlen( argv[2] ) > 1 ) {
01275            Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
01276                           argv[1], "' must be a single character", 
01277                           (char *)0 );
01278            return TCL_ERROR;
01279        }
01280        set_param_char( parm, argv[2][0] );
01281        break;
01282 
01283     case PARAM_INT:
01284        if ( Tcl_GetInt( ip, argv[2], &tmp_int ) != TCL_OK ) {
01285            Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
01286                           argv[1], "' must be an integer", 
01287                           (char *)0 );
01288            return TCL_ERROR;
01289        }
01290        set_param_int( parm, tmp_int );
01291        break;
01292 
01293     case PARAM_BOOL:
01294        if ( Tcl_GetBoolean( ip, argv[2], &tmp_int ) != TCL_OK ) {
01295            Tcl_AppendResult(ip, "\n", argv[0], ": value for `",
01296                           argv[1], "' must be a boolean", 
01297                           (char *)0 );
01298            return TCL_ERROR;
01299        }
01300        check_assertion( tmp_int == 0 || tmp_int == 1, 
01301                       "invalid boolean value" );
01302        set_param_bool( parm, (bool) tmp_int );
01303        break;
01304 
01305     default:
01306        code_not_reached();
01307     }
01308 
01309     return TCL_OK;
01310 } 
01311 
01312 void register_game_config_callbacks( Tcl_Interp *ip )
01313 {
01314     Tcl_CreateCommand (ip, "tux_get_param", get_param_cb,   0,0);
01315     Tcl_CreateCommand (ip, "tux_set_param", set_param_cb,   0,0);
01316 }
01317