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