src/settings.cpp
branchgamebalance
changeset 9908 0fa543611bbe
parent 9907 3b068c3a1c74
child 9909 dce9a6923bb7
equal deleted inserted replaced
9907:3b068c3a1c74 9908:0fa543611bbe
     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;
   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.
   683 		const SettingDescBase *sdb = &sd->desc;
   696 		const SettingDescBase *sdb = &sd->desc;
   684 		const SaveLoad        *sld = &sd->save;
   697 		const SaveLoad        *sld = &sd->save;
   685 
   698 
   686 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   699 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   687 
   700 
   688 		// XXX - wtf is this?? (group override?)
   701 		/* XXX - wtf is this?? (group override?) */
   689 		s = strchr(sdb->name, '.');
   702 		s = strchr(sdb->name, '.');
   690 		if (s != NULL) {
   703 		if (s != NULL) {
   691 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   704 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   692 			s++;
   705 			s++;
   693 		} else {
   706 		} else {
   759 		/* If the setting is not saved to the configuration
   772 		/* If the setting is not saved to the configuration
   760 		 * file, just continue with the next setting */
   773 		 * file, just continue with the next setting */
   761 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   774 		if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
   762 		if (sld->conv & SLF_CONFIG_NO) continue;
   775 		if (sld->conv & SLF_CONFIG_NO) continue;
   763 
   776 
   764 		// XXX - wtf is this?? (group override?)
   777 		/* XXX - wtf is this?? (group override?) */
   765 		s = strchr(sdb->name, '.');
   778 		s = strchr(sdb->name, '.');
   766 		if (s != NULL) {
   779 		if (s != NULL) {
   767 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   780 			group = ini_getgroup(ini, sdb->name, s - sdb->name);
   768 			s++;
   781 			s++;
   769 		} else {
   782 		} else {
   774 
   787 
   775 		item = ini_getitem(group, s, true);
   788 		item = ini_getitem(group, s, true);
   776 		ptr = GetVariableAddress(object, sld);
   789 		ptr = GetVariableAddress(object, sld);
   777 
   790 
   778 		if (item->value != NULL) {
   791 		if (item->value != NULL) {
   779 			// check if the value is the same as the old value
   792 			/* check if the value is the same as the old value */
   780 			const void *p = string_to_val(sdb, item->value);
   793 			const void *p = string_to_val(sdb, item->value);
   781 
   794 
   782 			/* The main type of a variable/setting is in bytes 8-15
   795 			/* 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 */
   796 			 * The subtype (what kind of numbers do we have there) is in 0-7 */
   784 			switch (sdb->cmd) {
   797 			switch (sdb->cmd) {
   927  * We have two types of list:
   940  * We have two types of list:
   928  * 1. SDTG_something
   941  * 1. SDTG_something
   929  * 2. SDT_something
   942  * 2. SDT_something
   930  * The 'G' stands for global, so this is the one you will use for a
   943  * 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
   944  * 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).
   945  * Base/Offset and runtime variable selection mechanism, known from the saveload
       
   946  * 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
   947  * Of each type there are again two versions, the normal one and one prefixed
   934  * with 'COND'.
   948  * with 'COND'.
   935  * COND means that the setting is only valid in certain savegame versions
   949  * COND means that the setting is only valid in certain savegame versions
   936  * (since patches are saved to the savegame, this bookkeeping is necessary.
   950  * (since patches are saved to the savegame, this bookkeeping is necessary.
   937  * Now there are a lot of types. Easy ones are:
   951  * Now there are a lot of types. Easy ones are:
  1050 #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL, NULL}, SLE_END()}
  1064 #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, NULL, NULL}, SLE_END()}
  1051 
  1065 
  1052 /* Shortcuts for macros below. Logically if we don't save the value
  1066 /* Shortcuts for macros below. Logically if we don't save the value
  1053  * we also don't sync it in a network game */
  1067  * we also don't sync it in a network game */
  1054 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1068 #define S SLF_SAVE_NO | SLF_NETWORK_NO
  1055 #define NS SLF_SAVE_NO
       
  1056 #define C SLF_CONFIG_NO
  1069 #define C SLF_CONFIG_NO
  1057 #define N SLF_NETWORK_NO
  1070 #define N SLF_NETWORK_NO
  1058 
  1071 
  1059 #define D0 SGF_0ISDISABLED
  1072 #define D0 SGF_0ISDISABLED
  1060 #define NC SGF_NOCOMMA
  1073 #define NC SGF_NOCOMMA
  1067 /* Begin - Callback Functions for the various settings */
  1080 /* Begin - Callback Functions for the various settings */
  1068 #include "window.h"
  1081 #include "window.h"
  1069 #include "gui.h"
  1082 #include "gui.h"
  1070 #include "town.h"
  1083 #include "town.h"
  1071 #include "gfx.h"
  1084 #include "gfx.h"
  1072 // virtual PositionMainToolbar function, calls the right one.
  1085 /* virtual PositionMainToolbar function, calls the right one.*/
  1073 static int32 v_PositionMainToolbar(int32 p1)
  1086 static int32 v_PositionMainToolbar(int32 p1)
  1074 {
  1087 {
  1075 	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
  1088 	if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
  1076 	return 0;
  1089 	return 0;
  1077 }
  1090 }
  1203 	 SDTG_END()
  1216 	 SDTG_END()
  1204 };
  1217 };
  1205 #endif /* WIN32 */
  1218 #endif /* WIN32 */
  1206 
  1219 
  1207 static const SettingDescGlobVarList _misc_settings[] = {
  1220 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),
  1221 	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_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),
  1222 	 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),
  1223 	 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),
  1224 	  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),
  1225 	  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),
  1226 	  SDTG_STR("sounddriver",      SLE_STRB,C|S,0, _ini_sounddriver,       NULL,    STR_NULL, NULL),
  1378 	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
  1391 	 SDT_VAR(Patches, colored_news_year,SLE_INT32, 0,NC,  2000, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_COLORED_NEWS_YEAR,NULL),
  1379 	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
  1392 	 SDT_VAR(Patches, starting_year,    SLE_INT32, 0,NC,  1950, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_STARTING_YEAR,NULL),
  1380 	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
  1393 	 SDT_VAR(Patches, ending_year,      SLE_INT32,0,NC|NO,2051, MIN_YEAR, MAX_YEAR, 1, STR_CONFIG_PATCHES_ENDING_YEAR,  NULL),
  1381 	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
  1394 	SDT_BOOL(Patches, smooth_economy,             0, 0,  true,            STR_CONFIG_PATCHES_SMOOTH_ECONOMY,   NULL),
  1382 	SDT_BOOL(Patches, allow_shares,               0, 0, false,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
  1395 	SDT_BOOL(Patches, allow_shares,               0, 0, false,            STR_CONFIG_PATCHES_ALLOW_SHARES,     NULL),
       
  1396 	SDT_CONDVAR(Patches, town_growth_rate, SLE_UINT8, 54, SL_MAX_VERSION, 0, MS, 2, 0,   4, 0, STR_CONFIG_PATCHES_TOWN_GROWTH,  NULL),
       
  1397 	SDT_CONDVAR(Patches, larger_towns,     SLE_UINT8, 54, SL_MAX_VERSION, 0, D0, 4, 0, 255, 1, STR_CONFIG_PATCHES_LARGER_TOWNS, NULL),
  1383 
  1398 
  1384 	/***************************************************************************/
  1399 	/***************************************************************************/
  1385 	/* AI section of the GUI-configure patches window */
  1400 	/* AI section of the GUI-configure patches window */
  1386 	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
  1401 	SDT_BOOL(Patches, ainew_active,           0, 0, false, STR_CONFIG_PATCHES_AINEW_ACTIVE,      AiNew_PatchActive_Warning),
  1387 	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
  1402 	SDT_BOOL(Patches, ai_in_multiplayer,      0, 0, false, STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER, Ai_In_Multiplayer_Warning),
  1459 	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
  1474 	SDT_VAR(Patches, npf_crossing_penalty,          SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH),  0, 100000, 0, STR_NULL, NULL),
  1460 	/* This is the penalty for drive-through road, stops. */
  1475 	/* This is the penalty for drive-through road, stops. */
  1461 	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),
  1476 	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),
  1462 
  1477 
  1463 
  1478 
  1464 	// The maximum number of nodes to search
  1479 	/* The maximum number of nodes to search */
  1465 	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
  1480 	SDT_CONDBOOL(Patches, yapf.disable_node_optimization  ,           28, SL_MAX_VERSION, 0, 0, false                   ,                       STR_NULL, NULL),
  1466 	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
  1481 	SDT_CONDVAR (Patches, yapf.max_search_nodes           , SLE_UINT, 28, SL_MAX_VERSION, 0, 0, 10000                   ,      500, 1000000, 0, STR_NULL, NULL),
  1467 	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
  1482 	SDT_CONDBOOL(Patches, yapf.rail_firstred_twoway_eol   ,           28, SL_MAX_VERSION, 0, 0,  true                   ,                       STR_NULL, NULL),
  1468 	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),
  1483 	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),
  1469 	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),
  1484 	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),
  1471 	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),
  1486 	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),
  1472 	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),
  1487 	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),
  1473 	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),
  1488 	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),
  1474 	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),
  1489 	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),
  1475 	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),
  1490 	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),
  1476 	// This penalty is applied when a train reverses inside a depot
  1491 	/* This penalty is applied when a train reverses inside a depot */
  1477 	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),
  1492 	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),
  1478 	// This is the penalty for level crossings (for trains only)
  1493 	/* This is the penalty for level crossings (for trains only) */
  1479 	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),
  1494 	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),
  1480 	// look-ahead how many signals are checked
  1495 	/* look-ahead how many signals are checked */
  1481 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
  1496 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_max_signals, SLE_UINT, 28, SL_MAX_VERSION, 0, 0,    10                   ,        1,     100, 0, STR_NULL, NULL),
  1482 	// look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0
  1497 	/* look-ahead n-th red signal penalty polynomial: penalty = p2 * n^2 + p1 * n + p0 */
  1483 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1498 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p0  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,   500                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1484 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1499 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p1  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,  -100                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1485 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1500 	SDT_CONDVAR (Patches, yapf.rail_look_ahead_signal_p2  , SLE_INT , 28, SL_MAX_VERSION, 0, 0,     5                   , -1000000, 1000000, 0, STR_NULL, NULL),
  1486 	// penalties for too long or too short station platforms
  1501 	/* penalties for too long or too short station platforms */
  1487 	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),
  1502 	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),
  1488 	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),
  1503 	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),
  1489 	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),
  1504 	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),
  1490 	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),
  1505 	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),
  1491 	// road vehicles - penalties
  1506 	/* road vehicles - penalties */
  1492 	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),
  1507 	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),
  1493 	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),
  1508 	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),
  1494 	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),
  1509 	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),
  1495 	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),
  1510 	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),
  1496 
  1511 
  1575 
  1590 
  1576 	if (group == NULL) return NULL;
  1591 	if (group == NULL) return NULL;
  1577 
  1592 
  1578 	for (item = group->item; item != NULL; item = item->next) {
  1593 	for (item = group->item; item != NULL; item = item->next) {
  1579 		GRFConfig *c = CallocT<GRFConfig>(1);
  1594 		GRFConfig *c = CallocT<GRFConfig>(1);
  1580 		c->filename = strdup(item->name);
  1595 		c->full_path = strdup(item->name);
  1581 
  1596 
  1582 		/* Parse parameters */
  1597 		/* Parse parameters */
  1583 		if (*item->value != '\0') {
  1598 		if (*item->value != '\0') {
  1584 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1599 			c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
  1585 			if (c->num_params == (byte)-1) {
  1600 			if (c->num_params == (byte)-1) {
  1652 
  1667 
  1653 	for (c = list; c != NULL; c = c->next) {
  1668 	for (c = list; c != NULL; c = c->next) {
  1654 		char params[512];
  1669 		char params[512];
  1655 		GRFBuildParamList(params, c, lastof(params));
  1670 		GRFBuildParamList(params, c, lastof(params));
  1656 
  1671 
  1657 		*item = ini_item_alloc(group, c->filename, strlen(c->filename));
  1672 		*item = ini_item_alloc(group, c->full_path, strlen(c->full_path));
  1658 		(*item)->value = (char*)pool_strdup(&ini->pool, params, strlen(params));
  1673 		(*item)->value = (char*)pool_strdup(&ini->pool, params, strlen(params));
  1659 		item = &(*item)->next;
  1674 		item = &(*item)->next;
  1660 	}
  1675 	}
  1661 }
  1676 }
  1662 
  1677 
  1828 
  1843 
  1829 	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
  1844 	IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
  1830 		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
  1845 		name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
  1831 }
  1846 }
  1832 
  1847 
       
  1848 void IConsoleListPatches()
       
  1849 {
       
  1850 	IConsolePrintF(_icolour_warn, "All patches with their current value:");
       
  1851 
       
  1852 	for (const SettingDesc *sd = _patch_settings; sd->save.cmd != SL_END; sd++) {
       
  1853 		char value[80];
       
  1854 		const void *ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_patches_newgame : &_patches, &sd->save);
       
  1855 
       
  1856 		if (sd->desc.cmd == SDT_BOOLX) {
       
  1857 			snprintf(value, lengthof(value), (*(bool*)ptr == 1) ? "on" : "off");
       
  1858 		} else {
       
  1859 			snprintf(value, lengthof(value), "%d", (uint32)ReadValue(ptr, sd->save.conv));
       
  1860 		}
       
  1861 		IConsolePrintF(_icolour_def, "%s = %s", sd->desc.name, value);
       
  1862 	}
       
  1863 
       
  1864 	IConsolePrintF(_icolour_warn, "Use 'patch' command to change a value");
       
  1865 }
       
  1866 
  1833 /** Save and load handler for patches/settings
  1867 /** Save and load handler for patches/settings
  1834  * @param osd SettingDesc struct containing all information
  1868  * @param osd SettingDesc struct containing all information
  1835  * @param object can be either NULL in which case we load global variables or
  1869  * @param object can be either NULL in which case we load global variables or
  1836  * a pointer to a struct which is getting saved */
  1870  * a pointer to a struct which is getting saved */
  1837 static void LoadSettings(const SettingDesc *osd, void *object)
  1871 static void LoadSettings(const SettingDesc *osd, void *object)