mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-02 09:40:35 +00:00
2aa94201dc
- Fix: There would be duplicate entries in the resolutions dropdown box. Copy SDL method or removing duplicates and sort the list. - Feature: in the settings menu, you don't have to click on the arrows anymore, clicking on the dropdown box itself has the same effect. Consistent with other dropdowns in the game
1511 lines
53 KiB
C
1511 lines
53 KiB
C
#include "stdafx.h"
|
|
#include "ttd.h"
|
|
#include "string.h"
|
|
#include "strings.h" // XXX GetCurrentCurrencyRate()
|
|
#include "table/sprites.h"
|
|
#include "table/strings.h"
|
|
#include "window.h"
|
|
#include "gui.h"
|
|
#include "gfx.h"
|
|
#include "command.h"
|
|
#include "engine.h"
|
|
#include "screenshot.h"
|
|
#include "newgrf.h"
|
|
#include "network.h"
|
|
#include "console.h"
|
|
#include "town.h"
|
|
|
|
static uint32 _difficulty_click_a;
|
|
static uint32 _difficulty_click_b;
|
|
static byte _difficulty_timeout;
|
|
|
|
extern const StringID _currency_string_list[];
|
|
extern uint GetMaskOfAllowedCurrencies(void);
|
|
|
|
static const StringID _distances_dropdown[] = {
|
|
STR_0139_IMPERIAL_MILES,
|
|
STR_013A_METRIC_KILOMETERS,
|
|
INVALID_STRING_ID
|
|
};
|
|
|
|
static const StringID _driveside_dropdown[] = {
|
|
STR_02E9_DRIVE_ON_LEFT,
|
|
STR_02EA_DRIVE_ON_RIGHT,
|
|
INVALID_STRING_ID
|
|
};
|
|
|
|
static const StringID _autosave_dropdown[] = {
|
|
STR_02F7_OFF,
|
|
STR_AUTOSAVE_1_MONTH,
|
|
STR_02F8_EVERY_3_MONTHS,
|
|
STR_02F9_EVERY_6_MONTHS,
|
|
STR_02FA_EVERY_12_MONTHS,
|
|
INVALID_STRING_ID,
|
|
};
|
|
|
|
static const StringID _designnames_dropdown[] = {
|
|
STR_02BE_DEFAULT,
|
|
STR_02BF_CUSTOM,
|
|
INVALID_STRING_ID
|
|
};
|
|
|
|
static StringID *BuildDynamicDropdown(StringID base, int num)
|
|
{
|
|
static StringID buf[32 + 1];
|
|
StringID *p = buf;
|
|
while (--num>=0) *p++ = base++;
|
|
*p = INVALID_STRING_ID;
|
|
return buf;
|
|
}
|
|
|
|
static int GetCurRes(void)
|
|
{
|
|
int i;
|
|
for(i = 0; i != _num_resolutions; i++)
|
|
if (_resolutions[i][0] == _screen.width &&
|
|
_resolutions[i][1] == _screen.height)
|
|
break;
|
|
return i;
|
|
}
|
|
|
|
static inline bool RoadVehiclesAreBuilt(void)
|
|
{
|
|
const Vehicle *v;
|
|
FOR_ALL_VEHICLES(v) {
|
|
if (v->type == VEH_Road) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void GameOptionsWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
switch (e->event) {
|
|
case WE_PAINT: {
|
|
int i;
|
|
StringID str = STR_02BE_DEFAULT;
|
|
w->disabled_state = (_vehicle_design_names & 1) ? (++str, 0) : (1 << 21);
|
|
SetDParam(0, str);
|
|
SetDParam(1, _currency_string_list[_opt_ptr->currency]);
|
|
SetDParam(2, _opt_ptr->kilometers + STR_0139_IMPERIAL_MILES);
|
|
SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
|
|
SetDParam(4, STR_TOWNNAME_ORIGINAL_ENGLISH + _opt_ptr->town_name);
|
|
SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
|
|
SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
|
|
i = GetCurRes();
|
|
SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
|
|
SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
|
|
(_fullscreen) ? SETBIT(w->click_state, 28) : CLRBIT(w->click_state, 28); // fullscreen button
|
|
|
|
DrawWindowWidgets(w);
|
|
DrawString(20, 175, STR_OPTIONS_FULLSCREEN, 0); // fullscreen
|
|
} break;
|
|
|
|
case WE_CLICK:
|
|
switch (e->click.widget) {
|
|
case 4: case 5: /* Setup currencies dropdown */
|
|
ShowDropDownMenu(w, _currency_string_list, _opt_ptr->currency, 5, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
|
|
return;
|
|
case 7: case 8: /* Setup distance unit dropdown */
|
|
ShowDropDownMenu(w, _distances_dropdown, _opt_ptr->kilometers, 8, 0, 0);
|
|
return;
|
|
case 10: case 11: { /* Setup road-side dropdown */
|
|
int i = 0;
|
|
|
|
/* You can only change the drive side if you are in the menu or ingame with
|
|
* no vehicles present. In a networking game only the server can change it */
|
|
if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
|
|
i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
|
|
|
|
ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, 11, i, 0);
|
|
} return;
|
|
case 13: case 14: { /* Setup townname dropdown */
|
|
int i = _opt_ptr->town_name;
|
|
ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ORIGINAL_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, 14, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i), 0);
|
|
return;
|
|
}
|
|
case 16: case 17: /* Setup autosave dropdown */
|
|
ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, 17, 0, 0);
|
|
return;
|
|
case 19: case 20: /* Setup customized vehicle-names dropdown */
|
|
ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, 20, (_vehicle_design_names & 2) ? 0 : 2, 0);
|
|
return;
|
|
case 21: /* Save customized vehicle-names to disk */
|
|
return;
|
|
case 23: case 24: /* Setup interface language dropdown */
|
|
ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, 24, 0, 0);
|
|
return;
|
|
case 26: case 27: /* Setup resolution dropdown */
|
|
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), 27, 0, 0);
|
|
return;
|
|
case 28: /* Click fullscreen on/off */
|
|
(_fullscreen) ? CLRBIT(w->click_state, 28) : SETBIT(w->click_state, 28);
|
|
ToggleFullScreen(!_fullscreen); // toggle full-screen on/off
|
|
SetWindowDirty(w);
|
|
return;
|
|
case 30: case 31: /* Setup screenshot format dropdown */
|
|
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, 31, 0, 0);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case WE_DROPDOWN_SELECT:
|
|
switch (e->dropdown.button) {
|
|
case 20: /* Vehicle design names */
|
|
if (e->dropdown.index == 0) {
|
|
DeleteCustomEngineNames();
|
|
MarkWholeScreenDirty();
|
|
} else if (!(_vehicle_design_names & 1)) {
|
|
LoadCustomEngineNames();
|
|
MarkWholeScreenDirty();
|
|
}
|
|
break;
|
|
case 5: /* Currency */
|
|
if (e->dropdown.index == 23)
|
|
ShowCustCurrency();
|
|
_opt_ptr->currency = e->dropdown.index;
|
|
MarkWholeScreenDirty();
|
|
break;
|
|
case 8: /* Distance units */
|
|
_opt_ptr->kilometers = e->dropdown.index;
|
|
MarkWholeScreenDirty();
|
|
break;
|
|
case 11: /* Road side */
|
|
if (_opt_ptr->road_side != e->dropdown.index) { // only change if setting changed
|
|
DoCommandP(0, e->dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
|
|
MarkWholeScreenDirty();
|
|
}
|
|
break;
|
|
case 14: /* Town names */
|
|
if (_game_mode == GM_MENU) {
|
|
_opt_ptr->town_name = e->dropdown.index;
|
|
InvalidateWindow(WC_GAME_OPTIONS, 0);
|
|
}
|
|
break;
|
|
case 17: /* Autosave options */
|
|
_opt_ptr->autosave = e->dropdown.index;
|
|
SetWindowDirty(w);
|
|
break;
|
|
case 24: /* Change interface language */
|
|
ReadLanguagePack(e->dropdown.index);
|
|
MarkWholeScreenDirty();
|
|
break;
|
|
case 27: /* Change resolution */
|
|
if (e->dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->dropdown.index][0],_resolutions[e->dropdown.index][1]))
|
|
SetWindowDirty(w);
|
|
break;
|
|
case 31: /* Change screenshot format */
|
|
SetScreenshotFormat(e->dropdown.index);
|
|
SetWindowDirty(w);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WE_DESTROY:
|
|
DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/** Change the side of the road vehicles drive on (server only).
|
|
* @param x,y unused
|
|
* @param p1 the side of the road; 0 = left side and 1 = right side
|
|
* @param p2 unused
|
|
*/
|
|
int32 CmdSetRoadDriveSide(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|
{
|
|
/* Check boundaries and you can only change this if NO vehicles have been built yet,
|
|
* except in the intro-menu where of course it's always possible to do so. */
|
|
if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
|
|
|
|
if (flags & DC_EXEC) {
|
|
_opt_ptr->road_side = p1;
|
|
InvalidateWindow(WC_GAME_OPTIONS,0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const Widget _game_options_widgets[] = {
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 369, 0, 13, STR_00B1_GAME_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_PANEL, RESIZE_NONE, 14, 0, 369, 14, 238, 0x0, STR_NULL},
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 10, 179, 20, 55, STR_02E0_CURRENCY_UNITS, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 20, 169, 34, 45, STR_02E1, STR_02E2_CURRENCY_UNITS_SELECTION},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 158, 168, 35, 44, STR_0225, STR_02E2_CURRENCY_UNITS_SELECTION},
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 190, 359, 20, 55, STR_02E3_DISTANCE_UNITS, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 200, 349, 34, 45, STR_02E4, STR_02E5_DISTANCE_UNITS_SELECTION},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 338, 348, 35, 44, STR_0225, STR_02E5_DISTANCE_UNITS_SELECTION},
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 10, 179, 62, 97, STR_02E6_ROAD_VEHICLES, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 20, 169, 76, 87, STR_02E7, STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 158, 168, 77, 86, STR_0225, STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 190, 359, 62, 97, STR_02EB_TOWN_NAMES, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 200, 349, 76, 87, STR_02EC, STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 338, 348, 77, 86, STR_0225, STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 10, 179, 104, 139, STR_02F4_AUTOSAVE, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 20, 169, 118, 129, STR_02F5, STR_02F6_SELECT_INTERVAL_BETWEEN},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 158, 168, 119, 128, STR_0225, STR_02F6_SELECT_INTERVAL_BETWEEN},
|
|
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 10, 359, 194, 228, STR_02BC_VEHICLE_DESIGN_NAMES, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 20, 119, 207, 218, STR_02BD, STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 108, 118, 208, 217, STR_0225, STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 130, 349, 207, 218, STR_02C0_SAVE_CUSTOM_NAMES, STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
|
|
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 190, 359, 104, 139, STR_OPTIONS_LANG, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 200, 349, 118, 129, STR_OPTIONS_LANG_CBO, STR_OPTIONS_LANG_TIP},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 338, 348, 119, 128, STR_0225, STR_OPTIONS_LANG_TIP},
|
|
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 10, 179, 146, 190, STR_OPTIONS_RES, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 20, 169, 160, 171, STR_OPTIONS_RES_CBO, STR_OPTIONS_RES_TIP},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 158, 168, 161, 170, STR_0225, STR_OPTIONS_RES_TIP},
|
|
{ WWT_TEXTBTN, RESIZE_NONE, 14, 149, 169, 176, 184, STR_EMPTY, STR_OPTIONS_FULLSCREEN_TIP},
|
|
|
|
{ WWT_FRAME, RESIZE_NONE, 14, 190, 359, 146, 190, STR_OPTIONS_SCREENSHOT_FORMAT, STR_NULL},
|
|
{ WWT_6, RESIZE_NONE, 14, 200, 349, 160, 171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 338, 348, 161, 170, STR_0225, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
|
|
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _game_options_desc = {
|
|
WDP_CENTER, WDP_CENTER, 370, 239,
|
|
WC_GAME_OPTIONS,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESTORE_DPARAM | WDF_UNCLICK_BUTTONS,
|
|
_game_options_widgets,
|
|
GameOptionsWndProc
|
|
};
|
|
|
|
|
|
void ShowGameOptions(void)
|
|
{
|
|
DeleteWindowById(WC_GAME_OPTIONS, 0);
|
|
AllocateWindowDesc(&_game_options_desc);
|
|
}
|
|
|
|
typedef struct {
|
|
int16 min;
|
|
int16 max;
|
|
int16 step;
|
|
StringID str;
|
|
} GameSettingData;
|
|
|
|
static const GameSettingData _game_setting_info[] = {
|
|
{ 0, 7, 1, STR_NULL},
|
|
{ 0, 3, 1, STR_6830_IMMEDIATE},
|
|
{ 0, 2, 1, STR_6816_LOW},
|
|
{ 0, 3, 1, STR_26816_NONE},
|
|
{100, 500, 50, STR_NULL},
|
|
{ 2, 4, 1, STR_NULL},
|
|
{ 0, 2, 1, STR_6820_LOW},
|
|
{ 0, 4, 1, STR_681B_VERY_SLOW},
|
|
{ 0, 2, 1, STR_6820_LOW},
|
|
{ 0, 2, 1, STR_6823_NONE},
|
|
{ 0, 3, 1, STR_6826_X1_5},
|
|
{ 0, 2, 1, STR_6820_LOW},
|
|
{ 0, 3, 1, STR_682A_VERY_FLAT},
|
|
{ 0, 3, 1, STR_VERY_LOW},
|
|
{ 0, 1, 1, STR_682E_STEADY},
|
|
{ 0, 1, 1, STR_6834_AT_END_OF_LINE_AND_AT_STATIONS},
|
|
{ 0, 1, 1, STR_6836_OFF},
|
|
{ 0, 2, 1, STR_6839_PERMISSIVE},
|
|
};
|
|
|
|
static inline bool GetBitAndShift(uint32 *b)
|
|
{
|
|
uint32 x = *b;
|
|
*b >>= 1;
|
|
return HASBIT(x, 0);
|
|
}
|
|
|
|
/*
|
|
A: competitors
|
|
B: start time in months / 3
|
|
C: town count (2 = high, 0 = low)
|
|
D: industry count (3 = high, 0 = none)
|
|
E: inital loan / 1000 (in GBP)
|
|
F: interest rate
|
|
G: running costs (0 = low, 2 = high)
|
|
H: construction speed of competitors (0 = very slow, 4 = very fast)
|
|
I: intelligence (0-2)
|
|
J: breakdowns(0 = off, 2 = normal)
|
|
K: subsidy multiplier (0 = 1.5, 3 = 4.0)
|
|
L: construction cost (0-2)
|
|
M: terrain type (0 = very flat, 3 = mountainous)
|
|
N: amount of water (0 = very low, 3 = high)
|
|
O: economy (0 = steady, 1 = fluctuating)
|
|
P: Train reversing (0 = end of line + stations, 1 = end of line)
|
|
Q: disasters
|
|
R: area restructuring (0 = permissive, 2 = hostile)
|
|
*/
|
|
static const int16 _default_game_diff[3][GAME_DIFFICULTY_NUM] = { /*
|
|
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R*/
|
|
{2, 2, 1, 3, 300, 2, 0, 2, 0, 1, 2, 0, 1, 0, 0, 0, 0, 0}, //easy
|
|
{4, 1, 1, 2, 150, 3, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1}, //medium
|
|
{7, 0, 2, 2, 100, 4, 1, 3, 2, 2, 0, 2, 3, 2, 1, 1, 1, 2}, //hard
|
|
};
|
|
|
|
void SetDifficultyLevel(int mode, GameOptions *gm_opt)
|
|
{
|
|
int i;
|
|
assert(mode <= 3);
|
|
|
|
gm_opt->diff_level = mode;
|
|
if (mode != 3) { // not custom
|
|
for (i = 0; i != GAME_DIFFICULTY_NUM; i++)
|
|
((int*)&gm_opt->diff)[i] = _default_game_diff[mode][i];
|
|
}
|
|
}
|
|
|
|
extern void StartupEconomy(void);
|
|
|
|
enum {
|
|
GAMEDIFF_WND_TOP_OFFSET = 45,
|
|
GAMEDIFF_WND_ROWSIZE = 9
|
|
};
|
|
|
|
// Temporary holding place of values in the difficulty window until 'Save' is clicked
|
|
static GameOptions _opt_mod_temp;
|
|
// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
|
|
#define DIFF_INGAME_DISABLED_BUTTONS 0x383E
|
|
|
|
static void GameDifficultyWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
switch (e->event) {
|
|
case WE_CREATE: /* Setup disabled buttons when creating window */
|
|
// disable all other difficulty buttons during gameplay except for 'custom'
|
|
w->disabled_state = (_game_mode != GM_NORMAL) ? 0 : (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
|
|
|
if (_game_mode == GM_EDITOR) SETBIT(w->disabled_state, 7);
|
|
|
|
if (_networking) {
|
|
SETBIT(w->disabled_state, 7); // disable highscore chart in multiplayer
|
|
if (!_network_server)
|
|
SETBIT(w->disabled_state, 10); // Disable save-button in multiplayer (and if client)
|
|
}
|
|
break;
|
|
case WE_PAINT: {
|
|
uint32 click_a, click_b, disabled;
|
|
int i;
|
|
int y, value;
|
|
|
|
w->click_state = (1 << 3) << _opt_mod_temp.diff_level; // have current difficulty button clicked
|
|
DrawWindowWidgets(w);
|
|
|
|
click_a = _difficulty_click_a;
|
|
click_b = _difficulty_click_b;
|
|
|
|
/* XXX - Disabled buttons in normal gameplay. Bitshifted for each button to see if
|
|
* that bit is set. If it is set, the button is disabled */
|
|
disabled = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
|
|
|
|
y = GAMEDIFF_WND_TOP_OFFSET;
|
|
for (i = 0; i != GAME_DIFFICULTY_NUM; i++) {
|
|
DrawFrameRect( 5, y, 5 + 8, y + 8, 3, GetBitAndShift(&click_a) ? (1 << 5) : 0);
|
|
DrawFrameRect(15, y, 15 + 8, y + 8, 3, GetBitAndShift(&click_b) ? (1 << 5) : 0);
|
|
if (GetBitAndShift(&disabled) || (_networking && !_network_server)) {
|
|
int color = PALETTE_MODIFIER_COLOR | _color_list[3].unk2;
|
|
GfxFillRect( 6, y + 1, 6 + 8, y + 8, color);
|
|
GfxFillRect(16, y + 1, 16 + 8, y + 8, color);
|
|
}
|
|
|
|
DrawStringCentered(10, y, STR_6819, 0);
|
|
DrawStringCentered(20, y, STR_681A, 0);
|
|
|
|
|
|
value = _game_setting_info[i].str + ((int*)&_opt_mod_temp.diff)[i];
|
|
if (i == 4) value *= 1000; // XXX - handle currency option
|
|
SetDParam(0, value);
|
|
DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, 0);
|
|
|
|
y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
|
|
}
|
|
} break;
|
|
|
|
case WE_CLICK:
|
|
switch (e->click.widget) {
|
|
case 8: { /* Difficulty settings widget, decode click */
|
|
const GameSettingData *info;
|
|
int x, y;
|
|
uint btn, dis;
|
|
int val;
|
|
|
|
// Don't allow clients to make any changes
|
|
if (_networking && !_network_server)
|
|
return;
|
|
|
|
x = e->click.pt.x - 5;
|
|
if (!IS_INT_INSIDE(x, 0, 21)) // Button area
|
|
return;
|
|
|
|
y = e->click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
|
|
if (y < 0)
|
|
return;
|
|
|
|
// Get button from Y coord.
|
|
btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
|
|
if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
|
|
return;
|
|
|
|
// Clicked disabled button?
|
|
dis = (_game_mode == GM_NORMAL) ? DIFF_INGAME_DISABLED_BUTTONS : 0;
|
|
|
|
if (HASBIT(dis, btn))
|
|
return;
|
|
|
|
_difficulty_timeout = 5;
|
|
|
|
val = ((int*)&_opt_mod_temp.diff)[btn];
|
|
|
|
info = &_game_setting_info[btn]; // get information about the difficulty setting
|
|
if (x >= 10) {
|
|
// Increase button clicked
|
|
val = min(val + info->step, info->max);
|
|
SETBIT(_difficulty_click_b, btn);
|
|
} else {
|
|
// Decrease button clicked
|
|
val = max(val - info->step, info->min);
|
|
SETBIT(_difficulty_click_a, btn);
|
|
}
|
|
|
|
// save value in temporary variable
|
|
((int*)&_opt_mod_temp.diff)[btn] = val;
|
|
SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
|
|
SetWindowDirty(w);
|
|
} break;
|
|
case 3: case 4: case 5: case 6: /* Easy / Medium / Hard / Custom */
|
|
// temporarily change difficulty level
|
|
SetDifficultyLevel(e->click.widget - 3, &_opt_mod_temp);
|
|
SetWindowDirty(w);
|
|
break;
|
|
case 7: /* Highscore Table */
|
|
ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
|
|
break;
|
|
case 10: { /* Save button - save changes */
|
|
int btn, val;
|
|
for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
|
|
val = ((int*)&_opt_mod_temp.diff)[btn];
|
|
// if setting has changed, change it
|
|
if (val != ((int*)&_opt_ptr->diff)[btn])
|
|
DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
|
|
}
|
|
DoCommandP(0, -1, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
|
|
DeleteWindow(w);
|
|
// If we are in the editor, we should reload the economy.
|
|
// This way when you load a game, the max loan and interest rate
|
|
// are loaded correctly.
|
|
if (_game_mode == GM_EDITOR)
|
|
StartupEconomy();
|
|
break;
|
|
}
|
|
case 11: /* Cancel button - close window, abandon changes */
|
|
DeleteWindow(w);
|
|
break;
|
|
} break;
|
|
|
|
case WE_MOUSELOOP: /* Handle the visual 'clicking' of the buttons */
|
|
if (_difficulty_timeout != 0 && !--_difficulty_timeout) {
|
|
_difficulty_click_a = 0;
|
|
_difficulty_click_b = 0;
|
|
SetWindowDirty(w);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#undef DIFF_INGAME_DISABLED_BUTTONS
|
|
|
|
static const Widget _game_difficulty_widgets[] = {
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, RESIZE_NONE, 10, 11, 369, 0, 13, STR_6800_DIFFICULTY_LEVEL, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_PANEL, RESIZE_NONE, 10, 0, 369, 14, 29, 0x0, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 10, 96, 16, 27, STR_6801_EASY, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 97, 183, 16, 27, STR_6802_MEDIUM, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 184, 270, 16, 27, STR_6803_HARD, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 271, 357, 16, 27, STR_6804_CUSTOM, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 369, 30, 41, STR_6838_SHOW_HI_SCORE_CHART,STR_NULL},
|
|
{ WWT_PANEL, RESIZE_NONE, 10, 0, 369, 42, 262, 0x0, STR_NULL},
|
|
{ WWT_PANEL, RESIZE_NONE, 10, 0, 369, 263, 278, 0x0, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 105, 185, 265, 276, STR_OPTIONS_SAVE_CHANGES, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 186, 266, 265, 276, STR_012E_CANCEL, STR_NULL},
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _game_difficulty_desc = {
|
|
WDP_CENTER, WDP_CENTER, 370, 279,
|
|
WC_GAME_OPTIONS,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
|
|
_game_difficulty_widgets,
|
|
GameDifficultyWndProc
|
|
};
|
|
|
|
void ShowGameDifficulty(void)
|
|
{
|
|
DeleteWindowById(WC_GAME_OPTIONS, 0);
|
|
/* Copy current settings (ingame or in intro) to temporary holding place
|
|
* change that when setting stuff, copy back on clicking 'OK' */
|
|
memcpy(&_opt_mod_temp, _opt_ptr, sizeof(GameOptions));
|
|
AllocateWindowDesc(&_game_difficulty_desc);
|
|
}
|
|
|
|
// virtual PositionMainToolbar function, calls the right one.
|
|
static int32 v_PositionMainToolbar(int32 p1)
|
|
{
|
|
if (_game_mode != GM_MENU)
|
|
PositionMainToolbar(NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32 AiNew_PatchActive_Warning(int32 p1)
|
|
{
|
|
if (p1 == 1)
|
|
ShowErrorMessage(-1, TEMP_AI_ACTIVATED, 0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32 PopulationInLabelActive(int32 p1)
|
|
{
|
|
Town *t;
|
|
|
|
FOR_ALL_TOWNS(t) {
|
|
if (t->xy) {
|
|
UpdateTownVirtCoord(t);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32 InvisibleTreesActive(int32 p1)
|
|
{
|
|
MarkWholeScreenDirty();
|
|
return 0;
|
|
}
|
|
|
|
static int32 InValidateDetailsWindow(int32 p1)
|
|
{
|
|
InvalidateWindowClasses(WC_VEHICLE_DETAILS);
|
|
return 0;
|
|
}
|
|
|
|
static int32 InvalidateStationBuildWindow(int32 p1)
|
|
{
|
|
InvalidateWindow(WC_BUILD_STATION, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* Check service intervals of vehicles, p1 is value of % or day based servicing */
|
|
static int32 CheckInterval(int32 p1)
|
|
{
|
|
bool warning;
|
|
if (p1) {
|
|
warning = ( (IS_INT_INSIDE(_patches.servint_trains, 5, 90+1) || _patches.servint_trains == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_roadveh, 5, 90+1) || _patches.servint_roadveh == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_aircraft, 5, 90+1) || _patches.servint_aircraft == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_ships, 5, 90+1) || _patches.servint_ships == 0) );
|
|
} else {
|
|
warning = ( (IS_INT_INSIDE(_patches.servint_trains, 30, 800+1) || _patches.servint_trains == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_roadveh, 30, 800+1) || _patches.servint_roadveh == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_aircraft, 30, 800+1) || _patches.servint_aircraft == 0) &&
|
|
(IS_INT_INSIDE(_patches.servint_ships, 30, 800+1) || _patches.servint_ships == 0) );
|
|
}
|
|
|
|
if (!warning)
|
|
ShowErrorMessage(-1, STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE, 0, 0);
|
|
|
|
return InValidateDetailsWindow(0);
|
|
}
|
|
|
|
typedef int32 PatchButtonClick(int32);
|
|
|
|
typedef struct PatchEntry {
|
|
byte type; // type of selector
|
|
byte flags; // selector flags
|
|
StringID str; // string with descriptive text
|
|
char console_name[40]; // the name this patch has in console
|
|
void *variable; // pointer to the variable
|
|
int32 min, max; // range for spinbox setting
|
|
uint32 step; // step for spinbox
|
|
PatchButtonClick *click_proc; // callback procedure
|
|
} PatchEntry;
|
|
|
|
enum {
|
|
PE_BOOL = 0,
|
|
PE_UINT8 = 1,
|
|
PE_INT16 = 2,
|
|
PE_UINT16 = 3,
|
|
PE_INT32 = 4,
|
|
PE_CURRENCY = 5,
|
|
// selector flags
|
|
PF_0ISDIS = 1 << 0,
|
|
PF_NOCOMMA = 1 << 1,
|
|
PF_MULTISTRING = 1 << 2,
|
|
PF_PLAYERBASED = 1 << 3, // This has to match the entries that are in settings.c, patch_player_settings
|
|
PF_NETWORK_ONLY = 1 << 4, // this setting only applies to network games
|
|
};
|
|
|
|
static const PatchEntry _patches_ui[] = {
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_VEHICLESPEED, "vehicle_speed", &_patches.vehicle_speed, 0, 0, 0, NULL},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_LONGDATE, "long_date", &_patches.status_long_date, 0, 0, 0, NULL},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_SHOWFINANCES, "show_finances", &_patches.show_finances, 0, 0, 0, NULL},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTOSCROLL, "autoscroll", &_patches.autoscroll, 0, 0, 0, NULL},
|
|
|
|
{PE_UINT8, PF_PLAYERBASED, STR_CONFIG_PATCHES_ERRMSG_DURATION, "errmsg_duration", &_patches.errmsg_duration, 0, 20, 1, NULL},
|
|
|
|
{PE_UINT8, PF_MULTISTRING | PF_PLAYERBASED, STR_CONFIG_PATCHES_TOOLBAR_POS, "toolbar_pos", &_patches.toolbar_pos, 0, 2, 1, &v_PositionMainToolbar},
|
|
{PE_UINT8, PF_0ISDIS | PF_PLAYERBASED, STR_CONFIG_PATCHES_SNAP_RADIUS, "window_snap_radius", &_patches.window_snap_radius, 1, 32, 1, NULL},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_INVISIBLE_TREES, "invisible_trees", &_patches.invisible_trees, 0, 1, 1, &InvisibleTreesActive},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_POPULATION_IN_LABEL, "population_in_label", &_patches.population_in_label, 0, 1, 1, &PopulationInLabelActive},
|
|
|
|
{PE_INT32, 0, STR_CONFIG_PATCHES_MAP_X, "map_x", &_patches.map_x, 6, 11, 1, NULL},
|
|
{PE_INT32, 0, STR_CONFIG_PATCHES_MAP_Y, "map_y", &_patches.map_y, 6, 11, 1, NULL},
|
|
};
|
|
|
|
static const PatchEntry _patches_construction[] = {
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_BUILDONSLOPES, "build_on_slopes", &_patches.build_on_slopes, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_EXTRADYNAMITE, "extra_dynamite", &_patches.extra_dynamite, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_LONGBRIDGES, "long_bridges", &_patches.longbridges, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SIGNALSIDE, "signal_side", &_patches.signal_side, 0, 0, 0, NULL},
|
|
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SMALL_AIRPORTS, "always_small_airport", &_patches.always_small_airport, 0, 0, 0, NULL},
|
|
{PE_UINT8, PF_PLAYERBASED, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY, "drag_signals_density", &_patches.drag_signals_density, 1, 20, 1, NULL},
|
|
|
|
};
|
|
|
|
static const PatchEntry _patches_vehicles[] = {
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_REALISTICACCEL, "realistic_acceleration", &_patches.realistic_acceleration, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_FORBID_90_DEG, "forbid_90_deg", &_patches.forbid_90_deg, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_MAMMOTHTRAINS, "mammoth_trains", &_patches.mammoth_trains, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_GOTODEPOT, "goto_depot", &_patches.gotodepot, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_ROADVEH_QUEUE, "roadveh_queue", &_patches.roadveh_queue, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_DEPOT_FINDING,"depot_finding", &_patches.new_depot_finding, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_TRAIN_PATHFIND,"new_pathfinding", &_patches.new_pathfinding, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL, "new_pathfinding_all", &_patches.new_pathfinding_all, 0, 0, 0, NULL},
|
|
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_WARN_INCOME_LESS, "train_income_warn", &_patches.train_income_warn, 0, 0, 0, NULL},
|
|
{PE_UINT8, PF_MULTISTRING | PF_PLAYERBASED, STR_CONFIG_PATCHES_ORDER_REVIEW, "order_review_system", &_patches.order_review_system,0,2, 1, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES, "never_expire_vehicles", &_patches.never_expire_vehicles,0,0,0, NULL},
|
|
|
|
{PE_UINT16, PF_0ISDIS | PF_PLAYERBASED, STR_CONFIG_PATCHES_LOST_TRAIN_DAYS, "lost_train_days", &_patches.lost_train_days, 180,720, 60, NULL},
|
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_VEHICLE,"autorenew", &_patches.autorenew, 0, 0, 0, NULL},
|
|
{PE_INT16, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_MONTHS, "autorenew_months", &_patches.autorenew_months, -12, 12, 1, NULL},
|
|
{PE_CURRENCY, PF_PLAYERBASED, STR_CONFIG_PATCHES_AUTORENEW_MONEY,"autorenew_money", &_patches.autorenew_money, 0, 2000000, 100000, NULL},
|
|
|
|
{PE_UINT16, 0, STR_CONFIG_PATCHES_MAX_TRAINS, "max_trains", &_patches.max_trains, 0,5000, 50, NULL},
|
|
{PE_UINT16, 0, STR_CONFIG_PATCHES_MAX_ROADVEH, "max_roadveh", &_patches.max_roadveh, 0,5000, 50, NULL},
|
|
{PE_UINT16, 0, STR_CONFIG_PATCHES_MAX_AIRCRAFT, "max_aircraft", &_patches.max_aircraft, 0,5000, 50, NULL},
|
|
{PE_UINT16, 0, STR_CONFIG_PATCHES_MAX_SHIPS, "max_ships", &_patches.max_ships, 0,5000, 50, NULL},
|
|
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SERVINT_ISPERCENT,"servint_isperfect",&_patches.servint_ispercent, 0, 0, 0, &CheckInterval},
|
|
{PE_UINT16, PF_0ISDIS, STR_CONFIG_PATCHES_SERVINT_TRAINS, "servint_trains", &_patches.servint_trains, 5,800, 5, &InValidateDetailsWindow},
|
|
{PE_UINT16, PF_0ISDIS, STR_CONFIG_PATCHES_SERVINT_ROADVEH, "servint_roadveh", &_patches.servint_roadveh, 5,800, 5, &InValidateDetailsWindow},
|
|
{PE_UINT16, PF_0ISDIS, STR_CONFIG_PATCHES_SERVINT_AIRCRAFT, "servint_aircraft", &_patches.servint_aircraft, 5,800, 5, &InValidateDetailsWindow},
|
|
{PE_UINT16, PF_0ISDIS, STR_CONFIG_PATCHES_SERVINT_SHIPS, "servint_ships", &_patches.servint_ships, 5,800, 5, &InValidateDetailsWindow},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NOSERVICE, "no_servicing_if_no_breakdowns", &_patches.no_servicing_if_no_breakdowns, 0, 0, 0, NULL},
|
|
};
|
|
|
|
static const PatchEntry _patches_stations[] = {
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_JOINSTATIONS, "join_stations", &_patches.join_stations, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_FULLLOADANY, "full_load_any", &_patches.full_load_any, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_IMPROVEDLOAD, "improved_load", &_patches.improved_load, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SELECTGOODS, "select_goods", &_patches.selectgoods, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_NONSTOP, "new_nonstop", &_patches.new_nonstop, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NONUNIFORM_STATIONS, "nonuniform_stations", &_patches.nonuniform_stations, 0, 0, 0, NULL},
|
|
{PE_UINT8, 0, STR_CONFIG_PATCHES_STATION_SPREAD, "station_spread", &_patches.station_spread, 4, 64, 1, &InvalidateStationBuildWindow},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SERVICEATHELIPAD, "service_at_helipad", &_patches.serviceathelipad, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_CATCHMENT, "modified_catchment", &_patches.modified_catchment, 0, 0, 0, NULL},
|
|
|
|
};
|
|
|
|
static const PatchEntry _patches_economy[] = {
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_INFLATION, "inflation", &_patches.inflation, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_BUILDXTRAIND, "build_rawmaterial", &_patches.build_rawmaterial_ind, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_MULTIPINDTOWN, "multiple_industry_per_town", &_patches.multiple_industry_per_town,0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SAMEINDCLOSE, "same_industry_close", &_patches.same_industry_close, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_BRIBE, "bribe", &_patches.bribe, 0, 0, 0, NULL},
|
|
{PE_UINT8, 0, STR_CONFIG_PATCHES_SNOWLINE_HEIGHT, "snow_line_height", &_patches.snow_line_height, 2, 13, 1, NULL},
|
|
|
|
{PE_INT32, PF_NOCOMMA, STR_CONFIG_PATCHES_COLORED_NEWS_DATE, "colored_new_data", &_patches.colored_news_date, 1900, 2200, 5, NULL},
|
|
{PE_INT32, PF_NOCOMMA, STR_CONFIG_PATCHES_STARTING_DATE, "starting_date", &_patches.starting_date, MAX_YEAR_BEGIN_REAL, MAX_YEAR_END_REAL, 1, NULL},
|
|
{PE_INT32, PF_NOCOMMA | PF_NETWORK_ONLY, STR_CONFIG_PATCHES_ENDING_DATE, "ending_date", &_patches.ending_date, MAX_YEAR_BEGIN_REAL, MAX_YEAR_END_REAL, 1, NULL},
|
|
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_SMOOTH_ECONOMY, "smooth_economy", &_patches.smooth_economy, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_ALLOW_SHARES, "allow_shares", &_patches.allow_shares, 0, 0, 0, NULL},
|
|
};
|
|
|
|
static const PatchEntry _patches_ai[] = {
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_AINEW_ACTIVE, "ainew_active", &_patches.ainew_active, 0, 1, 1, &AiNew_PatchActive_Warning},
|
|
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_AI_BUILDS_TRAINS, "ai_disable_veh_train", &_patches.ai_disable_veh_train, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_AI_BUILDS_ROADVEH,"ai_disable_veh_roadveh",&_patches.ai_disable_veh_roadveh, 0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_AI_BUILDS_AIRCRAFT,"ai_disable_veh_aircraft",&_patches.ai_disable_veh_aircraft,0, 0, 0, NULL},
|
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_AI_BUILDS_SHIPS,"ai_disable_veh_ship",&_patches.ai_disable_veh_ship, 0, 0, 0, NULL},
|
|
};
|
|
|
|
typedef struct PatchPage {
|
|
const PatchEntry *entries;
|
|
uint num;
|
|
} PatchPage;
|
|
|
|
static const PatchPage _patches_page[] = {
|
|
{_patches_ui, lengthof(_patches_ui) },
|
|
{_patches_construction, lengthof(_patches_construction) },
|
|
{_patches_vehicles, lengthof(_patches_vehicles) },
|
|
{_patches_stations, lengthof(_patches_stations) },
|
|
{_patches_economy, lengthof(_patches_economy) },
|
|
{_patches_ai, lengthof(_patches_ai) },
|
|
};
|
|
|
|
|
|
static int32 ReadPE(const PatchEntry*pe)
|
|
{
|
|
switch (pe->type) {
|
|
case PE_BOOL: return *(bool*)pe->variable;
|
|
case PE_UINT8: return *(uint8*)pe->variable;
|
|
case PE_INT16: return *(int16*)pe->variable;
|
|
case PE_UINT16: return *(uint16*)pe->variable;
|
|
case PE_INT32: return *(int32*)pe->variable;
|
|
case PE_CURRENCY: return (*(int32*)pe->variable) * GetCurrentCurrencyRate();
|
|
default: NOT_REACHED();
|
|
}
|
|
|
|
/* useless, but avoids compiler warning this way */
|
|
return 0;
|
|
}
|
|
|
|
static void WritePE(const PatchEntry *pe, int32 val)
|
|
{
|
|
if ((pe->flags & PF_0ISDIS) && val <= 0) {
|
|
switch (pe->type) {
|
|
case PE_BOOL: case PE_UINT8:
|
|
*(bool*)pe->variable = 0;
|
|
break;
|
|
case PE_INT16: case PE_UINT16:
|
|
*(int16*)pe->variable = 0;
|
|
break;
|
|
case PE_CURRENCY: case PE_INT32:
|
|
*(int32*)pe->variable = 0;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// "clamp" 'disabled' value to smallest type
|
|
switch (pe->type) {
|
|
case PE_BOOL:
|
|
*(bool*)pe->variable = (bool)val;
|
|
break;
|
|
case PE_UINT8:
|
|
*(uint8*)pe->variable = (uint8)clamp((uint8)val, (uint8)pe->min, (uint8)pe->max);
|
|
break;
|
|
case PE_INT16:
|
|
*(int16*)pe->variable = (int16)clamp((int16)val, (int16)pe->min, (int16)pe->max);
|
|
break;
|
|
case PE_UINT16:
|
|
*(uint16*)pe->variable = (uint16)clamp((uint16)val, (uint16)pe->min, (uint16)pe->max);
|
|
break;
|
|
case PE_CURRENCY: case PE_INT32:
|
|
*(int32*)pe->variable = (int32)clamp((int32)val, (int32)pe->min, (int32)pe->max);
|
|
break;
|
|
default: NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
uint i;
|
|
switch (e->event) {
|
|
case WE_PAINT: {
|
|
int x,y;
|
|
const PatchEntry *pe;
|
|
const PatchPage *page;
|
|
uint clk;
|
|
int32 val;
|
|
|
|
w->click_state = 1 << (WP(w,def_d).data_1 + 4);
|
|
|
|
DrawWindowWidgets(w);
|
|
|
|
x = 0;
|
|
y = 46;
|
|
clk = WP(w,def_d).data_2;
|
|
page = &_patches_page[WP(w,def_d).data_1];
|
|
for (i = 0, pe = page->entries; i != page->num; i++, pe++) {
|
|
bool disabled = false;
|
|
bool editable = true;
|
|
|
|
if ((pe->flags & PF_NETWORK_ONLY) && !_networking)
|
|
editable = false;
|
|
|
|
// We do not allow changes of some items when we are a client in a networkgame
|
|
if (!(pe->flags & PF_PLAYERBASED) && _networking && !_network_server)
|
|
editable = false;
|
|
if (pe->type == PE_BOOL) {
|
|
if (editable)
|
|
DrawFrameRect(x+5, y+1, x+15+9, y+9, (*(bool*)pe->variable)?6:4, (*(bool*)pe->variable)?0x20:0);
|
|
else
|
|
DrawFrameRect(x+5, y+1, x+15+9, y+9, (*(bool*)pe->variable)?7:9, (*(bool*)pe->variable)?0x20:0);
|
|
SetDParam(0, *(bool*)pe->variable ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
|
|
} else {
|
|
DrawFrameRect(x+5, y+1, x+5+9, y+9, 3, clk == i*2+1 ? 0x20 : 0);
|
|
DrawFrameRect(x+15, y+1, x+15+9, y+9, 3, clk == i*2+2 ? 0x20 : 0);
|
|
if (!editable) {
|
|
int color = 0x8000 | _color_list[3].unk2;
|
|
GfxFillRect(x+6, y+2, x+6+8, y+9, color);
|
|
GfxFillRect(x+16, y+2, x+16+8, y+9, color);
|
|
}
|
|
DrawStringCentered(x+10, y+1, STR_6819, 0);
|
|
DrawStringCentered(x+20, y+1, STR_681A, 0);
|
|
|
|
val = ReadPE(pe);
|
|
if (pe->type == PE_CURRENCY)
|
|
val /= GetCurrentCurrencyRate();
|
|
disabled = ((val == 0) && (pe->flags & PF_0ISDIS));
|
|
if (disabled) {
|
|
SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
|
|
} else {
|
|
SetDParam(1, val);
|
|
if (pe->type == PE_CURRENCY)
|
|
SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
|
|
else {
|
|
if (pe->flags & PF_MULTISTRING)
|
|
SetDParam(0, pe->str + val + 1);
|
|
else
|
|
SetDParam(0, pe->flags & PF_NOCOMMA ? STR_CONFIG_PATCHES_INT32 : STR_7024);
|
|
}
|
|
}
|
|
}
|
|
DrawString(30, y+1, (pe->str)+disabled, 0);
|
|
y += 11;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WE_CLICK:
|
|
switch(e->click.widget) {
|
|
case 3: {
|
|
int x,y;
|
|
uint btn;
|
|
const PatchPage *page;
|
|
const PatchEntry *pe;
|
|
|
|
y = e->click.pt.y - 46 - 1;
|
|
if (y < 0) return;
|
|
|
|
btn = y / 11;
|
|
if (y % 11 > 9) return;
|
|
|
|
page = &_patches_page[WP(w,def_d).data_1];
|
|
if (btn >= page->num) return;
|
|
pe = &page->entries[btn];
|
|
|
|
x = e->click.pt.x - 5;
|
|
if (x < 0) return;
|
|
|
|
if (((pe->flags & PF_NETWORK_ONLY) && !_networking) || // return if action is only active in network
|
|
(!(pe->flags & PF_PLAYERBASED) && _networking && !_network_server)) // return if only server can change it
|
|
return;
|
|
|
|
if (x < 21) { // clicked on the icon on the left side. Either scroller or bool on/off
|
|
int32 val = ReadPE(pe), oval = val;
|
|
|
|
switch(pe->type) {
|
|
case PE_BOOL:
|
|
val ^= 1;
|
|
break;
|
|
case PE_UINT8:
|
|
case PE_INT16:
|
|
case PE_UINT16:
|
|
case PE_INT32:
|
|
case PE_CURRENCY:
|
|
// don't allow too fast scrolling
|
|
if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
|
|
_left_button_clicked = false;
|
|
return;
|
|
}
|
|
|
|
if (x >= 10) {
|
|
//increase
|
|
if (pe->flags & PF_0ISDIS && val == 0)
|
|
val = pe->min;
|
|
else
|
|
val += pe->step;
|
|
if (val > pe->max) val = pe->max;
|
|
} else {
|
|
// decrease
|
|
if (val <= pe->min && pe->flags & PF_0ISDIS) {
|
|
val = 0;
|
|
} else {
|
|
val -= pe->step;
|
|
if (val < pe->min) val = pe->min;
|
|
}
|
|
}
|
|
|
|
if (val != oval) {
|
|
WP(w,def_d).data_2 = btn * 2 + 1 + ((x>=10) ? 1 : 0);
|
|
w->flags4 |= 5 << WF_TIMEOUT_SHL;
|
|
_left_button_clicked = false;
|
|
}
|
|
break;
|
|
}
|
|
if (val != oval) {
|
|
// To make patch-changes network-safe
|
|
if (pe->type == PE_CURRENCY) {
|
|
val /= GetCurrentCurrencyRate();
|
|
}
|
|
// If an item is playerbased, we do not send it over the network (if any)
|
|
if (pe->flags & PF_PLAYERBASED) {
|
|
WritePE(pe, val);
|
|
} else {
|
|
// Else we do
|
|
DoCommandP(0, (byte)WP(w,def_d).data_1 + ((byte)btn << 8), val, NULL, CMD_CHANGE_PATCH_SETTING);
|
|
}
|
|
SetWindowDirty(w);
|
|
|
|
if (pe->click_proc != NULL) // call callback function
|
|
pe->click_proc(val);
|
|
}
|
|
} else {
|
|
if (pe->type != PE_BOOL && !(pe->flags & PF_MULTISTRING)) { // do not open editbox
|
|
WP(w,def_d).data_3 = btn;
|
|
SetDParam(0, ReadPE(pe));
|
|
ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, WC_GAME_OPTIONS, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 4: case 5: case 6: case 7: case 8: case 9:
|
|
WP(w,def_d).data_1 = e->click.widget - 4;
|
|
DeleteWindowById(WC_QUERY_STRING, 0);
|
|
SetWindowDirty(w);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WE_TIMEOUT:
|
|
WP(w,def_d).data_2 = 0;
|
|
SetWindowDirty(w);
|
|
break;
|
|
|
|
case WE_ON_EDIT_TEXT: {
|
|
if (*e->edittext.str) {
|
|
const PatchPage *page = &_patches_page[WP(w,def_d).data_1];
|
|
const PatchEntry *pe = &page->entries[WP(w,def_d).data_3];
|
|
int32 val;
|
|
val = atoi(e->edittext.str);
|
|
if (pe->type == PE_CURRENCY) {
|
|
val /= GetCurrentCurrencyRate();
|
|
}
|
|
// If an item is playerbased, we do not send it over the network (if any)
|
|
if (pe->flags & PF_PLAYERBASED) {
|
|
WritePE(pe, val);
|
|
} else {
|
|
// Else we do
|
|
DoCommandP(0, (byte)WP(w,def_d).data_1 + ((byte)WP(w,def_d).data_3 << 8), val, NULL, CMD_CHANGE_PATCH_SETTING);
|
|
}
|
|
SetWindowDirty(w);
|
|
|
|
if (pe->click_proc != NULL) // call callback function
|
|
pe->click_proc(*(int32*)pe->variable);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WE_DESTROY:
|
|
DeleteWindowById(WC_QUERY_STRING, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/** Network-safe changing of patch-settings.
|
|
* @param p1 various bitstuffed elements
|
|
* - p1 = (bit 0- 7) - the patches type (page) that is being changed (construction, network, ai) (p1 & 0xFF)
|
|
* - p2 = (bit 8-15) - the actual patch (entry) being set inside the category ((p1>>8) & 0xFF)
|
|
* @param p2 the new value for the patch
|
|
* @todo check that the new value is a valid one. Awful lot of work, but since only
|
|
* the server is allowed to do this, we trust it on this one :)
|
|
*/
|
|
int32 CmdChangePatchSetting(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|
{
|
|
byte pcat = p1 & 0xFF;
|
|
byte pel = (p1 >> 8) & 0xFF;
|
|
|
|
if (pcat >= lengthof(_patches_page)) return CMD_ERROR;
|
|
if (pel >= _patches_page[pcat].num) return CMD_ERROR;
|
|
|
|
if (flags & DC_EXEC) {
|
|
const PatchEntry *pe = &_patches_page[pcat].entries[pel];
|
|
WritePE(pe, (int32)p2);
|
|
|
|
InvalidateWindow(WC_GAME_OPTIONS, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const PatchEntry *IConsoleGetPatch(const char *name, uint *page, uint *entry)
|
|
{
|
|
const PatchPage *pp;
|
|
const PatchEntry *pe;
|
|
|
|
for (*page = 0; *page < lengthof(_patches_page); (*page)++) {
|
|
pp = &_patches_page[*page];
|
|
for (*entry = 0; *entry < pp->num; (*entry)++) {
|
|
pe = &pp->entries[*entry];
|
|
if (strncmp(pe->console_name, name, sizeof(pe->console_name)) == 0)
|
|
return pe;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Those 2 functions need to be here, else we have to make some stuff non-static
|
|
and besides, it is also better to keep stuff like this at the same place */
|
|
void IConsoleSetPatchSetting(char *name, const char *value)
|
|
{
|
|
const PatchEntry *pe;
|
|
uint page, entry;
|
|
int val;
|
|
|
|
pe = IConsoleGetPatch(name, &page, &entry);
|
|
|
|
if (pe == NULL) {
|
|
IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
|
|
return;
|
|
}
|
|
|
|
sscanf(value, "%d", &val);
|
|
|
|
if (pe->type == PE_CURRENCY) // currency can be different on each client
|
|
val /= GetCurrentCurrencyRate();
|
|
|
|
// If an item is playerbased, we do not send it over the network (if any)
|
|
if (pe->flags & PF_PLAYERBASED) {
|
|
WritePE(pe, val);
|
|
} else // Else we do
|
|
DoCommandP(0, page + (entry << 8), val, NULL, CMD_CHANGE_PATCH_SETTING);
|
|
|
|
{
|
|
char tval[20];
|
|
const char *tval2 = value;
|
|
if (pe->type == PE_BOOL) {
|
|
snprintf(tval, sizeof(tval), (val == 1) ? "on" : "off");
|
|
tval2 = tval;
|
|
}
|
|
|
|
IConsolePrintF(_icolour_warn, "'%s' changed to: %s", name, tval2);
|
|
}
|
|
}
|
|
|
|
void IConsoleGetPatchSetting(const char *name)
|
|
{
|
|
char value[20];
|
|
uint page, entry;
|
|
const PatchEntry *pe = IConsoleGetPatch(name, &page, &entry);
|
|
|
|
/* We did not find the patch setting */
|
|
if (pe == NULL) {
|
|
IConsolePrintF(_icolour_warn, "'%s' is an unknown patch setting.", name);
|
|
return;
|
|
}
|
|
|
|
if (pe->type == PE_BOOL) {
|
|
snprintf(value, sizeof(value), (ReadPE(pe) == 1) ? "on" : "off");
|
|
} else
|
|
snprintf(value, sizeof(value), "%d", ReadPE(pe));
|
|
|
|
IConsolePrintF(_icolour_warn, "Current value for '%s' is: '%s'", name, value);
|
|
}
|
|
|
|
static const Widget _patches_selection_widgets[] = {
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, RESIZE_NONE, 10, 11, 369, 0, 13, STR_CONFIG_PATCHES_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_PANEL, RESIZE_NONE, 10, 0, 369, 14, 41, 0x0, STR_NULL},
|
|
{ WWT_PANEL, RESIZE_NONE, 10, 0, 369, 42, 320, 0x0, STR_NULL},
|
|
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 10, 96, 16, 27, STR_CONFIG_PATCHES_GUI, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 97, 183, 16, 27, STR_CONFIG_PATCHES_CONSTRUCTION, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 184, 270, 16, 27, STR_CONFIG_PATCHES_VEHICLES, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 271, 357, 16, 27, STR_CONFIG_PATCHES_STATIONS, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 10, 96, 28, 39, STR_CONFIG_PATCHES_ECONOMY, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 3, 97, 183, 28, 39, STR_CONFIG_PATCHES_AI, STR_NULL},
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _patches_selection_desc = {
|
|
WDP_CENTER, WDP_CENTER, 370, 321,
|
|
WC_GAME_OPTIONS,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
|
|
_patches_selection_widgets,
|
|
PatchesSelectionWndProc,
|
|
};
|
|
|
|
void ShowPatchesSelection(void)
|
|
{
|
|
DeleteWindowById(WC_GAME_OPTIONS, 0);
|
|
AllocateWindowDesc(&_patches_selection_desc);
|
|
}
|
|
|
|
enum {
|
|
NEWGRF_WND_PROC_OFFSET_TOP_WIDGET = 14,
|
|
NEWGRF_WND_PROC_ROWSIZE = 14
|
|
};
|
|
|
|
static void NewgrfWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
static GRFFile *_sel_grffile;
|
|
switch (e->event) {
|
|
case WE_PAINT: {
|
|
int x, y = NEWGRF_WND_PROC_OFFSET_TOP_WIDGET;
|
|
uint16 i = 0;
|
|
GRFFile *c = _first_grffile;
|
|
|
|
DrawWindowWidgets(w);
|
|
|
|
if (_first_grffile == NULL) { // no grf sets installed
|
|
DrawStringMultiCenter(140, 210, STR_NEWGRF_NO_FILES_INSTALLED, 250);
|
|
break;
|
|
}
|
|
|
|
// draw list of all grf files
|
|
while (c != NULL) {
|
|
if (i >= w->vscroll.pos) { // draw files according to scrollbar position
|
|
bool h = (_sel_grffile==c);
|
|
// show highlighted item with a different background and highlighted text
|
|
if(h) GfxFillRect(1, y + 1, 267, y + 12, 156);
|
|
// XXX - will be grf name later
|
|
DoDrawString(c->filename, 25, y + 2, h ? 0xC : 0x10);
|
|
DrawSprite(SPRITE_PALETTE(SPR_SQUARE | 0x30b8000), 5, y + 2);
|
|
y += NEWGRF_WND_PROC_ROWSIZE;
|
|
}
|
|
|
|
c = c->next;
|
|
if (++i == w->vscroll.cap + w->vscroll.pos) break; // stop after displaying 12 items
|
|
}
|
|
|
|
// DoDrawString(_sel_grffile->setname, 120, 200, 0x01); // draw grf name
|
|
|
|
if (_sel_grffile == NULL) { // no grf file selected yet
|
|
DrawStringMultiCenter(140, 210, STR_NEWGRF_TIP, 250);
|
|
} else {
|
|
// draw filename
|
|
x = DrawString(5, 199, STR_NEWGRF_FILENAME, 0);
|
|
DoDrawString(_sel_grffile->filename, x + 2, 199, 0x01);
|
|
|
|
// draw grf id
|
|
x = DrawString(5, 209, STR_NEWGRF_GRF_ID, 0);
|
|
snprintf(_userstring, USERSTRING_LEN, "%08X", _sel_grffile->grfid);
|
|
DrawString(x + 2, 209, STR_SPEC_USERSTRING, 0x01);
|
|
}
|
|
} break;
|
|
|
|
case WE_CLICK:
|
|
switch(e->click.widget) {
|
|
case 3: { // select a grf file
|
|
int y = (e->click.pt.y - NEWGRF_WND_PROC_OFFSET_TOP_WIDGET) / NEWGRF_WND_PROC_ROWSIZE;
|
|
|
|
if (y >= w->vscroll.cap) { return;} // click out of bounds
|
|
|
|
y += w->vscroll.pos;
|
|
|
|
if (y >= _grffile_count) return;
|
|
|
|
_sel_grffile = _first_grffile;
|
|
// get selected grf-file
|
|
while (y-- != 0) _sel_grffile = _sel_grffile->next;
|
|
|
|
SetWindowDirty(w);
|
|
} break;
|
|
case 9: /* Cancel button */
|
|
DeleteWindowById(WC_GAME_OPTIONS, 0);
|
|
break;
|
|
} break;
|
|
|
|
/* Parameter edit box not used yet
|
|
case WE_TIMEOUT:
|
|
WP(w,def_d).data_2 = 0;
|
|
SetWindowDirty(w);
|
|
break;
|
|
|
|
case WE_ON_EDIT_TEXT: {
|
|
if (*e->edittext.str) {
|
|
SetWindowDirty(w);
|
|
}
|
|
break;
|
|
}
|
|
*/
|
|
case WE_DESTROY:
|
|
_sel_grffile = NULL;
|
|
DeleteWindowById(WC_QUERY_STRING, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const Widget _newgrf_widgets[] = {
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 279, 0, 13, STR_NEWGRF_SETTINGS_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_PANEL, RESIZE_NONE, 14, 0, 279, 183, 276, 0x0, STR_NULL},
|
|
|
|
{ WWT_MATRIX, RESIZE_NONE, 14, 0, 267, 14, 182, 0xC01,/*small rows*/ STR_NEWGRF_TIP},
|
|
{ WWT_SCROLLBAR, RESIZE_NONE, 14, 268, 279, 14, 182, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
|
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 147, 158, 244, 255, STR_0188, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 159, 170, 244, 255, STR_0189, STR_NULL},
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 175, 274, 244, 255, STR_NEWGRF_SET_PARAMETERS, STR_NULL},
|
|
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 5, 138, 261, 272, STR_NEWGRF_APPLY_CHANGES, STR_NULL},
|
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, 3, 142, 274, 261, 272, STR_012E_CANCEL, STR_NULL},
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _newgrf_desc = {
|
|
WDP_CENTER, WDP_CENTER, 280, 277,
|
|
WC_GAME_OPTIONS,0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
|
|
_newgrf_widgets,
|
|
NewgrfWndProc,
|
|
};
|
|
|
|
void ShowNewgrf(void)
|
|
{
|
|
Window *w;
|
|
DeleteWindowById(WC_GAME_OPTIONS, 0);
|
|
w = AllocateWindowDesc(&_newgrf_desc);
|
|
|
|
{ // little helper function to calculate _grffile_count
|
|
// should be REMOVED once _grffile_count is calculated at loading
|
|
GRFFile *c = _first_grffile;
|
|
|
|
_grffile_count = 0;
|
|
while (c != NULL) {
|
|
_grffile_count++;
|
|
c = c->next;
|
|
}
|
|
}
|
|
|
|
w->vscroll.cap = 12;
|
|
w->vscroll.count = _grffile_count;
|
|
w->vscroll.pos = 0;
|
|
w->disabled_state = (1 << 5) | (1 << 6) | (1 << 7);
|
|
}
|
|
|
|
/* state: 0 = none clicked, 0x01 = first clicked, 0x02 = second clicked */
|
|
void DrawArrowButtons(int x, int y, int state)
|
|
{
|
|
DrawFrameRect(x, y+1, x+9, y+9, 3, (state&0x01) ? 0x20 : 0);
|
|
DrawFrameRect(x+10, y+1, x+19, y+9, 3, (state&0x02) ? 0x20 : 0);
|
|
DrawStringCentered(x+5, y+1, STR_6819, 0);
|
|
DrawStringCentered(x+15, y+1, STR_681A, 0);
|
|
}
|
|
|
|
char _str_separator[2];
|
|
|
|
static void CustCurrencyWndProc(Window *w, WindowEvent *e)
|
|
{
|
|
switch (e->event) {
|
|
case WE_PAINT: {
|
|
int x=35, y=20, i=0;
|
|
int clk = WP(w,def_d).data_1;
|
|
DrawWindowWidgets(w);
|
|
|
|
// exchange rate
|
|
DrawArrowButtons(10, y, (clk >> (i*2)) & 0x03);
|
|
SetDParam(0, 1);
|
|
SetDParam(1, 1);
|
|
DrawString(x, y + 1, STR_CURRENCY_EXCHANGE_RATE, 0);
|
|
x = 35;
|
|
y+=12;
|
|
i++;
|
|
|
|
// separator
|
|
DrawFrameRect(10, y+1, 29, y+9, 0, ((clk >> (i*2)) & 0x03)?0x20:0x00);
|
|
x = DrawString(x, y + 1, STR_CURRENCY_SEPARATOR, 0);
|
|
DoDrawString(_str_separator, x + 4, y + 1, 6);
|
|
x = 35;
|
|
y+=12;
|
|
i++;
|
|
|
|
// prefix
|
|
DrawFrameRect(10, y+1, 29, y+9, 0, ((clk >> (i*2)) & 0x03)?0x20:0x00);
|
|
x = DrawString(x, y + 1, STR_CURRENCY_PREFIX, 0);
|
|
DoDrawString(_currency_specs[23].prefix, x + 4, y + 1, 6);
|
|
x = 35;
|
|
y+=12;
|
|
i++;
|
|
|
|
// suffix
|
|
DrawFrameRect(10, y+1, 29, y+9, 0, ((clk >> (i*2)) & 0x03)?0x20:0x00);
|
|
x = DrawString(x, y + 1, STR_CURRENCY_SUFFIX, 0);
|
|
DoDrawString(_currency_specs[23].suffix, x + 4, y + 1, 6);
|
|
x = 35;
|
|
y+=12;
|
|
i++;
|
|
|
|
// switch to euro
|
|
DrawArrowButtons(10, y, (clk >> (i*2)) & 0x03);
|
|
SetDParam(0, _currency_specs[23].to_euro);
|
|
DrawString(x, y + 1, (_currency_specs[23].to_euro)?STR_CURRENCY_SWITCH_TO_EURO:STR_CURRENCY_SWITCH_TO_EURO_NEVER, 0);
|
|
x = 35;
|
|
y+=12;
|
|
i++;
|
|
|
|
// Preview
|
|
y+=12;
|
|
SetDParam(0, 10000);
|
|
DrawString(x, y + 1, STR_CURRENCY_PREVIEW, 0);
|
|
} break;
|
|
|
|
case WE_CLICK: {
|
|
bool edittext = false;
|
|
int line = (e->click.pt.y - 20)/12;
|
|
int len = 0;
|
|
int x = e->click.pt.x;
|
|
StringID str = 0;
|
|
|
|
switch ( line ) {
|
|
case 0: // rate
|
|
if ( IS_INT_INSIDE(x, 10, 30) ) { // clicked buttons
|
|
if (x < 20) {
|
|
_currency_specs[23].rate = max(1, _currency_specs[23].rate-1);
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 0));
|
|
} else {
|
|
_currency_specs[23].rate = min(5000, _currency_specs[23].rate+1);
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 1));
|
|
}
|
|
} else { // enter text
|
|
SetDParam(0, _currency_specs[23].rate);
|
|
str = STR_CONFIG_PATCHES_INT32;
|
|
len = 4;
|
|
edittext = true;
|
|
}
|
|
break;
|
|
case 1: // separator
|
|
if ( IS_INT_INSIDE(x, 10, 30) ) // clicked button
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 1));
|
|
str = AllocateName(_str_separator, 0);
|
|
len = 1;
|
|
edittext = true;
|
|
break;
|
|
case 2: // prefix
|
|
if ( IS_INT_INSIDE(x, 10, 30) ) // clicked button
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 1));
|
|
str = AllocateName(_currency_specs[23].prefix, 0);
|
|
len = 12;
|
|
edittext = true;
|
|
break;
|
|
case 3: // suffix
|
|
if ( IS_INT_INSIDE(x, 10, 30) ) // clicked button
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 1));
|
|
str = AllocateName(_currency_specs[23].suffix, 0);
|
|
len = 12;
|
|
edittext = true;
|
|
break;
|
|
case 4: // to euro
|
|
if ( IS_INT_INSIDE(x, 10, 30) ) { // clicked buttons
|
|
if (x < 20) {
|
|
if(_currency_specs[23].to_euro <= 2000) _currency_specs[23].to_euro = 0;
|
|
else _currency_specs[23].to_euro--;
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 0));
|
|
} else {
|
|
if(_currency_specs[23].to_euro == 0) _currency_specs[23].to_euro = 2000;
|
|
else _currency_specs[23].to_euro++;
|
|
_currency_specs[23].to_euro = min(MAX_YEAR_END_REAL, _currency_specs[23].to_euro);
|
|
WP(w,def_d).data_1 = (1 << (line * 2 + 1));
|
|
}
|
|
} else { // enter text
|
|
SetDParam(0, _currency_specs[23].to_euro);
|
|
str = STR_CONFIG_PATCHES_INT32;
|
|
len = 4;
|
|
edittext = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (edittext) {
|
|
WP(w,def_d).data_2 = line;
|
|
ShowQueryString(
|
|
str,
|
|
STR_CURRENCY_CHANGE_PARAMETER,
|
|
len + 1, // maximum number of characters OR
|
|
250, // characters up to this width pixels, whichever is satisfied first
|
|
w->window_class,
|
|
w->window_number);
|
|
if (str != STR_CONFIG_PATCHES_INT32) DeleteName(str);
|
|
}
|
|
|
|
w->flags4 |= 5 << WF_TIMEOUT_SHL;
|
|
SetWindowDirty(w);
|
|
} break;
|
|
|
|
case WE_ON_EDIT_TEXT: {
|
|
int val;
|
|
const char *b = e->edittext.str;
|
|
switch (WP(w,def_d).data_2) {
|
|
case 0: /* Exchange rate */
|
|
val = atoi(b);
|
|
val = clamp(val, 1, 5000);
|
|
_currency_specs[23].rate = val;
|
|
break;
|
|
case 1: /* Thousands seperator */
|
|
_currency_specs[23].separator = (b[0] == '\0') ? ' ' : b[0];
|
|
ttd_strlcpy(_str_separator, b, 16);
|
|
break;
|
|
case 2: /* Currency prefix */
|
|
ttd_strlcpy(_currency_specs[23].prefix, b, 16);
|
|
break;
|
|
case 3: /* Currency suffix */
|
|
ttd_strlcpy(_currency_specs[23].suffix, b, 16);
|
|
break;
|
|
case 4: /* Year to switch to euro */
|
|
val = atoi(b);
|
|
val = clamp(val, 1999, MAX_YEAR_END_REAL);
|
|
if (val == 1999) val = 0;
|
|
_currency_specs[23].to_euro = val;
|
|
break;
|
|
}
|
|
MarkWholeScreenDirty();
|
|
|
|
|
|
} break;
|
|
|
|
case WE_TIMEOUT:
|
|
WP(w,def_d).data_1 = 0;
|
|
SetWindowDirty(w);
|
|
break;
|
|
|
|
case WE_DESTROY:
|
|
DeleteWindowById(WC_QUERY_STRING, 0);
|
|
MarkWholeScreenDirty();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const Widget _cust_currency_widgets[] = {
|
|
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
|
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 229, 0, 13, STR_CURRENCY_WINDOW, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
|
{ WWT_PANEL, RESIZE_NONE, 14, 0, 229, 14, 119, 0x0, STR_NULL},
|
|
{ WIDGETS_END},
|
|
};
|
|
|
|
static const WindowDesc _cust_currency_desc = {
|
|
WDP_CENTER, WDP_CENTER, 230, 120,
|
|
WC_CUSTOM_CURRENCY, 0,
|
|
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
|
|
_cust_currency_widgets,
|
|
CustCurrencyWndProc,
|
|
};
|
|
|
|
void ShowCustCurrency(void)
|
|
{
|
|
Window *w;
|
|
|
|
_str_separator[0] = _currency_specs[23].separator;
|
|
_str_separator[1] = '\0';
|
|
|
|
DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
|
|
w = AllocateWindowDesc(&_cust_currency_desc);
|
|
}
|
|
|