1 /******************************************************************************
2 * Warmux is a convivial mass murder game.
3 * Copyright (C) 2001-2011 Warmux Team.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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 * Warmux configuration : all variables interesting to tweak should be here.
20 * A default value is affected for each variable, the value can be changed by
21 * the configuration file.
22 *****************************************************************************/
23
24 #include <cstdlib>
25 #include <sstream>
26 #include <string>
27 #include <iostream>
28 #include <errno.h>
29 #include <libxml/tree.h>
30
31 #ifdef __APPLE__
32 # include <CoreFoundation/CoreFoundation.h>
33 #endif
34
35 #ifdef WIN32
36 # include <windows.h>
37 # include <direct.h>
38 #endif
39
40 #include <WARMUX_file_tools.h>
41 #include <WARMUX_team_config.h>
42
43 #include "game/config.h"
44 #include "game/game.h"
45 #include "graphic/font.h"
46 #include "graphic/video.h"
47 #include "include/app.h"
48 #include "include/constant.h"
49 #include "interface/keyboard.h"
50 #include "network/network.h"
51 #include "object/object_cfg.h"
52 #include "sound/jukebox.h"
53 #include "team/team.h"
54 #include "team/teams_list.h"
55 #include "tool/resource_manager.h"
56 #include "tool/string_tools.h"
57 #include "tool/xml_document.h"
58 #include "weapon/weapons_list.h"
59
60 #ifdef _WIN32
61 // Under Windows, binary may be relocated
GetWarmuxPath()62 static std::string GetWarmuxPath()
63 {
64 WCHAR buffer[4*MAX_PATH];
65 DWORD size = GetModuleFileNameW(NULL, buffer, 4*MAX_PATH);
66
67 if (size<1)
68 return std::string("");
69
70 // Now get shortname
71 size = GetShortPathNameW(buffer, NULL, 0);
72 ASSERT(size);
73 WCHAR *buf = new WCHAR[size];
74 GetShortPathNameW(buffer, buf, size);
75
76 // Retrieve the path and convert it to ANSI
77 size = wcsrchr((wchar_t*)buf, L'\\')+1 - buf;
78 ASSERT(size < MAX_PATH);
79 int ulen = WideCharToMultiByte(CP_UTF8, 0, buf, size, NULL, 0, NULL, NULL);
80
81 std::string ret;
82 ret.resize(ulen-1);
83 WideCharToMultiByte(CP_UTF8, 0, buf, size, (LPSTR)ret.c_str(), ulen-1, NULL, NULL);
84 delete[] buf;
85
86 return ret;
87 }
88 #else
89 # if defined(ANDROID)
GetWarmuxPath()90 static std::string GetWarmuxPath() { return "."; }
91 # elif defined(GEKKO)
GetWarmuxPath()92 static std::string GetWarmuxPath() { return "sd:/apps/Warmux"; }
93 # endif
94 # include <unistd.h> // not needed by mingw
95 #endif
96
97 static const std::string FILENAME="config.xml";
98
Config()99 Config::Config()
100 : default_language("")
101 , m_game_mode("classic")
102 , display_energy_character(true)
103 , display_name_character(true)
104
105 #ifdef HAVE_HANDHELD
106 , wind_particles_percentage(0) // Too CPU intensive
107 , display_multi_layer_sky(false) // Memory hungry + CPU intensive
108 #else
109 , wind_particles_percentage(100)
110 , display_multi_layer_sky(true)
111 #endif
112
113 , default_mouse_cursor(false)
114 , video_width(0)
115 , video_height(0)
116
117 #ifdef HAVE_TOUCHSCREEN
118 , video_fullscreen(true) // No other mode supported
119 , max_fps(25)
120 #else
121 , video_fullscreen(false)
122 , max_fps(50)
123 #endif
124
125 , bling_bling_interface(false)
126 , scroll_on_border(false)
127 , scroll_border_size(50)
128 , sound_music(true)
129 , sound_effects(true)
130 #ifdef HAVE_HANDHELD
131 , sound_frequency(22050)
132 #else
133 , sound_frequency(44100)
134 #endif
135 , warn_on_new_player(true)
136 , check_updates(false)
137 , lefthanded_mouse(false)
138 , m_network_client_host("localhost")
139 , m_network_client_port(WARMUX_NETWORK_PORT)
140 , m_network_server_game_name("Warmux party")
141 , m_network_server_port(WARMUX_NETWORK_PORT)
142 , m_network_server_public(true)
143
144 #ifdef HAVE_HANDHELD
145 , quality(QUALITY_16BPP)
146 #else
147 , quality(QUALITY_32BPP)
148 #endif
149 {
150 // Set audio volume
151 volume_music = JukeBox::GetMaxVolume()/2;
152 volume_effects = JukeBox::GetMaxVolume()/2;
153
154 Constants::GetInstance();
155
156 // directories
157 #if defined(__APPLE__)
158 // the following code will enable warmux to find its data when placed in an app bundle on mac OS X.
159 // configure with './configure ... CPPFLAGS=-DOSX_BUNDLE' to enable
160 char path[1024];
161 CFBundleRef mainBundle = CFBundleGetMainBundle(); assert(mainBundle);
162 CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle); assert(mainBundleURL);
163 CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle); assert(cfStringRef);
164 CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
165 CFRelease(mainBundleURL);
166 CFRelease(cfStringRef);
167
168 std::string contents = std::string(path) + std::string("/Contents");
169 if(contents.find(".app") != std::string::npos){
170 // executable is inside an app bundle, use app bundle-relative paths
171 std::string default_data_dir = contents + std::string("/Resources/data/");
172 std::string default_ttf_filename = contents + std::string("/Resources/data/font/Ubuntu-R.ttf");
173
174 // if environment variables exist, they will override default values
175 data_dir = GetEnv(Constants::ENV_DATADIR, default_data_dir);
176 ttf_filename = GetEnv(Constants::ENV_FONT_PATH, default_ttf_filename);
177 personal_config_dir = GetHome() + "/Library/Application Support/Warmux/";
178 personal_data_dir = personal_config_dir;
179 # ifdef ENABLE_NLS
180 std::string default_locale_dir = contents + std::string("/Resources/locale/");
181 locale_dir = GetEnv(Constants::ENV_LOCALEDIR, default_locale_dir);
182 # endif
183 }
184 else {
185 // executable is installed Unix-style, use default paths
186 data_dir = GetEnv(Constants::ENV_DATADIR, INSTALL_DATADIR);
187 # ifdef ENABLE_NLS
188 locale_dir = GetEnv(Constants::ENV_LOCALEDIR, INSTALL_LOCALEDIR);
189 # endif
190 ttf_filename = GetEnv(Constants::ENV_FONT_PATH, FONT_FILE);
191 }
192 #elif defined(_WIN32) || defined(ANDROID) || defined(GEKKO)
193 std::string basepath = GetWarmuxPath();
194 data_dir = basepath + PATH_SEPARATOR "data" PATH_SEPARATOR;
195 # ifdef ENABLE_NLS
196 locale_dir = basepath + PATH_SEPARATOR "locale" PATH_SEPARATOR;
197 # endif
198 ttf_filename = basepath + PATH_SEPARATOR FONT_FILE;
199 font_dir = data_dir + PATH_SEPARATOR "font" PATH_SEPARATOR;
200
201 personal_config_dir = GetHome() + PATH_SEPARATOR "Warmux" PATH_SEPARATOR;
202 personal_data_dir = personal_config_dir;
203
204 #else //Neither WIN32, ANDROID or __APPLE__
205 data_dir = GetEnv(Constants::ENV_DATADIR, INSTALL_DATADIR);
206 # ifdef ENABLE_NLS
207 locale_dir = GetEnv(Constants::ENV_LOCALEDIR, INSTALL_LOCALEDIR);
208 # endif
209 ttf_filename = GetEnv(Constants::ENV_FONT_PATH, FONT_FILE);
210 font_dir = GetEnv(Constants::ENV_FONT_PATH, data_dir + PATH_SEPARATOR "font" PATH_SEPARATOR);
211
212 // To respect XDG Base Directory Specification from FreeDesktop
213 // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
214
215 const char * c_config_dir = std::getenv("XDG_CONFIG_HOME");
216 const char * c_data_dir = std::getenv("XDG_DATA_HOME");
217
218 if (c_config_dir == NULL)
219 personal_config_dir = GetHome() + "/.config";
220 else
221 personal_config_dir = c_config_dir;
222
223 personal_config_dir += "/wormux/";
224
225 if (c_data_dir == NULL) {
226 personal_data_dir = GetHome() + "/.local/share";
227 }
228 else
229 personal_data_dir = c_data_dir;
230
231 personal_data_dir += "/wormux/";
232 #endif
233
234 std::string old_dir = GetOldPersonalDir();
235 if (old_dir != "") {
236 std::cout << "Moving " << old_dir << " to " << personal_data_dir << std::endl;
237 if (old_dir != personal_data_dir)
238 Rename(old_dir, personal_data_dir);
239 }
240
241 std::string old_config_file_name = personal_data_dir + "config.xml";
242 std::string config_file_name = personal_config_dir + "config.xml";
243 if (old_config_file_name != config_file_name) {
244 std::cout << "Moving " << old_config_file_name
245 << " to " << config_file_name << std::endl;
246 Rename(old_config_file_name, config_file_name);
247 }
248
249 chat_log_dir = personal_data_dir + "logs" PATH_SEPARATOR;
250
251 // Create the directories
252 // Delayed after copy/creation of personal_data_dir, because they
253 // might cause an access denied (because of indexing under Windows)
254 MkdirChatLogDir();
255 MkdirPersonalConfigDir();
256 MkdirPersonalDataDir();
257
258 LoadDefaultValue();
259
260 // Load personal config
261 std::string dir;
262 if (!DoLoading())
263 {
264 #ifdef ENABLE_NLS
265 // Failed, still try to apply default config then
266 SetLanguage("");
267 #endif
268 }
269
270 dir = TranslateDirectory(data_dir);
271 GetResourceManager().SetDataPath(dir + PATH_SEPARATOR);
272 }
273
MkdirChatLogDir() const274 bool Config::MkdirChatLogDir() const
275 {
276 return CreateFolder(chat_log_dir);
277 }
278
MkdirPersonalConfigDir() const279 bool Config::MkdirPersonalConfigDir() const
280 {
281 bool r = CreateFolder(personal_config_dir);
282
283 if (r) {
284 CreateFolder(personal_config_dir + "custom_team");
285 }
286
287 return r;
288 }
289
MkdirPersonalDataDir() const290 bool Config::MkdirPersonalDataDir() const
291 {
292 bool r = CreateFolder(personal_data_dir);
293
294 if (r) {
295 CreateFolder(personal_data_dir + "map");
296 CreateFolder(personal_data_dir + "team");
297 CreateFolder(personal_data_dir + "game_mode");
298 }
299
300 return r;
301 }
302
RemovePersonalConfigFile() const303 bool Config::RemovePersonalConfigFile() const
304 {
305 std::string personal_config_file = personal_config_dir + FILENAME;
306
307 int r = unlink(personal_config_file.c_str());
308 if (r) {
309 if (errno == -ENOENT) {
310 r = 0;
311 } else {
312 perror((Format("Fail to remove personal config file %s", personal_config_file.c_str())).c_str());
313 }
314 }
315
316 if (r)
317 return false;
318
319 return true;
320 }
321
322 #ifdef ENABLE_NLS
SetLanguage(const std::string & language)323 void Config::SetLanguage(const std::string& language)
324 {
325 default_language = language;
326 InitI18N(TranslateDirectory(locale_dir), language);
327
328 Font::ReleaseInstances();
329 if (GameIsRunning()) {
330 Game::GetInstance()->UpdateTranslation();
331 }
332 }
333 #endif
334
335 /*
336 * Load physics constants from the xml file and cache it.
337 * This tries to find already loaded data in the map<> config_set and actually
338 * load it if it cannot be found.
339 */
GetObjectConfig(const std::string & name,const std::string & xml_config) const340 const ObjectConfig &Config::GetObjectConfig(const std::string &name, const std::string &xml_config) const
341 {
342 ObjectConfig * objcfg;
343
344 std::map<std::string, ObjectConfig*>::const_iterator it = config_set.find(name);
345 if (it == config_set.end()) {
346 objcfg = new ObjectConfig();
347 objcfg->LoadXml(name,xml_config);
348 config_set[name] = objcfg;
349 } else {
350 objcfg = it->second;
351 }
352 return *objcfg;
353 }
354
RemoveAllObjectConfigs()355 void Config::RemoveAllObjectConfigs()
356 {
357 std::map<std::string, ObjectConfig*>::iterator it = config_set.begin(),
358 end = config_set.end();
359
360 while (it != end) {
361 delete (it->second);
362 config_set.erase(it);
363 it = config_set.begin();
364 }
365 }
366
DoLoading(void)367 bool Config::DoLoading(void)
368 {
369 // create the directory if it does not exist (we should do it before exiting the game)
370 // the user can ask to start an internet game and download a file in the personnal dir
371 // so it should exist
372 MkdirPersonalDataDir();
373 MkdirPersonalConfigDir();
374
375 // Load XML conf
376 XmlReader doc;
377
378 m_filename = personal_config_dir + FILENAME;
379
380 if (!doc.Load(m_filename))
381 return false;
382
383 LoadXml(doc.GetRoot());
384 return true;
385 }
386
LoadDefaultValue()387 void Config::LoadDefaultValue()
388 {
389 // Load default XML conf
390 #ifdef ANDROID
391 m_default_config = GetDataDir() + "warmux_default_android_config.xml";
392 #elif MAEMO
393 m_default_config = GetDataDir() + "warmux_default_maemo_config.xml";
394 #elif __SYMBIAN32__
395 m_default_config = GetDataDir() + "warmux_default_symbian_config.xml";
396 #else
397 m_default_config = GetDataDir() + "warmux_default_config.xml";
398 #endif
399 Profile *res = GetResourceManager().LoadXMLProfile(m_default_config, true);
400
401 std::cout << "o " << _("Reading the default config file") << std::endl;
402 std::ostringstream section;
403 Point2i tmp;
404
405 //=== Default video value ===
406 int number_of_resolution_available = GetResourceManager().LoadInt(res, "default_video_mode/number_of_resolution_available");
407 for(int i = 1; i <= number_of_resolution_available; i++) {
408 tmp = Point2i(0, 0);
409 std::ostringstream section; section << "default_video_mode/" << i;
410 tmp = GetResourceManager().LoadPoint2i(res, section.str());
411 if(tmp.GetX() > 0 && tmp.GetY() > 0)
412 resolution_available.push_back(tmp);
413 }
414
415 //== Default keyboard key
416 const xmlNode *node = GetResourceManager().GetElement(res, "section", "default_keyboard_layout");
417 if (node) {
418 Keyboard::GetInstance()->SetConfig(node);
419 }
420
421 #ifdef ENABLE_NLS
422 //=== Default fonts value ===
423 node = GetResourceManager().GetElement(res, "section", "default_language_fonts");
424 if (node) {
425 xmlNodeArray list = XmlReader::GetNamedChildren(node, "language");
426 for (xmlNodeArray::iterator it = list.begin(); it != list.end(); ++it) {
427 std::string lang, font;
428 if (res->doc->ReadStringAttr(*it, "name", lang) &&
429 res->doc->ReadStringAttr(*it, "file", font)) {
430 bool rel = false;
431 res->doc->ReadBoolAttr(*it, "relative", rel);
432 fonts[lang] = (rel) ? font_dir + font : font;
433 //std::cout << "Language " << lang << ": " << fonts[lang] << std::endl;
434 }
435 }
436 }
437 #endif
438
439 #if 0 //== Team Color
440 int number_of_team_color = GetResourceManager().LoadInt(res, "team_colors/number_of_team_color");
441 for(int i = 1; i <= number_of_team_color; i++) {
442 tmp = Point2i(0, 0);
443 std::ostringstream section; section << "team_colors/" << i;
444 tmp = GetResourceManager().LoadPoint2i(res, section.str());
445 if(tmp.GetX() > 0 && tmp.GetY() > 0)
446 resolution_available.push_back(tmp);
447 }
448 #endif
449
450 GetResourceManager().UnLoadXMLProfile(res);
451 }
452
453 // Read personal config file
LoadXml(const xmlNode * xml)454 void Config::LoadXml(const xmlNode *xml)
455 {
456 const xmlNode *elem;
457
458 std::cout << "o " << _("Reading the personal config file") << std::endl;
459
460 //=== Map ===
461 XmlReader::ReadString(xml, "map", map_name);
462
463 //=== Language ===
464 XmlReader::ReadString(xml, "default_language", default_language);
465 #ifdef ENABLE_NLS
466 SetLanguage(default_language);
467 #endif
468
469 //=== Teams ===
470 if ((elem = XmlReader::GetMarker(xml, "teams"))) {
471 int i = 0;
472
473 const xmlNode *team;
474
475 while ((team = XmlReader::GetMarker(elem, "team_" + int2str(i)))) {
476 ConfigTeam one_team;
477 XmlReader::ReadString(team, "id", one_team.id);
478 XmlReader::ReadString(team, "player_name", one_team.player_name);
479 XmlReader::ReadUint(team, "nb_characters", one_team.nb_characters);
480 // The ai element needs a defaut as it has been added afterwards:
481 if (!XmlReader::ReadString(team, "ai", one_team.ai)) {
482 one_team.ai = (i == 1) ? DEFAULT_AI_NAME : NO_AI_NAME;
483 }
484
485 teams.push_back(one_team);
486
487 // get next team
488 i++;
489 }
490 }
491
492 //=== Video ===
493 if ((elem = XmlReader::GetMarker(xml, "video"))) {
494 XmlReader::ReadBool(elem, "bling_bling_interface", bling_bling_interface);
495 XmlReader::ReadUint(elem, "max_fps", max_fps);
496 XmlReader::ReadUint(elem, "wind_particles_percentage", wind_particles_percentage);
497 if (wind_particles_percentage > 100)
498 wind_particles_percentage = 100;
499 XmlReader::ReadBool(elem, "display_multi_layer_sky", display_multi_layer_sky);
500 XmlReader::ReadBool(elem, "display_energy_character", display_energy_character);
501 XmlReader::ReadBool(elem, "display_name_character", display_name_character);
502 XmlReader::ReadBool(elem, "default_mouse_cursor", default_mouse_cursor);
503 #ifndef HAVE_TOUCHSCREEN // Those should never be set
504 XmlReader::ReadBool(elem, "scroll_on_border", scroll_on_border);
505 XmlReader::ReadUint(elem, "scroll_border_size", scroll_border_size);
506 #endif
507 XmlReader::ReadUint(elem, "width", video_width);
508 XmlReader::ReadUint(elem, "height", video_height);
509 XmlReader::ReadBool(elem, "full_screen", video_fullscreen);
510
511 uint qual;
512 if (XmlReader::ReadUint(elem, "quality", qual)) {
513 if (qual>QUALITY_MAX-1) qual=QUALITY_MAX-1;
514 quality = (Quality)qual;
515 }
516 }
517
518 //=== Sound ===
519 if ((elem = XmlReader::GetMarker(xml, "sound"))) {
520 XmlReader::ReadBool(elem, "music", sound_music);
521 XmlReader::ReadBool(elem, "effects", sound_effects);
522 #ifndef HAVE_HANDHELD
523 XmlReader::ReadUint(elem, "frequency", sound_frequency);
524 #endif
525 XmlReader::ReadUint(elem, "volume_music", volume_music);
526 XmlReader::ReadUint(elem, "volume_effects", volume_effects);
527 }
528
529 //=== network ===
530 if ((elem = XmlReader::GetMarker(xml, "network"))) {
531 const xmlNode *sub_elem;
532 if ((sub_elem = XmlReader::GetMarker(elem, "as_client"))) {
533 XmlReader::ReadString(sub_elem, "host", m_network_client_host);
534 XmlReader::ReadString(sub_elem, "port", m_network_client_port);
535 }
536
537 if ((sub_elem = XmlReader::GetMarker(elem, "as_server"))) {
538 XmlReader::ReadString(sub_elem, "game_name", m_network_server_game_name);
539 XmlReader::ReadString(sub_elem, "port", m_network_server_port);
540 XmlReader::ReadBool(sub_elem, "public", m_network_server_public);
541 }
542
543 //=== personal teams used in last network game ===
544 if ((sub_elem = XmlReader::GetMarker(elem, "local_teams"))) {
545 int i = 0;
546 const xmlNode *team;
547
548 while ((team = XmlReader::GetMarker(sub_elem, "team_" + int2str(i)))) {
549 ConfigTeam one_team;
550 XmlReader::ReadString(team, "id", one_team.id);
551 XmlReader::ReadString(team, "player_name", one_team.player_name);
552 XmlReader::ReadUint(team, "nb_characters", one_team.nb_characters);
553 // The ai element needs a defaut as it has been added afterwards:
554 if (!XmlReader::ReadString(team, "ai", one_team.ai)) {
555 one_team.ai = NO_AI_NAME;
556 }
557
558 network_local_teams.push_back(one_team);
559
560 // get next team
561 i++;
562 }
563 }
564 }
565
566 //=== misc ===
567 if ((elem = XmlReader::GetMarker(xml, "misc"))) {
568 XmlReader::ReadBool(elem, "check_updates", check_updates);
569 XmlReader::ReadBool(elem, "left-handed_mouse", lefthanded_mouse);
570 }
571
572 //=== game mode ===
573 XmlReader::ReadString(xml, "game_mode", m_game_mode);
574
575 //=== controls ===
576 if ((elem = XmlReader::GetMarker(xml, "controls"))) {
577 const xmlNode *node = XmlReader::GetMarker(elem, "keyboard");
578 if (node) {
579 Keyboard::GetInstance()->SetConfig(node);
580 }
581 }
582 }
583
Save(bool save_current_teams)584 bool Config::Save(bool save_current_teams)
585 {
586 std::string rep = personal_config_dir;
587
588 // Create the directory if it doesn't exist
589 if (!MkdirPersonalConfigDir())
590 {
591 std::cerr << "o "
592 << Format(_("Error while creating directory \"%s\": unable to store configuration file."),
593 rep.c_str())
594 << " " << strerror(errno)
595 << std::endl;
596 return false;
597 }
598
599 return SaveXml(save_current_teams);
600 }
601
SaveXml(bool save_current_teams)602 bool Config::SaveXml(bool save_current_teams)
603 {
604 XmlWriter doc;
605
606 doc.Create(m_filename, "config", "1.0", "utf-8");
607 xmlNode *root = doc.GetRoot();
608 doc.WriteElement(root, "version", Constants::WARMUX_VERSION);
609
610 //=== Map ===
611 //The map name is modified when the player validate its choice in the
612 //map selection box.
613 doc.WriteElement(root, "map", map_name);
614
615 //=== Language ==
616 doc.WriteElement(root, "default_language", default_language);
617
618 //=== Teams ===
619 xmlNode *team_elements = xmlAddChild(root,
620 xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"teams"));
621
622 if (TeamsList::IsLoaded()) {
623 if (save_current_teams) {
624 teams.clear();
625
626 TeamsList::iterator
627 it = GetTeamsList().playing_list.begin(),
628 end = GetTeamsList().playing_list.end();
629
630 for (int i=0; it!=end; ++it, i++) {
631 ConfigTeam config;
632 config.id = (**it).GetId();
633 config.player_name = (**it).GetPlayerName();
634 config.nb_characters = (**it).GetNbCharacters();
635 config.ai = (**it).GetAIName();
636
637 teams.push_back(config);
638 }
639 }
640
641 std::list<ConfigTeam>::iterator
642 it = teams.begin(),
643 end = teams.end();
644
645 for (int i=0; it!=end; ++it, i++) {
646 std::string name = "team_"+int2str(i);
647 xmlNode* a_team = xmlAddChild(team_elements,
648 xmlNewNode(NULL /* empty prefix */, (const xmlChar*)name.c_str()));
649 doc.WriteElement(a_team, "id", (*it).id);
650 doc.WriteElement(a_team, "player_name", (*it).player_name);
651 doc.WriteElement(a_team, "nb_characters", uint2str((*it).nb_characters));
652 doc.WriteElement(a_team, "ai", (*it).ai);
653 }
654 }
655
656 //=== Video ===
657 Video * video = AppWarmux::GetInstance()->video;
658 xmlNode* video_node = xmlAddChild(root, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"video"));
659 doc.WriteElement(video_node, "wind_particles_percentage", uint2str(wind_particles_percentage));
660 doc.WriteElement(video_node, "display_multi_layer_sky", bool2str(display_multi_layer_sky));
661 doc.WriteElement(video_node, "display_energy_character", bool2str(display_energy_character));
662 doc.WriteElement(video_node, "display_name_character", bool2str(display_name_character));
663 doc.WriteElement(video_node, "bling_bling_interface", bool2str(bling_bling_interface));
664 doc.WriteElement(video_node, "default_mouse_cursor", bool2str(default_mouse_cursor));
665 doc.WriteElement(video_node, "scroll_on_border", bool2str(scroll_on_border));
666 doc.WriteElement(video_node, "scroll_border_size", uint2str(scroll_border_size));
667 doc.WriteElement(video_node, "width", uint2str(video->window.GetWidth()));
668 doc.WriteElement(video_node, "height", uint2str(video->window.GetHeight()));
669 doc.WriteElement(video_node, "full_screen", bool2str(video->IsFullScreen()));
670 doc.WriteElement(video_node, "quality", uint2str(quality));
671 doc.WriteElement(video_node, "max_fps", uint2str(video->GetMaxFps()));
672
673 //=== Sound ===
674 xmlNode *sound_node = xmlAddChild(root, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"sound"));
675 doc.WriteElement(sound_node, "music", bool2str(sound_music));
676 doc.WriteElement(sound_node, "effects", bool2str(sound_effects));
677 #ifndef HAVE_HANDHELD
678 doc.WriteElement(sound_node, "frequency", uint2str(sound_frequency));
679 #endif
680 doc.WriteElement(sound_node, "volume_music", uint2str(volume_music));
681 doc.WriteElement(sound_node, "volume_effects", uint2str(volume_effects));
682
683 //=== Network ===
684 xmlNode *net_node = xmlAddChild(root, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"network"));
685
686 // Network as client parameters
687 xmlNode *net_as_client_node = xmlAddChild(net_node, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"as_client"));
688 doc.WriteElement(net_as_client_node, "host", m_network_client_host);
689 doc.WriteElement(net_as_client_node, "port", m_network_client_port);
690
691 // Network as server parameters
692 xmlNode *net_as_server_node = xmlAddChild(net_node, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"as_server"));
693 doc.WriteElement(net_as_server_node, "game_name", m_network_server_game_name);
694 doc.WriteElement(net_as_server_node, "port", m_network_server_port);
695 doc.WriteElement(net_as_server_node, "public", bool2str(m_network_server_public));
696
697 // personal teams used durint last network game
698 xmlNode *net_teams = xmlAddChild(net_node, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"local_teams"));
699 std::list<ConfigTeam>::iterator
700 it = network_local_teams.begin(),
701 end = network_local_teams.end();
702
703 for (int i=0; it != end; ++it, i++) {
704 std::string name = "team_"+int2str(i);
705 xmlNode* a_team = xmlAddChild(net_teams,
706 xmlNewNode(NULL /* empty prefix */, (const xmlChar*)name.c_str()));
707 doc.WriteElement(a_team, "id", (*it).id);
708 doc.WriteElement(a_team, "player_name", (*it).player_name);
709 doc.WriteElement(a_team, "nb_characters", uint2str((*it).nb_characters));
710 doc.WriteElement(a_team, "ai", (*it).ai);
711 }
712
713 //=== Misc ===
714 xmlNode *misc_node = xmlAddChild(root, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"misc"));
715 doc.WriteElement(misc_node, "check_updates", bool2str(check_updates));
716 doc.WriteElement(misc_node, "left-handed_mouse", bool2str(lefthanded_mouse));
717
718 //=== game mode ===
719 doc.WriteElement(root, "game_mode", m_game_mode);
720
721 //=== controls ===
722 xmlNode *controls_node = xmlAddChild(root, xmlNewNode(NULL /* empty prefix */, (const xmlChar*)"controls"));
723 Keyboard::GetInstance()->SaveConfig(controls_node);
724
725 return doc.Save();
726 }
727
728 /*
729 * Return the value of the environment variable 'name' or
730 * 'default' if not set
731 */
GetEnv(const std::string & name,const std::string & default_value) const732 std::string Config::GetEnv(const std::string & name, const std::string &default_value) const
733 {
734 const char *env = std::getenv(name.c_str());
735 return (env) ? env : default_value;
736 }
737
SetVolumeMusic(uint vol)738 void Config::SetVolumeMusic(uint vol)
739 {
740 volume_music = vol;
741 JukeBox::SetMusicVolume(vol);
742 }
743
GetMaxVolume()744 uint Config::GetMaxVolume()
745 {
746 return JukeBox::GetMaxVolume();
747 }
748
GetTtfFilename() const749 const std::string& Config::GetTtfFilename() const
750 {
751 #ifdef ENABLE_NLS
752 if (fonts.find(default_language) == fonts.end())
753 return ttf_filename;
754 else {
755 std::map<std::string, std::string>::const_iterator it = fonts.find(default_language);
756 ASSERT(it != fonts.end());
757 return it->second;
758 }
759 #else
760 return ttf_filename;
761 #endif
762 }
763
SetNetworkLocalTeams()764 void Config::SetNetworkLocalTeams()
765 {
766 // personal teams used durint last network game
767 network_local_teams.clear();
768
769 TeamsList::iterator
770 it = GetTeamsList().playing_list.begin(),
771 end = GetTeamsList().playing_list.end();
772
773 for (int i=0; it != end; ++it, i++) {
774 if ((**it).IsLocal()) {
775 ConfigTeam config;
776 config.id = (**it).GetId();
777 config.player_name = (**it).GetPlayerName();
778 config.nb_characters = (**it).GetNbCharacters();
779 config.ai = (**it).GetAIName();
780 network_local_teams.push_back(config);
781 }
782 }
783 }
784