1. In variables.h add this code
Code: Select all
#define MAX_REFRESH_RATES 16
uint16 _refresh_rates[MAX_REFRESH_RATES];
uint16 _num_refresh_rates;
uint16 _currentRefreshRate;
uint16 g_uiMaxRefresh;
void (*enumRefreshRates)(uint16 uiWidth, uint16 uiHeight);
int GetCurRes();
Code: Select all
...,
STR_OPTIONS_REFRESH_CBO,
STR_OPTIONS_REFRESH_TIP,
...
Code: Select all
...
//refresh rates
if (IS_INT_INSIDE(ind, (SPECSTR_REFRESH_START - 0x70E4), (SPECSTR_REFRESH_END - 0x70E4) + 1))
{
int i = ind - (SPECSTR_REFRESH_START - 0x70E4);
return buff + sprintf(buff, _refresh_rates[i]?"%d hz":"default", _refresh_rates[i]);
}
...
Code: Select all
bool ChangeRefreshInGame(uint16 uiRefreshNumber)
{
uint16 uiOldRefresh = _display_hz;
uint16 uiOldRefreshNumber = _currentRefreshRate;
if(!_fullscreen) return false;
if(uiRefreshNumber == _currentRefreshRate) return false;
_display_hz = _refresh_rates[uiRefreshNumber];
if(!_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1]))
{
_display_hz = uiOldRefresh;
return false;
}
_currentRefreshRate = uiRefreshNumber;
return true;
}
Code: Select all
...
SPECSTR_REFRESH_START = 0x7160,
SPECSTR_REFRESH_END = 0x717F,
...
Code: Select all
bool ChangeRefreshInGame(uint16 uiRefreshNumber);
so it would be look as
Code: Select all
int GetCurRes()
{...
Code: Select all
//refresh rate combobox
{ WWT_6, 14, 115, 169, 160, 171, STR_OPTIONS_REFRESH_CBO, STR_OPTIONS_REFRESH_TIP},
{ WWT_CLOSEBOX, 14, 158, 168, 161, 170, STR_0225, STR_OPTIONS_REFRESH_TIP},
Code: Select all
static const Widget _game_options_widgets[] = {
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, 14, 11, 369, 0, 13, STR_00B1_GAME_OPTIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, 14, 0, 369, 14, 238, 0x0, STR_NULL},
{ WWT_FRAME, 14, 10, 179, 20, 55, STR_02E0_CURRENCY_UNITS, STR_NULL},
{ WWT_6, 14, 20, 169, 34, 45, STR_02E1, STR_02E2_CURRENCY_UNITS_SELECTION},
{ WWT_CLOSEBOX, 14, 158, 168, 35, 44, STR_0225, STR_02E2_CURRENCY_UNITS_SELECTION},
{ WWT_FRAME, 14, 190, 359, 20, 55, STR_02E3_DISTANCE_UNITS, STR_NULL},
{ WWT_6, 14, 200, 349, 34, 45, STR_02E4, STR_02E5_DISTANCE_UNITS_SELECTION},
{ WWT_CLOSEBOX, 14, 338, 348, 35, 44, STR_0225, STR_02E5_DISTANCE_UNITS_SELECTION},
{ WWT_FRAME, 14, 10, 179, 62, 97, STR_02E6_ROAD_VEHICLES, STR_NULL},
{ WWT_6, 14, 20, 169, 76, 87, STR_02E7, STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
{ WWT_CLOSEBOX, 14, 158, 168, 77, 86, STR_0225, STR_02E8_SELECT_SIDE_OF_ROAD_FOR},
{ WWT_FRAME, 14, 190, 359, 62, 97, STR_02EB_TOWN_NAMES, STR_NULL},
{ WWT_6, 14, 200, 349, 76, 87, STR_02EC, STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
{ WWT_CLOSEBOX, 14, 338, 348, 77, 86, STR_0225, STR_02ED_SELECT_STYLE_OF_TOWN_NAMES},
{ WWT_FRAME, 14, 10, 179, 104, 139, STR_02F4_AUTOSAVE, STR_NULL},
{ WWT_6, 14, 20, 169, 118, 129, STR_02F5, STR_02F6_SELECT_INTERVAL_BETWEEN},
{ WWT_CLOSEBOX, 14, 158, 168, 119, 128, STR_0225, STR_02F6_SELECT_INTERVAL_BETWEEN},
{ WWT_FRAME, 14, 10, 359, 194, 228, STR_02BC_VEHICLE_DESIGN_NAMES, STR_NULL},
{ WWT_6, 14, 20, 119, 207, 218, STR_02BD, STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
{ WWT_CLOSEBOX, 14, 108, 118, 208, 217, STR_0225, STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION},
{ WWT_CLOSEBOX, 14, 130, 349, 207, 218, STR_02C0_SAVE_CUSTOM_NAMES_TO_DISK, STR_02C2_SAVE_CUSTOMIZED_VEHICLE},
{ WWT_FRAME, 14, 190, 359, 104, 139, STR_OPTIONS_LANG, STR_NULL},
{ WWT_6, 14, 200, 349, 118, 129, STR_OPTIONS_LANG_CBO, STR_OPTIONS_LANG_TIP},
{ WWT_CLOSEBOX, 14, 338, 348, 119, 128, STR_0225, STR_OPTIONS_LANG_TIP},
{ WWT_FRAME, 14, 10, 179, 146, 190, STR_OPTIONS_RES, STR_NULL},
{ WWT_6, 14, 20, 110, 160, 171, STR_OPTIONS_RES_CBO, STR_OPTIONS_RES_TIP},
{ WWT_CLOSEBOX, 14, 99, 109, 161, 170, STR_0225, STR_OPTIONS_RES_TIP},
{ WWT_TEXTBTN, 14, 149, 169, 176, 184, STR_EMPTY, STR_OPTIONS_FULLSCREEN_TIP},
{ WWT_FRAME, 14, 190, 359, 146, 190, STR_OPTIONS_SCREENSHOT_FORMAT, STR_NULL},
{ WWT_6, 14, 200, 349, 160, 171, STR_OPTIONS_SCREENSHOT_FORMAT_CBO, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
{ WWT_CLOSEBOX, 14, 338, 348, 161, 170, STR_0225, STR_OPTIONS_SCREENSHOT_FORMAT_TIP},
//refresh rate combobox
{ WWT_6, 14, 115, 169, 160, 171, STR_OPTIONS_REFRESH_CBO, STR_OPTIONS_REFRESH_TIP},
{ WWT_CLOSEBOX, 14, 158, 168, 161, 170, STR_0225, STR_OPTIONS_REFRESH_TIP},
{ WIDGETS_END},
};
Code: Select all
static void GameOptionsWndProc(Window *w, WindowEvent *e)
{
int i;
switch(e->event)
{
case WE_PAINT:
{
StringID str = STR_02BE_DEFAULT;
i = GetCurRes();
w->disabled_state = (_vehicle_design_names & 1) ? (++str, 0) : (1 << 21);
SetDParam(0, str);
SetDParam(1, _currency_string_list[_opt_mod_ptr->currency]);
SetDParam(2, _opt_mod_ptr->kilometers + STR_0139_IMPERIAL_MILES);
SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_mod_ptr->road_side);
SetDParam(4, STR_TOWNNAME_ENGLISH + _opt_mod_ptr->town_name);
SetDParam(5, _autosave_dropdown[_opt_mod_ptr->autosave]);
SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
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
SetDParam(9, SPECSTR_REFRESH_START + _currentRefreshRate);
DrawWindowWidgets(w);
DrawString(20, 175, STR_OPTIONS_FULLSCREEN, 0); // fullscreen
} break;
case WE_CLICK:
switch(e->click.widget) {
case 5:
ShowDropDownMenu(w, _currency_string_list, _opt_mod_ptr->currency, e->click.widget, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies());
return;
case 8:
ShowDropDownMenu(w, _distances_dropdown, _opt_mod_ptr->kilometers, e->click.widget, 0);
return;
case 11: {
int i = _opt_mod_ptr->road_side;
ShowDropDownMenu(w, _driveside_dropdown, i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i));
return;
}
case 14: {
int i = _opt_mod_ptr->town_name;
ShowDropDownMenu(w, BuildDynamicDropdown(STR_TOWNNAME_ENGLISH, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1), i, e->click.widget, (_game_mode == GM_MENU) ? 0 : (-1) ^ (1 << i));
return;
}
case 17:
ShowDropDownMenu(w, _autosave_dropdown, _opt_mod_ptr->autosave, e->click.widget, 0);
return;
case 20:
ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names&1)?1:0, e->click.widget, (_vehicle_design_names&2)?0:2);
return;
case 21:
return;
case 24:
ShowDropDownMenu(w, _dynlang.dropdown, _dynlang.curr, e->click.widget, 0);
return;
case 27:
// setup resolution dropdown
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), e->click.widget, 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 31: /* Setup screenshot format dropdown */
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, e->click.widget, 0);
return;
case 33:
//setup refresh dropdown
ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_REFRESH_START, _num_refresh_rates), _currentRefreshRate, e->click.widget, 0);
return;
}
break;
case WE_DROPDOWN_SELECT:
switch(e->dropdown.button) {
case 20:
if (e->dropdown.index == 0) {
DeleteCustomEngineNames();
MarkWholeScreenDirty();
} else if (!(_vehicle_design_names&1)) {
LoadCustomEngineNames();
MarkWholeScreenDirty();
}
break;
case 5:
_opt_mod_ptr->currency = _opt.currency = e->dropdown.index;
MarkWholeScreenDirty();
break;
case 8:
_opt_mod_ptr->kilometers = e->dropdown.index;
MarkWholeScreenDirty();
break;
case 11:
if (_game_mode == GM_MENU)
DoCommandP(0, e->dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_EMPTY));
break;
case 14:
if (_game_mode == GM_MENU)
DoCommandP(0, e->dropdown.index, 0, NULL, CMD_SET_TOWN_NAME_TYPE | CMD_MSG(STR_EMPTY));
break;
case 17:
_opt_mod_ptr->autosave = e->dropdown.index;
SetWindowDirty(w);
break;
// change interface language
case 24:
ReadLanguagePack(e->dropdown.index);
MarkWholeScreenDirty();
break;
// change resolution
case 27:
if(e->dropdown.index < _num_resolutions)
{
if(ChangeResInGame(_resolutions[e->dropdown.index][0],_resolutions[e->dropdown.index][1]))
{
SetWindowDirty(w);
}
}
break;
// change screenshot format
case 31:
SetScreenshotFormat(e->dropdown.index);
SetWindowDirty(w);
break;
//change refresh
case 33:
if(e->dropdown.index < _num_refresh_rates)
{
if(ChangeRefreshInGame(e->dropdown.index)) SetWindowDirty(w);
}
break;
}
break;
}
}
Code: Select all
void EnumRefreshRates(uint16 uiWidth, uint16 uiHeight)
{
DEVMODE displayMode;
DWORD dwModeNumber = 0;
g_uiMaxRefresh = 0;
_num_refresh_rates = 0;
while(EnumDisplaySettings(NULL, dwModeNumber, &displayMode))
{
if((displayMode.dmBitsPerPel == _fullscreen_bpp)&(displayMode.dmPelsWidth == (DWORD)uiWidth)&(displayMode.dmPelsWidth == (DWORD)uiWidth)&(displayMode.dmPelsHeight == (DWORD)uiHeight))
{
_refresh_rates[_num_refresh_rates] = displayMode.dmDisplayFrequency;
if(_refresh_rates[_num_refresh_rates] == _display_hz) _currentRefreshRate = _num_refresh_rates;
if(displayMode.dmDisplayFrequency >= g_uiMaxRefresh) g_uiMaxRefresh = displayMode.dmDisplayFrequency;
_num_refresh_rates++;
if(_num_refresh_rates >= MAX_REFRESH_RATES) break;
}
dwModeNumber++;
}
//why not before previous code block? because we need correct maximum refresh rate for first run
if(!_wnd.fullscreen)
{
_num_refresh_rates = 1;
_refresh_rates[0] = 0;
_currentRefreshRate = 0;
return;
}
if(!_display_hz) _currentRefreshRate = 0;
}
Code: Select all
static void MakeWindow(bool full_screen)
{
_fullscreen = full_screen;
_wnd.double_size = _double_size && !full_screen;
// recreate window?
if((full_screen|_wnd.fullscreen) && _wnd.main_wnd) {
DestroyWindow(_wnd.main_wnd);
_wnd.main_wnd = 0;
}
if(full_screen)
{
DEVMODE settings;
//calculte maximum refresh rate for selecting resolution
{
int i = GetCurRes();
enumRefreshRates(_wnd.width_org, _wnd.height_org);
if(_display_hz > g_uiMaxRefresh) _display_hz = 0;
}
memset(&settings, 0, sizeof(DEVMODE));
settings.dmSize = sizeof(DEVMODE);
settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
settings.dmPelsWidth = _wnd.width_org;
settings.dmPelsHeight = _wnd.height_org;
if(_fullscreen_bpp)
{
settings.dmBitsPerPel = _fullscreen_bpp;
settings.dmFields |= DM_BITSPERPEL;
}
if((settings.dmDisplayFrequency = _display_hz) != 0)
{
settings.dmFields |= DM_DISPLAYFREQUENCY;
}
if(!ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
{
MakeWindow(false);
return;
}
}
else if(_wnd.fullscreen)
{
//restore display?
ChangeDisplaySettings(NULL, 0);
}
{
RECT r;
uint style;
int x, y, w, h;
if((_wnd.fullscreen=full_screen) != false)
{
style = WS_POPUP | WS_VISIBLE;
SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
}
else
{
style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
SetRect(&r, 0, 0, _wnd.width, _wnd.height);
}
AdjustWindowRect(&r, style, FALSE);
w = r.right - r.left;
h = r.bottom - r.top;
x = (GetSystemMetrics(SM_CXSCREEN)-w)>>1;
y = (GetSystemMetrics(SM_CYSCREEN)-h)>>1;
if(_wnd.main_wnd)
{
SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
else
{
char Windowtitle[50] = "OpenTTD ";
#ifdef WITH_REV_HACK
// also show revision number/release in window title
extern const char _openttd_revision[];
strncat(Windowtitle, _openttd_revision, sizeof(Windowtitle)-(strlen(Windowtitle) + 1));
#endif
_wnd.main_wnd = CreateWindow("TTD", Windowtitle, style, x, y, w, h, 0, 0, _inst, 0);
if (_wnd.main_wnd == NULL)
error("CreateWindow failed");
}
}
//calculte available refresh rates for selected resolution
{
int i = GetCurRes();
enumRefreshRates(_resolutions[i][0], _resolutions[i][1]);
}
GameSizeChanged(); // invalidate all windows, force redraw
}
Code: Select all
enumRefreshRates = EnumRefreshRates;
Code: Select all
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
int argc;
char *argv[64]; // max 64 command line arguments
_inst = hInstance;
enumRefreshRates = EnumRefreshRates;
.....
Code: Select all
STR_OPTIONS_REFRESH_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
STR_OPTIONS_REFRESH_TIP :{BLACK}Select the screen refresh to use
Big thanks for LordOfThePigs.