1 // Copyright 2005 by Anthony Liekens anthony@liekens.net
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 
6 #include <sys/stat.h>
7 
8 #include <cstdio>
9 #include <iostream>
10 #include <sstream>
11 #include <fstream>
12 #include <stdexcept>
13 
14 #include <SDL/SDL.h>
15 
16 #include "lisp/lisp.hpp"
17 #include "lisp/writer.hpp"
18 #include "lisp/parser.hpp"
19 
20 #include "settings.h"
21 #include "input.h"
22 
23 using namespace lisp;
24 using namespace std;
25 
26 string Settings::fileName = getConfigFilePath() + "qonk.config";
27 
28 int Settings::screenWidth = 0;
29 int Settings::screenHeight = 0;
30 bool Settings::fullscreen = false;
31 
32 int Settings::gameWidth = 0;
33 int Settings::gameHeight = 0;
34 int Settings::gameOffsetX = 0;
35 
36 int Settings::numberOfPlanets = 6;
37 int Settings::numberOfComputerPlayers = 1;
38 bool Settings::enemyVisibility = false;
39 
40 Input Settings::inputMap[GA_COUNT][2];
41 
42 string
getConfigFilePath()43 Settings::getConfigFilePath(){
44 	string pathname = "";
45 #ifdef WINDOWS
46 	// Do nothing. Falls back to application directory.
47 #elif MAC_OSX
48 	// Get from some mysterious directory ...
49 #else
50 	// GNU/LINUX/BSD/POSIX/...
51 	if(getenv("HOME")!=NULL) {
52 		pathname = getenv("HOME");
53 		pathname += "/.qonk/";
54 		mkdir(pathname.c_str(), 0755);
55         }
56 #endif
57 
58 	return pathname;
59 }
60 
61 void
init()62 Settings::init() {
63   // Ensures that input map is zeroed.
64   memset(inputMap, 0, sizeof(inputMap));
65 
66   // Those are fixed and not supposed to be changed via a config file.
67   set(GA_TOGGLE_GRAB, IT_KEYBOARD, SDLK_g, 0, 0);
68   set(GA_LEAVE, IT_KEYBOARD, SDLK_ESCAPE, 0, 0);
69 
70   const lisp::Lisp* root = 0;
71 
72  	if( !fileExists(fileName))
73   {
74 	  cout << "configuration was not available - using defaults" << endl;
75     setScreenSize(800, 600);
76     setupDefaultActionMap();
77     return;
78   }
79 
80   try
81   {
82     Parser parser;
83     root = parser.parse(fileName);
84   }
85   catch(std::exception& e)
86   {
87     printf("Config file '%s' does not exist, it will be created.\n",
88            fileName.c_str());
89     delete root;
90 
91     return;
92   }
93 
94   const Lisp *qonkReader = 0;
95   if (!(qonkReader = root->getLisp("qonk-config")))
96   {
97 	  cout << "configuration file malformed - using defaults" << endl;
98     setScreenSize(800, 600);
99     setupDefaultActionMap();
100 
101     delete root;
102 
103     return;
104   }
105 
106   int configFileVersion = 0;
107   qonkReader->get("configFileVersion", configFileVersion);
108 
109   if (configFileVersion < REQUIRED_CONFIG_FILE_VERSION)
110   {
111 	  cout << "configuration file version " << configFileVersion << " not supported - using default values." << endl;
112     setScreenSize(800, 600);
113     setupDefaultActionMap();
114 
115     delete root;
116 //    delete qonkReader;
117     return;
118   }
119 
120   qonkReader->get("screenWidth", screenWidth);
121   qonkReader->get("screenHeight", screenHeight);
122   setScreenSize(screenWidth, screenHeight);
123 
124   qonkReader->get("fullscreen", fullscreen);
125 
126   qonkReader->get("planets", numberOfPlanets);
127   qonkReader->get("enemies", numberOfComputerPlayers);
128   qonkReader->get("enemiesVisible", enemyVisibility);
129 
130   const Lisp *reader = 0;
131   reader = qonkReader->getLisp("input");
132   if (reader)
133   {
134     readInput(reader, "screenshot", GA_SCREENSHOT);
135     readInput(reader, "pause", GA_PAUSE);
136     readInput(reader, "toggleFullscreen", GA_TOGGLE_FULLSCREEN);
137     readInput(reader, "restartRound", GA_RESTART_ROUND);
138     readInput(reader, "nextRound", GA_NEXT_ROUND);
139 
140     readInput(reader, "selectAll", GA_SELECT_ALL);
141     readInput(reader, "toggleEnemyVisibility", GA_TOGGLE_ENEMY_VISIBILITY);
142 
143     readInput(reader, "selection", GA_SELECTION);
144 
145     readInput(reader, "cursorUp", GA_CURSOR_UP);
146     readInput(reader, "cursorDown", GA_CURSOR_DOWN);
147     readInput(reader, "cursorLeft", GA_CURSOR_LEFT);
148     readInput(reader, "cursorRight", GA_CURSOR_RIGHT);
149 
150     readInput(reader, "selectNearestPlanet", GA_SELECT_NEAREST_PLANET);
151     readInput(reader, "moveToNearestPlanet", GA_MOVE_TO_NEAREST_PLANET);
152 
153     readInput(reader, "setFleetStrengthSingle", GA_SET_FLEET_STRENGTH_SINGLE);
154     readInput(reader, "fleetStrengthUp", GA_FLEET_STRENGTH_UP);
155     readInput(reader, "fleetStrengthDown", GA_FLEET_STRENGTH_DOWN);
156 
157     readInput(reader, "setFleetStrength10", GA_SET_FLEET_STRENGTH_10);
158     readInput(reader, "setFleetStrength20", GA_SET_FLEET_STRENGTH_20);
159     readInput(reader, "setFleetStrength30", GA_SET_FLEET_STRENGTH_30);
160     readInput(reader, "setFleetStrength40", GA_SET_FLEET_STRENGTH_40);
161     readInput(reader, "setFleetStrength50", GA_SET_FLEET_STRENGTH_50);
162     readInput(reader, "setFleetStrength60", GA_SET_FLEET_STRENGTH_60);
163     readInput(reader, "setFleetStrength70", GA_SET_FLEET_STRENGTH_70);
164     readInput(reader, "setFleetStrength80", GA_SET_FLEET_STRENGTH_80);
165     readInput(reader, "setFleetStrength90", GA_SET_FLEET_STRENGTH_90);
166     readInput(reader, "setFleetStrength100", GA_SET_FLEET_STRENGTH_100);
167   }
168   else
169   {
170     cerr << "Input configuration not present or damaged - using defaults" << endl;
171     setupDefaultActionMap();
172   }
173 
174   delete root;
175 }
176 
177 void
setScreenSize(int width,int height)178 Settings::setScreenSize( int width, int height ) {
179   screenWidth = width;
180   screenHeight = height;
181   gameWidth = height;
182   gameHeight = height;
183   gameOffsetX = ( width - height ) / 2;
184 }
185 
186 void
store()187 Settings::store()
188 {
189   Writer *writer = new Writer(fileName);
190 
191   try
192   {
193     writer->beginList("qonk-config");
194     writer->writeComment("If the game's supported config file version is higher than this number the configuration is discarded.");
195     writer->write("configFileVersion", CURRENT_CONFIG_FILE_VERSION);
196 
197     writer->writeComment("General display properties");
198     writer->write("screenWidth", screenWidth);
199     writer->write("screenHeight", screenHeight);
200     writer->write("fullscreen", fullscreen);
201 
202     writer->writeComment("General gameplay properties");
203     writer->write("planets", numberOfPlanets);
204     writer->write("enemies", numberOfComputerPlayers);
205     writer->write("enemiesVisible", enemyVisibility);
206 
207     writer->beginList("input");
208 
209     writeInput(writer, "screenshot", GA_SCREENSHOT);
210     writeInput(writer, "pause", GA_PAUSE);
211     writeInput(writer, "toggleFullscreen", GA_TOGGLE_FULLSCREEN);
212     writeInput(writer, "restartRound", GA_RESTART_ROUND);
213     writeInput(writer, "nextRound", GA_NEXT_ROUND);
214 
215     writeInput(writer, "selectAll", GA_SELECT_ALL);
216     writeInput(writer, "toggleEnemyVisibility", GA_TOGGLE_ENEMY_VISIBILITY);
217 
218     writeInput(writer, "selection", GA_SELECTION);
219 
220     writeInput(writer, "cursorUp", GA_CURSOR_UP);
221     writeInput(writer, "cursorDown", GA_CURSOR_DOWN);
222     writeInput(writer, "cursorLeft", GA_CURSOR_LEFT);
223     writeInput(writer, "cursorRight", GA_CURSOR_RIGHT);
224 
225     writeInput(writer, "selectNearestPlanet", GA_SELECT_NEAREST_PLANET);
226     writeInput(writer, "moveToNearestPlanet", GA_MOVE_TO_NEAREST_PLANET);
227 
228     writeInput(writer, "setFleetStrengthSingle", GA_SET_FLEET_STRENGTH_SINGLE);
229     writeInput(writer, "fleetStrengthUp", GA_FLEET_STRENGTH_UP);
230     writeInput(writer, "fleetStrengthDown", GA_FLEET_STRENGTH_DOWN);
231 
232     writeInput(writer, "setFleetStrength10", GA_SET_FLEET_STRENGTH_10);
233     writeInput(writer, "setFleetStrength20", GA_SET_FLEET_STRENGTH_20);
234     writeInput(writer, "setFleetStrength30", GA_SET_FLEET_STRENGTH_30);
235     writeInput(writer, "setFleetStrength40", GA_SET_FLEET_STRENGTH_40);
236     writeInput(writer, "setFleetStrength50", GA_SET_FLEET_STRENGTH_50);
237     writeInput(writer, "setFleetStrength60", GA_SET_FLEET_STRENGTH_60);
238     writeInput(writer, "setFleetStrength70", GA_SET_FLEET_STRENGTH_70);
239     writeInput(writer, "setFleetStrength80", GA_SET_FLEET_STRENGTH_80);
240     writeInput(writer, "setFleetStrength90", GA_SET_FLEET_STRENGTH_90);
241     writeInput(writer, "setFleetStrength100", GA_SET_FLEET_STRENGTH_100);
242 
243     writer->endList("input");
244 
245     writer->endList("qonk-config");
246   }
247   catch (exception &)
248   {
249     cerr << "Could not write config file." << endl;
250   }
251 
252   delete writer;
253 }
254 
255 void
readInput(const lisp::Lisp * r,const char * node,GameAction action)256 Settings::readInput(const lisp::Lisp* r,
257                        const char *node,
258                        GameAction action)
259 {
260     string inputTypeName;
261     char *which[] = { "normal", "alternate" };
262 
263     const Lisp* nodeReader = r->getLisp(node);
264     if (!nodeReader)
265       return;
266 
267     for(int i=0;i<2;i++)
268     {
269     InputType it=IT_NONE;
270     // Every unused id variable *must* be set to
271     // something different than -1. Otherwise
272     // the restored mapping will not be applied.
273     int id0 = -1, id1 = -1, id2 = -1;
274 
275     const Lisp *subReader = nodeReader->getLisp(which[i]);
276     if (!subReader)
277       break;
278 
279     subReader->get("type", inputTypeName);
280     if (inputTypeName == "keyboard")
281     {
282         it = IT_KEYBOARD;
283         subReader->get("key", id0);
284         id1 = id2 = 0;
285     }
286     else if (inputTypeName == "stickaxis")
287     {
288         it = IT_STICKMOTION;
289         subReader->get("stick", id0);
290         subReader->get("axis", id1);
291         subReader->get("direction", id2);
292     }
293     else if (inputTypeName == "stickbutton")
294     {
295         it = IT_STICKBUTTON;
296         subReader->get("stick", id0);
297         subReader->get("button", id1);
298         id2 = 0;
299     }
300     else if (inputTypeName == "stickhat")
301     {
302         it = IT_STICKHAT;
303         // TODO: Implement me
304     }
305     else if (inputTypeName == "mouseaxis")
306     {
307         it = IT_MOUSEMOTION;
308         subReader->get("axis", id0);
309         subReader->get("direction", id1);
310         id2 = 0;
311     }
312     else if (inputTypeName == "mousebutton")
313     {
314         it = IT_MOUSEBUTTON;
315         subReader->get("button", id0);
316         id1 = id2 = 0;
317     }
318 
319     if (id0 != -1 && id1 != -1 && id2 != -1)
320         set(action, it, id0, id1, id2);
321 
322     }
323 
324 }
325 
326 void
unset(GameAction ga)327 Settings::unset(GameAction ga)
328 {
329   // Deletes the 2nd entry if it exists or
330   // the first if not.
331   if (inputMap[ga][1].inputType != IT_NONE)
332     inputMap[ga][1].inputType = IT_NONE;
333   else
334     inputMap[ga][0].inputType = IT_NONE;
335 }
336 
337 void
unsetDuplicates(GameAction ga,InputType it,int id0,int id1,int id2)338 Settings::unsetDuplicates (GameAction ga, InputType it, int id0, int id1, int id2)
339 {
340   for (int cga = GA_FIRST; cga < GA_COUNT; cga++)
341   {
342     if (cga != ga)
343     {
344       // If the input occurs in any other mapping
345       // delete it properly from there.
346 
347       if (inputMap[cga][1].inputType == it
348           && inputMap[cga][1].id0 == id0
349           && inputMap[cga][1].id1 == id1
350           && inputMap[cga][1].id2 == id2)
351       {
352         // Deletes it from the 2nd entry.
353         inputMap[cga][1].inputType = IT_NONE;
354       }
355 
356       if (inputMap[cga][0].inputType == it
357           && inputMap[cga][0].id0 == id0
358           && inputMap[cga][0].id1 == id1
359           && inputMap[cga][0].id2 == id2)
360       {
361         // Deletes it from the 1st entry and
362         // shifts the 2nd to the first.
363         inputMap[cga][0] = inputMap[cga][1];
364         inputMap[cga][1].inputType = IT_NONE;
365       }
366     }
367   }
368 }
369 
370 void
set(GameAction ga,InputType it,int id0,int id1,int id2)371 Settings::set(GameAction ga, InputType it, int id0, int id1, int id2)
372 {
373   // Do not change anything if the sensed input already
374   // exists for the game action.
375   if (inputMap[ga][0].inputType == it
376           && inputMap[ga][0].id0 == id0
377           && inputMap[ga][0].id1 == id1
378           && inputMap[ga][0].id2 == id2
379           || inputMap[ga][1].inputType == it
380           && inputMap[ga][1].id0 == id0
381           && inputMap[ga][1].id1 == id1
382           && inputMap[ga][1].id2 == id2)
383     return;
384 
385   // Removes the input from all mappings where it occurs.
386   unsetDuplicates(ga, it, id0, id1, id2);
387 
388   // Setting a new value is implemented by shifting the value to the
389   // right and applying the new values in the 1st location.
390 
391   inputMap[ga][1] = inputMap[ga][0];
392 
393   // New input is always placed on the first location.
394   Input &im = inputMap[ga][0];
395 
396   im.inputType = it;
397   im.id0 = id0;
398   im.id1 = id1;
399   im.id2 = id2;
400 }
401 
402 /**
403  * Connects the given Input with the GameAction.
404  *
405  * TODO: In the future the return value may indicate whether
406  * the input is already in use (conflict) and was rejected.
407  */
408 void
set(GameAction ga,Input & input)409 Settings::set(GameAction ga, Input &input)
410 {
411   set(ga, input.inputType, input.id0, input.id1, input.id2);
412 }
413 
414 void
writeInput(lisp::Writer * writer,const char * node,GameAction action)415 Settings::writeInput(lisp::Writer *writer, const char *node, GameAction action)
416 {
417     writer->beginList(node);
418 
419     for (int i=0;i<2;i++)
420     {
421     const Input input = inputMap[action][i];
422     const char *which[] =  { "normal", "alternate" };
423 
424     if (input.inputType != IT_NONE)
425     {
426     writer->beginList(which[i]);
427 
428     switch (input.inputType)
429     {
430     case IT_KEYBOARD:
431         writer->write("type", "keyboard");
432         writer->write("key", input.id0);
433         break;
434     case IT_STICKMOTION:
435         writer->write("type", "stickaxis");
436         writer->write("stick", input.id0);
437         writer->write("axis", input.id1);
438         writer->writeComment("0 is negative/left/up, 1 is positive/right/down");
439         writer->write("direction", input.id2);
440         break;
441     case IT_STICKBUTTON:
442         writer->write("type", "stickbutton");
443         writer->write("stick", input.id0);
444         writer->write("button", input.id1);
445         break;
446     case IT_STICKHAT:
447         // TODO: Implement me
448         break;
449     case IT_MOUSEMOTION:
450         writer->write("type", "mouseaxis");
451         writer->write("axis", input.id0);
452         writer->writeComment("0 is negative/left/up, 1 is positive/right/down");
453         writer->write("direction", input.id1);
454         break;
455     case IT_MOUSEBUTTON:
456         writer->write("type", "mousebutton");
457         writer->writeComment("0 is left, 1 is middle, 2 is right, 3 is wheel up, 4 is wheel down");
458         writer->writeComment("other values denote auxillary buttons");
459         writer->write("button", input.id0);
460         break;
461     }
462     writer->endList(which[i]);
463     }
464 
465     }
466 
467     writer->endList(node);
468 }
469 
470 void
setupDefaultActionMap()471 Settings::setupDefaultActionMap()
472 {
473   set(GA_SCREENSHOT, IT_KEYBOARD, SDLK_F12, 0, 0);
474   set(GA_PAUSE, IT_KEYBOARD, SDLK_p, 0, 0);
475   set(GA_TOGGLE_FULLSCREEN, IT_KEYBOARD, SDLK_f, 0, 0);
476 
477   set(GA_RESTART_ROUND, IT_KEYBOARD, SDLK_r, 0, 0);
478   set(GA_NEXT_ROUND, IT_KEYBOARD, SDLK_n, 0, 0);
479 
480   set(GA_SELECT_ALL, IT_KEYBOARD, SDLK_a, 0, 0);
481   set(GA_TOGGLE_ENEMY_VISIBILITY, IT_KEYBOARD, SDLK_e, 0, 0);
482 
483   set(GA_SELECTION, IT_MOUSEBUTTON, SDL_BUTTON_LEFT, 0, 0);
484   set(GA_SELECTION, IT_KEYBOARD, SDLK_LSHIFT, 0, 0);
485 
486   set(GA_SELECT_NEAREST_PLANET, IT_MOUSEBUTTON, SDL_BUTTON_MIDDLE, 0, 0);
487   set(GA_SELECT_NEAREST_PLANET, IT_KEYBOARD, SDLK_TAB, 0, 0);
488 
489   set(GA_MOVE_TO_NEAREST_PLANET, IT_MOUSEBUTTON, SDL_BUTTON_RIGHT, 0, 0);
490   set(GA_MOVE_TO_NEAREST_PLANET, IT_KEYBOARD, SDLK_LCTRL, 0, 0);
491 
492   set(GA_CURSOR_LEFT, IT_MOUSEMOTION, 0, AD_NEGATIVE, 0);
493   set(GA_CURSOR_LEFT, IT_KEYBOARD, SDLK_LEFT, 0, 0);
494 
495   set(GA_CURSOR_RIGHT, IT_MOUSEMOTION, 0, AD_POSITIVE, 0);
496   set(GA_CURSOR_RIGHT, IT_KEYBOARD, SDLK_RIGHT, 0, 0);
497 
498   set(GA_CURSOR_UP, IT_MOUSEMOTION, 1, AD_NEGATIVE, 0);
499   set(GA_CURSOR_UP, IT_KEYBOARD, SDLK_UP, 0, 0);
500 
501   set(GA_CURSOR_DOWN, IT_MOUSEMOTION, 1, AD_POSITIVE, 0);
502   set(GA_CURSOR_DOWN, IT_KEYBOARD, SDLK_DOWN, 0, 0);
503 
504 /* preliminary: cursor control with joystick - works good
505   set(GA_SELECTION, IT_STICKBUTTON, 0, 1, 0);
506   set(GA_SELECT_NEAREST_PLANET, IT_STICKBUTTON, 0, 2, 0);
507   set(GA_MOVE_TO_NEAREST_PLANET, IT_STICKBUTTON, 0, 3, 0);
508   set(GA_CURSOR_LEFT, IT_STICKMOTION, 0, 0, AD_NEGATIVE);
509   set(GA_CURSOR_RIGHT, IT_STICKMOTION, 0, 0, AD_POSITIVE);
510   set(GA_CURSOR_UP, IT_STICKMOTION, 0, 1, AD_NEGATIVE);
511   set(GA_CURSOR_DOWN, IT_STICKMOTION, 0, 1, AD_POSITIVE);
512 */
513 
514   set(GA_FLEET_STRENGTH_UP, IT_MOUSEBUTTON, SDL_BUTTON_WHEELUP, 0, 0);
515   set(GA_FLEET_STRENGTH_UP, IT_KEYBOARD, SDLK_PLUS, 0, 0);
516 
517   set(GA_FLEET_STRENGTH_DOWN, IT_MOUSEBUTTON, SDL_BUTTON_WHEELDOWN, 0, 0);
518   set(GA_FLEET_STRENGTH_DOWN, IT_KEYBOARD, SDLK_MINUS, 0, 0);
519 
520   set(GA_SET_FLEET_STRENGTH_SINGLE, IT_KEYBOARD, SDLK_s, 0, 0);
521   set(GA_SET_FLEET_STRENGTH_10, IT_KEYBOARD, SDLK_1, 0, 0);
522   set(GA_SET_FLEET_STRENGTH_20, IT_KEYBOARD, SDLK_2, 0, 0);
523   set(GA_SET_FLEET_STRENGTH_30, IT_KEYBOARD, SDLK_3, 0, 0);
524   set(GA_SET_FLEET_STRENGTH_40, IT_KEYBOARD, SDLK_4, 0, 0);
525   set(GA_SET_FLEET_STRENGTH_50, IT_KEYBOARD, SDLK_5, 0, 0);
526   set(GA_SET_FLEET_STRENGTH_60, IT_KEYBOARD, SDLK_6, 0, 0);
527   set(GA_SET_FLEET_STRENGTH_70, IT_KEYBOARD, SDLK_7, 0, 0);
528   set(GA_SET_FLEET_STRENGTH_80, IT_KEYBOARD, SDLK_8, 0, 0);
529   set(GA_SET_FLEET_STRENGTH_90, IT_KEYBOARD, SDLK_9, 0, 0);
530   set(GA_SET_FLEET_STRENGTH_100, IT_KEYBOARD, SDLK_0, 0, 0);
531 }
532 
533 Input
getInput(GameAction ga)534 Settings::getInput(GameAction ga)
535 {
536   return inputMap[ga][0];
537 }
538 
539 Input
getAltInput(GameAction ga)540 Settings::getAltInput(GameAction ga)
541 {
542   return inputMap[ga][1];
543 }
544 
545 string
getInputAsString(Input & input)546 Settings::getInputAsString(Input &input)
547 {
548     char msg[512];
549     std::ostringstream stm;
550 
551     switch (input.inputType)
552     {
553     case IT_KEYBOARD:
554         snprintf(msg, sizeof(msg), ("%s"), SDL_GetKeyName((SDLKey) input.id0));
555         break;
556     case IT_STICKMOTION:
557         snprintf(msg, sizeof(msg), ("joy %d axis %d  %c"),
558                  input.id0, input.id1, (input.id2 == AD_NEGATIVE) ? '-' : '+');
559         break;
560     case IT_STICKBUTTON:
561         snprintf(msg, sizeof(msg), ("joy %d button %d"), input.id0, input.id1);
562         break;
563     case IT_STICKHAT:
564         snprintf(msg, sizeof(msg), ("joy %d hat %d"), input.id0, input.id1);
565         break;
566     case IT_MOUSEBUTTON:
567         snprintf(msg, sizeof(msg), ("mouse button %d"), input.id0);
568         break;
569     case IT_MOUSEMOTION:
570         // Axis 0 and 1 represent x and y. Thats for sure. If we get higher
571         // numbers just print those instead.
572         if (input.id0 < 2)
573           snprintf(msg, sizeof(msg), ("mouse %c axis %c"),
574                    ((input.id0 == 0) ? 'x' : 'y'), ((input.id1 == AD_NEGATIVE) ? '-' : '+'));
575         else
576           snprintf(msg, sizeof(msg), ("mouse axis %d %c"),
577                    input.id0, ((input.id1 == AD_NEGATIVE) ? '-' : '+'));
578 
579         break;
580     default:
581         snprintf(msg, sizeof(msg), ("Invalid"));
582     }
583 
584     stm << msg;
585 
586     return stm.str();
587 }
588 
589 string
getAsString(GameAction ga)590 Settings::getAsString(GameAction ga)
591 {
592   Input input = inputMap[ga][0];
593   if (input.inputType != IT_NONE)
594   {
595     stringstream s;
596     s << getInputAsString(input);
597 
598     input = inputMap[ga][1];
599     if (input.inputType != IT_NONE)
600       s << " or " << getInputAsString(input);
601 
602     return s.str();
603   }
604   else
605   {
606     return string("undefined");
607   }
608 }
609 
610 void
printInput(char * msg)611 Settings::printInput(char *msg)
612 {
613   cerr << msg << ":" << endl;
614 
615   int size = GA_FIRST + GA_COUNT;
616   for (int i=GA_FIRST; i<size;i++)
617   {
618     Input input = inputMap[i][0];
619     cerr << "normal action: " << i << " - input.inputType: " << input.inputType << " - input.id0: " << input.id0 << endl;
620     input = inputMap[i][1];
621     cerr << "   alt action: " << i << " - input.inputType: " << input.inputType << " - input.id0: " << input.id0 << endl << endl;
622   }
623 }
624 
625 bool
fileExists(const std::string & fileName)626 Settings::fileExists( const std::string& fileName ) {
627 	std::ifstream infile( fileName.c_str() );
628 	bool result = infile.good();
629 	infile.close();
630 
631 	return result;
632 }
633