00001
00002
00003
00004
00005
00006
00007
00008
00009
00025 #include "stdafx.h"
00026 #include "currency.h"
00027 #include "screenshot.h"
00028 #include "variables.h"
00029 #include "network/network.h"
00030 #include "network/network_func.h"
00031 #include "settings_internal.h"
00032 #include "command_func.h"
00033 #include "console_func.h"
00034 #include "pathfinder/pathfinder_type.h"
00035 #include "genworld.h"
00036 #include "train.h"
00037 #include "news_func.h"
00038 #include "window_func.h"
00039 #include "strings_func.h"
00040 #include "vehicle_func.h"
00041 #include "sound_func.h"
00042 #include "company_func.h"
00043 #include "rev.h"
00044 #ifdef WITH_FREETYPE
00045 #include "fontcache.h"
00046 #endif
00047 #include "textbuf_gui.h"
00048 #include "rail_gui.h"
00049 #include "elrail_func.h"
00050 #include "gui.h"
00051 #include "town.h"
00052 #include "video/video_driver.hpp"
00053 #include "sound/sound_driver.hpp"
00054 #include "music/music_driver.hpp"
00055 #include "blitter/factory.hpp"
00056 #include "base_media_base.h"
00057 #include "gamelog.h"
00058 #include "settings_func.h"
00059 #include "ini_type.h"
00060 #include "ai/ai_config.hpp"
00061 #include "ai/ai.hpp"
00062 #include "newgrf.h"
00063 #include "ship.h"
00064 #include "company_base.h"
00065 #include "engine_base.h"
00066
00067 #include "void_map.h"
00068 #include "station_base.h"
00069
00070 #include "table/strings.h"
00071 #include "table/settings.h"
00072
00073 ClientSettings _settings_client;
00074 GameSettings _settings_game;
00075 GameSettings _settings_newgame;
00076 VehicleDefaultSettings _old_vds;
00077
00078 typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object);
00079 typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list);
00080
00081 static bool IsSignedVarMemType(VarType vt);
00082
00086 static const char * const _list_group_names[] = {
00087 "bans",
00088 "newgrf",
00089 "servers",
00090 "server_bind_addresses",
00091 NULL
00092 };
00093
00099 static int lookup_oneofmany(const char *many, const char *one, size_t onelen = 0)
00100 {
00101 const char *s;
00102 int idx;
00103
00104 if (onelen == 0) onelen = strlen(one);
00105
00106
00107 if (*one >= '0' && *one <= '9')
00108 return strtoul(one, NULL, 0);
00109
00110 idx = 0;
00111 for (;;) {
00112
00113 s = many;
00114 while (*s != '|' && *s != 0) s++;
00115 if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx;
00116 if (*s == 0) return -1;
00117 many = s + 1;
00118 idx++;
00119 }
00120 }
00121
00127 static uint32 lookup_manyofmany(const char *many, const char *str)
00128 {
00129 const char *s;
00130 int r;
00131 uint32 res = 0;
00132
00133 for (;;) {
00134
00135 while (*str == ' ' || *str == '\t' || *str == '|') str++;
00136 if (*str == 0) break;
00137
00138 s = str;
00139 while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
00140
00141 r = lookup_oneofmany(many, str, s - str);
00142 if (r == -1) return (uint32)-1;
00143
00144 SetBit(res, r);
00145 if (*s == 0) break;
00146 str = s + 1;
00147 }
00148 return res;
00149 }
00150
00157 static int parse_intlist(const char *p, int *items, int maxitems)
00158 {
00159 int n = 0, v;
00160 char *end;
00161
00162 for (;;) {
00163 v = strtol(p, &end, 0);
00164 if (p == end || n == maxitems) return -1;
00165 p = end;
00166 items[n++] = v;
00167 if (*p == '\0') break;
00168 if (*p != ',' && *p != ' ') return -1;
00169 p++;
00170 }
00171
00172 return n;
00173 }
00174
00181 static bool load_intlist(const char *str, void *array, int nelems, VarType type)
00182 {
00183 int items[64];
00184 int i, nitems;
00185
00186 if (str == NULL) {
00187 memset(items, 0, sizeof(items));
00188 nitems = nelems;
00189 } else {
00190 nitems = parse_intlist(str, items, lengthof(items));
00191 if (nitems != nelems) return false;
00192 }
00193
00194 switch (type) {
00195 case SLE_VAR_BL:
00196 case SLE_VAR_I8:
00197 case SLE_VAR_U8:
00198 for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i];
00199 break;
00200 case SLE_VAR_I16:
00201 case SLE_VAR_U16:
00202 for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i];
00203 break;
00204 case SLE_VAR_I32:
00205 case SLE_VAR_U32:
00206 for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i];
00207 break;
00208 default: NOT_REACHED();
00209 }
00210
00211 return true;
00212 }
00213
00221 static void make_intlist(char *buf, const char *last, const void *array, int nelems, VarType type)
00222 {
00223 int i, v = 0;
00224 byte *p = (byte*)array;
00225
00226 for (i = 0; i != nelems; i++) {
00227 switch (type) {
00228 case SLE_VAR_BL:
00229 case SLE_VAR_I8: v = *(int8*)p; p += 1; break;
00230 case SLE_VAR_U8: v = *(byte*)p; p += 1; break;
00231 case SLE_VAR_I16: v = *(int16*)p; p += 2; break;
00232 case SLE_VAR_U16: v = *(uint16*)p; p += 2; break;
00233 case SLE_VAR_I32: v = *(int32*)p; p += 4; break;
00234 case SLE_VAR_U32: v = *(uint32*)p; p += 4; break;
00235 default: NOT_REACHED();
00236 }
00237 buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v);
00238 }
00239 }
00240
00246 static void make_oneofmany(char *buf, const char *last, const char *many, int id)
00247 {
00248 int orig_id = id;
00249
00250
00251 while (--id >= 0) {
00252 for (; *many != '|'; many++) {
00253 if (*many == '\0') {
00254 seprintf(buf, last, "%d", orig_id);
00255 return;
00256 }
00257 }
00258 many++;
00259 }
00260
00261
00262 while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++;
00263 *buf = '\0';
00264 }
00265
00272 static void make_manyofmany(char *buf, const char *last, const char *many, uint32 x)
00273 {
00274 const char *start;
00275 int i = 0;
00276 bool init = true;
00277
00278 for (; x != 0; x >>= 1, i++) {
00279 start = many;
00280 while (*many != 0 && *many != '|') many++;
00281
00282 if (HasBit(x, 0)) {
00283 if (!init) buf += seprintf(buf, last, "|");
00284 init = false;
00285 if (start == many) {
00286 buf += seprintf(buf, last, "%d", i);
00287 } else {
00288 memcpy(buf, start, many - start);
00289 buf += many - start;
00290 }
00291 }
00292
00293 if (*many == '|') many++;
00294 }
00295
00296 *buf = '\0';
00297 }
00298
00303 static const void *string_to_val(const SettingDescBase *desc, const char *orig_str)
00304 {
00305 const char *str = orig_str == NULL ? "" : orig_str;
00306 switch (desc->cmd) {
00307 case SDT_NUMX: {
00308 char *end;
00309 unsigned long val = strtoul(str, &end, 0);
00310 if (*end != '\0') ShowInfoF("ini: trailing characters at end of setting '%s'", desc->name);
00311 return (void*)val;
00312 }
00313 case SDT_ONEOFMANY: {
00314 long r = lookup_oneofmany(desc->many, str);
00315
00316
00317 if (r == -1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str);
00318 if (r != -1) return (void*)r;
00319 ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
00320 return 0;
00321 }
00322 case SDT_MANYOFMANY: {
00323 unsigned long r = lookup_manyofmany(desc->many, str);
00324 if (r != (unsigned long)-1) return (void*)r;
00325 ShowInfoF("ini: invalid value '%s' for '%s'", str, desc->name);
00326 return 0;
00327 }
00328 case SDT_BOOLX:
00329 if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0)
00330 return (void*)true;
00331 if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0)
00332 return (void*)false;
00333 ShowInfoF("ini: invalid setting value '%s' for '%s'", str, desc->name);
00334 break;
00335
00336 case SDT_STRING: return orig_str;
00337 case SDT_INTLIST: return str;
00338 default: break;
00339 }
00340
00341 return NULL;
00342 }
00343
00351 static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val)
00352 {
00353 const SettingDescBase *sdb = &sd->desc;
00354
00355 if (sdb->cmd != SDT_BOOLX &&
00356 sdb->cmd != SDT_NUMX &&
00357 sdb->cmd != SDT_ONEOFMANY &&
00358 sdb->cmd != SDT_MANYOFMANY) {
00359 return;
00360 }
00361
00362
00363 if (sdb->cmd != SDT_MANYOFMANY) {
00364
00365
00366
00367
00368
00369 switch (GetVarMemType(sd->save.conv)) {
00370 case SLE_VAR_NULL: return;
00371 case SLE_VAR_BL:
00372 case SLE_VAR_I8:
00373 case SLE_VAR_U8:
00374 case SLE_VAR_I16:
00375 case SLE_VAR_U16:
00376 case SLE_VAR_I32: {
00377
00378 if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max);
00379 } break;
00380 case SLE_VAR_U32: {
00381
00382 uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min;
00383 WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max));
00384 return;
00385 }
00386 case SLE_VAR_I64:
00387 case SLE_VAR_U64:
00388 default: NOT_REACHED();
00389 }
00390 }
00391
00392 WriteValue(ptr, sd->save.conv, (int64)val);
00393 }
00394
00401 static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
00402 {
00403 IniGroup *group;
00404 IniGroup *group_def = ini->GetGroup(grpname);
00405 IniItem *item;
00406 const void *p;
00407 void *ptr;
00408 const char *s;
00409
00410 for (; sd->save.cmd != SL_END; sd++) {
00411 const SettingDescBase *sdb = &sd->desc;
00412 const SaveLoad *sld = &sd->save;
00413
00414 if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
00415
00416
00417 s = strchr(sdb->name, '.');
00418 if (s != NULL) {
00419 group = ini->GetGroup(sdb->name, s - sdb->name);
00420 s++;
00421 } else {
00422 s = sdb->name;
00423 group = group_def;
00424 }
00425
00426 item = group->GetItem(s, false);
00427 if (item == NULL && group != group_def) {
00428
00429
00430 item = group_def->GetItem(s, false);
00431 }
00432 if (item == NULL) {
00433
00434
00435 const char *sc = strchr(s, '.');
00436 if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false);
00437 }
00438
00439 p = (item == NULL) ? sdb->def : string_to_val(sdb, item->value);
00440 ptr = GetVariableAddress(object, sld);
00441
00442 switch (sdb->cmd) {
00443 case SDT_BOOLX:
00444 case SDT_NUMX:
00445 case SDT_ONEOFMANY:
00446 case SDT_MANYOFMANY:
00447 Write_ValidateSetting(ptr, sd, (int32)(size_t)p); break;
00448
00449 case SDT_STRING:
00450 switch (GetVarMemType(sld->conv)) {
00451 case SLE_VAR_STRB:
00452 case SLE_VAR_STRBQ:
00453 if (p != NULL) ttd_strlcpy((char*)ptr, (const char*)p, sld->length);
00454 break;
00455 case SLE_VAR_STR:
00456 case SLE_VAR_STRQ:
00457 free(*(char**)ptr);
00458 *(char**)ptr = p == NULL ? NULL : strdup((const char*)p);
00459 break;
00460 case SLE_VAR_CHAR: if (p != NULL) *(char*)ptr = *(char*)p; break;
00461 default: NOT_REACHED();
00462 }
00463 break;
00464
00465 case SDT_INTLIST: {
00466 if (!load_intlist((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) {
00467 ShowInfoF("ini: error in array '%s'", sdb->name);
00468 } else if (sd->desc.proc_cnvt != NULL) {
00469 sd->desc.proc_cnvt((const char*)p);
00470 }
00471 break;
00472 }
00473 default: NOT_REACHED();
00474 }
00475 }
00476 }
00477
00489 static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object)
00490 {
00491 IniGroup *group_def = NULL, *group;
00492 IniItem *item;
00493 char buf[512];
00494 const char *s;
00495 void *ptr;
00496
00497 for (; sd->save.cmd != SL_END; sd++) {
00498 const SettingDescBase *sdb = &sd->desc;
00499 const SaveLoad *sld = &sd->save;
00500
00501
00502
00503 if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue;
00504 if (sld->conv & SLF_CONFIG_NO) continue;
00505
00506
00507 s = strchr(sdb->name, '.');
00508 if (s != NULL) {
00509 group = ini->GetGroup(sdb->name, s - sdb->name);
00510 s++;
00511 } else {
00512 if (group_def == NULL) group_def = ini->GetGroup(grpname);
00513 s = sdb->name;
00514 group = group_def;
00515 }
00516
00517 item = group->GetItem(s, true);
00518 ptr = GetVariableAddress(object, sld);
00519
00520 if (item->value != NULL) {
00521
00522 const void *p = string_to_val(sdb, item->value);
00523
00524
00525
00526 switch (sdb->cmd) {
00527 case SDT_BOOLX:
00528 case SDT_NUMX:
00529 case SDT_ONEOFMANY:
00530 case SDT_MANYOFMANY:
00531 switch (GetVarMemType(sld->conv)) {
00532 case SLE_VAR_BL:
00533 if (*(bool*)ptr == (p != NULL)) continue;
00534 break;
00535 case SLE_VAR_I8:
00536 case SLE_VAR_U8:
00537 if (*(byte*)ptr == (byte)(unsigned long)p) continue;
00538 break;
00539 case SLE_VAR_I16:
00540 case SLE_VAR_U16:
00541 if (*(uint16*)ptr == (uint16)(unsigned long)p) continue;
00542 break;
00543 case SLE_VAR_I32:
00544 case SLE_VAR_U32:
00545 if (*(uint32*)ptr == (uint32)(unsigned long)p) continue;
00546 break;
00547 default: NOT_REACHED();
00548 }
00549 break;
00550 default: break;
00551 }
00552 }
00553
00554
00555 switch (sdb->cmd) {
00556 case SDT_BOOLX:
00557 case SDT_NUMX:
00558 case SDT_ONEOFMANY:
00559 case SDT_MANYOFMANY: {
00560 uint32 i = (uint32)ReadValue(ptr, sld->conv);
00561
00562 switch (sdb->cmd) {
00563 case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break;
00564 case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break;
00565 case SDT_ONEOFMANY: make_oneofmany(buf, lastof(buf), sdb->many, i); break;
00566 case SDT_MANYOFMANY: make_manyofmany(buf, lastof(buf), sdb->many, i); break;
00567 default: NOT_REACHED();
00568 }
00569 } break;
00570
00571 case SDT_STRING:
00572 switch (GetVarMemType(sld->conv)) {
00573 case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break;
00574 case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break;
00575 case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break;
00576 case SLE_VAR_STRQ:
00577 if (*(char**)ptr == NULL) {
00578 buf[0] = '\0';
00579 } else {
00580 seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr);
00581 }
00582 break;
00583 case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break;
00584 default: NOT_REACHED();
00585 }
00586 break;
00587
00588 case SDT_INTLIST:
00589 make_intlist(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv));
00590 break;
00591 default: NOT_REACHED();
00592 }
00593
00594
00595 free(item->value);
00596 item->value = strdup(buf);
00597 }
00598 }
00599
00608 static void ini_load_setting_list(IniFile *ini, const char *grpname, StringList *list)
00609 {
00610 IniGroup *group = ini->GetGroup(grpname);
00611
00612 if (group == NULL || list == NULL) return;
00613
00614 list->Clear();
00615
00616 for (const IniItem *item = group->item; item != NULL; item = item->next) {
00617 if (item->name != NULL) *list->Append() = strdup(item->name);
00618 }
00619 }
00620
00629 static void ini_save_setting_list(IniFile *ini, const char *grpname, StringList *list)
00630 {
00631 IniGroup *group = ini->GetGroup(grpname);
00632
00633 if (group == NULL || list == NULL) return;
00634 group->Clear();
00635
00636 for (char **iter = list->Begin(); iter != list->End(); iter++) {
00637 group->GetItem(*iter, true)->SetValue("");
00638 }
00639 }
00640
00641
00642
00643 static bool v_PositionMainToolbar(int32 p1)
00644 {
00645 if (_game_mode != GM_MENU) PositionMainToolbar(NULL);
00646 return true;
00647 }
00648
00649 static bool PopulationInLabelActive(int32 p1)
00650 {
00651 UpdateAllTownVirtCoords();
00652 return true;
00653 }
00654
00655 static bool RedrawScreen(int32 p1)
00656 {
00657 MarkWholeScreenDirty();
00658 return true;
00659 }
00660
00661 static bool InvalidateDetailsWindow(int32 p1)
00662 {
00663 SetWindowClassesDirty(WC_VEHICLE_DETAILS);
00664 return true;
00665 }
00666
00667 static bool InvalidateStationBuildWindow(int32 p1)
00668 {
00669 SetWindowDirty(WC_BUILD_STATION, 0);
00670 return true;
00671 }
00672
00673 static bool InvalidateBuildIndustryWindow(int32 p1)
00674 {
00675 InvalidateWindowData(WC_BUILD_INDUSTRY, 0);
00676 return true;
00677 }
00678
00679 static bool CloseSignalGUI(int32 p1)
00680 {
00681 if (p1 == 0) {
00682 DeleteWindowByClass(WC_BUILD_SIGNAL);
00683 }
00684 return true;
00685 }
00686
00687 static bool InvalidateTownViewWindow(int32 p1)
00688 {
00689 InvalidateWindowClassesData(WC_TOWN_VIEW, p1);
00690 return true;
00691 }
00692
00693 static bool DeleteSelectStationWindow(int32 p1)
00694 {
00695 DeleteWindowById(WC_SELECT_STATION, 0);
00696 return true;
00697 }
00698
00699 static bool UpdateConsists(int32 p1)
00700 {
00701 Train *t;
00702 FOR_ALL_TRAINS(t) {
00703
00704 if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(true);
00705 }
00706 return true;
00707 }
00708
00709
00710 static bool CheckInterval(int32 p1)
00711 {
00712 VehicleDefaultSettings *vds;
00713 if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) {
00714 vds = &_settings_client.company.vehicle;
00715 } else {
00716 vds = &Company::Get(_current_company)->settings.vehicle;
00717 }
00718
00719 if (p1) {
00720 vds->servint_trains = 50;
00721 vds->servint_roadveh = 50;
00722 vds->servint_aircraft = 50;
00723 vds->servint_ships = 50;
00724 } else {
00725 vds->servint_trains = 150;
00726 vds->servint_roadveh = 150;
00727 vds->servint_aircraft = 360;
00728 vds->servint_ships = 100;
00729 }
00730
00731 InvalidateDetailsWindow(0);
00732
00733 return true;
00734 }
00735
00736 static bool TrainAccelerationModelChanged(int32 p1)
00737 {
00738 Train *t;
00739 FOR_ALL_TRAINS(t) {
00740 if (t->IsFrontEngine()) {
00741 t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit();
00742 t->UpdateAcceleration();
00743 }
00744 }
00745
00746 return true;
00747 }
00748
00754 static bool TrainSlopeSteepnessChanged(int32 p1)
00755 {
00756 Train *t;
00757 FOR_ALL_TRAINS(t) {
00758 if (t->IsFrontEngine()) t->CargoChanged();
00759 }
00760
00761 return true;
00762 }
00763
00764 static bool DragSignalsDensityChanged(int32)
00765 {
00766 InvalidateWindowData(WC_BUILD_SIGNAL, 0);
00767
00768 return true;
00769 }
00770
00771 static bool TownFoundingChanged(int32 p1)
00772 {
00773 if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) {
00774 DeleteWindowById(WC_FOUND_TOWN, 0);
00775 return true;
00776 }
00777 InvalidateWindowData(WC_FOUND_TOWN, 0);
00778 return true;
00779 }
00780
00781 static bool InvalidateVehTimetableWindow(int32 p1)
00782 {
00783 InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, -2);
00784 return true;
00785 }
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808 static const DifficultySettings _default_game_diff[3] = {
00809
00810 {2, 2, 4, 300000, 2, 0, 2, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0},
00811 {4, 2, 3, 150000, 3, 1, 3, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1},
00812 {7, 3, 3, 100000, 4, 1, 3, 2, 0, 2, 3, 2, 1, 1, 1, 2, 2},
00813 };
00814
00815 void SetDifficultyLevel(int mode, DifficultySettings *gm_opt)
00816 {
00817 assert(mode <= 3);
00818
00819 if (mode != 3) {
00820 *gm_opt = _default_game_diff[mode];
00821 } else {
00822 gm_opt->diff_level = 3;
00823 }
00824 }
00825
00830 static void CheckDifficultyLevels()
00831 {
00832 if (_settings_newgame.difficulty.diff_level != 3) {
00833 SetDifficultyLevel(_settings_newgame.difficulty.diff_level, &_settings_newgame.difficulty);
00834 }
00835 }
00836
00837 static bool DifficultyReset(int32 level)
00838 {
00839 SetDifficultyLevel(level, (_game_mode == GM_MENU) ? &_settings_newgame.difficulty : &_settings_game.difficulty);
00840 return true;
00841 }
00842
00843 static bool DifficultyChange(int32)
00844 {
00845 if (_game_mode == GM_MENU) {
00846 if (_settings_newgame.difficulty.diff_level != 3) {
00847 ShowErrorMessage(STR_WARNING_DIFFICULTY_TO_CUSTOM, INVALID_STRING_ID, 0, 0);
00848 _settings_newgame.difficulty.diff_level = 3;
00849 }
00850 SetWindowClassesDirty(WC_SELECT_GAME);
00851 } else {
00852 _settings_game.difficulty.diff_level = 3;
00853 }
00854
00855 if (((_game_mode == GM_MENU) ? _settings_newgame.difficulty : _settings_game.difficulty).max_no_competitors != 0 &&
00856 AI::GetInfoList()->size() == 0 && (!_networking || _network_server)) {
00857 ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, 0, 0, true);
00858 }
00859
00860
00861
00862
00863 if (_networking && FindWindowById(WC_GAME_OPTIONS, 0) != NULL) {
00864 ShowGameDifficulty();
00865 }
00866
00867 return true;
00868 }
00869
00870 static bool DifficultyNoiseChange(int32 i)
00871 {
00872 if (_game_mode == GM_NORMAL) {
00873 UpdateAirportsNoise();
00874 if (_settings_game.economy.station_noise_level) {
00875 InvalidateWindowClassesData(WC_TOWN_VIEW, 0);
00876 }
00877 }
00878
00879 return DifficultyChange(i);
00880 }
00881
00887 static bool CheckRoadSide(int p1)
00888 {
00889 extern bool RoadVehiclesAreBuilt();
00890 return _game_mode == GM_MENU || !RoadVehiclesAreBuilt();
00891 }
00892
00899 static int32 ConvertLandscape(const char *value)
00900 {
00901
00902 return lookup_oneofmany("normal|hilly|desert|candy", value);
00903 }
00904
00905 static bool CheckFreeformEdges(int32 p1)
00906 {
00907 if (_game_mode == GM_MENU) return true;
00908 if (p1 != 0) {
00909 Ship *s;
00910 FOR_ALL_SHIPS(s) {
00911 if (TileX(s->tile) == 0 || TileY(s->tile) == 0) {
00912 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, 0, 0);
00913 return false;
00914 }
00915 }
00916 Station *st;
00917 FOR_ALL_STATIONS(st) {
00918 if (TileX(st->xy) == 0 || TileY(st->xy) == 0) {
00919 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, 0, 0);
00920 return false;
00921 }
00922 }
00923 for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0));
00924 for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i));
00925 } else {
00926 for (uint i = 0; i < MapMaxX(); i++) {
00927 if (TileHeight(TileXY(i, 1)) != 0) {
00928 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
00929 return false;
00930 }
00931 }
00932 for (uint i = 1; i < MapMaxX(); i++) {
00933 if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) {
00934 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
00935 return false;
00936 }
00937 }
00938 for (uint i = 0; i < MapMaxY(); i++) {
00939 if (TileHeight(TileXY(1, i)) != 0) {
00940 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
00941 return false;
00942 }
00943 }
00944 for (uint i = 1; i < MapMaxY(); i++) {
00945 if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) {
00946 ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, 0, 0);
00947 return false;
00948 }
00949 }
00950
00951 for (uint i = 0; i < MapMaxX(); i++) {
00952 SetTileHeight(TileXY(i, 0), 0);
00953 SetTileType(TileXY(i, 0), MP_WATER);
00954 }
00955 for (uint i = 0; i < MapMaxY(); i++) {
00956 SetTileHeight(TileXY(0, i), 0);
00957 SetTileType(TileXY(0, i), MP_WATER);
00958 }
00959 }
00960 MarkWholeScreenDirty();
00961 return true;
00962 }
00963
00968 static bool ChangeDynamicEngines(int32 p1)
00969 {
00970 if (_game_mode == GM_MENU) return true;
00971
00972 const Vehicle *v;
00973 FOR_ALL_VEHICLES(v) {
00974 if (IsCompanyBuildableVehicleType(v)) {
00975 ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, 0, 0);
00976 return false;
00977 }
00978 }
00979
00980
00981 _engine_mngr.ResetToDefaultMapping();
00982 ReloadNewGRFData();
00983
00984 return true;
00985 }
00986
00987 static bool StationCatchmentChanged(int32 p1)
00988 {
00989 Station::RecomputeIndustriesNearForAll();
00990 return true;
00991 }
00992
00993 #ifdef ENABLE_NETWORK
00994
00995 static bool UpdateClientName(int32 p1)
00996 {
00997 NetworkUpdateClientName();
00998 return true;
00999 }
01000
01001 static bool UpdateServerPassword(int32 p1)
01002 {
01003 if (strcmp(_settings_client.network.server_password, "*") == 0) {
01004 _settings_client.network.server_password[0] = '\0';
01005 }
01006
01007 return true;
01008 }
01009
01010 static bool UpdateRconPassword(int32 p1)
01011 {
01012 if (strcmp(_settings_client.network.rcon_password, "*") == 0) {
01013 _settings_client.network.rcon_password[0] = '\0';
01014 }
01015
01016 return true;
01017 }
01018
01019 static bool UpdateClientConfigValues(int32 p1)
01020 {
01021 if (_network_server) NetworkServerSendConfigUpdate();
01022
01023 return true;
01024 }
01025
01026 #endif
01027
01028
01029
01030
01034 static void PrepareOldDiffCustom()
01035 {
01036 memset(_old_diff_custom, 0, sizeof(_old_diff_custom));
01037 }
01038
01045 static void HandleOldDiffCustom(bool savegame)
01046 {
01047 uint options_to_load = GAME_DIFFICULTY_NUM - ((savegame && CheckSavegameVersion(4)) ? 1 : 0);
01048
01049 if (!savegame) {
01050
01051 bool old_diff_custom_used = false;
01052 for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) {
01053 old_diff_custom_used = (_old_diff_custom[i] != 0);
01054 }
01055
01056 if (!old_diff_custom_used) return;
01057 }
01058
01059 for (uint i = 0; i < options_to_load; i++) {
01060 const SettingDesc *sd = &_settings[i];
01061
01062 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
01063 void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save);
01064 Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i]));
01065 }
01066 }
01067
01072 static bool ConvertOldNewsSetting(const char *name, const char *value)
01073 {
01074 if (strcasecmp(name, "openclose") == 0) {
01075
01076
01077
01078
01079 NewsDisplay display = ND_OFF;
01080 if (strcasecmp(value, "full") == 0) {
01081 display = ND_FULL;
01082 } else if (strcasecmp(value, "summarized") == 0) {
01083 display = ND_SUMMARY;
01084 }
01085
01086 _news_type_data[NT_INDUSTRY_OPEN].display = display;
01087 _news_type_data[NT_INDUSTRY_CLOSE].display = display;
01088 return true;
01089 }
01090 return false;
01091 }
01092
01093 static void NewsDisplayLoadConfig(IniFile *ini, const char *grpname)
01094 {
01095 IniGroup *group = ini->GetGroup(grpname);
01096 IniItem *item;
01097
01098
01099 if (group == NULL) return;
01100
01101 for (item = group->item; item != NULL; item = item->next) {
01102 int news_item = -1;
01103 for (int i = 0; i < NT_END; i++) {
01104 if (strcasecmp(item->name, _news_type_data[i].name) == 0) {
01105 news_item = i;
01106 break;
01107 }
01108 }
01109
01110
01111 if (news_item == -1) {
01112
01113 if (!ConvertOldNewsSetting(item->name, item->value)) {
01114 DEBUG(misc, 0, "Invalid display option: %s", item->name);
01115 }
01116
01117 continue;
01118 }
01119
01120 if (strcasecmp(item->value, "full") == 0) {
01121 _news_type_data[news_item].display = ND_FULL;
01122 } else if (strcasecmp(item->value, "off") == 0) {
01123 _news_type_data[news_item].display = ND_OFF;
01124 } else if (strcasecmp(item->value, "summarized") == 0) {
01125 _news_type_data[news_item].display = ND_SUMMARY;
01126 } else {
01127 DEBUG(misc, 0, "Invalid display value: %s", item->value);
01128 continue;
01129 }
01130 }
01131 }
01132
01133 static void AILoadConfig(IniFile *ini, const char *grpname)
01134 {
01135 IniGroup *group = ini->GetGroup(grpname);
01136 IniItem *item;
01137
01138
01139 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
01140 AIConfig::GetConfig(c, true)->ChangeAI(NULL);
01141 }
01142
01143
01144 if (group == NULL) return;
01145
01146 CompanyID c = COMPANY_FIRST;
01147 for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) {
01148 AIConfig *config = AIConfig::GetConfig(c, true);
01149
01150 config->ChangeAI(item->name);
01151 if (!config->HasAI()) {
01152 if (strcmp(item->name, "none") != 0) {
01153 DEBUG(ai, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name);
01154 continue;
01155 }
01156 }
01157 if (item->value != NULL) config->StringToSettings(item->value);
01158 }
01159 }
01160
01161
01162 static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static)
01163 {
01164 IniGroup *group = ini->GetGroup(grpname);
01165 IniItem *item;
01166 GRFConfig *first = NULL;
01167 GRFConfig **curr = &first;
01168
01169 if (group == NULL) return NULL;
01170
01171 for (item = group->item; item != NULL; item = item->next) {
01172 GRFConfig *c = CallocT<GRFConfig>(1);
01173 c->filename = strdup(item->name);
01174
01175
01176 if (!StrEmpty(item->value)) {
01177 c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param));
01178 if (c->num_params == (byte)-1) {
01179 ShowInfoF("ini: error in array '%s'", item->name);
01180 c->num_params = 0;
01181 }
01182 }
01183
01184
01185 if (!FillGRFDetails(c, is_static)) {
01186 const char *msg;
01187
01188 if (c->status == GCS_NOT_FOUND) {
01189 msg = "not found";
01190 } else if (HasBit(c->flags, GCF_UNSAFE)) {
01191 msg = "unsafe for static use";
01192 } else if (HasBit(c->flags, GCF_SYSTEM)) {
01193 msg = "system NewGRF";
01194 } else {
01195 msg = "unknown";
01196 }
01197
01198 ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg);
01199 ClearGRFConfig(&c);
01200 continue;
01201 }
01202
01203
01204 bool duplicate = false;
01205 for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) {
01206 if (gc->grfid == c->grfid) {
01207 ShowInfoF("ini: ignoring NewGRF '%s': duplicate GRF ID with '%s'", item->name, gc->filename);
01208 duplicate = true;
01209 break;
01210 }
01211 }
01212 if (duplicate) {
01213 ClearGRFConfig(&c);
01214 continue;
01215 }
01216
01217
01218 if (is_static) SetBit(c->flags, GCF_STATIC);
01219
01220
01221 *curr = c;
01222 curr = &c->next;
01223 }
01224
01225 return first;
01226 }
01227
01228 static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname)
01229 {
01230 IniGroup *group = ini->GetGroup(grpname);
01231
01232 for (int i = 0; i < NT_END; i++) {
01233 const char *value;
01234 int v = _news_type_data[i].display;
01235
01236 value = (v == ND_OFF ? "off" : (v == ND_SUMMARY ? "summarized" : "full"));
01237
01238 group->GetItem(_news_type_data[i].name, true)->SetValue(value);
01239 }
01240 }
01241
01242 static void AISaveConfig(IniFile *ini, const char *grpname)
01243 {
01244 IniGroup *group = ini->GetGroup(grpname);
01245
01246 if (group == NULL) return;
01247 group->Clear();
01248
01249 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
01250 AIConfig *config = AIConfig::GetConfig(c, true);
01251 const char *name;
01252 char value[1024];
01253 config->SettingsToString(value, lengthof(value));
01254
01255 if (config->HasAI()) {
01256 name = config->GetName();
01257 } else {
01258 name = "none";
01259 }
01260
01261 IniItem *item = new IniItem(group, name, strlen(name));
01262 item->SetValue(value);
01263 }
01264 }
01265
01270 static void SaveVersionInConfig(IniFile *ini)
01271 {
01272 IniGroup *group = ini->GetGroup("version");
01273
01274 char version[9];
01275 snprintf(version, lengthof(version), "%08X", _openttd_newgrf_version);
01276
01277 const char * const versions[][2] = {
01278 { "version_string", _openttd_revision },
01279 { "version_number", version }
01280 };
01281
01282 for (uint i = 0; i < lengthof(versions); i++) {
01283 group->GetItem(versions[i][0], true)->SetValue(versions[i][1]);
01284 }
01285 }
01286
01287
01288 static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list)
01289 {
01290 ini->RemoveGroup(grpname);
01291 IniGroup *group = ini->GetGroup(grpname);
01292 const GRFConfig *c;
01293
01294 for (c = list; c != NULL; c = c->next) {
01295 char params[512];
01296 GRFBuildParamList(params, c, lastof(params));
01297
01298 group->GetItem(c->filename, true)->SetValue(params);
01299 }
01300 }
01301
01302
01303 static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list)
01304 {
01305 proc(ini, (const SettingDesc*)_misc_settings, "misc", NULL);
01306 proc(ini, (const SettingDesc*)_music_settings, "music", &msf);
01307 #if defined(WIN32) && !defined(DEDICATED)
01308 proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL);
01309 #endif
01310
01311 proc(ini, _settings, "patches", &_settings_newgame);
01312 proc(ini, _currency_settings,"currency", &_custom_currency);
01313 proc(ini, _company_settings, "company", &_settings_client.company);
01314
01315 #ifdef ENABLE_NETWORK
01316 proc_list(ini, "server_bind_addresses", &_network_bind_list);
01317 proc_list(ini, "servers", &_network_host_list);
01318 proc_list(ini, "bans", &_network_ban_list);
01319 #endif
01320 }
01321
01322 static IniFile *IniLoadConfig()
01323 {
01324 IniFile *ini = new IniFile(_list_group_names);
01325 ini->LoadFromDisk(_config_file);
01326 return ini;
01327 }
01328
01330 void LoadFromConfig()
01331 {
01332 IniFile *ini = IniLoadConfig();
01333 ResetCurrencies(false);
01334
01335 HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list);
01336 _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
01337 _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true);
01338 NewsDisplayLoadConfig(ini, "news_display");
01339 AILoadConfig(ini, "ai_players");
01340
01341 PrepareOldDiffCustom();
01342 ini_load_settings(ini, _gameopt_settings, "gameopt", &_settings_newgame);
01343 HandleOldDiffCustom(false);
01344
01345 CheckDifficultyLevels();
01346 delete ini;
01347 }
01348
01350 void SaveToConfig()
01351 {
01352 IniFile *ini = IniLoadConfig();
01353
01354
01355 ini->RemoveGroup("patches");
01356 ini->RemoveGroup("yapf");
01357 ini->RemoveGroup("gameopt");
01358
01359 HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list);
01360 GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
01361 GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
01362 NewsDisplaySaveConfig(ini, "news_display");
01363 AISaveConfig(ini, "ai_players");
01364 SaveVersionInConfig(ini);
01365 ini->SaveToDisk(_config_file);
01366 delete ini;
01367 }
01368
01369 void GetGRFPresetList(GRFPresetList *list)
01370 {
01371 list->Clear();
01372
01373 IniFile *ini = IniLoadConfig();
01374 IniGroup *group;
01375 for (group = ini->group; group != NULL; group = group->next) {
01376 if (strncmp(group->name, "preset-", 7) == 0) {
01377 *list->Append() = strdup(group->name + 7);
01378 }
01379 }
01380
01381 delete ini;
01382 }
01383
01384 GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
01385 {
01386 char *section = (char*)alloca(strlen(config_name) + 8);
01387 sprintf(section, "preset-%s", config_name);
01388
01389 IniFile *ini = IniLoadConfig();
01390 GRFConfig *config = GRFLoadConfig(ini, section, false);
01391 delete ini;
01392
01393 return config;
01394 }
01395
01396 void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
01397 {
01398 char *section = (char*)alloca(strlen(config_name) + 8);
01399 sprintf(section, "preset-%s", config_name);
01400
01401 IniFile *ini = IniLoadConfig();
01402 GRFSaveConfig(ini, section, config);
01403 ini->SaveToDisk(_config_file);
01404 delete ini;
01405 }
01406
01407 void DeleteGRFPresetFromConfig(const char *config_name)
01408 {
01409 char *section = (char*)alloca(strlen(config_name) + 8);
01410 sprintf(section, "preset-%s", config_name);
01411
01412 IniFile *ini = IniLoadConfig();
01413 ini->RemoveGroup(section);
01414 ini->SaveToDisk(_config_file);
01415 delete ini;
01416 }
01417
01418 static const SettingDesc *GetSettingDescription(uint index)
01419 {
01420 if (index >= lengthof(_settings)) return NULL;
01421 return &_settings[index];
01422 }
01423
01434 CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01435 {
01436 const SettingDesc *sd = GetSettingDescription(p1);
01437
01438 if (sd == NULL) return CMD_ERROR;
01439 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR;
01440
01441 if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return CMD_ERROR;
01442 if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return CMD_ERROR;
01443 if ((sd->desc.flags & SGF_NEWGAME_ONLY) &&
01444 (_game_mode == GM_NORMAL ||
01445 (_game_mode == GM_EDITOR && (sd->desc.flags & SGF_SCENEDIT_TOO) == 0))) {
01446 return CMD_ERROR;
01447 }
01448
01449 if (flags & DC_EXEC) {
01450 GameSettings *s = (_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game;
01451 void *var = GetVariableAddress(s, &sd->save);
01452
01453 int32 oldval = (int32)ReadValue(var, sd->save.conv);
01454 int32 newval = (int32)p2;
01455
01456 Write_ValidateSetting(var, sd, newval);
01457 newval = (int32)ReadValue(var, sd->save.conv);
01458
01459 if (oldval == newval) return CommandCost();
01460
01461 if (sd->desc.proc != NULL && !sd->desc.proc(newval)) {
01462 WriteValue(var, sd->save.conv, (int64)oldval);
01463 return CommandCost();
01464 }
01465
01466 if (sd->desc.flags & SGF_NO_NETWORK) {
01467 GamelogStartAction(GLAT_SETTING);
01468 GamelogSetting(sd->desc.name, oldval, newval);
01469 GamelogStopAction();
01470 }
01471
01472 SetWindowDirty(WC_GAME_OPTIONS, 0);
01473 }
01474
01475 return CommandCost();
01476 }
01477
01487 CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01488 {
01489 if (p1 >= lengthof(_company_settings)) return CMD_ERROR;
01490 const SettingDesc *sd = &_company_settings[p1];
01491
01492 if (flags & DC_EXEC) {
01493 void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save);
01494
01495 int32 oldval = (int32)ReadValue(var, sd->save.conv);
01496 int32 newval = (int32)p2;
01497
01498 Write_ValidateSetting(var, sd, newval);
01499 newval = (int32)ReadValue(var, sd->save.conv);
01500
01501 if (oldval == newval) return CommandCost();
01502
01503 if (sd->desc.proc != NULL && !sd->desc.proc(newval)) {
01504 WriteValue(var, sd->save.conv, (int64)oldval);
01505 return CommandCost();
01506 }
01507
01508 SetWindowDirty(WC_GAME_OPTIONS, 0);
01509 }
01510
01511 return CommandCost();
01512 }
01513
01520 bool SetSettingValue(uint index, int32 value, bool force_newgame)
01521 {
01522 const SettingDesc *sd = &_settings[index];
01523
01524
01525
01526
01527 if (sd->save.conv & SLF_NETWORK_NO) {
01528 void *var = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
01529 Write_ValidateSetting(var, sd, value);
01530
01531 if (_game_mode != GM_MENU) {
01532 void *var2 = GetVariableAddress(&_settings_newgame, &sd->save);
01533 Write_ValidateSetting(var2, sd, value);
01534 }
01535 if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
01536 SetWindowDirty(WC_GAME_OPTIONS, 0);
01537 return true;
01538 }
01539
01540 if (force_newgame) {
01541 void *var2 = GetVariableAddress(&_settings_newgame, &sd->save);
01542 Write_ValidateSetting(var2, sd, value);
01543 return true;
01544 }
01545
01546
01547 if (!_networking || (_networking && _network_server)) {
01548 return DoCommandP(0, index, value, CMD_CHANGE_SETTING);
01549 }
01550 return false;
01551 }
01552
01558 void SetCompanySetting(uint index, int32 value)
01559 {
01560 const SettingDesc *sd = &_company_settings[index];
01561 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
01562 DoCommandP(0, index, value, CMD_CHANGE_COMPANY_SETTING);
01563 } else {
01564 void *var = GetVariableAddress(&_settings_client.company, &sd->save);
01565 Write_ValidateSetting(var, sd, value);
01566 if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv));
01567 }
01568 }
01569
01573 void SetDefaultCompanySettings(CompanyID cid)
01574 {
01575 Company *c = Company::Get(cid);
01576 const SettingDesc *sd;
01577 for (sd = _company_settings; sd->save.cmd != SL_END; sd++) {
01578 void *var = GetVariableAddress(&c->settings, &sd->save);
01579 Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def);
01580 }
01581 }
01582
01583 #if defined(ENABLE_NETWORK)
01584
01587 void SyncCompanySettings()
01588 {
01589 const SettingDesc *sd;
01590 uint i = 0;
01591 for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) {
01592 const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save);
01593 const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save);
01594 uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv);
01595 uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv);
01596 if (old_value != new_value) NetworkSend_Command(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company);
01597 }
01598 }
01599 #endif
01600
01606 uint GetCompanySettingIndex(const char *name)
01607 {
01608 uint i;
01609 const SettingDesc *sd = GetSettingFromName(name, &i);
01610 assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0);
01611 return i;
01612 }
01613
01620 bool SetSettingValue(uint index, const char *value)
01621 {
01622 const SettingDesc *sd = &_settings[index];
01623 assert(sd->save.conv & SLF_NETWORK_NO);
01624
01625 char *var = (char*)GetVariableAddress(NULL, &sd->save);
01626 ttd_strlcpy(var, value, sd->save.length);
01627 if (sd->desc.proc != NULL) sd->desc.proc(0);
01628
01629 return true;
01630 }
01631
01639 const SettingDesc *GetSettingFromName(const char *name, uint *i)
01640 {
01641 const SettingDesc *sd;
01642
01643
01644 for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
01645 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
01646 if (strcmp(sd->desc.name, name) == 0) return sd;
01647 }
01648
01649
01650 for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) {
01651 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
01652 const char *short_name = strchr(sd->desc.name, '.');
01653 if (short_name != NULL) {
01654 short_name++;
01655 if (strcmp(short_name, name) == 0) return sd;
01656 }
01657 }
01658
01659 if (strncmp(name, "company.", 8) == 0) name += 8;
01660
01661 for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) {
01662 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
01663 if (strcmp(sd->desc.name, name) == 0) return sd;
01664 }
01665
01666 return NULL;
01667 }
01668
01669
01670
01671 void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
01672 {
01673 uint index;
01674 const SettingDesc *sd = GetSettingFromName(name, &index);
01675
01676 if (sd == NULL) {
01677 IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name);
01678 return;
01679 }
01680
01681 bool success;
01682 if (sd->desc.cmd == SDT_STRING) {
01683 success = SetSettingValue(index, value);
01684 } else {
01685 uint32 val;
01686 extern bool GetArgumentInteger(uint32 *value, const char *arg);
01687 success = GetArgumentInteger(&val, value);
01688 if (!success) {
01689 IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value);
01690 return;
01691 }
01692
01693 success = SetSettingValue(index, val, force_newgame);
01694 }
01695
01696 if (!success) {
01697 if (_network_server) {
01698 IConsoleError("This command/variable is not available during network games.");
01699 } else {
01700 IConsoleError("This command/variable is only available to a network server.");
01701 }
01702 }
01703 }
01704
01705 void IConsoleSetSetting(const char *name, int value)
01706 {
01707 uint index;
01708 const SettingDesc *sd = GetSettingFromName(name, &index);
01709 assert(sd != NULL);
01710 SetSettingValue(index, value);
01711 }
01712
01718 void IConsoleGetSetting(const char *name, bool force_newgame)
01719 {
01720 char value[20];
01721 uint index;
01722 const SettingDesc *sd = GetSettingFromName(name, &index);
01723 const void *ptr;
01724
01725 if (sd == NULL) {
01726 IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name);
01727 return;
01728 }
01729
01730 ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save);
01731
01732 if (sd->desc.cmd == SDT_STRING) {
01733 IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (const char *)ptr);
01734 } else {
01735 if (sd->desc.cmd == SDT_BOOLX) {
01736 snprintf(value, sizeof(value), (*(bool*)ptr == 1) ? "on" : "off");
01737 } else {
01738 snprintf(value, sizeof(value), "%d", (int32)ReadValue(ptr, sd->save.conv));
01739 }
01740
01741 IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %d)",
01742 name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max);
01743 }
01744 }
01745
01751 void IConsoleListSettings(const char *prefilter)
01752 {
01753 IConsolePrintF(CC_WARNING, "All settings with their current value:");
01754
01755 for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) {
01756 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
01757 if (prefilter != NULL) {
01758 if (strncmp(sd->desc.name, prefilter, min(strlen(sd->desc.name), strlen(prefilter))) != 0) continue;
01759 }
01760 char value[80];
01761 const void *ptr = GetVariableAddress((_game_mode == GM_MENU) ? &_settings_newgame : &_settings_game, &sd->save);
01762
01763 if (sd->desc.cmd == SDT_BOOLX) {
01764 snprintf(value, lengthof(value), (*(bool*)ptr == 1) ? "on" : "off");
01765 } else if (sd->desc.cmd == SDT_STRING) {
01766 snprintf(value, sizeof(value), "%s", (const char *)ptr);
01767 } else {
01768 snprintf(value, lengthof(value), "%d", (uint32)ReadValue(ptr, sd->save.conv));
01769 }
01770 IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value);
01771 }
01772
01773 IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value");
01774 }
01775
01780 static void LoadSettings(const SettingDesc *osd, void *object)
01781 {
01782 for (; osd->save.cmd != SL_END; osd++) {
01783 const SaveLoad *sld = &osd->save;
01784 void *ptr = GetVariableAddress(object, sld);
01785
01786 if (!SlObjectMember(ptr, sld)) continue;
01787 if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd, ReadValue(ptr, sld->conv));
01788 }
01789 }
01790
01795 static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg)
01796 {
01797 LoadSettings((const SettingDesc*)sdg, NULL);
01798 }
01799
01804 static void SaveSettings(const SettingDesc *sd, void *object)
01805 {
01806
01807
01808 const SettingDesc *i;
01809 size_t length = 0;
01810 for (i = sd; i->save.cmd != SL_END; i++) {
01811 length += SlCalcObjMemberLength(object, &i->save);
01812 }
01813 SlSetLength(length);
01814
01815 for (i = sd; i->save.cmd != SL_END; i++) {
01816 void *ptr = GetVariableAddress(object, &i->save);
01817 SlObjectMember(ptr, &i->save);
01818 }
01819 }
01820
01824 static inline void SaveSettingsGlobList(const SettingDescGlobVarList *sdg)
01825 {
01826 SaveSettings((const SettingDesc*)sdg, NULL);
01827 }
01828
01829 static void Load_OPTS()
01830 {
01831
01832
01833
01834 PrepareOldDiffCustom();
01835 LoadSettings(_gameopt_settings, &_settings_game);
01836 HandleOldDiffCustom(true);
01837 }
01838
01839 static void Load_PATS()
01840 {
01841
01842
01843
01844 LoadSettings(_settings, &_settings_game);
01845 }
01846
01847 static void Save_PATS()
01848 {
01849 SaveSettings(_settings, &_settings_game);
01850 }
01851
01852 void CheckConfig()
01853 {
01854
01855
01856
01857
01858 if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) {
01859 _settings_newgame.pf.opf.pf_maxdepth = 48;
01860 _settings_newgame.pf.opf.pf_maxlength = 4096;
01861 }
01862 }
01863
01864 extern const ChunkHandler _setting_chunk_handlers[] = {
01865 { 'OPTS', NULL, Load_OPTS, NULL, CH_RIFF},
01866 { 'PATS', Save_PATS, Load_PATS, NULL, CH_RIFF | CH_LAST},
01867 };
01868
01869 static bool IsSignedVarMemType(VarType vt)
01870 {
01871 switch (GetVarMemType(vt)) {
01872 case SLE_VAR_I8:
01873 case SLE_VAR_I16:
01874 case SLE_VAR_I32:
01875 case SLE_VAR_I64:
01876 return true;
01877 }
01878 return false;
01879 }