src/settings.cpp
branchNewGRF_ports
changeset 6719 4cc327ad39d5
parent 6706 af52927cfd72
child 6720 35756db7e577
equal deleted inserted replaced
6718:5a8b295aa345 6719:4cc327ad39d5
     1 /* $Id$ */
     1 /* $Id$ */
     2 
     2 
     3 /** @file
     3 /** @file settings.cpp
     4  * All actions handling saving and loading of the settings/configuration goes on in this file.
     4  * All actions handling saving and loading of the settings/configuration goes on in this file.
     5  * The file consists of four parts:
     5  * The file consists of four parts:
     6  * <ol>
     6  * <ol>
     7  * <li>Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which
     7  * <li>Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which
     8  *     handle various types, such as normal 'key = value' pairs, lists and value combinations of
     8  *     handle various types, such as normal 'key = value' pairs, lists and value combinations of
    93 	uint pos;
    93 	uint pos;
    94 	SettingsMemoryPool *p = *pool;
    94 	SettingsMemoryPool *p = *pool;
    95 
    95 
    96 	size = ALIGN(size, sizeof(void*));
    96 	size = ALIGN(size, sizeof(void*));
    97 
    97 
    98 	// first check if there's memory in the next pool
    98 	/* first check if there's memory in the next pool */
    99 	if (p->next && p->next->pos + size <= p->next->size) {
    99 	if (p->next && p->next->pos + size <= p->next->size) {
   100 		p = p->next;
   100 		p = p->next;
   101 	// then check if there's not memory in the cur pool
   101 	/* then check if there's not memory in the cur pool */
   102 	} else if (p->pos + size > p->size) {
   102 	} else if (p->pos + size > p->size) {
   103 		SettingsMemoryPool *n = pool_new(size);
   103 		SettingsMemoryPool *n = pool_new(size);
   104 		*pool = n;
   104 		*pool = n;
   105 		n->next = p;
   105 		n->next = p;
   106 		p = n;
   106 		p = n;
   128 		free(p);
   128 		free(p);
   129 		p = n;
   129 		p = n;
   130 	}
   130 	}
   131 }
   131 }
   132 
   132 
   133 // structs describing the ini format.
   133 /** structs describing the ini format. */
   134 struct IniItem {
   134 struct IniItem {
   135 	char *name;
   135 	char *name;
   136 	char *value;
   136 	char *value;
   137 	char *comment;
   137 	char *comment;
   138 	IniItem *next;
   138 	IniItem *next;
   139 };
   139 };
   140 
   140 
   141 struct IniGroup {
   141 struct IniGroup {
   142 	char *name; // name of group
   142 	char *name;        ///< name of group
   143 	char *comment; //comment for group
   143 	char *comment;     ///<comment for group
   144 	IniItem *item, **last_item;
   144 	IniItem *item, **last_item;
   145 	IniGroup *next;
   145 	IniGroup *next;
   146 	IniFile *ini;
   146 	IniFile *ini;
   147 	IniGroupType type; // type of group
   147 	IniGroupType type; ///< type of group
   148 };
   148 };
   149 
   149 
   150 struct IniFile {
   150 struct IniFile {
   151 	SettingsMemoryPool *pool;
   151 	SettingsMemoryPool *pool;
   152 	IniGroup *group, **last_group;
   152 	IniGroup *group, **last_group;
   153 	char *comment; // last comment in file
   153 	char *comment;     ///< last comment in file
   154 };
   154 };
   155 
   155 
   156 // allocate an inifile object
   156 /** allocate an inifile object */
   157 static IniFile *ini_alloc()
   157 static IniFile *ini_alloc()
   158 {
   158 {
   159 	IniFile *ini;
   159 	IniFile *ini;
   160 	SettingsMemoryPool *pool;
   160 	SettingsMemoryPool *pool;
   161 	pool_init(&pool);
   161 	pool_init(&pool);
   165 	ini->last_group = &ini->group;
   165 	ini->last_group = &ini->group;
   166 	ini->comment = NULL;
   166 	ini->comment = NULL;
   167 	return ini;
   167 	return ini;
   168 }
   168 }
   169 
   169 
   170 // allocate an ini group object
   170 /** allocate an ini group object */
   171 static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
   171 static IniGroup *ini_group_alloc(IniFile *ini, const char *grpt, int len)
   172 {
   172 {
   173 	IniGroup *grp = (IniGroup*)pool_alloc(&ini->pool, sizeof(IniGroup));
   173 	IniGroup *grp = (IniGroup*)pool_alloc(&ini->pool, sizeof(IniGroup));
   174 	grp->ini = ini;
   174 	grp->ini = ini;
   175 	grp->name = (char*)pool_strdup(&ini->pool, grpt, len);
   175 	grp->name = (char*)pool_strdup(&ini->pool, grpt, len);
   197 	*group->last_item = item;
   197 	*group->last_item = item;
   198 	group->last_item = &item->next;
   198 	group->last_item = &item->next;
   199 	return item;
   199 	return item;
   200 }
   200 }
   201 
   201 
   202 // load an ini file into the "abstract" format
   202 /** load an ini file into the "abstract" format */
   203 static IniFile *ini_load(const char *filename)
   203 static IniFile *ini_load(const char *filename)
   204 {
   204 {
   205 	char buffer[1024], c, *s, *t, *e;
   205 	char buffer[1024], c, *s, *t, *e;
   206 	FILE *in;
   206 	FILE *in;
   207 	IniFile *ini;
   207 	IniFile *ini;
   215 	ini = ini_alloc();
   215 	ini = ini_alloc();
   216 
   216 
   217 	in = fopen(filename, "r");
   217 	in = fopen(filename, "r");
   218 	if (in == NULL) return ini;
   218 	if (in == NULL) return ini;
   219 
   219 
   220 	// for each line in the file
   220 	/* for each line in the file */
   221 	while (fgets(buffer, sizeof(buffer), in)) {
   221 	while (fgets(buffer, sizeof(buffer), in)) {
   222 
   222 
   223 		// trim whitespace from the left side
   223 		/* trim whitespace from the left side */
   224 		for (s = buffer; *s == ' ' || *s == '\t'; s++);
   224 		for (s = buffer; *s == ' ' || *s == '\t'; s++);
   225 
   225 
   226 		// trim whitespace from right side.
   226 		/* trim whitespace from right side. */
   227 		e = s + strlen(s);
   227 		e = s + strlen(s);
   228 		while (e > s && ((c=e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
   228 		while (e > s && ((c=e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--;
   229 		*e = '\0';
   229 		*e = '\0';
   230 
   230 
   231 		// skip comments and empty lines
   231 		/* skip comments and empty lines */
   232 		if (*s == '#' || *s == ';' || *s == '\0') {
   232 		if (*s == '#' || *s == ';' || *s == '\0') {
   233 			uint ns = comment_size + (e - s + 1);
   233 			uint ns = comment_size + (e - s + 1);
   234 			uint a = comment_alloc;
   234 			uint a = comment_alloc;
   235 			uint pos;
   235 			uint pos;
   236 			// add to comment
   236 			/* add to comment */
   237 			if (ns > a) {
   237 			if (ns > a) {
   238 				a = max(a, 128U);
   238 				a = max(a, 128U);
   239 				do a*=2; while (a < ns);
   239 				do a*=2; while (a < ns);
   240 				comment = ReallocT(comment, comment_alloc = a);
   240 				comment = ReallocT(comment, comment_alloc = a);
   241 			}
   241 			}
   244 			comment[pos + e - s] = '\n'; // comment newline
   244 			comment[pos + e - s] = '\n'; // comment newline
   245 			memcpy(comment + pos, s, e - s); // copy comment contents
   245 			memcpy(comment + pos, s, e - s); // copy comment contents
   246 			continue;
   246 			continue;
   247 		}
   247 		}
   248 
   248 
   249 		// it's a group?
   249 		/* it's a group? */
   250 		if (s[0] == '[') {
   250 		if (s[0] == '[') {
   251 			if (e[-1] != ']') {
   251 			if (e[-1] != ']') {
   252 				ShowInfoF("ini: invalid group name '%s'", buffer);
   252 				ShowInfoF("ini: invalid group name '%s'", buffer);
   253 			} else {
   253 			} else {
   254 				e--;
   254 				e--;
   258 			if (comment_size) {
   258 			if (comment_size) {
   259 				group->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   259 				group->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   260 				comment_size = 0;
   260 				comment_size = 0;
   261 			}
   261 			}
   262 		} else if (group) {
   262 		} else if (group) {
   263 			// find end of keyname
   263 			/* find end of keyname */
   264 			for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
   264 			if (*s == '\"') {
   265 
   265 				s++;
   266 			// it's an item in an existing group
   266 				for (t = s; *t != '\0' && *t != '\"'; t++);
       
   267 				if (*t == '\"') *t = ' ';
       
   268 			} else {
       
   269 				for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++);
       
   270 			}
       
   271 
       
   272 			/* it's an item in an existing group */
   267 			item = ini_item_alloc(group, s, t-s);
   273 			item = ini_item_alloc(group, s, t-s);
   268 			if (comment_size) {
   274 			if (comment_size) {
   269 				item->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   275 				item->comment = (char*)pool_strdup(&ini->pool, comment, comment_size);
   270 				comment_size = 0;
   276 				comment_size = 0;
   271 			}
   277 			}
   272 
   278 
   273 			// find start of parameter
   279 			/* find start of parameter */
   274 			while (*t == '=' || *t == ' ' || *t == '\t') t++;
   280 			while (*t == '=' || *t == ' ' || *t == '\t') t++;
   275 
   281 
   276 
   282 
   277 			// remove starting quotation marks
   283 			/* remove starting quotation marks */
   278 			if (*t == '\"') t++;
   284 			if (*t == '\"') t++;
   279 			// remove ending quotation marks
   285 			/* remove ending quotation marks */
   280 			e = t + strlen(t);
   286 			e = t + strlen(t);
   281 			if (e > t && e[-1] == '\"') e--;
   287 			if (e > t && e[-1] == '\"') e--;
   282 			*e = '\0';
   288 			*e = '\0';
   283 
   289 
   284 			item->value = (char*)pool_strdup(&ini->pool, t, e - t);
   290 			item->value = (char*)pool_strdup(&ini->pool, t, e - t);
   285 		} else {
   291 		} else {
   286 			// it's an orphan item
   292 			/* it's an orphan item */
   287 			ShowInfoF("ini: '%s' outside of group", buffer);
   293 			ShowInfoF("ini: '%s' outside of group", buffer);
   288 		}
   294 		}
   289 	}
   295 	}
   290 
   296 
   291 	if (comment_size > 0) {
   297 	if (comment_size > 0) {
   297 	fclose(in);
   303 	fclose(in);
   298 
   304 
   299 	return ini;
   305 	return ini;
   300 }
   306 }
   301 
   307 
   302 // lookup a group or make a new one
   308 /** lookup a group or make a new one */
   303 static IniGroup *ini_getgroup(IniFile *ini, const char *name, int len)
   309 static IniGroup *ini_getgroup(IniFile *ini, const char *name, int len)
   304 {
   310 {
   305 	IniGroup *group;
   311 	IniGroup *group;
   306 
   312 
   307 	if (len == -1) len = strlen(name);
   313 	if (len == -1) len = strlen(name);
   308 
   314 
   309 	// does it exist already?
   315 	/* does it exist already? */
   310 	for (group = ini->group; group; group = group->next)
   316 	for (group = ini->group; group; group = group->next)
   311 		if (!memcmp(group->name, name, len) && group->name[len] == 0)
   317 		if (!memcmp(group->name, name, len) && group->name[len] == 0)
   312 			return group;
   318 			return group;
   313 
   319 
   314 	// otherwise make a new one
   320 	/* otherwise make a new one */
   315 	group = ini_group_alloc(ini, name, len);
   321 	group = ini_group_alloc(ini, name, len);
   316 	group->comment = (char*)pool_strdup(&ini->pool, "\n", 1);
   322 	group->comment = (char*)pool_strdup(&ini->pool, "\n", 1);
   317 	return group;
   323 	return group;
   318 }
   324 }
   319 
   325 
   320 // lookup an item or make a new one
   326 /** lookup an item or make a new one */
   321 static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
   327 static IniItem *ini_getitem(IniGroup *group, const char *name, bool create)
   322 {
   328 {
   323 	IniItem *item;
   329 	IniItem *item;
   324 	uint len = strlen(name);
   330 	uint len = strlen(name);
   325 
   331 
   326 	for (item = group->item; item; item = item->next)
   332 	for (item = group->item; item; item = item->next)
   327 		if (strcmp(item->name, name) == 0) return item;
   333 		if (strcmp(item->name, name) == 0) return item;
   328 
   334 
   329 	if (!create) return NULL;
   335 	if (!create) return NULL;
   330 
   336 
   331 	// otherwise make a new one
   337 	/* otherwise make a new one */
   332 	return ini_item_alloc(group, name, len);
   338 	return ini_item_alloc(group, name, len);
   333 }
   339 }
   334 
   340 
   335 // save ini file from the "abstract" format.
   341 /** save ini file from the "abstract" format. */
   336 static bool ini_save(const char *filename, IniFile *ini)
   342 static bool ini_save(const char *filename, IniFile *ini)
   337 {
   343 {
   338 	FILE *f;
   344 	FILE *f;
   339 	IniGroup *group;
   345 	IniGroup *group;
   340 	IniItem *item;
   346 	IniItem *item;
   347 		fprintf(f, "[%s]\n", group->name);
   353 		fprintf(f, "[%s]\n", group->name);
   348 		for (item = group->item; item != NULL; item = item->next) {
   354 		for (item = group->item; item != NULL; item = item->next) {
   349 			assert(item->value != NULL);
   355 			assert(item->value != NULL);
   350 			if (item->comment != NULL) fputs(item->comment, f);
   356 			if (item->comment != NULL) fputs(item->comment, f);
   351 
   357 
       
   358 			/* protect item->name with quotes if needed */
       
   359 			if (strchr(item->name, ' ') != NULL) {
       
   360 				fprintf(f, "\"%s\"", item->name);
       
   361 			} else {
       
   362 				fprintf(f, "%s", item->name);
       
   363 			}
       
   364 
   352 			/* Don't give an equal sign to list items that don't have a parameter */
   365 			/* Don't give an equal sign to list items that don't have a parameter */
   353 			if (group->type == IGT_LIST && *item->value == '\0') {
   366 			if (group->type == IGT_LIST && *item->value == '\0') {
   354 				fprintf(f, "%s\n", item->name);
   367 				fprintf(f, "\n");
   355 			} else {
   368 			} else {
   356 				fprintf(f, "%s = %s\n", item->name, item->value);
   369 				fprintf(f, " = %s\n", item->value);
   357 			}
   370 			}
   358 		}
   371 		}
   359 	}
   372 	}
   360 	if (ini->comment) fputs(ini->comment, f);
   373 	if (ini->comment) fputs(ini->comment, f);
   361 
   374 
   378 	const char *s;
   391 	const char *s;
   379 	int idx;
   392 	int idx;
   380 
   393 
   381 	if (onelen == -1) onelen = strlen(one);
   394 	if (onelen == -1) onelen = strlen(one);
   382 
   395 
   383 	// check if it's an integer
   396 	/* check if it's an integer */
   384 	if (*one >= '0' && *one <= '9')
   397 	if (*one >= '0' && *one <= '9')
   385 		return strtoul(one, NULL, 0);
   398 		return strtoul(one, NULL, 0);
   386 
   399 
   387 	idx = 0;
   400 	idx = 0;
   388 	for (;;) {
   401 	for (;;) {
   389 		// find end of item
   402 		/* find end of item */
   390 		s = many;
   403 		s = many;
   391 		while (*s != '|' && *s != 0) s++;
   404 		while (*s != '|' && *s != 0) s++;
   392 		if (s - many == onelen && !memcmp(one, many, onelen)) return idx;
   405 		if (s - many == onelen && !memcmp(one, many, onelen)) return idx;
   393 		if (*s == 0) return -1;
   406 		if (*s == 0) return -1;
   394 		many = s + 1;
   407 		many = s + 1;
   397 }
   410 }
   398 
   411 
   399 /** Find the set-integer value MANYofMANY type in a string
   412 /** Find the set-integer value MANYofMANY type in a string
   400  * @param many full domain of values the MANYofMANY setting can have
   413  * @param many full domain of values the MANYofMANY setting can have
   401  * @param str the current string value of the setting, each individual
   414  * @param str the current string value of the setting, each individual
   402  * of seperated by a whitespace\tab or | character
   415  * of seperated by a whitespace,tab or | character
   403  * @return the 'fully' set integer, or -1 if a set is not found */
   416  * @return the 'fully' set integer, or -1 if a set is not found */
   404 static uint32 lookup_manyofmany(const char *many, const char *str)
   417 static uint32 lookup_manyofmany(const char *many, const char *str)
   405 {
   418 {
   406 	const char *s;
   419 	const char *s;
   407 	int r;
   420 	int r;
   408 	uint32 res = 0;
   421 	uint32 res = 0;
   409 
   422 
   410 	for (;;) {
   423 	for (;;) {
   411 		// skip "whitespace"
   424 		/* skip "whitespace" */
   412 		while (*str == ' ' || *str == '\t' || *str == '|') str++;
   425 		while (*str == ' ' || *str == '\t' || *str == '|') str++;
   413 		if (*str == 0) break;
   426 		if (*str == 0) break;
   414 
   427 
   415 		s = str;
   428 		s = str;
   416 		while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
   429 		while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
   520  * @param id the value of the variable and whose string-representation must be found */
   533  * @param id the value of the variable and whose string-representation must be found */
   521 static void make_oneofmany(char *buf, const char *many, int id)
   534 static void make_oneofmany(char *buf, const char *many, int id)
   522 {
   535 {
   523 	int orig_id = id;
   536 	int orig_id = id;
   524 
   537 
   525 	// Look for the id'th element
   538 	/* Look for the id'th element */
   526 	while (--id >= 0) {
   539 	while (--id >= 0) {
   527 		for (; *many != '|'; many++) {
   540 		for (; *many != '|'; many++) {
   528 			if (*many == '\0') { // not found
   541 			if (*many == '\0') { // not found
   529 				sprintf(buf, "%d", orig_id);
   542 				sprintf(buf, "%d", orig_id);
   530 				return;
   543 				return;
   531 			}
   544 			}
   532 		}
   545 		}
   533 		many++; // pass the |-character
   546 		many++; // pass the |-character
   534 	}
   547 	}
   535 
   548 
   536 	// copy string until next item (|) or the end of the list if this is the last one
   549 	/* copy string until next item (|) or the end of the list if this is the last one */
   537 	while (*many != '\0' && *many != '|') *buf++ = *many++;
   550 	while (*many != '\0' && *many != '|') *buf++ = *many++;
   538 	*buf = '\0';
   551 	*buf = '\0';
   539 }
   552 }
   540 
   553 
   541 /** Convert a MANYofMANY structure to a string representation.
   554 /** Convert a MANYofMANY structure to a string representation.
   667 
   680 
   668 /** Load values from a group of an IniFile structure into the internal representation
   681 /** Load values from a group of an IniFile structure into the internal representation
   669  * @param ini pointer to IniFile structure that holds administrative information
   682  * @param ini pointer to IniFile structure that holds administrative information
   670  * @param sd pointer to SettingDesc structure whose internally pointed variables will
   683  * @param sd pointer to SettingDesc structure whose internally pointed variables will
   671  *        be given values
   684  *        be given values
   672  * @param grpname the group of the IniFile to search in for the new values */
   685  * @param grpname the group of the IniFile to search in for the new values
       
   686  * @param object pointer to the object been loaded */
   673 static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
   687 static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
   674 {
   688 {
   675 	IniGroup *group;
   689 	IniGroup *group;
   676 	IniGroup *group_def = ini_getgroup(ini, grpname, -1);
   690 	IniGroup *group_def = ini_getgroup(ini, grpname, -1);
   677 	IniItem *item;
   691 	IniItem *item;
   683 		const SettingDescBase *sdb = &sd->desc;
   697 		const SettingDescBase *sdb = &sd->desc;
   684 		const SaveLoad        *sld = &sd->save;
   698 		const SaveLoad        *sld = &sd->save;
   685 
   699 
   686 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   700 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   687 
   701 
   688 		// XXX - wtf is this?? (group override?)
   702 		/* XXX - wtf is this?? (group override?) */
   689 		s = strchr(sdb->name, '.');
   703 		s = strchr(sdb->name, '.');
   690 		if (s != NULL) {
   704 		if (s != NULL) {
   691 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   705 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   692 			s++;
   706 			s++;
   693 		} else {
   707 		} else {
   737 /** Save the values of settings to the inifile.
   751 /** Save the values of settings to the inifile.
   738  * @param ini pointer to IniFile structure
   752  * @param ini pointer to IniFile structure
   739  * @param sd read-only SettingDesc structure which contains the unmodified,
   753  * @param sd read-only SettingDesc structure which contains the unmodified,
   740  *        loaded values of the configuration file and various information about it
   754  *        loaded values of the configuration file and various information about it
   741  * @param grpname holds the name of the group (eg. [network]) where these will be saved
   755  * @param grpname holds the name of the group (eg. [network]) where these will be saved
       
   756  * @param object pointer to the object been saved
   742  * The function works as follows: for each item in the SettingDesc structure we
   757  * The function works as follows: for each item in the SettingDesc structure we
   743  * have a look if the value has changed since we started the game (the original
   758  * have a look if the value has changed since we started the game (the original
   744  * values are reloaded when saving). If settings indeed have changed, we get
   759  * values are reloaded when saving). If settings indeed have changed, we get
   745  * these and save them.
   760  * these and save them.
   746  */
   761  */
   759 		/* If the setting is not saved to the configuration
   774 		/* If the setting is not saved to the configuration
   760 		 * file, just continue with the next setting */
   775 		 * file, just continue with the next setting */
   761 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   776 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   762 		if (sld->conv & SLF_CONFIG_NO) continue;
   777 		if (sld->conv & SLF_CONFIG_NO) continue;
   763 
   778 
   764 		// XXX - wtf is this?? (group override?)
   779 		/* XXX - wtf is this?? (group override?) */
   765 		s = strchr(sdb->name, '.');
   780 		s = strchr(sdb->name, '.');
   766 		if (s != NULL) {
   781 		if (s != NULL) {
   767 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   782 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   768 			s++;
   783 			s++;
   769 		} else {
   784 		} else {
   774 
   789 
   775 		item = ini_getitem(group, s, true);
   790 		item = ini_getitem(group, s, true);
   776 		ptr = GetVariableAddress(object, sld);
   791 		ptr = GetVariableAddress(object, sld);
   777 
   792 
   778 		if (item->value != NULL) {
   793 		if (item->value != NULL) {
   779 			// check if the value is the same as the old value
   794 			/* check if the value is the same as the old value */
   780 			const void *p = string_to_val(sdb, item->value);
   795 			const void *p = string_to_val(sdb, item->value);
   781 
   796 
   782 			/* The main type of a variable/setting is in bytes 8-15
   797 			/* The main type of a variable/setting is in bytes 8-15
   783 			 * The subtype (what kind of numbers do we have there) is in 0-7 */
   798 			 * The subtype (what kind of numbers do we have there) is in 0-7 */
   784 			switch (sdb->cmd) {
   799 			switch (sdb->cmd) {
   850 
   865 
   851 /** Loads all items from a 'grpname' section into a list
   866 /** Loads all items from a 'grpname' section into a list
   852  * The list parameter can be a NULL pointer, in this case nothing will be
   867  * The list parameter can be a NULL pointer, in this case nothing will be
   853  * saved and a callback function should be defined that will take over the
   868  * saved and a callback function should be defined that will take over the
   854  * list-handling and store the data itself somewhere.
   869  * list-handling and store the data itself somewhere.
   855  * @param IniFile handle to the ini file with the source data
   870  * @param ini IniFile handle to the ini file with the source data
   856  * @param grpname character string identifying the section-header of the ini
   871  * @param grpname character string identifying the section-header of the ini
   857  * file that will be parsed
   872  * file that will be parsed
   858  * @param list pointer to an string(pointer) array that will store the parsed
   873  * @param list pointer to an string(pointer) array that will store the parsed
   859  * entries of the given section
   874  * entries of the given section
   860  * @param len the maximum number of items available for the above list
   875  * @param len the maximum number of items available for the above list
   880 }
   895 }
   881 
   896 
   882 /** Saves all items from a list into the 'grpname' section
   897 /** Saves all items from a list into the 'grpname' section
   883  * The list parameter can be a NULL pointer, in this case a callback function
   898  * The list parameter can be a NULL pointer, in this case a callback function
   884  * should be defined that will provide the source data to be saved.
   899  * should be defined that will provide the source data to be saved.
   885  * @param IniFile handle to the ini file where the destination data is saved
   900  * @param ini IniFile handle to the ini file where the destination data is saved
   886  * @param grpname character string identifying the section-header of the ini file
   901  * @param grpname character string identifying the section-header of the ini file
   887  * @param list pointer to an string(pointer) array that will be used as the
   902  * @param list pointer to an string(pointer) array that will be used as the
   888  * source to be saved into the relevant ini section
   903  *             source to be saved into the relevant ini section
   889  * @param len the maximum number of items available for the above list
   904  * @param len the maximum number of items available for the above list
   890  * @param proc callback function that can will provide the source data if defined */
   905  * @param proc callback function that can will provide the source data if defined */
   891 static void ini_save_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
   906 static void ini_save_setting_list(IniFile *ini, const char *grpname, char **list, uint len, SettingListCallbackProc proc)
   892 {
   907 {
   893 	IniGroup *group = ini_getgroup(ini, grpname, -1);
   908 	IniGroup *group = ini_getgroup(ini, grpname, -1);
   927  * We have two types of list:
   942  * We have two types of list:
   928  * 1. SDTG_something
   943  * 1. SDTG_something
   929  * 2. SDT_something
   944  * 2. SDT_something
   930  * The 'G' stands for global, so this is the one you will use for a
   945  * The 'G' stands for global, so this is the one you will use for a
   931  * SettingDescGlobVarList section meaning global variables. The other uses a
   946  * SettingDescGlobVarList section meaning global variables. The other uses a
   932  * Base/Offset and runtime variable selection mechanism, known from the saveload * convention (it also has global so it should not be hard).
   947  * Base/Offset and runtime variable selection mechanism, known from the saveload
       
   948  * convention (it also has global so it should not be hard).
   933  * Of each type there are again two versions, the normal one and one prefixed
   949  * Of each type there are again two versions, the normal one and one prefixed
   934  * with 'COND'.
   950  * with 'COND'.
   935  * COND means that the setting is only valid in certain savegame versions
   951  * COND means that the setting is only valid in certain savegame versions
   936  * (since patches are saved to the savegame, this bookkeeping is necessary.
   952  * (since patches are saved to the savegame, this bookkeeping is necessary.
   937  * Now there are a lot of types. Easy ones are:
   953  * Now there are a lot of types. Easy ones are:
   986 	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
  1002 	SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, proc, 0, SL_MAX_VERSION)
   987 
  1003 
   988 #define SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max, full, str, proc, from, to)\
  1004 #define SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max, full, str, proc, from, to)\
   989 	SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, proc, from, to)
  1005 	SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, proc, from, to)
   990 #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, proc)\
  1006 #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, proc)\
   991 	SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max full, str, proc, 0, SL_MAX_VERSION)
  1007 	SDTG_CONDOMANY(name, type, flags, guiflags, var, def, max, full, str, proc, 0, SL_MAX_VERSION)
   992 
  1008 
   993 #define SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, from, to)\
  1009 #define SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, from, to)\
   994 	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
  1010 	SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, proc, from, to)
   995 #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
  1011 #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, proc)\
   996 	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
  1012 	SDTG_CONDMMANY(name, type, flags, guiflags, var, def, full, str, proc, 0, SL_MAX_VERSION)
  1050 #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL, NULL}, SLE_END()}
  1066 #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL, NULL}, SLE_END()}
  1051 
  1067 
  1052 /* Shortcuts for macros below. Logically if we don't save the value
  1068 /* Shortcuts for macros below. Logically if we don't save the value
  1053  * we also don't sync it in a network game */
  1069  * we also don't sync it in a network game */
  1054 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1070 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1055 #define NS SLF_SAVE_NO
       
  1056 #define C SLF_CONFIG_NO
  1071 #define C SLF_CONFIG_NO
  1057 #define N SLF_NETWORK_NO
  1072 #define N SLF_NETWORK_NO
  1058 
  1073 
  1059 #define D0 SGF_0ISDISABLED
  1074 #define D0 SGF_0ISDISABLED
  1060 #define NC SGF_NOCOMMA
  1075 #define NC SGF_NOCOMMA
  1067 /* Begin - Callback Functions for the various settings */
  1082 /* Begin - Callback Functions for the various settings */
  1068 #include "window.h"
  1083 #include "window.h"
  1069 #include "gui.h"
  1084 #include "gui.h"
  1070 #include "town.h"
  1085 #include "town.h"
  1071 #include "gfx.h"
  1086 #include "gfx.h"
  1072 // virtual PositionMainToolbar function, calls the right one.
  1087 /* virtual PositionMainToolbar function, calls the right one.*/
  1073 static int32 v_PositionMainToolbar(int32 p1)
  1088 static int32 v_PositionMainToolbar(int32 p1)
  1074 {
  1089 {
  1075 	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
  1090 	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
  1076 	return 0;
  1091 	return 0;
  1077 }
  1092 }
  1123 {
  1138 {
  1124 	bool warning;
  1139 	bool warning;
  1125 	const Patches *ptc = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
  1140 	const Patches *ptc = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
  1126 
  1141 
  1127 	if (p1) {
  1142 	if (p1) {
  1128 		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   5, 90+1) || ptc->servint_trains   == 0) &&
  1143 		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   5, 90 + 1) || ptc->servint_trains   == 0) &&
  1129 								(IS_INT_INSIDE(ptc->servint_roadveh,  5, 90+1) || ptc->servint_roadveh  == 0) &&
  1144 								(IS_INT_INSIDE(ptc->servint_roadveh,  5, 90 + 1) || ptc->servint_roadveh  == 0) &&
  1130 								(IS_INT_INSIDE(ptc->servint_aircraft, 5, 90+1) || ptc->servint_aircraft == 0) &&
  1145 								(IS_INT_INSIDE(ptc->servint_aircraft, 5, 90 + 1) || ptc->servint_aircraft == 0) &&
  1131 								(IS_INT_INSIDE(ptc->servint_ships,    5, 90+1) || ptc->servint_ships    == 0) );
  1146 								(IS_INT_INSIDE(ptc->servint_ships,    5, 90 + 1) || ptc->servint_ships    == 0) );
  1132 	} else {
  1147 	} else {
  1133 		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   30, 800+1) || ptc->servint_trains   == 0) &&
  1148 		warning = ( (IS_INT_INSIDE(ptc->servint_trains,   30, 800 + 1) || ptc->servint_trains   == 0) &&
  1134 								(IS_INT_INSIDE(ptc->servint_roadveh,  30, 800+1) || ptc->servint_roadveh  == 0) &&
  1149 								(IS_INT_INSIDE(ptc->servint_roadveh,  30, 800 + 1) || ptc->servint_roadveh  == 0) &&
  1135 								(IS_INT_INSIDE(ptc->servint_aircraft, 30, 800+1) || ptc->servint_aircraft == 0) &&
  1150 								(IS_INT_INSIDE(ptc->servint_aircraft, 30, 800 + 1) || ptc->servint_aircraft == 0) &&
  1136 								(IS_INT_INSIDE(ptc->servint_ships,    30, 800+1) || ptc->servint_ships    == 0) );
  1151 								(IS_INT_INSIDE(ptc->servint_ships,    30, 800 + 1) || ptc->servint_ships    == 0) );
  1137 	}
  1152 	}
  1138 
  1153 
  1139 	if (!warning)
  1154 	if (!warning)
  1140 		ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE, 0, 0);
  1155 		ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE, 0, 0);
  1141 
  1156 
  1157 static int32 EngineRenewMoneyUpdate(int32 p1)
  1172 static int32 EngineRenewMoneyUpdate(int32 p1)
  1158 {
  1173 {
  1159 	DoCommandP(0, 2, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
  1174 	DoCommandP(0, 2, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
  1160 	return 0;
  1175 	return 0;
  1161 }
  1176 }
       
  1177 
       
  1178 /**
       
  1179  * Check for right TownLayout usage in editor mode.
       
  1180  * The No Road mode is not desirable since towns have to be
       
  1181  * able to grow. If a user desires to have a town with no road,
       
  1182  * he can easily remove them himself. This would create less confusion
       
  1183  * @param p1 unused
       
  1184  * @return always 0
       
  1185  */
       
  1186 static int32 CheckTownLayout(int32 p1)
       
  1187 {
       
  1188 	if (_patches.town_layout == TL_NO_ROADS && _game_mode == GM_EDITOR) {
       
  1189 		ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_TOWN_LAYOUT_INVALID, 0, 0);
       
  1190 		_patches.town_layout = TL_ORIGINAL;
       
  1191 	}
       
  1192 	return 0;
       
  1193 }
       
  1194 
  1162 /** Conversion callback for _gameopt_settings.landscape
  1195 /** Conversion callback for _gameopt_settings.landscape
  1163  * It converts (or try) between old values and the new ones,
  1196  * It converts (or try) between old values and the new ones,
  1164  * without loosing initial setting  of the user
  1197  * without loosing initial setting  of the user
  1165  * @param value that was read from config file
  1198  * @param value that was read from config file
  1166  * @return the "hopefully" converted value
  1199  * @return the "hopefully" converted value
  1203 	 SDTG_END()
  1236 	 SDTG_END()
  1204 };
  1237 };
  1205 #endif /* WIN32 */
  1238 #endif /* WIN32 */
  1206 
  1239 
  1207 static const SettingDescGlobVarList _misc_settings[] = {
  1240 static const SettingDescGlobVarList _misc_settings[] = {
  1208 	SDTG_MMANY("display_opt",     SLE_UINT8, S, 0, _display_opt,       (DO_SHOW_TOWN_NAMES|DO_SHOW_STATION_NAMES|DO_SHOW_SIGNS|DO_FULL_ANIMATION|DO_FULL_DETAIL|DO_TRANS_BUILDINGS|DO_WAYPOINTS), "SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION|TRANS_BUILDINGS|FULL_DETAIL|WAYPOINTS", STR_NULL, NULL),
  1241 	SDTG_MMANY("display_opt",     SLE_UINT8, S, 0, _display_opt,       (1 << DO_SHOW_TOWN_NAMES | 1 << DO_SHOW_STATION_NAMES | 1 << DO_SHOW_SIGNS | 1 << DO_FULL_ANIMATION | 1 << DO_FULL_DETAIL | 1 << DO_WAYPOINTS), "SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION||FULL_DETAIL|WAYPOINTS", STR_NULL, NULL),
  1209 	 SDTG_BOOL("news_ticker_sound",          S, 0, _news_ticker_sound,     true,    STR_NULL, NULL),
  1242 	 SDTG_BOOL("news_ticker_sound",          S, 0, _news_ticker_sound,     true,    STR_NULL, NULL),
  1210 	 SDTG_BOOL("fullscreen",                 S, 0, _fullscreen,           false,    STR_NULL, NULL),
  1243 	 SDTG_BOOL("fullscreen",                 S, 0, _fullscreen,           false,    STR_NULL, NULL),
  1211 	  SDTG_STR("videodriver",      SLE_STRB,C|S,0, _ini_videodriver,       NULL,    STR_NULL, NULL),
  1244 	  SDTG_STR("videodriver",      SLE_STRB,C|S,0, _ini_videodriver,       NULL,    STR_NULL, NULL),
  1212 	  SDTG_STR("musicdriver",      SLE_STRB,C|S,0, _ini_musicdriver,       NULL,    STR_NULL, NULL),
  1245 	  SDTG_STR("musicdriver",      SLE_STRB,C|S,0, _ini_musicdriver,       NULL,    STR_NULL, NULL),
  1213 	  SDTG_STR("sounddriver",      SLE_STRB,C|S,0, _ini_sounddriver,       NULL,    STR_NULL, NULL),
  1246 	  SDTG_STR("sounddriver",      SLE_STRB,C|S,0, _ini_sounddriver,       NULL,    STR_NULL, NULL),
  1227 	  SDTG_END()
  1260 	  SDTG_END()
  1228 };
  1261 };
  1229 
  1262 
  1230 #ifdef ENABLE_NETWORK
  1263 #ifdef ENABLE_NETWORK
  1231 static const SettingDescGlobVarList _network_settings[] = {
  1264 static const SettingDescGlobVarList _network_settings[] = {
  1232 	 SDTG_VAR("sync_freq",           SLE_UINT16,C|S,0, _network_sync_freq,            100, 0,   100,   0, STR_NULL, NULL),
  1265 	  SDTG_VAR("sync_freq",           SLE_UINT16,C|S,0, _network_sync_freq,            100, 0,   100,   0, STR_NULL, NULL),
  1233 	 SDTG_VAR("frame_freq",           SLE_UINT8,C|S,0, _network_frame_freq,             0, 0,   100,   0, STR_NULL, NULL),
  1266 	  SDTG_VAR("frame_freq",           SLE_UINT8,C|S,0, _network_frame_freq,             0, 0,   100,   0, STR_NULL, NULL),
  1234 	 SDTG_VAR("max_join_time",       SLE_UINT16, S, 0, _network_max_join_time,        500, 0, 32000,   0, STR_NULL, NULL),
  1267 	  SDTG_VAR("max_join_time",       SLE_UINT16, S, 0, _network_max_join_time,        500, 0, 32000,   0, STR_NULL, NULL),
  1235 	SDTG_BOOL("pause_on_join",                   S, 0, _network_pause_on_join,        true,               STR_NULL, NULL),
  1268 	 SDTG_BOOL("pause_on_join",                   S, 0, _network_pause_on_join,        true,               STR_NULL, NULL),
  1236 	 SDTG_STR("server_bind_ip",        SLE_STRB, S, 0, _network_server_bind_ip_host,  "0.0.0.0",          STR_NULL, NULL),
  1269 	  SDTG_STR("server_bind_ip",        SLE_STRB, S, 0, _network_server_bind_ip_host,  "0.0.0.0",          STR_NULL, NULL),
  1237 	 SDTG_VAR("server_port",         SLE_UINT16, S, 0, _network_server_port,          NETWORK_DEFAULT_PORT, 0, 65535, 0, STR_NULL, NULL),
  1270 	  SDTG_VAR("server_port",         SLE_UINT16, S, 0, _network_server_port,          NETWORK_DEFAULT_PORT, 0, 65535, 0, STR_NULL, NULL),
  1238 	SDTG_BOOL("server_advertise",                S, 0, _network_advertise,            false,              STR_NULL, NULL),
  1271 	 SDTG_BOOL("server_advertise",                S, 0, _network_advertise,            false,              STR_NULL, NULL),
  1239 	 SDTG_VAR("lan_internet",         SLE_UINT8, S, 0, _network_lan_internet,           0, 0,     1,   0, STR_NULL, NULL),
  1272 	  SDTG_VAR("lan_internet",         SLE_UINT8, S, 0, _network_lan_internet,           0, 0,     1,   0, STR_NULL, NULL),
  1240 	 SDTG_STR("player_name",           SLE_STRB, S, 0, _network_player_name,          NULL,               STR_NULL, NULL),
  1273 	  SDTG_STR("player_name",           SLE_STRB, S, 0, _network_player_name,          NULL,               STR_NULL, NULL),
  1241 	 SDTG_STR("server_password",       SLE_STRB, S, 0, _network_server_password,      NULL,               STR_NULL, NULL),
  1274 	  SDTG_STR("server_password",       SLE_STRB, S, 0, _network_server_password,      NULL,               STR_NULL, NULL),
  1242 	 SDTG_STR("rcon_password",         SLE_STRB, S, 0, _network_rcon_password,        NULL,               STR_NULL, NULL),
  1275 	  SDTG_STR("rcon_password",         SLE_STRB, S, 0, _network_rcon_password,        NULL,               STR_NULL, NULL),
  1243 	 SDTG_STR("server_name",           SLE_STRB, S, 0, _network_server_name,          NULL,               STR_NULL, NULL),
  1276 	  SDTG_STR("server_name",           SLE_STRB, S, 0, _network_server_name,          NULL,               STR_NULL, NULL),
  1244 	 SDTG_STR("connect_to_ip",         SLE_STRB, S, 0, _network_default_ip,           NULL,               STR_NULL, NULL),
  1277 	  SDTG_STR("connect_to_ip",         SLE_STRB, S, 0, _network_default_ip,           NULL,               STR_NULL, NULL),
  1245 	 SDTG_STR("network_id",            SLE_STRB, S, 0, _network_unique_id,            NULL,               STR_NULL, NULL),
  1278 	  SDTG_STR("network_id",            SLE_STRB, S, 0, _network_unique_id,            NULL,               STR_NULL, NULL),
  1246 	SDTG_BOOL("autoclean_companies",             S, 0, _network_autoclean_companies,  false,              STR_NULL, NULL),
  1279 	 SDTG_BOOL("autoclean_companies",             S, 0, _network_autoclean_companies,  false,              STR_NULL, NULL),
  1247 	 SDTG_VAR("autoclean_unprotected",SLE_UINT8, S, 0, _network_autoclean_unprotected,12, 0,     60,   0, STR_NULL, NULL),
  1280 	  SDTG_VAR("autoclean_unprotected",SLE_UINT8, S, 0, _network_autoclean_unprotected,12, 0,     60,   0, STR_NULL, NULL),
  1248 	 SDTG_VAR("autoclean_protected",  SLE_UINT8, S, 0, _network_autoclean_protected,  36, 0,    180,   0, STR_NULL, NULL),
  1281 	  SDTG_VAR("autoclean_protected",  SLE_UINT8, S, 0, _network_autoclean_protected,  36, 0,    180,   0, STR_NULL, NULL),
  1249 	 SDTG_VAR("max_companies",        SLE_UINT8, S, 0, _network_game_info.companies_max,   8, 0,  8,   0, STR_NULL, NULL),
  1282 	  SDTG_VAR("max_companies",        SLE_UINT8, S, 0, _network_game_info.companies_max,   8, 0,  8,   0, STR_NULL, NULL),
  1250 	 SDTG_VAR("max_clients",          SLE_UINT8, S, 0, _network_game_info.clients_max,    10, 0, 10,   0, STR_NULL, NULL),
  1283 	  SDTG_VAR("max_clients",          SLE_UINT8, S, 0, _network_game_info.clients_max,    10, 0, 10,   0, STR_NULL, NULL),
  1251 	 SDTG_VAR("max_spectators",       SLE_UINT8, S, 0, _network_game_info.spectators_max, 10, 0, 10,   0, STR_NULL, NULL),
  1284 	  SDTG_VAR("max_spectators",       SLE_UINT8, S, 0, _network_game_info.spectators_max, 10, 0, 10,   0, STR_NULL, NULL),
  1252 	 SDTG_VAR("restart_game_year",    SLE_INT32, S,D0, _network_restart_game_year,    0, MIN_YEAR, MAX_YEAR, 1, STR_NULL, NULL),
  1285 	  SDTG_VAR("restart_game_year",    SLE_INT32, S,D0, _network_restart_game_year,    0, MIN_YEAR, MAX_YEAR, 1, STR_NULL, NULL),
  1253 	 SDTG_VAR("min_players",          SLE_UINT8, S, 0, _network_min_players,               0, 0, 10,   0, STR_NULL, NULL),
  1286 	  SDTG_VAR("min_players",          SLE_UINT8, S, 0, _network_min_players,               0, 0, 10,   0, STR_NULL, NULL),
  1254 	 SDTG_END()
  1287 	SDTG_OMANY("server_lang",          SLE_UINT8, S, 0, _network_game_info.server_lang,     0, 28, "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN", STR_NULL, NULL),
       
  1288 	  SDTG_END()
  1255 };
  1289 };
  1256 #endif /* ENABLE_NETWORK */
  1290 #endif /* ENABLE_NETWORK */
  1257 
  1291 
  1258 static const SettingDesc _gameopt_settings[] = {
  1292 static const SettingDesc _gameopt_settings[] = {
  1259 	/* In version 4 a new difficulty setting has been added to the difficulty settings,
  1293 	/* In version 4 a new difficulty setting has been added to the difficulty settings,
  1263 	 * XXX - To save file-space and since values are never bigger than about 10? only
  1297 	 * XXX - To save file-space and since values are never bigger than about 10? only
  1264 	 * save the first 16 bits in the savegame. Question is why the values are still int32
  1298 	 * save the first 16 bits in the savegame. Question is why the values are still int32
  1265 	 * and why not byte for example? */
  1299 	 * and why not byte for example? */
  1266 	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 0, 3),
  1300 	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 17, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 0, 3),
  1267 	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 4, SL_MAX_VERSION),
  1301 	SDT_GENERAL("diff_custom", SDT_INTLIST, SL_ARR, (SLE_FILE_I16 | SLE_VAR_I32), 0, 0, GameOptions, diff, 18, 0, 0, 0, 0, NULL, STR_NULL, NULL, NULL, 4, SL_MAX_VERSION),
  1268 	    SDT_VAR(GameOptions, diff_level,SLE_UINT8, 0, 0, 0, 0,  3, 0, STR_NULL, NULL),
  1302 	    SDT_VAR(GameOptions, diff_level, SLE_UINT8, 0, 0, 0, 0,  3, 0, STR_NULL, NULL),
  1269 	  SDT_OMANY(GameOptions, currency,  SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL),
  1303 	  SDT_OMANY(GameOptions, currency,  SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL),
  1270 	  SDT_OMANY(GameOptions, units,     SLE_UINT8, N, 0, 1,     2, "imperial|metric|si", STR_NULL, NULL, NULL),
  1304 	  SDT_OMANY(GameOptions, units,     SLE_UINT8, N, 0, 1,     2, "imperial|metric|si", STR_NULL, NULL, NULL),
  1271 	  SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0,    20, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL),
  1305 	  SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0,    20, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL),
  1272 	  SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0,     3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape),
  1306 	  SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0,     3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape),
  1273 	    SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL),
  1307 	    SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL),
  1292 	SDT_BOOL(Patches, vehicle_speed,                 S, 0,  true,        STR_CONFIG_PATCHES_VEHICLESPEED,          NULL),
  1326 	SDT_BOOL(Patches, vehicle_speed,                 S, 0,  true,        STR_CONFIG_PATCHES_VEHICLESPEED,          NULL),
  1293 	SDT_BOOL(Patches, status_long_date,              S, 0,  true,        STR_CONFIG_PATCHES_LONGDATE,              NULL),
  1327 	SDT_BOOL(Patches, status_long_date,              S, 0,  true,        STR_CONFIG_PATCHES_LONGDATE,              NULL),
  1294 	SDT_BOOL(Patches, show_finances,                 S, 0,  true,        STR_CONFIG_PATCHES_SHOWFINANCES,          NULL),
  1328 	SDT_BOOL(Patches, show_finances,                 S, 0,  true,        STR_CONFIG_PATCHES_SHOWFINANCES,          NULL),
  1295 	SDT_BOOL(Patches, autoscroll,                    S, 0, false,        STR_CONFIG_PATCHES_AUTOSCROLL,            NULL),
  1329 	SDT_BOOL(Patches, autoscroll,                    S, 0, false,        STR_CONFIG_PATCHES_AUTOSCROLL,            NULL),
  1296 	SDT_BOOL(Patches, reverse_scroll,                S, 0, false,        STR_CONFIG_PATCHES_REVERSE_SCROLLING,     NULL),
  1330 	SDT_BOOL(Patches, reverse_scroll,                S, 0, false,        STR_CONFIG_PATCHES_REVERSE_SCROLLING,     NULL),
       
  1331 	SDT_BOOL(Patches, smooth_scroll,                 S, 0, false,        STR_CONFIG_PATCHES_SMOOTH_SCROLLING,      NULL),
  1297 	SDT_BOOL(Patches, measure_tooltip,               S, 0, false,        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,       NULL),
  1332 	SDT_BOOL(Patches, measure_tooltip,               S, 0, false,        STR_CONFIG_PATCHES_MEASURE_TOOLTIP,       NULL),
  1298 	 SDT_VAR(Patches, errmsg_duration,    SLE_UINT8, S, 0,  5, 0, 20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,       NULL),
  1333 	 SDT_VAR(Patches, errmsg_duration,    SLE_UINT8, S, 0,  5, 0, 20, 0, STR_CONFIG_PATCHES_ERRMSG_DURATION,       NULL),
  1299 	 SDT_VAR(Patches, toolbar_pos,        SLE_UINT8, S,MS,  0, 0,  2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,           v_PositionMainToolbar),
  1334 	 SDT_VAR(Patches, toolbar_pos,        SLE_UINT8, S,MS,  0, 0,  2, 0, STR_CONFIG_PATCHES_TOOLBAR_POS,           v_PositionMainToolbar),
  1300 	 SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1, 32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,           NULL),
  1335 	 SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1, 32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS,           NULL),
  1301 	SDT_BOOL(Patches, invisible_trees,               S, 0, false,        STR_CONFIG_PATCHES_INVISIBLE_TREES,       RedrawScreen),
  1336 	SDT_BOOL(Patches, invisible_trees,               S, 0, false,        STR_CONFIG_PATCHES_INVISIBLE_TREES,       RedrawScreen),
  1305 	SDT_BOOL(Patches, link_terraform_toolbar,        S, 0, false,        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL),
  1340 	SDT_BOOL(Patches, link_terraform_toolbar,        S, 0, false,        STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL),
  1306 	 SDT_VAR(Patches, liveries,           SLE_UINT8, S,MS,  2, 0,  2, 0, STR_CONFIG_PATCHES_LIVERIES,              RedrawScreen),
  1341 	 SDT_VAR(Patches, liveries,           SLE_UINT8, S,MS,  2, 0,  2, 0, STR_CONFIG_PATCHES_LIVERIES,              RedrawScreen),
  1307 	SDT_BOOL(Patches, prefer_teamchat,               S, 0, false,        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,       NULL),
  1342 	SDT_BOOL(Patches, prefer_teamchat,               S, 0, false,        STR_CONFIG_PATCHES_PREFER_TEAMCHAT,       NULL),
  1308 	SDT_VAR(Patches, scrollwheel_scrolling,SLE_UINT8,S,MS, 0,  0,  2, 0, STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING, NULL),
  1343 	SDT_VAR(Patches, scrollwheel_scrolling,SLE_UINT8,S,MS, 0,  0,  2, 0, STR_CONFIG_PATCHES_SCROLLWHEEL_SCROLLING, NULL),
  1309 	SDT_VAR(Patches,scrollwheel_multiplier,SLE_UINT8,S, 0, 5,  1, 15, 1, STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER,NULL),
  1344 	SDT_VAR(Patches,scrollwheel_multiplier,SLE_UINT8,S, 0, 5,  1, 15, 1, STR_CONFIG_PATCHES_SCROLLWHEEL_MULTIPLIER,NULL),
       
  1345 	SDT_BOOL(Patches, pause_on_newgame,              S, 0, false,        STR_CONFIG_PATCHES_PAUSE_ON_NEW_GAME,     NULL),
       
  1346 	SDT_BOOL(Patches, advanced_vehicle_list,         S, 0, true,        STR_CONFIG_PATCHES_ADVANCED_VEHICLE_LISTS,     NULL),
  1310 
  1347 
  1311 	/***************************************************************************/
  1348 	/***************************************************************************/
  1312 	/* Construction section of the GUI-configure patches window */
  1349 	/* Construction section of the GUI-configure patches window */
  1313 	SDT_BOOL(Patches, build_on_slopes,               0, 0,  true,        STR_CONFIG_PATCHES_BUILDONSLOPES,       NULL),
  1350 	SDT_BOOL(Patches, build_on_slopes,               0, 0,  true,        STR_CONFIG_PATCHES_BUILDONSLOPES,       NULL),
  1314 	SDT_BOOL(Patches, extra_dynamite,                0, 0, false,        STR_CONFIG_PATCHES_EXTRADYNAMITE,       NULL),
  1351 	SDT_BOOL(Patches, extra_dynamite,                0, 0, false,        STR_CONFIG_PATCHES_EXTRADYNAMITE,       NULL),
  1315 	SDT_BOOL(Patches, longbridges,                   0, 0,  true,        STR_CONFIG_PATCHES_LONGBRIDGES,         NULL),
  1352 	SDT_BOOL(Patches, longbridges,                   0, 0,  true,        STR_CONFIG_PATCHES_LONGBRIDGES,         NULL),
  1316 	SDT_BOOL(Patches, signal_side,                   N, 0,  true,        STR_CONFIG_PATCHES_SIGNALSIDE,          RedrawScreen),
  1353 	SDT_BOOL(Patches, signal_side,                   N, 0,  true,        STR_CONFIG_PATCHES_SIGNALSIDE,          RedrawScreen),
  1317 	SDT_BOOL(Patches, always_small_airport,          0, 0, false,        STR_CONFIG_PATCHES_SMALL_AIRPORTS,      NULL),
  1354 	SDT_BOOL(Patches, always_small_airport,          0, 0, false,        STR_CONFIG_PATCHES_SMALL_AIRPORTS,      NULL),
  1318 	 SDT_VAR(Patches, drag_signals_density,SLE_UINT8,S, 0,  4, 1, 20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,NULL),
  1355 	 SDT_VAR(Patches, drag_signals_density,SLE_UINT8,S, 0,  4, 1, 20, 0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY,NULL),
  1319 	 SDT_VAR(Patches, semaphore_build_before,SLE_INT32, S, NC, 1975, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_SEMAPHORE_BUILD_BEFORE_DATE, NULL),
  1356 	 SDT_VAR(Patches, semaphore_build_before,SLE_INT32, S, NC, 1975, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_SEMAPHORE_BUILD_BEFORE_DATE, NULL),
       
  1357 	SDT_CONDVAR(Patches, town_layout, SLE_UINT8, 59, SL_MAX_VERSION, 0, MS, TL_ORIGINAL, TL_NO_ROADS, NUM_TLS - 1, 1, STR_CONFIG_PATCHES_TOWN_LAYOUT, CheckTownLayout),
  1320 
  1358 
  1321 	/***************************************************************************/
  1359 	/***************************************************************************/
  1322 	/* Vehicle section of the GUI-configure patches window */
  1360 	/* Vehicle section of the GUI-configure patches window */
  1323 	SDT_BOOL(Patches, realistic_acceleration,        0, 0, false,                    STR_CONFIG_PATCHES_REALISTICACCEL,       NULL),
  1361 	SDT_BOOL(Patches, realistic_acceleration,        0, 0, false,                    STR_CONFIG_PATCHES_REALISTICACCEL,       NULL),
  1324 	SDT_BOOL(Patches, forbid_90_deg,                 0, 0, false,                    STR_CONFIG_PATCHES_FORBID_90_DEG,        NULL),
  1362 	SDT_BOOL(Patches, forbid_90_deg,                 0, 0, false,                    STR_CONFIG_PATCHES_FORBID_90_DEG,        NULL),
  1363 	 SDT_VAR(Patches, station_spread,SLE_UINT8,0, 0, 12, 4, 64, 0, STR_CONFIG_PATCHES_STATION_SPREAD,     InvalidateStationBuildWindow),
  1401 	 SDT_VAR(Patches, station_spread,SLE_UINT8,0, 0, 12, 4, 64, 0, STR_CONFIG_PATCHES_STATION_SPREAD,     InvalidateStationBuildWindow),
  1364 	SDT_BOOL(Patches, serviceathelipad,        0, 0,  true,        STR_CONFIG_PATCHES_SERVICEATHELIPAD,   NULL),
  1402 	SDT_BOOL(Patches, serviceathelipad,        0, 0,  true,        STR_CONFIG_PATCHES_SERVICEATHELIPAD,   NULL),
  1365 	SDT_BOOL(Patches, modified_catchment,      0, 0,  true,        STR_CONFIG_PATCHES_CATCHMENT,          NULL),
  1403 	SDT_BOOL(Patches, modified_catchment,      0, 0,  true,        STR_CONFIG_PATCHES_CATCHMENT,          NULL),
  1366 	SDT_CONDBOOL(Patches, gradual_loading, 40, SL_MAX_VERSION, 0, 0,  true, STR_CONFIG_PATCHES_GRADUAL_LOADING,    NULL),
  1404 	SDT_CONDBOOL(Patches, gradual_loading, 40, SL_MAX_VERSION, 0, 0,  true, STR_CONFIG_PATCHES_GRADUAL_LOADING,    NULL),
  1367 	SDT_CONDBOOL(Patches, road_stop_on_town_road, 47, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD, NULL),
  1405 	SDT_CONDBOOL(Patches, road_stop_on_town_road, 47, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD, NULL),
       
  1406 	SDT_CONDBOOL(Patches, adjacent_stations,      62, SL_MAX_VERSION, 0, 0, true,  STR_CONFIG_PATCHES_ADJACENT_STATIONS, NULL),
  1368 
  1407 
  1369 	/***************************************************************************/
  1408 	/***************************************************************************/
  1370 	/* Economy section of the GUI-configure patches window */
  1409 	/* Economy section of the GUI-configure patches window */
  1371 	SDT_BOOL(Patches, inflation,                  0, 0,  true,            STR_CONFIG_PATCHES_INFLATION,        NULL),
  1410 	SDT_BOOL(Patches, inflation,                  0, 0,  true,            STR_CONFIG_PATCHES_INFLATION,        NULL),
  1372 	SDT_BOOL(Patches, build_rawmaterial_ind,      0, 0, false,            STR_CONFIG_PATCHES_BUILDXTRAIND,     NULL),
  1411 	SDT_BOOL(Patches, build_rawmaterial_ind,      0, 0, false,            STR_CONFIG_PATCHES_BUILDXTRAIND,     NULL),
  1377 	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
  1416 	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
  1378 	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
  1417 	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
  1379 	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
  1418 	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
  1380 	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
  1419 	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
  1381 	SDT_BOOL(Patches, allow_shares,               0, 0, false,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
  1420 	SDT_BOOL(Patches, allow_shares,               0, 0, false,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
       
  1421 	SDT_CONDVAR(Patches, town_growth_rate,  SLE_UINT8, 54, SL_MAX_VERSION, 0, MS, 2, 0,   4, 0, STR_CONFIG_PATCHES_TOWN_GROWTH,          NULL),
       
  1422 	SDT_CONDVAR(Patches, larger_towns,      SLE_UINT8, 54, SL_MAX_VERSION, 0, D0, 4, 0, 255, 1, STR_CONFIG_PATCHES_LARGER_TOWNS,         NULL),
       
  1423 	SDT_CONDVAR(Patches, initial_city_size, SLE_UINT8, 56, SL_MAX_VERSION, 0, 0,  2, 1,  10, 1, STR_CONFIG_PATCHES_CITY_SIZE_MULTIPLIER, NULL),
  1382 
  1424 
  1383 	/***************************************************************************/
  1425 	/***************************************************************************/
  1384 	/* AI section of the GUI-configure patches window */
  1426 	/* AI section of the GUI-configure patches window */
  1385 	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
  1427 	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
  1386 	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
  1428 	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
  1458 	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
  1500 	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
  1459 	/* This is the penalty for drive-through road, stops. */
  1501 	/* This is the penalty for drive-through road, stops. */
  1460 	SDT_CONDVAR (Patches, npf_road_drive_through_penalty, SLE_UINT, 47, SL_MAX_VERSION, 0, 0,  8 * NPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1502 	SDT_CONDVAR (Patches, npf_road_drive_through_penalty, SLE_UINT, 47, SL_MAX_VERSION, 0, 0,  8 * NPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1461 
  1503 
  1462 
  1504 
  1463 	// The maximum number of nodes to search
  1505 	/* The maximum number of nodes to search */
  1464 	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
  1506 	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
  1465 	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
  1507 	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
  1466 	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
  1508 	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
  1467 	SDT_CONDVAR (Patches, yapf.rail_firstred_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1509 	SDT_CONDVAR (Patches, yapf.rail_firstred_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1468 	SDT_CONDVAR (Patches, yapf.rail_firstred_exit_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1510 	SDT_CONDVAR (Patches, yapf.rail_firstred_exit_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1470 	SDT_CONDVAR (Patches, yapf.rail_lastred_exit_penalty  , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1512 	SDT_CONDVAR (Patches, yapf.rail_lastred_exit_penalty  , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,   100 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1471 	SDT_CONDVAR (Patches, yapf.rail_station_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    30 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1513 	SDT_CONDVAR (Patches, yapf.rail_station_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    30 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1472 	SDT_CONDVAR (Patches, yapf.rail_slope_penalty         , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     2 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1514 	SDT_CONDVAR (Patches, yapf.rail_slope_penalty         , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     2 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1473 	SDT_CONDVAR (Patches, yapf.rail_curve45_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     1 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1515 	SDT_CONDVAR (Patches, yapf.rail_curve45_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     1 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1474 	SDT_CONDVAR (Patches, yapf.rail_curve90_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     6 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1516 	SDT_CONDVAR (Patches, yapf.rail_curve90_penalty       , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     6 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1475 	// This penalty is applied when a train reverses inside a depot
  1517 	/* This penalty is applied when a train reverses inside a depot */
  1476 	SDT_CONDVAR (Patches, yapf.rail_depot_reverse_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    50 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1518 	SDT_CONDVAR (Patches, yapf.rail_depot_reverse_penalty , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    50 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1477 	// This is the penalty for level crossings (for trains only)
  1519 	/* This is the penalty for level crossings (for trains only) */
  1478 	SDT_CONDVAR (Patches, yapf.rail_crossing_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     3 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1520 	SDT_CONDVAR (Patches, yapf.rail_crossing_penalty      , SLE_UINT, 28, SL_MAX_VERSION, 0, 0,     3 * YAPF_TILE_LENGTH,        0, 1000000, 0, STR_NULL, NULL),
  1479 	// look-ahead how many signals are checked
  1521 	/* look-ahead how many signals are checked */
  1480 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
  1522 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
  1481 	// look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0
  1523 	/* look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0 */
  1482 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1524 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1483 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1525 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1484 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1526 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1485 	// penalties for too long or too short station platforms
  1527 	/* penalties for too long or too short station platforms */
  1486 	SDT_CONDVAR (Patches, yapf.rail_longer_platform_penalty,           SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1528 	SDT_CONDVAR (Patches, yapf.rail_longer_platform_penalty,           SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1487 	SDT_CONDVAR (Patches, yapf.rail_longer_platform_per_tile_penalty,  SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1529 	SDT_CONDVAR (Patches, yapf.rail_longer_platform_per_tile_penalty,  SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1488 	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_penalty,          SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 40 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1530 	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_penalty,          SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 40 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1489 	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_per_tile_penalty, SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1531 	SDT_CONDVAR (Patches, yapf.rail_shorter_platform_per_tile_penalty, SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  0 * YAPF_TILE_LENGTH, 0,   20000, 0, STR_NULL, NULL),
  1490 	// road vehicles - penalties
  1532 	/* road vehicles - penalties */
  1491 	SDT_CONDVAR (Patches, yapf.road_slope_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  2 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1533 	SDT_CONDVAR (Patches, yapf.road_slope_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  2 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1492 	SDT_CONDVAR (Patches, yapf.road_curve_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  1 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1534 	SDT_CONDVAR (Patches, yapf.road_curve_penalty                    , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  1 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1493 	SDT_CONDVAR (Patches, yapf.road_crossing_penalty                 , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  3 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1535 	SDT_CONDVAR (Patches, yapf.road_crossing_penalty                 , SLE_UINT, 33, SL_MAX_VERSION, 0, 0,  3 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1494 	SDT_CONDVAR (Patches, yapf.road_stop_penalty                     , SLE_UINT, 47, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1536 	SDT_CONDVAR (Patches, yapf.road_stop_penalty                     , SLE_UINT, 47, SL_MAX_VERSION, 0, 0,  8 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL),
  1495 
  1537 
  1507 };
  1549 };
  1508 
  1550 
  1509 static const SettingDesc _currency_settings[] = {
  1551 static const SettingDesc _currency_settings[] = {
  1510 	SDT_VAR(CurrencySpec, rate,    SLE_UINT16, S, 0,  1, 0, 100, 0, STR_NULL, NULL),
  1552 	SDT_VAR(CurrencySpec, rate,    SLE_UINT16, S, 0,  1, 0, 100, 0, STR_NULL, NULL),
  1511 	SDT_CHR(CurrencySpec, separator,           S, 0,        ".",    STR_NULL, NULL),
  1553 	SDT_CHR(CurrencySpec, separator,           S, 0,        ".",    STR_NULL, NULL),
  1512 	SDT_VAR(CurrencySpec, to_euro,  SLE_INT32, S, 0,  0, 0,3000, 0, STR_NULL, NULL),
  1554 	SDT_VAR(CurrencySpec, to_euro,  SLE_INT32, S, 0,  0, 0, 3000, 0, STR_NULL, NULL),
  1513 	SDT_STR(CurrencySpec, prefix,   SLE_STRBQ, S, 0,       NULL,    STR_NULL, NULL),
  1555 	SDT_STR(CurrencySpec, prefix,   SLE_STRBQ, S, 0,       NULL,    STR_NULL, NULL),
  1514 	SDT_STR(CurrencySpec, suffix,   SLE_STRBQ, S, 0, " credits",    STR_NULL, NULL),
  1556 	SDT_STR(CurrencySpec, suffix,   SLE_STRBQ, S, 0, " credits",    STR_NULL, NULL),
  1515 	SDT_END()
  1557 	SDT_END()
  1516 };
  1558 };
  1517 
  1559 
  1574 
  1616 
  1575 	if (group == NULL) return NULL;
  1617 	if (group == NULL) return NULL;
  1576 
  1618 
  1577 	for (item = group->item; item != NULL; item = item->next) {
  1619 	for (item = group->item; item != NULL; item = item->next) {
  1578 		GRFConfig *c = CallocT<GRFConfig>(1);
  1620 		GRFConfig *c = CallocT<GRFConfig>(1);
  1579 		c->filename = strdup(item->name);
  1621 		c->full_path = strdup(item->name);
  1580 
  1622 
  1581 		/* Parse parameters */
  1623 		/* Parse parameters */
  1582 		if (*item->value != '\0') {
  1624 		if (*item->value != '\0') {
  1583 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1625 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1584 			if (c->num_params == (byte)-1) {
  1626 			if (c->num_params == (byte)-1) {
  1651 
  1693 
  1652 	for (c = list; c != NULL; c = c->next) {
  1694 	for (c = list; c != NULL; c = c->next) {
  1653 		char params[512];
  1695 		char params[512];
  1654 		GRFBuildParamList(params, c, lastof(params));
  1696 		GRFBuildParamList(params, c, lastof(params));
  1655 
  1697 
  1656 		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
  1698 		*item = ini_item_alloc(group, c->full_path, strlen(c->full_path));
  1657 		(*item)->value = (char*)pool_strdup(&ini->pool, params, strlen(params));
  1699 		(*item)->value = (char*)pool_strdup(&ini->pool, params, strlen(params));
  1658 		item = &(*item)->next;
  1700 		item = &(*item)->next;
  1659 	}
  1701 	}
  1660 }
  1702 }
  1661 
  1703 
  1711 	if (index >= lengthof(_patch_settings)) return NULL;
  1753 	if (index >= lengthof(_patch_settings)) return NULL;
  1712 	return &_patch_settings[index];
  1754 	return &_patch_settings[index];
  1713 }
  1755 }
  1714 
  1756 
  1715 /** Network-safe changing of patch-settings (server-only).
  1757 /** Network-safe changing of patch-settings (server-only).
       
  1758  * @param tile unused
       
  1759  * @param flags operation to perform
  1716  * @param p1 the index of the patch in the SettingDesc array which identifies it
  1760  * @param p1 the index of the patch in the SettingDesc array which identifies it
  1717  * @param p2 the new value for the patch
  1761  * @param p2 the new value for the patch
  1718  * The new value is properly clamped to its minimum/maximum when setting
  1762  * The new value is properly clamped to its minimum/maximum when setting
  1719  * @see _patch_settings
  1763  * @see _patch_settings
  1720  */
  1764  */
  1827 
  1871 
  1828 	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
  1872 	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
  1829 		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
  1873 		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
  1830 }
  1874 }
  1831 
  1875 
       
  1876 void IConsoleListPatches()
       
  1877 {
       
  1878 	IConsolePrintF(_icolour_warn, "All patches with their current value:");
       
  1879 
       
  1880 	for (const SettingDesc *sd = _patch_settings; sd->save.cmd != SL_END; sd++) {
       
  1881 		char value[80];
       
  1882 		const void *ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_patches_newgame : &_patches, &sd->save);
       
  1883 
       
  1884 		if (sd->desc.cmd == SDT_BOOLX) {
       
  1885 			snprintf(value, lengthof(value), (*(bool*)ptr == 1) ? "on" : "off");
       
  1886 		} else {
       
  1887 			snprintf(value, lengthof(value), "%d", (uint32)ReadValue(ptr, sd->save.conv));
       
  1888 		}
       
  1889 		IConsolePrintF(_icolour_def, "%s = %s", sd->desc.name, value);
       
  1890 	}
       
  1891 
       
  1892 	IConsolePrintF(_icolour_warn, "Use 'patch' command to change a value");
       
  1893 }
       
  1894 
  1832 /** Save and load handler for patches/settings
  1895 /** Save and load handler for patches/settings
  1833  * @param osd SettingDesc struct containing all information
  1896  * @param osd SettingDesc struct containing all information
  1834  * @param object can be either NULL in which case we load global variables or
  1897  * @param object can be either NULL in which case we load global variables or
  1835  * a pointer to a struct which is getting saved */
  1898  * a pointer to a struct which is getting saved */
  1836 static void LoadSettings(const SettingDesc *osd, void *object)
  1899 static void LoadSettings(const SettingDesc *osd, void *object)
  1842 		if (!SlObjectMember(ptr, sld)) continue;
  1905 		if (!SlObjectMember(ptr, sld)) continue;
  1843 	}
  1906 	}
  1844 }
  1907 }
  1845 
  1908 
  1846 /** Loadhandler for a list of global variables
  1909 /** Loadhandler for a list of global variables
       
  1910  * @param sdg pointer for the global variable list SettingDescGlobVarList
  1847  * @note this is actually a stub for LoadSettings with the
  1911  * @note this is actually a stub for LoadSettings with the
  1848  * object pointer set to NULL */
  1912  * object pointer set to NULL */
  1849 static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
  1913 static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
  1850 {
  1914 {
  1851 	LoadSettings((const SettingDesc*)sdg, NULL);
  1915 	LoadSettings((const SettingDesc*)sdg, NULL);
  1852 }
  1916 }
  1853 
  1917 
  1854 /** Save and load handler for patches/settings
  1918 /** Save and load handler for patches/settings
  1855  * @param osd SettingDesc struct containing all information
  1919  * @param sd SettingDesc struct containing all information
  1856  * @param object can be either NULL in which case we load global variables or
  1920  * @param object can be either NULL in which case we load global variables or
  1857  * a pointer to a struct which is getting saved */
  1921  * a pointer to a struct which is getting saved */
  1858 static void SaveSettings(const SettingDesc *sd, void *object)
  1922 static void SaveSettings(const SettingDesc *sd, void *object)
  1859 {
  1923 {
  1860 	/* We need to write the CH_RIFF header, but unfortunately can't call
  1924 	/* We need to write the CH_RIFF header, but unfortunately can't call