1
// $Id: config.cpp 760 2006-09-12 03:13:59Z hiker $
3
// SuperTuxKart - a fun racing game with go-kart
4
// Copyright (C) 2006 SuperTuxKart-Team
5
// Modelled after Supertux's configfile.cpp
7
// This program is free software; you can redistribute it and/or
8
// modify it under the terms of the GNU General Public License
9
// as published by the Free Software Foundation; either version 2
10
// of the License, or (at your option) any later version.
12
// This program is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
// GNU General Public License for more details.
17
// You should have received a copy of the GNU General Public License
18
// along with this program; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#if !defined(WIN32) || defined(__CYGWIN__)
25
# include <sys/stat.h>
26
# include <sys/types.h>
35
#include "lisp/lisp.hpp"
36
#include "lisp/parser.hpp"
37
#include "lisp/writer.hpp"
46
// -----------------------------------------------------------------------------
47
Config::Config(const std::string& filename) {
53
// -----------------------------------------------------------------------------
57
// -----------------------------------------------------------------------------
58
std::string Config::getConfigDir() {
61
// For now the old windows config way is used: store a config file
62
// in the current directory (in other OS a special subdirectory is created)
65
if(getenv("HOME")!=NULL) {
66
dirname = getenv("HOME");
76
// -----------------------------------------------------------------------------
77
/*set the config filename for this platform*/
78
void Config::setFilename() {
79
filename = getConfigDir();
82
filename += "supertuxkart.cfg";
88
// -----------------------------------------------------------------------------
89
/*load default values for options*/
90
void Config::setDefaults() {
93
noStartScreen = false;
98
singleWindowMenu = false;
99
oldStatusDisplay = false;
100
herringStyle = "new";
101
disableMagnet = true;
104
improvedPhysics = false;
105
newKeyboardStyle = true;
106
replayHistory = false;
111
player[0].setName("Player 1");
112
player[1].setName("Player 2");
113
player[2].setName("Player 3");
114
player[3].setName("Player 4");
116
player[0].setUseJoystick(true);
117
player[1].setUseJoystick(false);
118
player[2].setUseJoystick(false);
119
player[3].setUseJoystick(false);
121
/*player 1 default keyboard settings*/
122
player[0].setKey(KC_LEFT, PW_KEY_LEFT);
123
player[0].setKey(KC_RIGHT, PW_KEY_RIGHT);
124
player[0].setKey(KC_ACCEL, PW_KEY_UP);
125
player[0].setKey(KC_BRAKE, PW_KEY_DOWN);
126
player[0].setKey(KC_WHEELIE, 'a');
127
player[0].setKey(KC_JUMP, 's');
128
player[0].setKey(KC_RESCUE, 'd');
129
player[0].setKey(KC_FIRE, 'f');
130
/*player 1 default joystick settings*/
131
player[0].setButton(KC_BRAKE, 1);
132
player[0].setButton(KC_WHEELIE, 0x20);
133
player[0].setButton(KC_JUMP, 0x10);
134
player[0].setButton(KC_RESCUE, 0x04);
135
player[0].setButton(KC_FIRE, 0x08);
137
/*player 2 default keyboard settings*/
138
player[1].setKey(KC_LEFT, 'j');
139
player[1].setKey(KC_RIGHT, 'l');
140
player[1].setKey(KC_ACCEL, 'i');
141
player[1].setKey(KC_BRAKE, 'k');
142
player[1].setKey(KC_WHEELIE, 'q');
143
player[1].setKey(KC_JUMP, 'w');
144
player[1].setKey(KC_RESCUE, 'e');
145
player[1].setKey(KC_FIRE, 'r');
146
/*player 2 default joystick settings*/
147
player[1].setButton(KC_ACCEL, 0);
148
player[1].setButton(KC_BRAKE, 1);
149
player[1].setButton(KC_WHEELIE, 2);
150
player[1].setButton(KC_JUMP, 3);
151
player[1].setButton(KC_RESCUE, 4);
152
player[1].setButton(KC_FIRE, 5);
154
/*player 3 default joystick settings*/
155
player[2].setButton(KC_ACCEL, 0);
156
player[2].setButton(KC_BRAKE, 1);
157
player[2].setButton(KC_WHEELIE, 2);
158
player[2].setButton(KC_JUMP, 3);
159
player[2].setButton(KC_RESCUE, 4);
160
player[2].setButton(KC_FIRE, 5);
161
/*player 4 default joystick settings*/
162
player[3].setButton(KC_ACCEL, 0);
163
player[3].setButton(KC_BRAKE, 1);
164
player[3].setButton(KC_WHEELIE, 2);
165
player[3].setButton(KC_JUMP, 3);
166
player[3].setButton(KC_RESCUE, 4);
167
player[3].setButton(KC_FIRE, 5);
171
// -----------------------------------------------------------------------------
172
/*load default configuration file for this platform*/
173
void Config::loadConfig() {
174
loadConfig(filename);
177
// -----------------------------------------------------------------------------
178
// Checks for existance of the tuxkart configuration directory. If the
179
// directory does not exist, it will be created. Return values:
180
// 1: config dir exists
181
// 2: does not exist, but was created
182
// 0: does not exist, and could not be created.
183
int Config::CheckAndCreateDir() {
184
std::string dirname = getConfigDir();
185
ulDir* u = ulOpenDir(dirname.c_str());
186
if(u) { // OK, directory exists
190
// The directory does not exist, try to create it
192
#if defined(WIN32) && !defined(__CYGWIN__)
193
bError = _mkdir(dirname.c_str() ) != 0;
195
bError = mkdir(dirname.c_str(), 0755) != 0;
198
fprintf(stderr, "Couldn't create '%s', config files will not be saved.\n",
202
printf("Config directory '%s' successfully created.\n",dirname.c_str());
206
} // CheckAndCreateDir
208
// -----------------------------------------------------------------------------
209
/*load configuration values from file*/
210
void Config::loadConfig(const std::string& filename) {
212
const lisp::Lisp* root = 0;
214
int dirExist = CheckAndCreateDir();
215
// Check if the config directory exists. If not, exit without an error
216
// message, an appropriate message was printed by CheckAndCreateDir
217
if (dirExist != 1) return;
221
root = parser.parse(filename);
222
} catch(std::exception& e) {
223
std::cout << "Config file '"<<filename<<"' does not exist, it will be created.\n";
229
const lisp::Lisp* lisp = root->getLisp("tuxkart-config");
231
throw std::runtime_error("No tuxkart-config node");
234
lisp->get("fullscreen", fullscreen);
235
lisp->get("sfx" , sfx);
236
lisp->get("nostartscreen", noStartScreen);
237
lisp->get("music", music);
238
lisp->get("smoke", smoke);
239
lisp->get("displayFPS", displayFPS);
240
lisp->get("singlewindowmenu", singleWindowMenu);
241
lisp->get("oldStatusDisplay", oldStatusDisplay);
242
lisp->get("herringStyle", herringStyle);
243
lisp->get("disableMagnet", disableMagnet);
244
lisp->get("newKeyboardStyle", newKeyboardStyle);
245
lisp->get("useKPH", useKPH);
246
lisp->get("improvedPhysics", improvedPhysics);
248
/*get resolution width/height*/
249
lisp->get("width", width);
250
lisp->get("height", height);
252
/*get number of karts*/
253
lisp->get("karts", karts);
255
/*get player configurations*/
256
for(i=0; i<PLAYERS; ++i) {
260
const lisp::Lisp* reader = lisp->getLisp(temp);
262
temp = "No " + temp + " node";
263
throw std::runtime_error(temp);
266
reader->get("name", name);
267
player[i].setName(name);
270
/*get keyboard configuration*/
271
reader->get("left", tmp); player[i].setKey(KC_LEFT, tmp);
272
reader->get("right", tmp); player[i].setKey(KC_RIGHT, tmp);
273
reader->get("up", tmp); player[i].setKey(KC_ACCEL, tmp);
274
reader->get("down", tmp); player[i].setKey(KC_BRAKE, tmp);
275
reader->get("wheelie", tmp); player[i].setKey(KC_WHEELIE, tmp);
276
reader->get("jump", tmp); player[i].setKey(KC_JUMP, tmp);
277
reader->get("rescue", tmp); player[i].setKey(KC_RESCUE, tmp);
278
reader->get("fire", tmp); player[i].setKey(KC_FIRE, tmp);
280
/*get joystick configuration*/
281
reader->get("joy-up", tmp); player[i].setButton(KC_ACCEL, tmp);
282
reader->get("joy-down", tmp); player[i].setButton(KC_BRAKE, tmp);
283
reader->get("joy-wheelie", tmp); player[i].setButton(KC_WHEELIE, tmp);
284
reader->get("joy-jump", tmp); player[i].setButton(KC_JUMP, tmp);
285
reader->get("joy-rescue", tmp); player[i].setButton(KC_RESCUE, tmp);
286
reader->get("joy-fire", tmp); player[i].setButton(KC_FIRE, tmp);
288
} catch(std::exception& e) {
289
std::cout << "Error while parsing config '" << filename << "': " << e.what() << "\n";
295
// -----------------------------------------------------------------------------
296
/*call saveConfig w/ the default filename for this platform*/
297
void Config::saveConfig() {
298
saveConfig(filename);
301
// -----------------------------------------------------------------------------
302
/*write settings to config file*/
303
void Config::saveConfig(const std::string& filename) {
307
int dirExist = CheckAndCreateDir();
308
// Check if the config directory exists (again, since it was already checked
309
// when reading the config file - this is done in case that the problem was
310
// fixed while tuxkart is running). If the directory does not exist and
311
// can not be created, an error message was already printed to stderr,
312
// and we can exit here without any further messages.
313
if (dirExist == 0) return;
316
lisp::Writer writer(filename);
318
writer.beginList("tuxkart-config");
319
writer.writeComment("the following options can be set to #t or #f:");
320
writer.write("fullscreen\t", fullscreen);
321
writer.write("sfx\t", sfx);
322
writer.write("music\t", music);
323
writer.write("smoke\t", smoke);
324
writer.writeComment("Display frame per seconds");
325
writer.write("displayFPS\t", displayFPS);
326
writer.writeComment("Use the old, one-window style menu at startup");
327
writer.write("singleWindowMenu\t", singleWindowMenu);
328
writer.writeComment("Display kart icons in bottom row instead of at the left");
329
writer.write("oldStatusDisplay\t", oldStatusDisplay);
330
writer.writeComment("Name of the .herring file to use.");
331
writer.write("herringStyle\t", herringStyle);
332
writer.writeComment("Allow players to disable a magnet");
333
writer.write("disableMagnet\t", disableMagnet);
334
writer.writeComment("Use of kilometers per hours (km/h) instead of mph");
335
writer.write("useKPH\t", useKPH);
336
writer.writeComment("With improved physics the gravity on a non-horizontal");
337
writer.writeComment("plane will add an accelerating force on the kart");
338
writer.write("improvedPhysics\t", improvedPhysics);
339
writer.writeComment("#f: old 'digital' style, #t:new analog style, allows for better turning");
340
writer.write("newKeyboardStyle\t", newKeyboardStyle);
342
writer.writeComment("screen resolution");
343
writer.write("width\t", width);
344
writer.write("height\t", height);
346
writer.writeComment("number of karts. -1 means use all");
347
writer.write("karts\t", karts);
349
/*write player configurations*/
350
for(i=0; i<PLAYERS; ++i) {
354
writer.writeComment(temp);
357
writer.beginList(temp);
359
writer.write("name\t", player[i].getName());
361
writer.writeComment("keyboard layout");
362
writer.write("left\t", player[i].getKey(KC_LEFT));
363
writer.write("right\t", player[i].getKey(KC_RIGHT));
364
writer.write("up\t\t", player[i].getKey(KC_ACCEL));
365
writer.write("down\t", player[i].getKey(KC_BRAKE));
366
writer.write("wheelie\t", player[i].getKey(KC_WHEELIE));
367
writer.write("jump\t", player[i].getKey(KC_JUMP));
368
writer.write("rescue\t", player[i].getKey(KC_RESCUE));
369
writer.write("fire\t", player[i].getKey(KC_FIRE));
371
writer.writeComment("joystick layout");
372
writer.write("joy-up", player[i].getButton(KC_ACCEL));
373
writer.write("joy-down", player[i].getButton(KC_BRAKE));
374
writer.write("joy-wheelie\t", player[i].getButton(KC_WHEELIE));
375
writer.write("joy-jump\t", player[i].getButton(KC_JUMP));
376
writer.write("joy-rescue\t", player[i].getButton(KC_RESCUE));
377
writer.write("joy-fire\t", player[i].getButton(KC_FIRE));
379
writer.endList(temp);
382
writer.endList("tuxkart-config");
383
} catch(std::exception& e) {
384
std::cout << "Couldn't write config: " << e.what() << "\n";
387
// -----------------------------------------------------------------------------
388
std::string Config::GetKeyAsString(int player_index, KartActions control) {
389
int key = player[player_index].getKey(control);
390
int useJoystick = player[player_index].IsUsingJoystick();
393
case PW_KEY_RIGHT : ret="right" ; break;
394
case PW_KEY_LEFT : ret="left" ; break;
395
case PW_KEY_UP : ret="up" ; break;
396
case PW_KEY_DOWN : ret="down" ; break;
397
case PW_KEY_F1 : ret="F1" ; break;
398
case PW_KEY_F2 : ret="F2" ; break;
399
case PW_KEY_F3 : ret="F3" ; break;
400
case PW_KEY_F4 : ret="F4" ; break;
401
case PW_KEY_F5 : ret="F5" ; break;
402
case PW_KEY_F6 : ret="F6" ; break;
403
case PW_KEY_F7 : ret="F7" ; break;
404
case PW_KEY_F8 : ret="F8" ; break;
405
case PW_KEY_F9 : ret="F9" ; break;
406
case PW_KEY_F10 : ret="F10" ; break;
407
case PW_KEY_F11 : ret="F11" ; break;
408
case PW_KEY_F12 : ret="F12" ; break;
409
case PW_KEY_PAGE_UP : ret="pg up" ; break;
410
case PW_KEY_PAGE_DOWN : ret="pg down"; break;
411
case PW_KEY_HOME : ret="home" ; break;
412
case PW_KEY_END : ret="end" ; break;
413
case PW_KEY_INSERT : ret="insert" ; break;
414
case 13 : ret="enter" ; break;
415
case 32 : ret="space" ; break;
421
if (control == KC_LEFT) sprintf(joyInfo, " or stick left");
422
else if (control == KC_RIGHT) sprintf(joyInfo, " or stick right");
423
else if (control == KC_ACCEL) sprintf(joyInfo, " or stick up");
426
const int TARGET_BUTTON = config->player[player_index].getButton(control);
427
int button_number = 0;
428
while((1 << button_number != TARGET_BUTTON) && (button_number < 16))
431
if(button_number < 16)
432
sprintf(joyInfo, " or joybutton %d", button_number + 1 );
434
sprintf(joyInfo, " or unassigned" );