00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "currency.h"
00008 #include "gui.h"
00009 #include "window_gui.h"
00010 #include "textbuf_gui.h"
00011 #include "command_func.h"
00012 #include "engine.h"
00013 #include "screenshot.h"
00014 #include "newgrf.h"
00015 #include "network/network.h"
00016 #include "town.h"
00017 #include "variables.h"
00018 #include "settings_internal.h"
00019 #include "newgrf_townname.h"
00020 #include "strings_func.h"
00021 #include "functions.h"
00022 #include "window_func.h"
00023 #include "vehicle_base.h"
00024 #include "core/alloc_func.hpp"
00025 #include "string_func.h"
00026 #include "gfx_func.h"
00027 #include "waypoint.h"
00028 #include "widgets/dropdown_type.h"
00029 #include "widgets/dropdown_func.h"
00030
00031 #include "table/sprites.h"
00032 #include "table/strings.h"
00033
00034 static const StringID _units_dropdown[] = {
00035 STR_UNITS_IMPERIAL,
00036 STR_UNITS_METRIC,
00037 STR_UNITS_SI,
00038 INVALID_STRING_ID
00039 };
00040
00041 static const StringID _driveside_dropdown[] = {
00042 STR_02E9_DRIVE_ON_LEFT,
00043 STR_02EA_DRIVE_ON_RIGHT,
00044 INVALID_STRING_ID
00045 };
00046
00047 static const StringID _autosave_dropdown[] = {
00048 STR_02F7_OFF,
00049 STR_AUTOSAVE_1_MONTH,
00050 STR_02F8_EVERY_3_MONTHS,
00051 STR_02F9_EVERY_6_MONTHS,
00052 STR_02FA_EVERY_12_MONTHS,
00053 INVALID_STRING_ID,
00054 };
00055
00056 static const StringID _designnames_dropdown[] = {
00057 STR_02BE_DEFAULT,
00058 STR_02BF_CUSTOM,
00059 INVALID_STRING_ID
00060 };
00061
00062 static StringID *BuildDynamicDropdown(StringID base, int num)
00063 {
00064 static StringID buf[32 + 1];
00065 StringID *p = buf;
00066 while (--num>=0) *p++ = base++;
00067 *p = INVALID_STRING_ID;
00068 return buf;
00069 }
00070
00071 int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1;
00072 static StringID *_grf_names = NULL;
00073 static int _nb_grf_names = 0;
00074
00075 void InitGRFTownGeneratorNames()
00076 {
00077 free(_grf_names);
00078 _grf_names = GetGRFTownNameList();
00079 _nb_grf_names = 0;
00080 for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++;
00081 }
00082
00083 static inline StringID TownName(int town_name)
00084 {
00085 if (town_name < _nb_orig_names) return STR_TOWNNAME_ORIGINAL_ENGLISH + town_name;
00086 town_name -= _nb_orig_names;
00087 if (town_name < _nb_grf_names) return _grf_names[town_name];
00088 return STR_UNDEFINED;
00089 }
00090
00091 static int GetCurRes()
00092 {
00093 int i;
00094
00095 for (i = 0; i != _num_resolutions; i++) {
00096 if (_resolutions[i][0] == _screen.width &&
00097 _resolutions[i][1] == _screen.height) {
00098 break;
00099 }
00100 }
00101 return i;
00102 }
00103
00104 static inline bool RoadVehiclesAreBuilt()
00105 {
00106 const Vehicle* v;
00107
00108 FOR_ALL_VEHICLES(v) {
00109 if (v->type == VEH_ROAD) return true;
00110 }
00111 return false;
00112 }
00113
00114
00115 enum GameOptionsWidgets {
00116 GAMEOPT_CURRENCY_BTN = 4,
00117 GAMEOPT_DISTANCE_BTN = 6,
00118 GAMEOPT_ROADSIDE_BTN = 8,
00119 GAMEOPT_TOWNNAME_BTN = 10,
00120 GAMEOPT_AUTOSAVE_BTN = 12,
00121 GAMEOPT_VEHICLENAME_BTN = 14,
00122 GAMEOPT_VEHICLENAME_SAVE,
00123 GAMEOPT_LANG_BTN = 17,
00124 GAMEOPT_RESOLUTION_BTN = 19,
00125 GAMEOPT_FULLSCREEN,
00126 GAMEOPT_SCREENSHOT_BTN = 22,
00127 };
00128
00134 static void ShowTownnameDropdown(Window *w, int sel)
00135 {
00136 typedef std::map<StringID, int, StringIDCompare> TownList;
00137 TownList townnames;
00138
00139
00140 for (int i = 0; i < _nb_orig_names; i++) townnames[STR_TOWNNAME_ORIGINAL_ENGLISH + i] = i;
00141
00142
00143 for (int i = 0; i < _nb_grf_names; i++) townnames[_grf_names[i]] = _nb_orig_names + i;
00144
00145 DropDownList *list = new DropDownList();
00146 for (TownList::iterator it = townnames.begin(); it != townnames.end(); it++) {
00147 list->push_back(new DropDownListStringItem((*it).first, (*it).second, !(_game_mode == GM_MENU || (*it).second == sel)));
00148 }
00149
00150 ShowDropDownList(w, list, sel, GAMEOPT_TOWNNAME_BTN);
00151 }
00152
00157 static void ShowLangDropdown(Window *w)
00158 {
00159 typedef std::map<StringID, int, StringIDCompare> LangList;
00160
00161
00162 LangList langs;
00163 for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
00164
00165 DropDownList *list = new DropDownList();
00166 for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
00167 list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
00168 }
00169
00170 ShowDropDownList(w, list, _dynlang.curr, GAMEOPT_LANG_BTN);
00171 }
00172
00173 static void ShowCustCurrency();
00174
00175 static void GameOptionsWndProc(Window *w, WindowEvent *e)
00176 {
00177 switch (e->event) {
00178 case WE_PAINT: {
00179 int i;
00180 StringID str = STR_02BE_DEFAULT;
00181
00182 w->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
00183 if (!w->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
00184 SetDParam(0, str);
00185 SetDParam(1, _currency_specs[_opt_ptr->currency].name);
00186 SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
00187 SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
00188 SetDParam(4, TownName(_opt_ptr->town_name));
00189 SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
00190 SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
00191 i = GetCurRes();
00192 SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
00193 SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
00194 w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
00195
00196 DrawWindowWidgets(w);
00197 DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING);
00198 } break;
00199
00200 case WE_CLICK:
00201 switch (e->we.click.widget) {
00202 case GAMEOPT_CURRENCY_BTN:
00203 ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
00204 break;
00205
00206 case GAMEOPT_DISTANCE_BTN:
00207 ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
00208 break;
00209
00210 case GAMEOPT_ROADSIDE_BTN: {
00211 int i = 0;
00212
00213
00214
00215 if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
00216 i = (-1) ^ (1 << _opt_ptr->road_side);
00217
00218 ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
00219 } break;
00220
00221 case GAMEOPT_TOWNNAME_BTN:
00222 ShowTownnameDropdown(w, _opt_ptr->town_name);
00223 break;
00224
00225 case GAMEOPT_AUTOSAVE_BTN:
00226 ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
00227 break;
00228
00229 case GAMEOPT_VEHICLENAME_BTN:
00230 ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
00231 break;
00232
00233 case GAMEOPT_VEHICLENAME_SAVE:
00234 break;
00235
00236 case GAMEOPT_LANG_BTN:
00237 ShowLangDropdown(w);
00238 break;
00239
00240 case GAMEOPT_RESOLUTION_BTN:
00241 ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
00242 break;
00243
00244 case GAMEOPT_FULLSCREEN:
00245
00246 if (!ToggleFullScreen(!_fullscreen)) {
00247 ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
00248 }
00249 w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
00250 SetWindowDirty(w);
00251 break;
00252
00253 case GAMEOPT_SCREENSHOT_BTN:
00254 ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
00255 break;
00256 }
00257 break;
00258
00259 case WE_DROPDOWN_SELECT:
00260 switch (e->we.dropdown.button) {
00261 case GAMEOPT_VEHICLENAME_BTN:
00262 if (e->we.dropdown.index == 0) {
00263 DeleteCustomEngineNames();
00264 MarkWholeScreenDirty();
00265 } else if (!(_vehicle_design_names & 1)) {
00266 LoadCustomEngineNames();
00267 MarkWholeScreenDirty();
00268 }
00269 break;
00270
00271 case GAMEOPT_CURRENCY_BTN:
00272 if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
00273 _opt_ptr->currency = e->we.dropdown.index;
00274 MarkWholeScreenDirty();
00275 break;
00276
00277 case GAMEOPT_DISTANCE_BTN:
00278 _opt_ptr->units = e->we.dropdown.index;
00279 MarkWholeScreenDirty();
00280 break;
00281
00282 case GAMEOPT_ROADSIDE_BTN:
00283 if (_opt_ptr->road_side != e->we.dropdown.index) {
00284 DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
00285 MarkWholeScreenDirty();
00286 }
00287 break;
00288
00289 case GAMEOPT_TOWNNAME_BTN:
00290 if (_game_mode == GM_MENU) {
00291 _opt_ptr->town_name = e->we.dropdown.index;
00292 InvalidateWindow(WC_GAME_OPTIONS, 0);
00293 }
00294 break;
00295
00296 case GAMEOPT_AUTOSAVE_BTN:
00297 _opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
00298 SetWindowDirty(w);
00299 break;
00300
00301 case GAMEOPT_LANG_BTN:
00302 ReadLanguagePack(e->we.dropdown.index);
00303 CheckForMissingGlyphsInLoadedLanguagePack();
00304 UpdateAllStationVirtCoord();
00305 UpdateAllWaypointSigns();
00306 MarkWholeScreenDirty();
00307 break;
00308
00309 case GAMEOPT_RESOLUTION_BTN:
00310 if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0],_resolutions[e->we.dropdown.index][1]))
00311 SetWindowDirty(w);
00312 break;
00313
00314 case GAMEOPT_SCREENSHOT_BTN:
00315 SetScreenshotFormat(e->we.dropdown.index);
00316 SetWindowDirty(w);
00317 break;
00318 }
00319 break;
00320
00321 case WE_DESTROY:
00322 DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
00323 break;
00324 }
00325
00326 }
00327
00334 CommandCost CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00335 {
00336
00337
00338 if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
00339
00340 if (flags & DC_EXEC) {
00341 _opt_ptr->road_side = p1;
00342 InvalidateWindow(WC_GAME_OPTIONS,0);
00343 }
00344 return CommandCost();
00345 }
00346
00347 static const Widget _game_options_widgets[] = {
00348 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00349 { WWT_CAPTION, RESIZE_NONE, 14, 11, 369, 0, 13, STR_00B1_GAME_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00350 { WWT_PANEL, RESIZE_NONE, 14, 0, 369, 14, 238, 0x0, STR_NULL},
00351 { WWT_FRAME, RESIZE_NONE, 14, 10, 179, 20, 55, STR_02E0_CURRENCY_UNITS, STR_NULL},
00352 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 20, 169, 34, 45, STR_02E1, STR_02E2_CURRENCY_UNITS_SELECTION},
00353 { WWT_FRAME, RESIZE_NONE, 14, 190, 359, 20, 55, STR_MEASURING_UNITS, STR_NULL},
00354 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 200, 349, 34, 45, STR_02E4, STR_MEASURING_UNITS_SELECTION},
00355 { WWT_FRAME, RESIZE_NONE, 14, 10, 179, 62, 97, STR_02E6_ROAD_VEHICLES, STR_NULL},
00356 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 20, 169, 76, 87, STR_02E7, STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
00357 { WWT_FRAME, RESIZE_NONE, 14, 190, 359, 62, 97, STR_02EB_TOWN_NAMES, STR_NULL},
00358 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 200, 349, 76, 87, STR_02EC, STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
00359 { WWT_FRAME, RESIZE_NONE, 14, 10, 179, 104, 139, STR_02F4_AUTOSAVE, STR_NULL},
00360 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 20, 169, 118, 129, STR_02F5, STR_02F6_SELECT_INTERVAL_BETWEEN},
00361
00362 { WWT_FRAME, RESIZE_NONE, 14, 10, 359, 194, 228, STR_02BC_VEHICLE_DESIGN_NAMES, STR_NULL},
00363 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 20, 119, 207, 218, STR_02BD, STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
00364 { WWT_TEXTBTN, RESIZE_NONE, 14, 130, 349, 207, 218, STR_02C0_SAVE_CUSTOM_NAMES, STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
00365
00366 { WWT_FRAME, RESIZE_NONE, 14, 190, 359, 104, 139, STR_OPTIONS_LANG, STR_NULL},
00367 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 200, 349, 118, 129, STR_OPTIONS_LANG_CBO, STR_OPTIONS_LANG_TIP},
00368
00369 { WWT_FRAME, RESIZE_NONE, 14, 10, 179, 146, 190, STR_OPTIONS_RES, STR_NULL},
00370 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 20, 169, 160, 171, STR_OPTIONS_RES_CBO, STR_OPTIONS_RES_TIP},
00371 { WWT_TEXTBTN, RESIZE_NONE, 14, 149, 169, 176, 184, STR_EMPTY, STR_OPTIONS_FULLSCREEN_TIP},
00372
00373 { WWT_FRAME, RESIZE_NONE, 14, 190, 359, 146, 190, STR_OPTIONS_SCREENSHOT_FORMAT, STR_NULL},
00374 { WWT_DROPDOWNIN, RESIZE_NONE, 14, 200, 349, 160, 171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
00375
00376 { WIDGETS_END},
00377 };
00378
00379 static const WindowDesc _game_options_desc = {
00380 WDP_CENTER, WDP_CENTER, 370, 239, 370, 239,
00381 WC_GAME_OPTIONS, WC_NONE,
00382 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00383 _game_options_widgets,
00384 GameOptionsWndProc
00385 };
00386
00387
00388 void ShowGameOptions()
00389 {
00390 DeleteWindowById(WC_GAME_OPTIONS, 0);
00391 AllocateWindowDesc(&_game_options_desc);
00392 }
00393
00394 struct GameSettingData {
00395 int16 min;
00396 int16 max;
00397 int16 step;
00398 StringID str;
00399 };
00400
00401 static const GameSettingData _game_setting_info[] = {
00402 { 0, 7, 1, STR_NULL},
00403 { 0, 3, 1, STR_6830_IMMEDIATE},
00404 { 0, 3, 1, STR_NUM_VERY_LOW},
00405 { 0, 4, 1, STR_NONE},
00406 {100, 500, 50, STR_NULL},
00407 { 2, 4, 1, STR_NULL},
00408 { 0, 2, 1, STR_6820_LOW},
00409 { 0, 4, 1, STR_681B_VERY_SLOW},
00410 { 0, 2, 1, STR_6820_LOW},
00411 { 0, 2, 1, STR_6823_NONE},
00412 { 0, 3, 1, STR_6826_X1_5},
00413 { 0, 2, 1, STR_6820_LOW},
00414 { 0, 3, 1, STR_682A_VERY_FLAT},
00415 { 0, 3, 1, STR_VERY_LOW},
00416 { 0, 1, 1, STR_682E_STEADY},
00417 { 0, 1, 1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS},
00418 { 0, 1, 1, STR_6836_OFF},
00419 { 0, 2, 1, STR_PERMISSIVE},
00420 };
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 static const GDType _default_game_diff[3][GAME_DIFFICULTY_NUM] = {
00443
00444 {2, 2, 2, 4, 300, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0},
00445 {4, 1, 2, 3, 150, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1},
00446 {7, 0, 3, 3, 100, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2},
00447 };
00448
00449 void SetDifficultyLevel(int mode, GameOptions *gm_opt)
00450 {
00451 int i;
00452 assert(mode <= 3);
00453
00454 gm_opt->diff_level = mode;
00455 if (mode != 3) {
00456 for (i = 0; i != GAME_DIFFICULTY_NUM; i++)
00457 ((GDType*)&gm_opt->diff)[i] = _default_game_diff[mode][i];
00458 }
00459 }
00460
00465 void CheckDifficultyLevels()
00466 {
00467 if (_opt_newgame.diff_level != 3) {
00468 SetDifficultyLevel(_opt_newgame.diff_level, &_opt_newgame);
00469 } else {
00470 for (uint i = 0; i < GAME_DIFFICULTY_NUM; i++) {
00471 GDType *diff = ((GDType*)&_opt_newgame.diff) + i;
00472 *diff = Clamp(*diff, _game_setting_info[i].min, _game_setting_info[i].max);
00473 *diff -= *diff % _game_setting_info[i].step;
00474 }
00475 }
00476 }
00477
00478 extern void StartupEconomy();
00479
00480 enum {
00481 GAMEDIFF_WND_TOP_OFFSET = 45,
00482 GAMEDIFF_WND_ROWSIZE = 9
00483 };
00484
00485
00486 static GameOptions _opt_mod_temp;
00487
00488 #define DIFF_INGAME_DISABLED_BUTTONS 0x383E
00489
00490 #define NO_SETTINGS_BUTTON 0xFF
00491
00493 struct difficulty_d {
00494 bool clicked_increase;
00495 uint8 clicked_button;
00496 uint8 timeout;
00497 };
00498 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(difficulty_d));
00499
00500
00501 enum GameDifficultyWidgets {
00502 GDW_CLOSEBOX = 0,
00503 GDW_CAPTION,
00504 GDW_UPPER_BG,
00505 GDW_LVL_EASY,
00506 GDW_LVL_MEDIUM,
00507 GDW_LVL_HARD,
00508 GDW_LVL_CUSTOM,
00509 GDW_HIGHSCORE,
00510 GDW_SETTING_BG,
00511 GDW_LOWER_BG,
00512 GDW_ACCEPT,
00513 GDW_CANCEL,
00514 };
00515
00516 static void GameDifficultyWndProc(Window *w, WindowEvent *e)
00517 {
00518 difficulty_d *diffic_d = &WP(w, difficulty_d);
00519 switch (e->event) {
00520 case WE_CREATE:
00521 diffic_d->clicked_increase = false;
00522 diffic_d->clicked_button = NO_SETTINGS_BUTTON;
00523 diffic_d->timeout = 0;
00524
00525 w->HideWidget(GDW_CLOSEBOX);
00526 w->widget[GDW_CAPTION].left = 0;
00527
00528
00529 w->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
00530 GDW_LVL_EASY,
00531 GDW_LVL_MEDIUM,
00532 GDW_LVL_HARD,
00533 GDW_LVL_CUSTOM,
00534 WIDGET_LIST_END);
00535 w->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking);
00536 w->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server);
00537 w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
00538 break;
00539
00540 case WE_PAINT: {
00541 DrawWindowWidgets(w);
00542
00543
00544
00545
00546 uint32 disabled = 0;
00547 if (_networking && !_network_server) {
00548 disabled = MAX_UVALUE(uint32);
00549 } else if (_game_mode == GM_NORMAL) {
00550 disabled = DIFF_INGAME_DISABLED_BUTTONS;
00551 }
00552
00553 int value;
00554 int y = GAMEDIFF_WND_TOP_OFFSET;
00555 for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
00556 const GameSettingData *gsd = &_game_setting_info[i];
00557 value = ((GDType*)&_opt_mod_temp.diff)[i];
00558
00559 DrawArrowButtons(5, y, 3,
00560 (diffic_d->clicked_button == i) ? 1 + !!diffic_d->clicked_increase : 0,
00561 !(HasBit(disabled, i) || gsd->min == value),
00562 !(HasBit(disabled, i) || gsd->max == value));
00563
00564 value += _game_setting_info[i].str;
00565 if (i == 4) value *= 1000;
00566 SetDParam(0, value);
00567 DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
00568
00569 y += GAMEDIFF_WND_ROWSIZE + 2;
00570 }
00571 } break;
00572
00573 case WE_CLICK:
00574 switch (e->we.click.widget) {
00575 case GDW_SETTING_BG: {
00576
00577 if (_networking && !_network_server) return;
00578
00579 const int x = e->we.click.pt.x - 5;
00580 if (!IsInsideMM(x, 0, 21))
00581 return;
00582
00583 const int y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
00584 if (y < 0) return;
00585
00586
00587 const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
00588 if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
00589 return;
00590
00591
00592 if (_game_mode == GM_NORMAL && HasBit(DIFF_INGAME_DISABLED_BUTTONS, btn))
00593 return;
00594
00595 diffic_d->timeout = 5;
00596
00597 int16 val = ((GDType*)&_opt_mod_temp.diff)[btn];
00598
00599 const GameSettingData *info = &_game_setting_info[btn];
00600 if (x >= 10) {
00601
00602 val = min(val + info->step, info->max);
00603 diffic_d->clicked_increase = true;
00604 } else {
00605
00606 val -= info->step;
00607 val = max(val, info->min);
00608 diffic_d->clicked_increase = false;
00609 }
00610 diffic_d->clicked_button = btn;
00611
00612
00613 ((GDType*)&_opt_mod_temp.diff)[btn] = val;
00614 w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
00615 SetDifficultyLevel(3, &_opt_mod_temp);
00616 w->LowerWidget(GDW_LVL_CUSTOM);
00617 SetWindowDirty(w);
00618 } break;
00619
00620 case GDW_LVL_EASY:
00621 case GDW_LVL_MEDIUM:
00622 case GDW_LVL_HARD:
00623 case GDW_LVL_CUSTOM:
00624
00625 w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
00626 SetDifficultyLevel(e->we.click.widget - GDW_LVL_EASY, &_opt_mod_temp);
00627 w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
00628 SetWindowDirty(w);
00629 break;
00630
00631 case GDW_HIGHSCORE:
00632 ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
00633 break;
00634
00635 case GDW_ACCEPT: {
00636 GDType btn, val;
00637 for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
00638 val = ((GDType*)&_opt_mod_temp.diff)[btn];
00639
00640 if (val != ((GDType*)&_opt_ptr->diff)[btn])
00641 DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
00642 }
00643 DoCommandP(0, UINT_MAX, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
00644 DeleteWindow(w);
00645
00646
00647
00648 if (_game_mode == GM_EDITOR) StartupEconomy();
00649 break;
00650 }
00651
00652 case GDW_CANCEL:
00653 DeleteWindow(w);
00654 break;
00655 } break;
00656
00657 case WE_MOUSELOOP:
00658 if (diffic_d->timeout != 0) {
00659 diffic_d->timeout--;
00660 if (diffic_d->timeout == 0) diffic_d->clicked_button = NO_SETTINGS_BUTTON;
00661 SetWindowDirty(w);
00662 }
00663 break;
00664 }
00665 }
00666 #undef DIFF_INGAME_DISABLED_BUTTONS
00667
00668
00669 static const Widget _game_difficulty_widgets[] = {
00670 { WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00671 { WWT_CAPTION, RESIZE_NONE, 10, 11, 369, 0, 13, STR_6800_DIFFICULTY_LEVEL, STR_018C_WINDOW_TITLE_DRAG_THIS},
00672 { WWT_PANEL, RESIZE_NONE, 10, 0, 369, 14, 41, 0x0, STR_NULL},
00673 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 10, 96, 16, 27, STR_6801_EASY, STR_NULL},
00674 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 97, 183, 16, 27, STR_6802_MEDIUM, STR_NULL},
00675 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 184, 270, 16, 27, STR_6803_HARD, STR_NULL},
00676 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 271, 357, 16, 27, STR_6804_CUSTOM, STR_NULL},
00677 { WWT_TEXTBTN, RESIZE_NONE, 6, 10, 357, 28, 39, STR_6838_SHOW_HI_SCORE_CHART, STR_NULL},
00678 { WWT_PANEL, RESIZE_NONE, 10, 0, 369, 42, 262, 0x0, STR_NULL},
00679 { WWT_PANEL, RESIZE_NONE, 10, 0, 369, 263, 278, 0x0, STR_NULL},
00680 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 105, 185, 265, 276, STR_OPTIONS_SAVE_CHANGES, STR_NULL},
00681 { WWT_PUSHTXTBTN, RESIZE_NONE, 3, 186, 266, 265, 276, STR_012E_CANCEL, STR_NULL},
00682 { WIDGETS_END},
00683 };
00684
00685
00686 static const WindowDesc _game_difficulty_desc = {
00687 WDP_CENTER, WDP_CENTER, 370, 279, 370, 279,
00688 WC_GAME_OPTIONS, WC_NONE,
00689 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00690 _game_difficulty_widgets,
00691 GameDifficultyWndProc
00692 };
00693
00694 void ShowGameDifficulty()
00695 {
00696 DeleteWindowById(WC_GAME_OPTIONS, 0);
00697
00698
00699 _opt_mod_temp = *_opt_ptr;
00700 AllocateWindowDesc(&_game_difficulty_desc);
00701 }
00702
00703 static const char *_patches_ui[] = {
00704 "vehicle_speed",
00705 "status_long_date",
00706 "show_finances",
00707 "autoscroll",
00708 "reverse_scroll",
00709 "smooth_scroll",
00710 "errmsg_duration",
00711 "toolbar_pos",
00712 "measure_tooltip",
00713 "window_snap_radius",
00714 "invisible_trees",
00715 "population_in_label",
00716 "link_terraform_toolbar",
00717 "liveries",
00718 "prefer_teamchat",
00719
00720
00721
00722 "scrollwheel_scrolling",
00723 "scrollwheel_multiplier",
00724 #ifdef __APPLE__
00725
00726 "right_mouse_btn_emulation",
00727 #endif
00728 "pause_on_newgame",
00729 "advanced_vehicle_list",
00730 "loading_indicators",
00731 "timetable_in_ticks",
00732 "default_rail_type",
00733 "always_build_infrastructure",
00734 };
00735
00736 static const char *_patches_construction[] = {
00737 "build_on_slopes",
00738 "autoslope",
00739 "extra_dynamite",
00740 "longbridges",
00741 "signal_side",
00742 "always_small_airport",
00743 "enable_signal_gui",
00744 "drag_signals_density",
00745 "oil_refinery_limit",
00746 "semaphore_build_before",
00747 };
00748
00749 static const char *_patches_stations[] = {
00750 "join_stations",
00751 "full_load_any",
00752 "improved_load",
00753 "selectgoods",
00754 "new_nonstop",
00755 "nonuniform_stations",
00756 "station_spread",
00757 "serviceathelipad",
00758 "modified_catchment",
00759 "gradual_loading",
00760 "road_stop_on_town_road",
00761 "adjacent_stations",
00762 };
00763
00764 static const char *_patches_economy[] = {
00765 "inflation",
00766 "raw_industry_construction",
00767 "multiple_industry_per_town",
00768 "same_industry_close",
00769 "bribe",
00770 "exclusive_rights",
00771 "give_money",
00772 "colored_news_year",
00773 "ending_year",
00774 "smooth_economy",
00775 "allow_shares",
00776 "town_layout",
00777 "mod_road_rebuild",
00778 "town_growth_rate",
00779 "larger_towns",
00780 "initial_city_size",
00781 };
00782
00783 static const char *_patches_ai[] = {
00784 "ainew_active",
00785 "ai_in_multiplayer",
00786 "ai_disable_veh_train",
00787 "ai_disable_veh_roadveh",
00788 "ai_disable_veh_aircraft",
00789 "ai_disable_veh_ship",
00790 };
00791
00792 static const char *_patches_vehicles[] = {
00793 "realistic_acceleration",
00794 "forbid_90_deg",
00795 "mammoth_trains",
00796 "gotodepot",
00797 "roadveh_queue",
00798 "pathfinder_for_trains",
00799 "pathfinder_for_roadvehs",
00800 "pathfinder_for_ships",
00801 "train_income_warn",
00802 "order_review_system",
00803 "never_expire_vehicles",
00804 "lost_train_warn",
00805 "autorenew",
00806 "autorenew_months",
00807 "autorenew_money",
00808 "max_trains",
00809 "max_roadveh",
00810 "max_aircraft",
00811 "max_ships",
00812 "servint_ispercent",
00813 "servint_trains",
00814 "servint_roadveh",
00815 "servint_ships",
00816 "servint_aircraft",
00817 "no_servicing_if_no_breakdowns",
00818 "wagon_speed_limits",
00819 "disable_elrails",
00820 "freight_trains",
00821 "plane_speed",
00822 "timetabling",
00823 };
00824
00825 struct PatchEntry {
00826 const SettingDesc *setting;
00827 uint index;
00828 };
00829
00830 struct PatchPage {
00831 const char **names;
00832 PatchEntry *entries;
00833 byte num;
00834 };
00835
00836
00837
00838
00839 static PatchPage _patches_page[] = {
00840 {_patches_ui, NULL, lengthof(_patches_ui)},
00841 {_patches_construction, NULL, lengthof(_patches_construction)},
00842 {_patches_vehicles, NULL, lengthof(_patches_vehicles)},
00843 {_patches_stations, NULL, lengthof(_patches_stations)},
00844 {_patches_economy, NULL, lengthof(_patches_economy)},
00845 {_patches_ai, NULL, lengthof(_patches_ai)},
00846 };
00847
00848 enum PatchesSelectionWidgets {
00849 PATCHSEL_OPTIONSPANEL = 3,
00850 PATCHSEL_INTERFACE,
00851 PATCHSEL_CONSTRUCTION,
00852 PATCHSEL_VEHICLES,
00853 PATCHSEL_STATIONS,
00854 PATCHSEL_ECONOMY,
00855 PATCHSEL_COMPETITORS
00856 };
00857
00861 static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
00862 {
00863 static Patches *patches_ptr;
00864 static int patches_max = 0;
00865
00866 switch (e->event) {
00867 case WE_CREATE: {
00868 static bool first_time = true;
00869
00870 patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
00871
00872
00873 if (first_time) {
00874 PatchPage *page;
00875 for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
00876 uint i;
00877
00878 if (patches_max < page->num) patches_max = page->num;
00879
00880 page->entries = MallocT<PatchEntry>(page->num);
00881 for (i = 0; i != page->num; i++) {
00882 uint index;
00883 const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
00884 assert(sd != NULL);
00885
00886 page->entries[i].setting = sd;
00887 page->entries[i].index = index;
00888 }
00889 }
00890 first_time = false;
00891 }
00892
00893
00894 ResizeWindowForWidget(w, PATCHSEL_OPTIONSPANEL, 0, patches_max * 11);
00895
00896
00897 w->top = w->top - (patches_max * 11) / 2;
00898
00899 w->LowerWidget(4);
00900 } break;
00901
00902 case WE_PAINT: {
00903 int x, y;
00904 const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
00905 uint i;
00906
00907
00908 DrawWindowWidgets(w);
00909
00910 x = 5;
00911 y = 47;
00912 for (i = 0; i != page->num; i++) {
00913 const SettingDesc *sd = page->entries[i].setting;
00914 const SettingDescBase *sdb = &sd->desc;
00915 const void *var = GetVariableAddress(patches_ptr, &sd->save);
00916 bool editable = true;
00917 bool disabled = false;
00918
00919
00920 if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
00921 if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
00922 if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
00923
00924 if (sdb->cmd == SDT_BOOLX) {
00925 static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
00926
00927 bool on = (*(bool*)var);
00928
00929 DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
00930 SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
00931 } else {
00932 int32 value;
00933
00934 value = (int32)ReadValue(var, sd->save.conv);
00935
00936
00937 DrawArrowButtons(x, y, 3, WP(w, def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
00938
00939 disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
00940 if (disabled) {
00941 SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
00942 } else {
00943 if (sdb->flags & SGF_CURRENCY) {
00944 SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
00945 } else if (sdb->flags & SGF_MULTISTRING) {
00946 SetDParam(0, sdb->str + value + 1);
00947 } else {
00948 SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
00949 }
00950 SetDParam(1, value);
00951 }
00952 }
00953 DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
00954 y += 11;
00955 }
00956 } break;
00957
00958 case WE_CLICK:
00959 switch (e->we.click.widget) {
00960 case PATCHSEL_OPTIONSPANEL: {
00961 const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
00962 const SettingDesc *sd;
00963 void *var;
00964 int32 value;
00965 int x, y;
00966 byte btn;
00967
00968 y = e->we.click.pt.y - 46 - 1;
00969 if (y < 0) return;
00970
00971 x = e->we.click.pt.x - 5;
00972 if (x < 0) return;
00973
00974 btn = y / 11;
00975 if (y % 11 > 9) return;
00976 if (btn >= page->num) return;
00977
00978 sd = page->entries[btn].setting;
00979
00980
00981 if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
00982 if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
00983 if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
00984
00985 var = GetVariableAddress(patches_ptr, &sd->save);
00986 value = (int32)ReadValue(var, sd->save.conv);
00987
00988
00989 if (x < 21) {
00990 const SettingDescBase *sdb = &sd->desc;
00991 int32 oldvalue = value;
00992
00993 switch (sdb->cmd) {
00994 case SDT_BOOLX: value ^= 1; break;
00995 case SDT_NUMX: {
00996
00997
00998
00999
01000 uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
01001 if (step == 0) step = 1;
01002
01003
01004 if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
01005 _left_button_clicked = false;
01006 return;
01007 }
01008
01009
01010 if (x >= 10) {
01011 value += step;
01012 if (value > sdb->max) value = sdb->max;
01013 } else {
01014 value -= step;
01015 if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
01016 }
01017
01018
01019 if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
01020 WP(w, def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
01021 w->flags4 |= 5 << WF_TIMEOUT_SHL;
01022 _left_button_clicked = false;
01023 }
01024 } break;
01025 default: NOT_REACHED();
01026 }
01027
01028 if (value != oldvalue) {
01029 SetPatchValue(page->entries[btn].index, patches_ptr, value);
01030 SetWindowDirty(w);
01031 }
01032 } else {
01033
01034 if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
01035
01036 if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
01037
01038 WP(w, def_d).data_3 = btn;
01039 SetDParam(0, value);
01040 ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
01041 }
01042 }
01043 } break;
01044
01045 case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
01046 case PATCHSEL_STATIONS: case PATCHSEL_ECONOMY: case PATCHSEL_COMPETITORS:
01047 w->RaiseWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
01048 WP(w, def_d).data_1 = e->we.click.widget - PATCHSEL_INTERFACE;
01049 w->LowerWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
01050 DeleteWindowById(WC_QUERY_STRING, 0);
01051 SetWindowDirty(w);
01052 break;
01053 }
01054 break;
01055
01056 case WE_TIMEOUT:
01057 WP(w, def_d).data_2 = 0;
01058 SetWindowDirty(w);
01059 break;
01060
01061 case WE_ON_EDIT_TEXT:
01062 if (e->we.edittext.str != NULL) {
01063 const PatchEntry *pe = &_patches_page[WP(w, def_d).data_1].entries[WP(w,def_d).data_3];
01064 const SettingDesc *sd = pe->setting;
01065 int32 value = atoi(e->we.edittext.str);
01066
01067
01068 if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
01069
01070 SetPatchValue(pe->index, patches_ptr, value);
01071 SetWindowDirty(w);
01072 }
01073 break;
01074
01075 case WE_DESTROY:
01076 DeleteWindowById(WC_QUERY_STRING, 0);
01077 break;
01078 }
01079 }
01080
01081 static const Widget _patches_selection_widgets[] = {
01082 { WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01083 { WWT_CAPTION, RESIZE_NONE, 10, 11, 369, 0, 13, STR_CONFIG_PATCHES_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
01084 { WWT_PANEL, RESIZE_NONE, 10, 0, 369, 14, 41, 0x0, STR_NULL},
01085 { WWT_PANEL, RESIZE_NONE, 10, 0, 369, 42, 50, 0x0, STR_NULL},
01086
01087 { WWT_TEXTBTN, RESIZE_NONE, 3, 10, 96, 16, 27, STR_CONFIG_PATCHES_GUI, STR_NULL},
01088 { WWT_TEXTBTN, RESIZE_NONE, 3, 97, 183, 16, 27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL},
01089 { WWT_TEXTBTN, RESIZE_NONE, 3, 184, 270, 16, 27, STR_CONFIG_PATCHES_VEHICLES, STR_NULL},
01090 { WWT_TEXTBTN, RESIZE_NONE, 3, 271, 357, 16, 27, STR_CONFIG_PATCHES_STATIONS, STR_NULL},
01091 { WWT_TEXTBTN, RESIZE_NONE, 3, 10, 96, 28, 39, STR_CONFIG_PATCHES_ECONOMY, STR_NULL},
01092 { WWT_TEXTBTN, RESIZE_NONE, 3, 97, 183, 28, 39, STR_CONFIG_PATCHES_AI, STR_NULL},
01093 { WIDGETS_END},
01094 };
01095
01096 static const WindowDesc _patches_selection_desc = {
01097 WDP_CENTER, WDP_CENTER, 370, 51, 370, 51,
01098 WC_GAME_OPTIONS, WC_NONE,
01099 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
01100 _patches_selection_widgets,
01101 PatchesSelectionWndProc,
01102 };
01103
01104 void ShowPatchesSelection()
01105 {
01106 DeleteWindowById(WC_GAME_OPTIONS, 0);
01107 AllocateWindowDesc(&_patches_selection_desc);
01108 }
01109
01110
01120 void DrawArrowButtons(int x, int y, int ctab, byte state, bool clickable_left, bool clickable_right)
01121 {
01122 int color = (1 << PALETTE_MODIFIER_GREYOUT) | _colour_gradient[COLOUR_YELLOW][2];
01123
01124 DrawFrameRect(x, y + 1, x + 9, y + 9, ctab, (state == 1) ? FR_LOWERED : FR_NONE);
01125 DrawFrameRect(x + 10, y + 1, x + 19, y + 9, ctab, (state == 2) ? FR_LOWERED : FR_NONE);
01126 DrawStringCentered(x + 5, y + 1, STR_6819, TC_FROMSTRING);
01127 DrawStringCentered(x + 15, y + 1, STR_681A, TC_FROMSTRING);
01128
01129
01130 if (!clickable_left)
01131 GfxFillRect(x + 1, y + 1, x + 1 + 8, y + 8, color);
01132 if (!clickable_right)
01133 GfxFillRect(x + 11, y + 1, x + 11 + 8, y + 8, color);
01134 }
01135
01139 enum CustomCurrenciesWidgets {
01140 CUSTCURR_EXCHANGERATE = 0,
01141 CUSTCURR_SEPARATOR,
01142 CUSTCURR_PREFIX,
01143 CUSTCURR_SUFFIX,
01144 CUSTCURR_TO_EURO,
01145 };
01146
01147 static char _str_separator[2];
01148
01149 static void CustCurrencyWndProc(Window *w, WindowEvent *e)
01150 {
01151 switch (e->event) {
01152 case WE_PAINT: {
01153 int x;
01154 int y = 20;
01155 int clk = WP(w, def_d).data_1;
01156 DrawWindowWidgets(w);
01157
01158
01159 DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
01160 SetDParam(0, 1);
01161 SetDParam(1, 1);
01162 DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
01163 y += 12;
01164
01165
01166 DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : FR_NONE);
01167 x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
01168 DoDrawString(_str_separator, x + 4, y + 1, TC_ORANGE);
01169 y += 12;
01170
01171
01172 DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : FR_NONE);
01173 x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
01174 DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
01175 y += 12;
01176
01177
01178 DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : FR_NONE);
01179 x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
01180 DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
01181 y += 12;
01182
01183
01184 DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
01185 SetDParam(0, _custom_currency.to_euro);
01186 DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
01187 y += 12;
01188
01189
01190 y += 12;
01191 SetDParam(0, 10000);
01192 DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
01193 } break;
01194
01195 case WE_CLICK: {
01196 int line = (e->we.click.pt.y - 20) / 12;
01197 int len = 0;
01198 int x = e->we.click.pt.x;
01199 StringID str = 0;
01200 CharSetFilter afilter = CS_ALPHANUMERAL;
01201
01202 switch (line) {
01203 case CUSTCURR_EXCHANGERATE:
01204 if (IsInsideMM(x, 10, 30)) {
01205 if (x < 20) {
01206 if (_custom_currency.rate > 1) _custom_currency.rate--;
01207 WP(w, def_d).data_1 = 1 << (line * 2 + 0);
01208 } else {
01209 if (_custom_currency.rate < 5000) _custom_currency.rate++;
01210 WP(w, def_d).data_1 = 1 << (line * 2 + 1);
01211 }
01212 } else {
01213 SetDParam(0, _custom_currency.rate);
01214 str = STR_CONFIG_PATCHES_INT32;
01215 len = 4;
01216 afilter = CS_NUMERAL;
01217 }
01218 break;
01219
01220 case CUSTCURR_SEPARATOR:
01221 if (IsInsideMM(x, 10, 30)) {
01222 WP(w, def_d).data_1 = 1 << (line * 2 + 1);
01223 }
01224 str = BindCString(_str_separator);
01225 len = 1;
01226 break;
01227
01228 case CUSTCURR_PREFIX:
01229 if (IsInsideMM(x, 10, 30)) {
01230 WP(w, def_d).data_1 = 1 << (line * 2 + 1);
01231 }
01232 str = BindCString(_custom_currency.prefix);
01233 len = 12;
01234 break;
01235
01236 case CUSTCURR_SUFFIX:
01237 if (IsInsideMM(x, 10, 30)) {
01238 WP(w, def_d).data_1 = 1 << (line * 2 + 1);
01239 }
01240 str = BindCString(_custom_currency.suffix);
01241 len = 12;
01242 break;
01243
01244 case CUSTCURR_TO_EURO:
01245 if (IsInsideMM(x, 10, 30)) {
01246 if (x < 20) {
01247 _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
01248 CF_NOEURO : _custom_currency.to_euro - 1;
01249 WP(w, def_d).data_1 = 1 << (line * 2 + 0);
01250 } else {
01251 _custom_currency.to_euro =
01252 Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
01253 WP(w, def_d).data_1 = 1 << (line * 2 + 1);
01254 }
01255 } else {
01256 SetDParam(0, _custom_currency.to_euro);
01257 str = STR_CONFIG_PATCHES_INT32;
01258 len = 4;
01259 afilter = CS_NUMERAL;
01260 }
01261 break;
01262 }
01263
01264 if (len != 0) {
01265 WP(w, def_d).data_2 = line;
01266 ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
01267 }
01268
01269 w->flags4 |= 5 << WF_TIMEOUT_SHL;
01270 SetWindowDirty(w);
01271 } break;
01272
01273 case WE_ON_EDIT_TEXT: {
01274 const char *b = e->we.edittext.str;
01275
01276 switch (WP(w, def_d).data_2) {
01277 case CUSTCURR_EXCHANGERATE:
01278 _custom_currency.rate = Clamp(atoi(b), 1, 5000);
01279 break;
01280
01281 case CUSTCURR_SEPARATOR:
01282 _custom_currency.separator = (b[0] == '\0') ? ' ' : b[0];
01283 ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
01284 break;
01285
01286 case CUSTCURR_PREFIX:
01287 ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
01288 break;
01289
01290 case CUSTCURR_SUFFIX:
01291 ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
01292 break;
01293
01294 case CUSTCURR_TO_EURO: {
01295 int val = atoi(b);
01296
01297 _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
01298 break;
01299 }
01300 }
01301 MarkWholeScreenDirty();
01302 } break;
01303
01304 case WE_TIMEOUT:
01305 WP(w, def_d).data_1 = 0;
01306 SetWindowDirty(w);
01307 break;
01308
01309 case WE_DESTROY:
01310 DeleteWindowById(WC_QUERY_STRING, 0);
01311 MarkWholeScreenDirty();
01312 break;
01313 }
01314 }
01315
01316 static const Widget _cust_currency_widgets[] = {
01317 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01318 { WWT_CAPTION, RESIZE_NONE, 14, 11, 229, 0, 13, STR_CURRENCY_WINDOW, STR_018C_WINDOW_TITLE_DRAG_THIS},
01319 { WWT_PANEL, RESIZE_NONE, 14, 0, 229, 14, 119, 0x0, STR_NULL},
01320 { WIDGETS_END},
01321 };
01322
01323 static const WindowDesc _cust_currency_desc = {
01324 WDP_CENTER, WDP_CENTER, 230, 120, 230, 120,
01325 WC_CUSTOM_CURRENCY, WC_NONE,
01326 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01327 _cust_currency_widgets,
01328 CustCurrencyWndProc,
01329 };
01330
01331 static void ShowCustCurrency()
01332 {
01333 _str_separator[0] = _custom_currency.separator;
01334 _str_separator[1] = '\0';
01335
01336 DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
01337 AllocateWindowDesc(&_cust_currency_desc);
01338 }