# settings.cpp

Go to the documentation of this file.

    00001 /* $Id: settings.cpp 18864 2010-01-18 21:44:31Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00025 #include "stdafx.h"
    00026 #include "currency.h"
    00027 #include "screenshot.h"
    00028 #include "variables.h"
    00029 #include "network/network.h"
    00030 #include "network/network_func.h"
    00031 #include "settings_internal.h"
    00032 #include "command_func.h"
    00033 #include "console_func.h"
    00034 #include "pathfinder/pathfinder_type.h"
    00035 #include "genworld.h"
    00036 #include "train.h"
    00037 #include "news_func.h"
    00038 #include "window_func.h"
    00039 #include "strings_func.h"
    00040 #include "vehicle_func.h"
    00041 #include "sound_func.h"
    00042 #include "company_func.h"
    00043 #include "rev.h"
    00044 #ifdef WITH_FREETYPE
    00045 #include "fontcache.h"
    00046 #endif
    00047 #include "textbuf_gui.h"
    00048 #include "rail_gui.h"
    00049 #include "elrail_func.h"
    00050 #include "gui.h"
    00051 #include "town.h"
    00052 #include "video/video_driver.hpp"
    00053 #include "sound/sound_driver.hpp"
    00054 #include "music/music_driver.hpp"
    00055 #include "blitter/factory.hpp"
    00056 #include "base_media_base.h"
    00057 #include "gamelog.h"
    00058 #include "settings_func.h"
    00059 #include "ini_type.h"
    00060 #include "ai/ai_config.hpp"
    00061 #include "newgrf.h"
    00062 #include "ship.h"
    00063 #include "company_base.h"
    00064 #include "engine_base.h"
    00065
    00066 #include "void_map.h"
    00067 #include "station_base.h"
    00068
    00069 #include "table/strings.h"
    00070 #include "table/settings.h"
    00071
    00072 ClientSettings _settings_client;
    00073 GameSettings _settings_game;
    00074 GameSettings _settings_newgame;
    00075 VehicleDefaultSettings _old_vds;
    00076
    00077 typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object);
    00078 typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list);
    00079
    00080 static bool IsSignedVarMemType(VarType vt);
    00081
    00085 static const char * const _list_group_names[] = {
    00086   "bans",
    00087   "newgrf",
    00088   "servers",
    00089   "server_bind_addresses",
    00090   NULL
    00091 };
    00092
    00098 static int lookup_oneofmany(const char *many, const char *one, size_t onelen = 0)
    00099 {
    00100   const char *s;
    00101   int idx;
    00102
    00103   if (onelen == 0) onelen = strlen(one);
    00104
    00105   /* check if it's an integer */
    00106   if (*one >= '0' && *one <= '9')
    00107     return strtoul(one, NULL, 0);
    00108
    00109   idx = 0;
    00110   for (;;) {
    00111     /* find end of item */
    00112     s = many;
    00113     while (*s != '|' && *s != 0) s++;
    00114     if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx;
    00115     if (*s == 0) return -1;
    00116     many = s + 1;
    00117     idx++;
    00118   }
    00119 }
    00120
    00126 static uint32 lookup_manyofmany(const char *many, const char *str)
    00127 {
    00128   const char *s;
    00129   int r;
    00130   uint32 res = 0;
    00131
    00132   for (;;) {
    00133     /* skip "whitespace" */
    00134     while (*str == ' ' || *str == '\t' || *str == '|') str++;
    00135     if (*str == 0) break;
    00136
    00137     s = str;
    00138     while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
    00139
    00140     r = lookup_oneofmany(many, str, s - str);
    00141     if (r == -1) return (uint32)-1;
    00142
    00143     SetBit(res, r); // value found, set it
    00144     if (*s == 0) break;
    00145     str = s + 1;
    00146   }
    00147   return res;
    00148 }
    00149
    00156 static int parse_intlist(const char *p, int *items, int maxitems)
    00157 {
    00158   int n = 0, v;
    00159   char *end;
    00160
    00161   for (;;) {
    00162     v = strtol(p, &end, 0);
    00163     if (p == end || n == maxitems) return -1;
    00164     p = end;
    00165     items[n++] = v;
    00166     if (*p == '\0') break;
    00167     if (*p != ',' && *p != ' ') return -1;
    00168     p++;
    00169   }
    00170
    00171   return n;
    00172 }
    00173
    00180 static bool load_intlist(const char *str, void *array, int nelems, VarType type)
    00181 {
    00182   int items[64];
    00183   int i, nitems;
    00184
    00185   if (str == NULL) {
    00186     memset(items, 0, sizeof(items));
    00187     nitems = nelems;
    00188   } else {
    00189     nitems = parse_intlist(str, items, lengthof(items));
    00190     if (nitems != nelems) return false;
    00191   }
    00192
    00193   switch (type) {
    00194   case SLE_VAR_BL:
    00195   case SLE_VAR_I8:
    00196   case SLE_VAR_U8:
    00197     for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i];
    00198     break;
    00199   case SLE_VAR_I16:
    00200   case SLE_VAR_U16:
    00201     for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i];
    00202     break;
    00203   case SLE_VAR_I32:
    00204   case SLE_VAR_U32:
    00205     for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i];
    00206     break;
    00207   default: NOT_REACHED();
    00208   }
    00209
    00210   return true;
    00211 }
    00212
    00220 static void make_intlist(char *buf, const char *last, const void *array, int nelems, VarType type)
    00221 {
    00222   int i, v = 0;
    00223   byte *p = (byte*)array;
    00224
    00225   for (i = 0; i != nelems; i++) {
    00226     switch (type) {
    00227     case SLE_VAR_BL:
    00228     case SLE_VAR_I8:  v = *(int8*)p;   p += 1; break;
    00229     case SLE_VAR_U8:  v = *(byte*)p;   p += 1; break;
    00230     case SLE_VAR_I16: v = *(int16*)p;  p += 2; break;
    00231     case SLE_VAR_U16: v = *(uint16*)p; p += 2; break;
    00232     case SLE_VAR_I32: v = *(int32*)p;  p += 4; break;
    00233     case SLE_VAR_U32: v = *(uint32*)p; p += 4; break;
    00234     default: NOT_REACHED();
    00235     }
    00236     buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v);
    00237   }
    00238 }
    00239
    00245 static void make_oneofmany(char *buf, const char *last, const char *many, int id)
    00246 {
    00247   int orig_id = id;
    00248
    00249   /* Look for the id'th element */
    00250   while (--id >= 0) {
    00251     for (; *many != '|'; many++) {
    00252       if (*many == '\0') { // not found
    00253         seprintf(buf, last, "%d", orig_id);
    00254         return;
    00255       }
    00256     }
    00257     many++; // pass the |-character
    00258   }
    00259
    00260   /* copy string until next item (|) or the end of the list if this is the last one */
    00261   while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++;
    00262   *buf = '\0';
    00263 }
    00264
    00271 static void make_manyofmany(char *buf, const char *last, const char *many, uint32 x)
    00272 {
    00273   const char *start;
    00274   int i = 0;
    00275   bool init = true;
    00276
    00277   for (; x != 0; x >>= 1, i++) {
    00278     start = many;
    00279     while (*many != 0 && *many != '|') many++; // advance to the next element
    00280
    00281     if (HasBit(x, 0)) { // item found, copy it
    00282       if (!init) buf += seprintf(buf, last, "|");
    00283       init = false;
    00284       if (start == many) {
    00285         buf += seprintf(buf, last, "%d", i);
    00286       } else {
    00287         memcpy(buf, start, many - start);
    00288         buf += many - start;
    00289       }
    00290     }
    00291
    00292     if (*many == '|') many++;
    00293   }
    00294
    00295   *buf = '\0';
    00296 }
    00297
    00302 static const void *string_to_val(const SettingDescBase *desc, const char *orig_str)
    00303 {
    00304   const char *str = orig_str == NULL ? "" : orig_str;
    00305   switch (desc->cmd) {
    00306   case SDT_NUMX: {
    00307     char *end;
    00308     unsigned long val = strtoul(str, &end, 0);
    00309     if (*end != '\0') ShowInfoF("ini: trailing characters at end of setting '%s'", desc->name);
    00310     return (void*)val;
    00311   }
    00312   case SDT_ONEOFMANY: {
    00313     long r = lookup_oneofmany(desc->many, str);
    00314     /* if the first attempt of conversion from string to the appropriate value fails,
    00315      * look if we have defined a converter from old value to new value. */
    00316     if (r == -1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str);
    00317     if (r != -1) return (void*)r; // and here goes converted value
    00318     ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name); // sorry, we failed
    00319     return 0;
    00320   }
    00321   case SDT_MANYOFMANY: {
    00322     unsigned long r = lookup_manyofmany(desc->many, str);
    00323     if (r != (unsigned long)-1) return (void*)r;
    00324     ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
    00325     return 0;
    00326   }
    00327   case SDT_BOOLX:
    00328     if (strcmp(str, "true")  == 0 || strcmp(str, "on")  == 0 || strcmp(str, "1") == 0)
    00329       return (void*)true;
    00330     if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0)
    00331       return (void*)false;
    00332     ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
    00333     break;
    00334
    00335   case SDT_STRING: return orig_str;
    00336   case SDT_INTLIST: return str;
    00337   default: break;
    00338   }
    00339
    00340   return NULL;
    00341 }
    00342
    00350 static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val)
    00351 {
    00352   const SettingDescBase *sdb = &sd->desc;
    00353
    00354   if (sdb->cmd != SDT_BOOLX &&
    00355       sdb->cmd != SDT_NUMX &&
    00356       sdb->cmd != SDT_ONEOFMANY &&
    00357       sdb->cmd != SDT_MANYOFMANY) {
    00358     return;
    00359   }
    00360
    00361   /* We cannot know the maximum value of a bitset variable, so just have faith */
    00362   if (sdb->cmd != SDT_MANYOFMANY) {
    00363     /* We need to take special care of the uint32 type as we receive from the function
    00364      * a signed integer. While here also bail out on 64-bit settings as those are not
    00365      * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
    00366      * 32-bit variable
    00367      * TODO: Support 64-bit settings/variables */
    00368     switch (GetVarMemType(sd->save.conv)) {
    00369       case SLE_VAR_NULL: return;
    00370       case SLE_VAR_BL:
    00371       case SLE_VAR_I8:
    00372       case SLE_VAR_U8:
    00373       case SLE_VAR_I16:
    00374       case SLE_VAR_U16:
    00375       case SLE_VAR_I32: {
    00376         /* Override the minimum value. No value below sdb->min, except special value 0 */
    00377         if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max);
    00378       } break;
    00379       case SLE_VAR_U32: {
    00380         /* Override the minimum value. No value below sdb->min, except special value 0 */
    00381         uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min;
    00382         WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max));
    00383         return;
    00384       }
    00385       case SLE_VAR_I64:
    00386       case SLE_VAR_U64:
    00387       default: NOT_REACHED();
    00388     }
    00389   }
    00390
    00391   WriteValue(ptr, sd->save.conv, (int64)val);
    00392 }
    00393
    00400 static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
    00401 {
    00402   IniGroup *group;
    00403   IniGroup *group_def = ini->GetGroup(grpname);
    00404   IniItem *item;
    00405   const void *p;
    00406   void *ptr;
    00407   const char *s;
    00408
    00409   for (; sd->save.cmd != SL_END; sd++) {
    00410     const SettingDescBase *sdb = &sd->desc;
    00411     const SaveLoad        *sld = &sd->save;
    00412
    00413     if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
    00414
    00415     /* For settings.xx.yy load the settings from [xx] yy = ? */
    00416     s = strchr(sdb->name, '.');
    00417     if (s != NULL) {
    00418       group = ini->GetGroup(sdb->name, s - sdb->name);
    00419       s++;
    00420     } else {
    00421       s = sdb->name;
    00422       group = group_def;
    00423     }
    00424
    00425     item = group->GetItem(s, false);
    00426     if (item == NULL && group != group_def) {
    00427       /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous
    00428        * did not exist (e.g. loading old config files with a [settings] section */
    00429       item = group_def->GetItem(s, false);
    00430     }
    00431     if (item == NULL) {
    00432       /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
    00433        * did not exist (e.g. loading old config files with a [yapf] section */
    00434       const char *sc = strchr(s, '.');
    00435       if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false);
    00436     }
    00437
    00438     p = (item == NULL) ? sdb->def : string_to_val(sdb, item->value);
    00439     ptr = GetVariableAddress(object, sld);
    00440
    00441     switch (sdb->cmd) {
    00442     case SDT_BOOLX: // All four are various types of (integer) numbers
    00443     case SDT_NUMX:
    00444     case SDT_ONEOFMANY:
    00445     case SDT_MANYOFMANY:
    00446       Write_ValidateSetting(ptr, sd, (int32)(size_t)p); break;
    00447
    00448     case SDT_STRING:
    00449       switch (GetVarMemType(sld->conv)) {
    00450         case SLE_VAR_STRB:
    00451         case SLE_VAR_STRBQ:
    00452           if (p != NULL) ttd_strlcpy((char*)ptr, (const char*)p, sld->length);
    00453           break;
    00454         case SLE_VAR_STR:
    00455         case SLE_VAR_STRQ:
    00456           free(*(char**)ptr);
    00457           *(char**)ptr = p == NULL ? NULL : strdup((const char*)p);
    00458           break;
    00459         case SLE_VAR_CHAR: if (p != NULL) *(char*)ptr = *(char*)p; break;
    00460         default: NOT_REACHED();
    00461       }
    00462       break;
    00463
    00464     case SDT_INTLIST: {
    00465       if (!load_intlist((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) {
    00466         ShowInfoF("ini: error in array '%s'", sdb->name);
    00467       } else if (sd->desc.proc_cnvt != NULL) {
    00468         sd->desc.proc_cnvt((const char*)p);
    00469       }
    00470       break;
    00471     }
    00472     default: NOT_REACHED();
    00473     }
    00474   }
    00475 }
    00476
    00488 static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
    00489 {
    00490   IniGroup *group_def = NULL, *group;
    00491   IniItem *item;
    00492   char buf[512];
    00493   const char *s;
    00494   void *ptr;
    00495
    00496   for (; sd->save.cmd != SL_END; sd++) {
    00497     const SettingDescBase *sdb = &sd->desc;
    00498     const SaveLoad        *sld = &sd->save;
    00499
    00500     /* If the setting is not saved to the configuration
    00501      * file, just continue with the next setting */
    00502     if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
    00503     if (sld->conv & SLF_CONFIG_NO) continue;
    00504
    00505     /* XXX - wtf is this?? (group override?) */
    00506     s = strchr(sdb->name, '.');
    00507     if (s != NULL) {
    00508       group = ini->GetGroup(sdb->name, s - sdb->name);
    00509       s++;
    00510     } else {
    00511       if (group_def == NULL) group_def = ini->GetGroup(grpname);
    00512       s = sdb->name;
    00513       group = group_def;
    00514     }
    00515
    00516     item = group->GetItem(s, true);
    00517     ptr = GetVariableAddress(object, sld);
    00518
    00519     if (item->value != NULL) {
    00520       /* check if the value is the same as the old value */
    00521       const void *p = string_to_val(sdb, item->value);
    00522
    00523       /* The main type of a variable/setting is in bytes 8-15
    00524        * The subtype (what kind of numbers do we have there) is in 0-7 */
    00525       switch (sdb->cmd) {
    00526       case SDT_BOOLX:
    00527       case SDT_NUMX:
    00528       case SDT_ONEOFMANY:
    00529       case SDT_MANYOFMANY:
    00530         switch (GetVarMemType(sld->conv)) {
    00531         case SLE_VAR_BL:
    00532           if (*(bool*)ptr == (p != NULL)) continue;
    00533           break;
    00534         case SLE_VAR_I8:
    00535         case SLE_VAR_U8:
    00536           if (*(byte*)ptr == (byte)(unsigned long)p) continue;
    00537           break;
    00538         case SLE_VAR_I16:
    00539         case SLE_VAR_U16:
    00540           if (*(uint16*)ptr == (uint16)(unsigned long)p) continue;
    00541           break;
    00542         case SLE_VAR_I32:
    00543         case SLE_VAR_U32:
    00544           if (*(uint32*)ptr == (uint32)(unsigned long)p) continue;
    00545           break;
    00546         default: NOT_REACHED();
    00547         }
    00548         break;
    00549       default: break; // Assume the other types are always changed
    00550       }
    00551     }
    00552
    00553     /* Value has changed, get the new value and put it into a buffer */
    00554     switch (sdb->cmd) {
    00555     case SDT_BOOLX:
    00556     case SDT_NUMX:
    00557     case SDT_ONEOFMANY:
    00558     case SDT_MANYOFMANY: {
    00559       uint32 i = (uint32)ReadValue(ptr, sld->conv);
    00560
    00561       switch (sdb->cmd) {
    00562       case SDT_BOOLX:      strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break;
    00563       case SDT_NUMX:       seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break;
    00564       case SDT_ONEOFMANY:  make_oneofmany(buf, lastof(buf), sdb->many, i); break;
    00565       case SDT_MANYOFMANY: make_manyofmany(buf, lastof(buf), sdb->many, i); break;
    00566       default: NOT_REACHED();
    00567       }
    00568     } break;
    00569
    00570     case SDT_STRING:
    00571       switch (GetVarMemType(sld->conv)) {
    00572       case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break;
    00573       case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break;
    00574       case SLE_VAR_STR:  strecpy(buf, *(char**)ptr, lastof(buf)); break;
    00575       case SLE_VAR_STRQ:
    00576         if (*(char**)ptr == NULL) {
    00577           buf[0] = '\0';
    00578         } else {
    00579           seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr);
    00580         }
    00581         break;
    00582       case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break;
    00583       default: NOT_REACHED();
    00584       }
    00585       break;
    00586
    00587     case SDT_INTLIST:
    00588       make_intlist(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv));
    00589       break;
    00590     default: NOT_REACHED();
    00591     }
    00592
    00593     /* The value is different, that means we have to write it to the ini */
    00594     free(item->value);
    00595     item->value = strdup(buf);
    00596   }
    00597 }
    00598
    00607 static void ini_load_setting_list(IniFile *ini, const char *grpname, StringList *list)
    00608 {
    00609   IniGroup *group = ini->GetGroup(grpname);
    00610
    00611   if (group == NULL || list == NULL) return;
    00612
    00613   list->Clear();
    00614
    00615   for (const IniItem *item = group->item; item != NULL; item = item->next) {
    00616     if (item->name != NULL) *list->Append() = strdup(item->name);
    00617   }
    00618 }
    00619
    00628 static void ini_save_setting_list(IniFile *ini, const char *grpname, StringList *list)
    00629 {
    00630   IniGroup *group = ini->GetGroup(grpname);
    00631
    00632   if (group == NULL || list == NULL) return;
    00633   group->Clear();
    00634
    00635   for (char **iter = list->Begin(); iter != list->End(); iter++) {
    00636     group->GetItem(*iter, true)->SetValue("");
    00637   }
    00638 }
    00639
    00640 /* Begin - Callback Functions for the various settings
    00641  * virtual PositionMainToolbar function, calls the right one.*/
    00642 static bool v_PositionMainToolbar(int32 p1)
    00643 {
    00644   if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
    00645   return true;
    00646 }
    00647
    00648 static bool PopulationInLabelActive(int32 p1)
    00649 {
    00650   UpdateAllTownVirtCoords();
    00651   return true;
    00652 }
    00653
    00654 static bool RedrawScreen(int32 p1)
    00655 {
    00656   MarkWholeScreenDirty();
    00657   return true;
    00658 }
    00659
    00660 static bool InvalidateDetailsWindow(int32 p1)
    00661 {
    00662   SetWindowClassesDirty(WC_VEHICLE_DETAILS);
    00663   return true;
    00664 }
    00665
    00666 static bool InvalidateStationBuildWindow(int32 p1)
    00667 {
    00668   SetWindowDirty(WC_BUILD_STATION, 0);
    00669   return true;
    00670 }
    00671
    00672 static bool InvalidateBuildIndustryWindow(int32 p1)
    00673 {
    00674   InvalidateWindowData(WC_BUILD_INDUSTRY, 0);
    00675   return true;
    00676 }
    00677
    00678 static bool CloseSignalGUI(int32 p1)
    00679 {
    00680   if (p1 == 0) {
    00681     DeleteWindowByClass(WC_BUILD_SIGNAL);
    00682   }
    00683   return true;
    00684 }
    00685
    00686 static bool InvalidateTownViewWindow(int32 p1)
    00687 {
    00688   InvalidateWindowClassesData(WC_TOWN_VIEW, p1);
    00689   return true;
    00690 }
    00691
    00692 static bool DeleteSelectStationWindow(int32 p1)
    00693 {
    00694   DeleteWindowById(WC_SELECT_STATION, 0);
    00695   return true;
    00696 }
    00697
    00698 static bool UpdateConsists(int32 p1)
    00699 {
    00700   Train *t;
    00701   FOR_ALL_TRAINS(t) {
    00702     /* Update the consist of all trains so the maximum speed is set correctly. */
    00703     if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(true);
    00704   }
    00705   return true;
    00706 }
    00707
    00708 /* Check service intervals of vehicles, p1 is value of % or day based servicing */
    00709 static bool CheckInterval(int32 p1)
    00710 {
    00711   VehicleDefaultSettings *vds;
    00712   if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) {
    00713     vds = &_settings_client.company.vehicle;
    00714   } else {
    00715     vds = &Company::Get(_current_company)->settings.vehicle;
    00716   }
    00717
    00718   if (p1) {
    00719     vds->servint_trains   = 50;
    00720     vds->servint_roadveh  = 50;
    00721     vds->servint_aircraft = 50;
    00722     vds->servint_ships    = 50;
    00723   } else {
    00724     vds->servint_trains   = 150;
    00725     vds->servint_roadveh  = 150;
    00726     vds->servint_aircraft = 360;
    00727     vds->servint_ships    = 100;
    00728   }
    00729
    00730   InvalidateDetailsWindow(0);
    00731
    00732   return true;
    00733 }
    00734
    00735 static bool TrainAccelerationModelChanged(int32 p1)
    00736 {
    00737   Train *t;
    00738   FOR_ALL_TRAINS(t) {
    00739     if (t->IsFrontEngine()) {
    00740       t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit();
    00741       t->UpdateAcceleration();
    00742     }
    00743   }
    00744
    00745   return true;
    00746 }
    00747
    00753 static bool TrainSlopeSteepnessChanged(int32 p1)
    00754 {
    00755   Train *t;
    00756   FOR_ALL_TRAINS(t) {
    00757     if (t->IsFrontEngine()) t->CargoChanged();
    00758   }
    00759
    00760   return true;
    00761 }
    00762
    00763 static bool DragSignalsDensityChanged(int32)
    00764 {
    00765   InvalidateWindowData(WC_BUILD_SIGNAL, 0);
    00766
    00767   return true;
    00768 }
    00769
    00770 static bool TownFoundingChanged(int32 p1)
    00771 {
    00772   if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) {
    00773     DeleteWindowById(WC_FOUND_TOWN, 0);
    00774     return true;
    00775   }
    00776   InvalidateWindowData(WC_FOUND_TOWN, 0);
    00777   return true;
    00778 }
    00779
    00780 static bool InvalidateVehTimetableWindow(int32 p1)
    00781 {
    00782   InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, -2);
    00783   return true;
    00784 }
    00785
    00786 /*
    00787  * A: competitors
    00788  * B: competitor start time. Deprecated since savegame version 110.
    00789  * C: town count (3 = high, 0 = very low)
    00790  * D: industry count (4 = high, 0 = none)
    00791  * E: inital loan (in GBP)
    00792  * F: interest rate
    00793  * G: running costs (0 = low, 2 = high)
    00794  * H: construction speed of competitors (0 = very slow, 4 = very fast)
    00795  * I: competitor intelligence. Deprecated since savegame version 110.
    00796  * J: breakdowns (0 = off, 2 = normal)
    00797  * K: subsidy multiplier (0 = 1.5, 3 = 4.0)
    00798  * L: construction cost (0-2)
    00799  * M: terrain type (0 = very flat, 3 = mountainous)
    00800  * N: amount of water (0 = very low, 3 = high)
    00801  * O: economy (0 = steady, 1 = fluctuating)
    00802  * P: Train reversing (0 = end of line + stations, 1 = end of line)
    00803  * Q: disasters
    00804  * R: area restructuring (0 = permissive, 2 = hostile)
    00805  * S: the difficulty level
    00806  */
    00807 static const DifficultySettings _default_game_diff[3] = { /*
    00808    A, C, D,      E, F, G, H, J, K, L, M, N, O, P, Q, R, S*/
    00809   {2, 2, 4, 300000, 2, 0, 2, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0},
    00810   {4, 2, 3, 150000, 3, 1, 3, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1},
    00811   {7, 3, 3, 100000, 4, 1, 3, 2, 0, 2, 3, 2, 1, 1, 1, 2, 2},
    00812 };
    00813
    00814 void SetDifficultyLevel(int mode, DifficultySettings *gm_opt)
    00815 {
    00816   assert(mode <= 3);
    00817
    00818   if (mode != 3) {
    00819     *gm_opt = _default_game_diff[mode];
    00820   } else {
    00821     gm_opt->diff_level = 3;
    00822   }
    00823 }
    00824
    00829 static void CheckDifficultyLevels()
    00830 {
    00831   if (_settings_newgame.difficulty.diff_level != 3) {
    00832     SetDifficultyLevel(_settings_newgame.difficulty.diff_level, &_settings_newgame.difficulty);
    00833   }
    00834 }
    00835
    00836 static bool DifficultyReset(int32 level)
    00837 {
    00838   SetDifficultyLevel(level, (_game_mode == GM_MENU) ? &_settings_newgame.difficulty : &_settings_game.difficulty);
    00839   return true;
    00840 }
    00841
    00842 static bool DifficultyChange(int32)
    00843 {
    00844   if (_game_mode == GM_MENU) {
    00845     if (_settings_newgame.difficulty.diff_level != 3) {
    00846       ShowErrorMessage(STR_WARNING_DIFFICULTY_TO_CUSTOM, INVALID_STRING_ID, 0, 0);
    00847       _settings_newgame.difficulty.diff_level = 3;
    00848     }
    00849     SetWindowClassesDirty(WC_SELECT_GAME);
    00850   } else {
    00851     _settings_game.difficulty.diff_level = 3;
    00852   }
    00853
    00854   /* If we are a network-client, update the difficult setting (if it is open).
    00855    * Use this instead of just dirtying the window because we need to load in
    00856    * the new difficulty settings */
    00857   if (_networking && FindWindowById(WC_GAME_OPTIONS, 0) != NULL) {
    00858     ShowGameDifficulty();
    00859   }
    00860
    00861   return true;
    00862 }
    00863
    00864 static bool DifficultyNoiseChange(int32 i)
    00865 {
    00866   if (_game_mode == GM_NORMAL) {
    00867     UpdateAirportsNoise();
    00868     if (_settings_game.economy.station_noise_level) {
    00869       InvalidateWindowClassesData(WC_TOWN_VIEW, 0);
    00870     }
    00871   }
    00872
    00873   return DifficultyChange(i);
    00874 }
    00875
    00881 static bool CheckRoadSide(int p1)
    00882 {
    00883   extern bool RoadVehiclesAreBuilt();
    00884   return _game_mode == GM_MENU || !RoadVehiclesAreBuilt();
    00885 }
    00886
    00893 static int32 ConvertLandscape(const char *value)
    00894 {
    00895   /* try with the old values */
    00896   return lookup_oneofmany("normal|hilly|desert|candy", value);
    00897 }
    00898
    00899 static bool CheckFreeformEdges(int32 p1)
    00900 {
    00901   if (_game_mode == GM_MENU) return true;
    00902   if (p1 != 0) {
    00903     Ship *s;
    00904     FOR_ALL_SHIPS(s) {
    00905       if (TileX(s->tile) == 0 || TileY(s->tile) == 0) {
    00906         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, 0, 0);
    00907         return false;
    00908       }
    00909     }
    00910     Station *st;
    00911     FOR_ALL_STATIONS(st) {
    00912       if (TileX(st->xy) == 0 || TileY(st->xy) == 0) {
    00913         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, 0, 0);
    00914         return false;
    00915       }
    00916     }
    00917     for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0));
    00918     for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i));
    00919   } else {
    00920     for (uint i = 0; i < MapMaxX(); i++) {
    00921       if (TileHeight(TileXY(i, 1)) != 0) {
    00922         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
    00923         return false;
    00924       }
    00925     }
    00926     for (uint i = 1; i < MapMaxX(); i++) {
    00927       if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) {
    00928         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
    00929         return false;
    00930       }
    00931     }
    00932     for (uint i = 0; i < MapMaxY(); i++) {
    00933       if (TileHeight(TileXY(1, i)) != 0) {
    00934         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
    00935         return false;
    00936       }
    00937     }
    00938     for (uint i = 1; i < MapMaxY(); i++) {
    00939       if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) {
    00940         ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
    00941         return false;
    00942       }
    00943     }
    00944     /* Make tiles at the border water again. */
    00945     for (uint i = 0; i < MapMaxX(); i++) {
    00946       SetTileHeight(TileXY(i, 0), 0);
    00947       SetTileType(TileXY(i, 0), MP_WATER);
    00948     }
    00949     for (uint i = 0; i < MapMaxY(); i++) {
    00950       SetTileHeight(TileXY(0, i), 0);
    00951       SetTileType(TileXY(0, i), MP_WATER);
    00952     }
    00953   }
    00954   MarkWholeScreenDirty();
    00955   return true;
    00956 }
    00957
    00962 static bool ChangeDynamicEngines(int32 p1)
    00963 {
    00964   if (_game_mode == GM_MENU) return true;
    00965
    00966   const Vehicle *v;
    00967   FOR_ALL_VEHICLES(v) {
    00968     if (IsCompanyBuildableVehicleType(v)) {
    00969       ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, 0, 0);
    00970       return false;
    00971     }
    00972   }
    00973
    00974   /* Reset the engines, they will get new EngineIDs */
    00975   _engine_mngr.ResetToDefaultMapping();
    00976   ReloadNewGRFData();
    00977
    00978   return true;
    00979 }
    00980
    00981 static bool StationCatchmentChanged(int32 p1)
    00982 {
    00983   Station::RecomputeIndustriesNearForAll();
    00984   return true;
    00985 }
    00986
    00987 #ifdef ENABLE_NETWORK
    00988
    00989 static bool UpdateClientName(int32 p1)
    00990 {
    00991   NetworkUpdateClientName();
    00992   return true;
    00993 }
    00994
    00995 static bool UpdateServerPassword(int32 p1)
    00996 {
    00997   if (strcmp(_settings_client.network.server_password, "*") == 0) {
    00998     _settings_client.network.server_password[0] = '\0';
    00999   }
    01000
    01001   return true;
    01002 }
    01003
    01004 static bool UpdateRconPassword(int32 p1)
    01005 {
    01006   if (strcmp(_settings_client.network.rcon_password, "*") == 0) {
    01007     _settings_client.network.rcon_password[0] = '\0';
    01008   }
    01009
    01010   return true;
    01011 }
    01012
    01013 static bool UpdateClientConfigValues(int32 p1)
    01014 {
    01015   if (_network_server) NetworkServerSendConfigUpdate();
    01016
    01017   return true;
    01018 }
    01019
    01020 #endif /* ENABLE_NETWORK */
    01021
    01022
    01023 /* End - Callback Functions */
    01024
    01028 static void PrepareOldDiffCustom()
    01029 {
    01030   memset(_old_diff_custom, 0, sizeof(_old_diff_custom));
    01031 }
    01032
    01039 static void HandleOldDiffCustom(bool savegame)
    01040 {
    01041   uint options_to_load = GAME_DIFFICULTY_NUM - ((savegame && CheckSavegameVersion(4)) ? 1 : 0);
    01042
    01043   if (!savegame) {
    01044     /* If we did read to old_diff_custom, then at least one value must be non 0. */
    01045     bool old_diff_custom_used = false;
    01046     for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) {
    01047       old_diff_custom_used = (_old_diff_custom[i] != 0);
    01048     }
    01049
    01050     if (!old_diff_custom_used) return;
    01051   }
    01052
    01053   for (uint i = 0; i < options_to_load; i++) {
    01054     const SettingDesc *sd = &_settings[i];
    01055     /* Skip deprecated options */
    01056     if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
    01057     void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save);
    01058     Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i]));
    01059   }
    01060 }
    01061
    01066 static bool ConvertOldNewsSetting(const char *name, const char *value)
    01067 {
    01068   if (strcasecmp(name, "openclose") == 0) {
    01069     /* openclose has been split in "open" and "close".
    01070      * So the job is now to decrypt the value of the old news config
    01071      * and give it to the two newly introduced ones*/
    01072
    01073     NewsDisplay display = ND_OFF; // default
    01074     if (strcasecmp(value, "full") == 0) {
    01075       display = ND_FULL;
    01076     } else if (strcasecmp(value, "summarized") == 0) {
    01077       display = ND_SUMMARY;
    01078     }
    01079     /* tranfert of values */
    01080     _news_type_data[NT_INDUSTRY_OPEN].display = display;
    01081     _news_type_data[NT_INDUSTRY_CLOSE].display = display;
    01082     return true;
    01083   }
    01084   return false;
    01085 }
    01086
    01087 static void NewsDisplayLoadConfig(IniFile *ini, const char *grpname)
    01088 {
    01089   IniGroup *group = ini->GetGroup(grpname);
    01090   IniItem *item;
    01091
    01092   /* If no group exists, return */
    01093   if (group == NULL) return;
    01094
    01095   for (item = group->item; item != NULL; item = item->next) {
    01096     int news_item = -1;
    01097     for (int i = 0; i < NT_END; i++) {
    01098       if (strcasecmp(item->name, _news_type_data[i].name) == 0) {
    01099         news_item = i;
    01100         break;
    01101       }
    01102     }
    01103
    01104     /* the config been read is not within current aceptable config */
    01105     if (news_item == -1) {
    01106       /* if the conversion function cannot process it, advice by a debug warning*/
    01107       if (!ConvertOldNewsSetting(item->name, item->value)) {
    01108         DEBUG(misc, 0, "Invalid display option: %s", item->name);
    01109       }
    01110       /* in all cases, there is nothing left to do */
    01111       continue;
    01112     }
    01113
    01114     if (strcasecmp(item->value, "full") == 0) {
    01115       _news_type_data[news_item].display = ND_FULL;
    01116     } else if (strcasecmp(item->value, "off") == 0) {
    01117       _news_type_data[news_item].display = ND_OFF;
    01118     } else if (strcasecmp(item->value, "summarized") == 0) {
    01119       _news_type_data[news_item].display = ND_SUMMARY;
    01120     } else {
    01121       DEBUG(misc, 0, "Invalid display value: %s", item->value);
    01122       continue;
    01123     }
    01124   }
    01125 }
    01126
    01127 static void AILoadConfig(IniFile *ini, const char *grpname)
    01128 {
    01129   IniGroup *group = ini->GetGroup(grpname);
    01130   IniItem *item;
    01131
    01132   /* Clean any configured AI */
    01133   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
    01134     AIConfig::GetConfig(c, true)->ChangeAI(NULL);
    01135   }
    01136
    01137   /* If no group exists, return */
    01138   if (group == NULL) return;
    01139
    01140   CompanyID c = COMPANY_FIRST;
    01141   for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) {
    01142     AIConfig *config = AIConfig::GetConfig(c, true);
    01143
    01144     config->ChangeAI(item->name);
    01145     if (!config->HasAI()) {
    01146       if (strcmp(item->name, "none") != 0) {
    01147         DEBUG(ai, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name);
    01148         continue;
    01149       }
    01150     }
    01151     if (item->value != NULL) config->StringToSettings(item->value);
    01152   }
    01153 }
    01154
    01155 /* Load a GRF configuration from the given group name */
    01156 static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static)
    01157 {
    01158   IniGroup *group = ini->GetGroup(grpname);
    01159   IniItem *item;
    01160   GRFConfig *first = NULL;
    01161   GRFConfig **curr = &first;
    01162
    01163   if (group == NULL) return NULL;
    01164
    01165   for (item = group->item; item != NULL; item = item->next) {
    01166     GRFConfig *c = CallocT<GRFConfig>(1);
    01167     c->filename = strdup(item->name);
    01168
    01169     /* Parse parameters */
    01170     if (!StrEmpty(item->value)) {
    01171       c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
    01172       if (c->num_params == (byte)-1) {
    01173         ShowInfoF("ini: error in array '%s'", item->name);
    01174         c->num_params = 0;
    01175       }
    01176     }
    01177
    01178     /* Check if item is valid */
    01179     if (!FillGRFDetails(c, is_static)) {
    01180       const char *msg;
    01181
    01182       if (c->status == GCS_NOT_FOUND) {
    01183         msg = "not found";
    01184       } else if (HasBit(c->flags, GCF_UNSAFE)) {
    01185         msg = "unsafe for static use";
    01186       } else if (HasBit(c->flags, GCF_SYSTEM)) {
    01187         msg = "system NewGRF";
    01188       } else {
    01189         msg = "unknown";
    01190       }
    01191
    01192       ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg);
    01193       ClearGRFConfig(&c);
    01194       continue;
    01195     }
    01196
    01197     /* Check for duplicate GRFID (will also check for duplicate filenames) */
    01198     bool duplicate = false;
    01199     for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) {
    01200       if (gc->grfid == c->grfid) {
    01201         ShowInfoF("ini: ignoring  NewGRF '%s': duplicate GRF ID with '%s'", item->name, gc->filename);
    01202         duplicate = true;
    01203         break;
    01204       }
    01205     }
    01206     if (duplicate) {
    01207       ClearGRFConfig(&c);
    01208       continue;
    01209     }
    01210
    01211     /* Mark file as static to avoid saving in savegame. */
    01212     if (is_static) SetBit(c->flags, GCF_STATIC);
    01213
    01214     /* Add item to list */
    01215     *curr = c;
    01216     curr = &c->next;
    01217   }
    01218
    01219   return first;
    01220 }
    01221
    01222 static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname)
    01223 {
    01224   IniGroup *group = ini->GetGroup(grpname);
    01225
    01226   for (int i = 0; i < NT_END; i++) {
    01227     const char *value;
    01228     int v = _news_type_data[i].display;
    01229
    01230     value = (v == ND_OFF ? "off" : (v == ND_SUMMARY ? "summarized" : "full"));
    01231
    01232     group->GetItem(_news_type_data[i].name, true)->SetValue(value);
    01233   }
    01234 }
    01235
    01236 static void AISaveConfig(IniFile *ini, const char *grpname)
    01237 {
    01238   IniGroup *group = ini->GetGroup(grpname);
    01239
    01240   if (group == NULL) return;
    01241   group->Clear();
    01242
    01243   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
    01244     AIConfig *config = AIConfig::GetConfig(c, true);
    01245     const char *name;
    01246     char value[1024];
    01247     config->SettingsToString(value, lengthof(value));
    01248
    01249     if (config->HasAI()) {
    01250       name = config->GetName();
    01251     } else {
    01252       name = "none";
    01253     }
    01254
    01255     IniItem *item = new IniItem(group, name, strlen(name));
    01256     item->SetValue(value);
    01257   }
    01258 }
    01259
    01264 static void SaveVersionInConfig(IniFile *ini)
    01265 {
    01266   IniGroup *group = ini->GetGroup("version");
    01267
    01268   char version[9];
    01269   snprintf(version, lengthof(version), "%08X", _openttd_newgrf_version);
    01270
    01271   const char * const versions[][2] = {
    01272     { "version_string", _openttd_revision },
    01273     { "version_number", version }
    01274   };
    01275
    01276   for (uint i = 0; i < lengthof(versions); i++) {
    01277     group->GetItem(versions[i][0], true)->SetValue(versions[i][1]);
    01278   }
    01279 }
    01280
    01281 /* Save a GRF configuration to the given group name */
    01282 static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list)
    01283 {
    01284   ini->RemoveGroup(grpname);
    01285   IniGroup *group = ini->GetGroup(grpname);
    01286   const GRFConfig *c;
    01287
    01288   for (c = list; c != NULL; c = c->next) {
    01289     char params[512];
    01290     GRFBuildParamList(params, c, lastof(params));
    01291
    01292     group->GetItem(c->filename, true)->SetValue(params);
    01293   }
    01294 }
    01295
    01296 /* Common handler for saving/loading variables to the configuration file */
    01297 static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list)
    01298 {
    01299   proc(ini, (const SettingDesc*)_misc_settings,    "misc",  NULL);
    01300   proc(ini, (const SettingDesc*)_music_settings,   "music", &msf);
    01301 #if defined(WIN32) && !defined(DEDICATED)
    01302   proc(ini, (const SettingDesc*)_win32_settings,   "win32", NULL);
    01303 #endif /* WIN32 */
    01304
    01305   proc(ini, _settings,         "patches",  &_settings_newgame);
    01306   proc(ini, _currency_settings,"currency", &_custom_currency);
    01307   proc(ini, _company_settings, "company",  &_settings_client.company);
    01308
    01309 #ifdef ENABLE_NETWORK
    01310   proc_list(ini, "server_bind_addresses", &_network_bind_list);
    01311   proc_list(ini, "servers", &_network_host_list);
    01312   proc_list(ini, "bans",    &_network_ban_list);
    01313 #endif /* ENABLE_NETWORK */
    01314 }
    01315
    01316 static IniFile *IniLoadConfig()
    01317 {
    01318   IniFile *ini = new IniFile(_list_group_names);
    01319   ini->LoadFromDisk(_config_file);
    01320   return ini;
    01321 }
    01322
    01324 void LoadFromConfig()
    01325 {
    01326   IniFile *ini = IniLoadConfig();
    01327   ResetCurrencies(false); // Initialize the array of curencies, without preserving the custom one
    01328
    01329   HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
    01330   _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
    01331   _grfconfig_static  = GRFLoadConfig(ini, "newgrf-static", true);
    01332   NewsDisplayLoadConfig(ini, "news_display");
    01333   AILoadConfig(ini, "ai_players");
    01334
    01335   PrepareOldDiffCustom();
    01336   ini_load_settings(ini, _gameopt_settings, "gameopt",  &_settings_newgame);
    01337   HandleOldDiffCustom(false);
    01338
    01339   CheckDifficultyLevels();
    01340   delete ini;
    01341 }
    01342
    01344 void SaveToConfig()
    01345 {
    01346   IniFile *ini = IniLoadConfig();
    01347
    01348   /* Remove some obsolete groups. These have all been loaded into other groups. */
    01349   ini->RemoveGroup("patches");
    01350   ini->RemoveGroup("yapf");
    01351   ini->RemoveGroup("gameopt");
    01352
    01353   HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
    01354   GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
    01355   GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
    01356   NewsDisplaySaveConfig(ini, "news_display");
    01357   AISaveConfig(ini, "ai_players");
    01358   SaveVersionInConfig(ini);
    01359   ini->SaveToDisk(_config_file);
    01360   delete ini;
    01361 }
    01362
    01363 void GetGRFPresetList(GRFPresetList *list)
    01364 {
    01365   list->Clear();
    01366
    01367   IniFile *ini = IniLoadConfig();
    01368   IniGroup *group;
    01369   for (group = ini->group; group != NULL; group = group->next) {
    01370     if (strncmp(group->name, "preset-", 7) == 0) {
    01371       *list->Append() = strdup(group->name + 7);
    01372     }
    01373   }
    01374
    01375   delete ini;
    01376 }
    01377
    01378 GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
    01379 {
    01380   char *section = (char*)alloca(strlen(config_name) + 8);
    01381   sprintf(section, "preset-%s", config_name);
    01382
    01383   IniFile *ini = IniLoadConfig();
    01384   GRFConfig *config = GRFLoadConfig(ini, section, false);
    01385   delete ini;
    01386
    01387   return config;
    01388 }
    01389
    01390 void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
    01391 {
    01392   char *section = (char*)alloca(strlen(config_name) + 8);
    01393   sprintf(section, "preset-%s", config_name);
    01394
    01395   IniFile *ini = IniLoadConfig();
    01396   GRFSaveConfig(ini, section, config);
    01397   ini->SaveToDisk(_config_file);
    01398   delete ini;
    01399 }
    01400
    01401 void DeleteGRFPresetFromConfig(const char *config_name)
    01402 {
    01403   char *section = (char*)alloca(strlen(config_name) + 8);
    01404   sprintf(section, "preset-%s", config_name);
    01405
    01406   IniFile *ini = IniLoadConfig();
    01407   ini->RemoveGroup(section);
    01408   ini->SaveToDisk(_config_file);
    01409   delete ini;
    01410 }
    01411
    01412 static const SettingDesc *GetSettingDescription(uint index)
    01413 {
    01414   if (index >= lengthof(_settings)) return NULL;
    01415   return &_settings[index];
    01416 }
    01417
    01428 CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01429 {
    01430   const SettingDesc *sd = GetSettingDescription(p1);
    01431
    01432   if (sd == NULL) return CMD_ERROR;
    01433   if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
    01434
    01435   if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return CMD_ERROR;
    01436   if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return CMD_ERROR;
    01437   if ((sd->desc.flags & SGF_NEWGAME_ONLY) &&
    01438       (_game_mode == GM_NORMAL ||
    01439       (_game_mode == GM_EDITOR && (sd->desc.flags & SGF_SCENEDIT_TOO) == 0))) {
    01440     return CMD_ERROR;
    01441   }
    01442
    01443   if (flags & DC_EXEC) {
    01444     GameSettings *s = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game;
    01445     void *var = GetVariableAddress(s, &sd->save);
    01446
    01447     int32 oldval = (int32)ReadValue(var, sd->save.conv);
    01448     int32 newval = (int32)p2;
    01449
    01450     Write_ValidateSetting(var, sd, newval);
    01451     newval = (int32)ReadValue(var, sd->save.conv);
    01452
    01453     if (oldval == newval) return CommandCost();
    01454
    01455     if (sd->desc.proc != NULL && !sd->desc.proc(newval)) {
    01456       WriteValue(var, sd->save.conv, (int64)oldval);
    01457       return CommandCost();
    01458     }
    01459
    01460     if (sd->desc.flags & SGF_NO_NETWORK) {
    01461       GamelogStartAction(GLAT_SETTING);
    01462       GamelogSetting(sd->desc.name, oldval, newval);
    01463       GamelogStopAction();
    01464     }
    01465
    01466     SetWindowDirty(WC_GAME_OPTIONS, 0);
    01467   }
    01468
    01469   return CommandCost();
    01470 }
    01471
    01481 CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01482 {
    01483   if (p1 >= lengthof(_company_settings)) return CMD_ERROR;
    01484   const SettingDesc *sd = &_company_settings[p1];
    01485
    01486   if (flags & DC_EXEC) {
    01487     void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save);
    01488
    01489     int32 oldval = (int32)ReadValue(var, sd->save.conv);
    01490     int32 newval = (int32)p2;
    01491
    01492     Write_ValidateSetting(var, sd, newval);
    01493     newval = (int32)ReadValue(var, sd->save.conv);
    01494
    01495     if (oldval == newval) return CommandCost();
    01496
    01497     if (sd->desc.proc != NULL && !sd->desc.proc(newval)) {
    01498       WriteValue(var, sd->save.conv, (int64)oldval);
    01499       return CommandCost();
    01500     }
    01501
    01502     SetWindowDirty(WC_GAME_OPTIONS, 0);
    01503   }
    01504
    01505   return CommandCost();
    01506 }
    01507
    01513 bool SetSettingValue(uint index, int32 value)
    01514 {
    01515   const SettingDesc *sd = &_settings[index];
    01516   /* If an item is company-based, we do not send it over the network
    01517    * (if any) to change. Also *hack*hack* we update the _newgame version
    01518    * of settings because changing a company-based setting in a game also
    01519    * changes its defaults. At least that is the convention we have chosen */
    01520   if (sd->save.conv & SLF_NETWORK_NO) {
    01521     void *var = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
    01522     Write_ValidateSetting(var, sd, value);
    01523
    01524     if (_game_mode != GM_MENU) {
    01525       void *var2 = GetVariableAddress(&_settings_newgame, &sd->save);
    01526       Write_ValidateSetting(var2, sd, value);
    01527     }
    01528     if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
    01529     SetWindowDirty(WC_GAME_OPTIONS, 0);
    01530     return true;
    01531   }
    01532
    01533   /* send non-company-based settings over the network */
    01534   if (!_networking || (_networking && _network_server)) {
    01535     return DoCommandP(0, index, value, CMD_CHANGE_SETTING);
    01536   }
    01537   return false;
    01538 }
    01539
    01545 void SetCompanySetting(uint index, int32 value)
    01546 {
    01547   const SettingDesc *sd = &_company_settings[index];
    01548   if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
    01549     DoCommandP(0, index, value, CMD_CHANGE_COMPANY_SETTING);
    01550   } else {
    01551     void *var = GetVariableAddress(&_settings_client.company, &sd->save);
    01552     Write_ValidateSetting(var, sd, value);
    01553     if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
    01554   }
    01555 }
    01556
    01560 void SetDefaultCompanySettings(CompanyID cid)
    01561 {
    01562   Company *c = Company::Get(cid);
    01563   const SettingDesc *sd;
    01564   for (sd = _company_settings; sd->save.cmd != SL_END; sd++) {
    01565     void *var = GetVariableAddress(&c->settings, &sd->save);
    01566     Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def);
    01567   }
    01568 }
    01569
    01570 #if defined(ENABLE_NETWORK)
    01571
    01574 void SyncCompanySettings()
    01575 {
    01576   const SettingDesc *sd;
    01577   uint i = 0;
    01578   for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) {
    01579     const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save);
    01580     const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save);
    01581     uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv);
    01582     uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv);
    01583     if (old_value != new_value) NetworkSend_Command(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company);
    01584   }
    01585 }
    01586 #endif /* ENABLE_NETWORK */
    01587
    01593 uint GetCompanySettingIndex(const char *name)
    01594 {
    01595   uint i;
    01596   const SettingDesc *sd = GetSettingFromName(name, &i);
    01597   assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0);
    01598   return i;
    01599 }
    01600
    01607 bool SetSettingValue(uint index, const char *value)
    01608 {
    01609   const SettingDesc *sd = &_settings[index];
    01610   assert(sd->save.conv & SLF_NETWORK_NO);
    01611
    01612   char *var = (char*)GetVariableAddress(NULL, &sd->save);
    01613   ttd_strlcpy(var, value, sd->save.length);
    01614   if (sd->desc.proc != NULL) sd->desc.proc(0);
    01615
    01616   return true;
    01617 }
    01618
    01626 const SettingDesc *GetSettingFromName(const char *name, uint *i)
    01627 {
    01628   const SettingDesc *sd;
    01629
    01630   /* First check all full names */
    01631   for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
    01632     if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
    01633     if (strcmp(sd->desc.name, name) == 0) return sd;
    01634   }
    01635
    01636   /* Then check the shortcut variant of the name. */
    01637   for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
    01638     if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
    01639     const char *short_name = strchr(sd->desc.name, '.');
    01640     if (short_name != NULL) {
    01641       short_name++;
    01642       if (strcmp(short_name, name) == 0) return sd;
    01643     }
    01644   }
    01645
    01646   if (strncmp(name, "company.", 8) == 0) name += 8;
    01647   /* And finally the company-based settings */
    01648   for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) {
    01649     if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
    01650     if (strcmp(sd->desc.name, name) == 0) return sd;
    01651   }
    01652
    01653   return NULL;
    01654 }
    01655
    01656 /* Those 2 functions need to be here, else we have to make some stuff non-static
    01657  * and besides, it is also better to keep stuff like this at the same place */
    01658 void IConsoleSetSetting(const char *name, const char *value)
    01659 {
    01660   uint index;
    01661   const SettingDesc *sd = GetSettingFromName(name, &index);
    01662
    01663   if (sd == NULL) {
    01664     IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name);
    01665     return;
    01666   }
    01667
    01668   bool success;
    01669   if (sd->desc.cmd == SDT_STRING) {
    01670     success = SetSettingValue(index, value);
    01671   } else {
    01672     uint32 val;
    01673     extern bool GetArgumentInteger(uint32 *value, const char *arg);
    01674     success = GetArgumentInteger(&val, value);
    01675     if (!success) {
    01676       IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value);
    01677       return;
    01678     }
    01679
    01680     success = SetSettingValue(index, val);
    01681   }
    01682
    01683   if (!success) {
    01684     if (_network_server) {
    01685       IConsoleError("This command/variable is not available during network games.");
    01686     } else {
    01687       IConsoleError("This command/variable is only available to a network server.");
    01688     }
    01689   }
    01690 }
    01691
    01692 void IConsoleSetSetting(const char *name, int value)
    01693 {
    01694   uint index;
    01695   const SettingDesc *sd = GetSettingFromName(name, &index);
    01696   assert(sd != NULL);
    01697   SetSettingValue(index, value);
    01698 }
    01699
    01704 void IConsoleGetSetting(const char *name)
    01705 {
    01706   char value[20];
    01707   uint index;
    01708   const SettingDesc *sd = GetSettingFromName(name, &index);
    01709   const void *ptr;
    01710
    01711   if (sd == NULL) {
    01712     IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name);
    01713     return;
    01714   }
    01715
    01716   ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
    01717
    01718   if (sd->desc.cmd == SDT_STRING) {
    01719     IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (const char *)ptr);
    01720   } else {
    01721     if (sd->desc.cmd == SDT_BOOLX) {
    01722       snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
    01723     } else {
    01724       snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
    01725     }
    01726
    01727     IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
    01728       name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
    01729   }
    01730 }
    01731
    01737 void IConsoleListSettings(const char *prefilter)
    01738 {
    01739   IConsolePrintF(CC_WARNING, "All settings with their current value:");
    01740
    01741   for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) {
    01742     if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
    01743     if (prefilter != NULL) {
    01744       if (strncmp(sd->desc.name, prefilter, min(strlen(sd->desc.name), strlen(prefilter))) != 0) continue;
    01745     }
    01746     char value[80];
    01747     const void *ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
    01748
    01749     if (sd->desc.cmd == SDT_BOOLX) {
    01750       snprintf(value, lengthof(value), (*(bool*)ptr == 1) ? "on" : "off");
    01751     } else if (sd->desc.cmd == SDT_STRING) {
    01752       snprintf(value, sizeof(value), "%s", (const char *)ptr);
    01753     } else {
    01754       snprintf(value, lengthof(value), "%d", (uint32)ReadValue(ptr, sd->save.conv));
    01755     }
    01756     IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value);
    01757   }
    01758
    01759   IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value");
    01760 }
    01761
    01766 static void LoadSettings(const SettingDesc *osd, void *object)
    01767 {
    01768   for (; osd->save.cmd != SL_END; osd++) {
    01769     const SaveLoad *sld = &osd->save;
    01770     void *ptr = GetVariableAddress(object, sld);
    01771
    01772     if (!SlObjectMember(ptr, sld)) continue;
    01773   }
    01774 }
    01775
    01780 static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
    01781 {
    01782   LoadSettings((const SettingDesc*)sdg, NULL);
    01783 }
    01784
    01789 static void SaveSettings(const SettingDesc *sd, void *object)
    01790 {
    01791   /* We need to write the CH_RIFF header, but unfortunately can't call
    01792    * SlCalcLength() because we have a different format. So do this manually */
    01793   const SettingDesc *i;
    01794   size_t length = 0;
    01795   for (i = sd; i->save.cmd != SL_END; i++) {
    01796     length += SlCalcObjMemberLength(object, &i->save);
    01797   }
    01798   SlSetLength(length);
    01799
    01800   for (i = sd; i->save.cmd != SL_END; i++) {
    01801     void *ptr = GetVariableAddress(object, &i->save);
    01802     SlObjectMember(ptr, &i->save);
    01803   }
    01804 }
    01805
    01809 static inline void SaveSettingsGlobList(const SettingDescGlobVarList *sdg)
    01810 {
    01811   SaveSettings((const SettingDesc*)sdg, NULL);
    01812 }
    01813
    01814 static void Load_OPTS()
    01815 {
    01816   /* Copy over default setting since some might not get loaded in
    01817    * a networking environment. This ensures for example that the local
    01818    * autosave-frequency stays when joining a network-server */
    01819   PrepareOldDiffCustom();
    01820   LoadSettings(_gameopt_settings, &_settings_game);
    01821   HandleOldDiffCustom(true);
    01822 }
    01823
    01824 static void Load_PATS()
    01825 {
    01826   /* Copy over default setting since some might not get loaded in
    01827    * a networking environment. This ensures for example that the local
    01828    * signal_side stays when joining a network-server */
    01829   LoadSettings(_settings, &_settings_game);
    01830 }
    01831
    01832 static void Save_PATS()
    01833 {
    01834   SaveSettings(_settings, &_settings_game);
    01835 }
    01836
    01837 void CheckConfig()
    01838 {
    01839   /*
    01840    * Increase old default values for pf_maxdepth and pf_maxlength
    01841    * to support big networks.
    01842    */
    01843   if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) {
    01844     _settings_newgame.pf.opf.pf_maxdepth = 48;
    01845     _settings_newgame.pf.opf.pf_maxlength = 4096;
    01846   }
    01847 }
    01848
    01849 extern const ChunkHandler _setting_chunk_handlers[] = {
    01850   { 'OPTS', NULL,      Load_OPTS, NULL, CH_RIFF},
    01851   { 'PATS', Save_PATS, Load_PATS, NULL, CH_RIFF | CH_LAST},
    01852 };
    01853
    01854 static bool IsSignedVarMemType(VarType vt)
    01855 {
    01856   switch (GetVarMemType(vt)) {
    01857     case SLE_VAR_I8:
    01858     case SLE_VAR_I16:
    01859     case SLE_VAR_I32:
    01860     case SLE_VAR_I64:
    01861       return true;
    01862   }
    01863   return false;
    01864 }