Merge branch 'jgrpp' into jgrpp-nrt

pull/104/head
Jonathan G Rennison 5 years ago
commit a30638bc4a

@ -48,6 +48,9 @@ struct LoadCheckData {
struct LoggedAction *gamelog_action; ///< Gamelog actions
uint gamelog_actions; ///< Number of gamelog actions
bool want_debug_log_data = false;
std::string debug_log_data;
LoadCheckData() : error_data(nullptr), grfconfig(nullptr),
grf_compatibility(GLC_NOT_FOUND), gamelog_action(nullptr), gamelog_actions(0)
{

@ -67,6 +67,8 @@ void LoadCheckData::Clear()
this->gamelog_actions = 0;
ClearGRFConfigList(&this->grfconfig);
this->debug_log_data.clear();
}
/** Load game/scenario with optional content download */

@ -36,6 +36,8 @@ byte _support8bpp;
CursorVars _cursor;
bool _ctrl_pressed; ///< Is Ctrl pressed?
bool _shift_pressed; ///< Is Shift pressed?
bool _invert_ctrl;
bool _invert_shift;
byte _fast_forward;
bool _left_button_down; ///< Is left mouse button pressed?
bool _left_button_clicked; ///< Is left mouse button clicked?

@ -56,6 +56,8 @@ extern byte _support8bpp;
extern CursorVars _cursor;
extern bool _ctrl_pressed; ///< Is Ctrl pressed?
extern bool _shift_pressed; ///< Is Shift pressed?
extern bool _invert_ctrl;
extern bool _invert_shift;
extern byte _fast_forward;
extern bool _left_button_down;
@ -73,6 +75,7 @@ extern Palette _cur_palette; ///< Current palette
void HandleKeypress(uint keycode, WChar key);
void HandleTextInput(const char *str, bool marked = false, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr);
void HandleCtrlChanged();
void HandleShiftChanged();
void HandleMouseEvents();
void UpdateWindows();

@ -59,6 +59,8 @@ void ShowEstimatedCostOrIncome(Money cost, int x, int y);
void ShowExtraViewPortWindow(TileIndex tile = INVALID_TILE);
void ShowExtraViewPortWindowForTileUnderCursor();
void ShowModifierKeyToggleWindow();
/* bridge_gui.cpp */
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type);

@ -490,6 +490,7 @@ STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Fully zoomed in
STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot
STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot
STR_ABOUT_MENU_SHOW_FRAMERATE :Show frame rate
STR_ABOUT_MENU_SHOW_TOGGLE_MODIFIER_KEYS :Modifier key window
STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD'
STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner
STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes
@ -6186,3 +6187,9 @@ STR_SCHDISPATCH_SUMMARY_L2 :{BLACK}This sch
STR_SCHDISPATCH_SUMMARY_L3 :{BLACK}Maximum delay of {STRING3} is allowed before the slot is skipped.
STR_SCHDISPATCH_SUMMARY_NOT_ENABLED :{BLACK}This schedule is not active.
# Modifier key toggle window
STR_MODIFIER_KEY_TOGGLE_CAPTION :{WHITE}Modifier keys
STR_SHIFT_KEY_NAME :{BLACK}Shift
STR_CTRL_KEY_NAME :{BLACK}Ctrl
STR_MODIFIER_TOGGLE_SHIFT_TOOLTIP :{BLACK}Click to invert state of Shift key
STR_MODIFIER_TOGGLE_CTRL_TOOLTIP :{BLACK}Click to invert state of Ctrl key

@ -1339,3 +1339,88 @@ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallback
new QueryWindow(&_query_desc, caption, message, parent, callback);
}
static const NWidgetPart _modifier_key_toggle_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MODIFIER_KEY_TOGGLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_SHADEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(NWID_SPACER), SetMinimalSize(0, 2),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MKT_SHIFT), SetMinimalSize(78, 12), SetFill(1, 0),
SetDataTip(STR_SHIFT_KEY_NAME, STR_MODIFIER_TOGGLE_SHIFT_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MKT_CTRL), SetMinimalSize(78, 12), SetFill(1, 0),
SetDataTip(STR_CTRL_KEY_NAME, STR_MODIFIER_TOGGLE_CTRL_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 2),
EndContainer(),
};
struct ModifierKeyToggleWindow : Window {
ModifierKeyToggleWindow(WindowDesc *desc, WindowNumber window_number) :
Window(desc)
{
this->InitNested(window_number);
this->UpdateButtons();
}
~ModifierKeyToggleWindow()
{
_invert_shift = false;
_invert_ctrl = false;
}
void UpdateButtons()
{
this->SetWidgetLoweredState(WID_MKT_SHIFT, _shift_pressed);
this->SetWidgetLoweredState(WID_MKT_CTRL, _ctrl_pressed);
this->SetDirty();
}
EventState OnCTRLStateChange() override
{
this->UpdateButtons();
return ES_NOT_HANDLED;
}
void OnShiftStateChange() override
{
this->UpdateButtons();
}
void OnClick(Point pt, int widget, int click_count) override
{
switch (widget) {
case WID_MKT_SHIFT:
_invert_shift = !_invert_shift;
UpdateButtons();
break;
case WID_MKT_CTRL:
_invert_ctrl = !_invert_ctrl;
UpdateButtons();
break;
}
}
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
if (!gui_scope) return;
this->UpdateButtons();
}
};
static WindowDesc _modifier_key_toggle_desc(
WDP_AUTO, "modifier_key_toggle", 0, 0,
WC_MODIFIER_KEY_TOGGLE, WC_NONE,
WDF_NO_FOCUS,
_modifier_key_toggle_widgets, lengthof(_modifier_key_toggle_widgets)
);
void ShowModifierKeyToggleWindow()
{
AllocateWindowDescFront<ModifierKeyToggleWindow>(&_modifier_key_toggle_desc, 0);
}

@ -281,7 +281,7 @@ static void WriteSavegameInfo(const char *name)
GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs);
char buf[8192];
char buf[65536];
char *p = buf;
p += seprintf(p, lastof(buf), "Name: %s\n", name);
const char *type = "";
@ -323,6 +323,40 @@ static void WriteSavegameInfo(const char *name)
#endif
}
static void WriteSavegameDebugData(const char *name)
{
char *buf = MallocT<char>(4096);
char *buflast = buf + 4095;
char *p = buf;
auto bump_size = [&]() {
size_t offset = p - buf;
size_t new_size = buflast - buf + 1 + 4096;
buf = ReallocT<char>(buf, new_size);
buflast = buf + new_size - 1;
p = buf + offset;
};
p += seprintf(p, buflast, "Name: %s\n", name);
if (_load_check_data.debug_log_data.size()) {
p += seprintf(p, buflast, "%u bytes of debug data in savegame\n", (uint) _load_check_data.debug_log_data.size());
std::string buffer = _load_check_data.debug_log_data;
ProcessLineByLine(const_cast<char *>(buffer.data()), [&](const char *line) {
if (buflast - p <= 1024) bump_size();
p += seprintf(p, buflast, "> %s\n", line);
});
} else {
p += seprintf(p, buflast, "No debug data in savegame\n");
}
/* ShowInfo put output to stderr, but version information should go
* to stdout; this is the only exception */
#if !defined(_WIN32)
printf("%s\n", buf);
#else
ShowInfo(buf);
#endif
free(buf);
}
/**
* Extract the resolution from the given string and store
@ -612,6 +646,7 @@ static const OptionData _options[] = {
GETOPT_SHORT_VALUE('c'),
GETOPT_SHORT_NOVAL('x'),
GETOPT_SHORT_VALUE('q'),
GETOPT_SHORT_VALUE('K'),
GETOPT_SHORT_NOVAL('h'),
GETOPT_SHORT_VALUE('J'),
GETOPT_END()
@ -730,7 +765,8 @@ int openttd_main(int argc, char *argv[])
scanner->generation_seed = InteractiveRandom();
}
break;
case 'q': {
case 'q':
case 'K': {
DeterminePaths(argv[0]);
if (StrEmpty(mgo.opt)) {
ret = 1;
@ -742,10 +778,12 @@ int openttd_main(int argc, char *argv[])
FiosGetSavegameListCallback(SLO_LOAD, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title));
_load_check_data.Clear();
if (i == 'K') _load_check_data.want_debug_log_data = true;
SaveOrLoadResult res = SaveOrLoad(mgo.opt, SLO_CHECK, DFT_GAME_FILE, SAVE_DIR, false);
if (res != SL_OK || _load_check_data.HasErrors()) {
fprintf(stderr, "Failed to open savegame\n");
if (_load_check_data.HasErrors()) {
InitializeLanguagePacks();
char buf[256];
SetDParamStr(0, _load_check_data.error_data);
GetString(buf, _load_check_data.error, lastof(buf));
@ -754,7 +792,11 @@ int openttd_main(int argc, char *argv[])
goto exit_noshutdown;
}
WriteSavegameInfo(title);
if (i == 'q') {
WriteSavegameInfo(title);
} else {
WriteSavegameDebugData(title);
}
goto exit_noshutdown;
}
@ -1528,7 +1570,12 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log)
}
if (veh_cache[length].cached_max_speed != u->vcache.cached_max_speed || veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ||
veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect || HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT)) {
CCLOG("vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length);
CCLOG("vehicle cache mismatch: %c%c%c%c, type %i, vehicle %i, company %i, unit number %i, wagon %i",
veh_cache[length].cached_max_speed != u->vcache.cached_max_speed ? 'm' : '-',
veh_cache[length].cached_cargo_age_period != u->vcache.cached_cargo_age_period ? 'c' : '-',
veh_cache[length].cached_vis_effect != u->vcache.cached_vis_effect ? 'v' : '-',
HasBit(veh_cache[length].cached_veh_flags ^ u->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT) ? 'l' : '-',
(int)v->type, v->index, (int)v->owner, v->unitnumber, length);
}
if (u->IsGroundVehicle() && (HasBit(u->GetGroundVehicleFlags(), GVF_GOINGUP_BIT) || HasBit(u->GetGroundVehicleFlags(), GVF_GOINGDOWN_BIT)) && u->GetGroundVehicleCache()->cached_slope_resistance && HasBit(v->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST)) {
CCLOG("VCF_GV_ZERO_SLOPE_RESIST set incorrectly (2): type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length);
@ -1642,8 +1689,17 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log)
if (_order_destination_refcount_map_valid) {
btree::btree_map<uint32, uint32> saved_order_destination_refcount_map = std::move(_order_destination_refcount_map);
for (auto iter = saved_order_destination_refcount_map.begin(); iter != saved_order_destination_refcount_map.end();) {
if (iter->second == 0) {
iter = saved_order_destination_refcount_map.erase(iter);
} else {
++iter;
}
}
IntialiseOrderDestinationRefcountMap();
if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch");
} else {
CCLOG("Order destination refcount map not valid");
}
#undef CCLOG

@ -58,6 +58,8 @@ INSTANTIATE_POOL_METHODS(OrderList)
btree::btree_map<uint32, uint32> _order_destination_refcount_map;
bool _order_destination_refcount_map_valid = false;
CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, bool allow_load_by_cargo_type);
void IntialiseOrderDestinationRefcountMap()
{
ClearOrderDestinationRefcountMap();
@ -942,7 +944,10 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
VehicleOrderID sel_ord = GB(p1, 20, 8);
Order new_order(p2);
Vehicle *v = Vehicle::GetIfValid(veh);
return CmdInsertOrderIntl(flags, Vehicle::GetIfValid(veh), sel_ord, new_order, false);
}
CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID sel_ord, const Order &new_order, bool allow_load_by_cargo_type) {
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner);
@ -972,10 +977,16 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
/* Filter invalid load/unload types. */
switch (new_order.GetLoadType()) {
case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
case OLFB_CARGO_TYPE_LOAD:
if (allow_load_by_cargo_type) break;
return CMD_ERROR;
default: return CMD_ERROR;
}
switch (new_order.GetUnloadType()) {
case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
case OUFB_CARGO_TYPE_UNLOAD:
if (allow_load_by_cargo_type) break;
return CMD_ERROR;
default: return CMD_ERROR;
}
@ -1928,6 +1939,17 @@ static void CheckAdvanceVehicleOrdersAfterClone(Vehicle *v, DoCommandFlag flags)
DoCommand(v->tile, v->index, skip_to, flags, CMD_SKIP_TO_ORDER);
}
static bool ShouldResetOrderIndicesOnOrderCopy(const Vehicle *src, const Vehicle *dst)
{
const int num_orders = src->GetNumOrders();
if (dst->GetNumOrders() != num_orders) return true;
for (int i = 0; i < num_orders; i++) {
if (!src->GetOrder(i)->Equals(*dst->GetOrder(i))) return true;
}
return false;
}
/**
* Clone/share/copy an order-list of another vehicle.
* @param tile unused
@ -1999,9 +2021,9 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (flags & DC_EXEC) {
/* If the destination vehicle had a OrderList, destroy it.
* We only reset the order indices, if the new orders are obviously different.
* We reset the order indices, if the new orders are different.
* (We mainly do this to keep the order indices valid and in range.) */
DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
DeleteVehicleOrders(dst, false, ShouldResetOrderIndicesOnOrderCopy(src, dst));
dst->orders.list = src->orders.list;
@ -2086,9 +2108,9 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
Order **order_dst;
/* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
* We only reset the order indices, if the new orders are obviously different.
* We only the order indices, if the new orders are different.
* (We mainly do this to keep the order indices valid and in range.) */
DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
DeleteVehicleOrders(dst, true, ShouldResetOrderIndicesOnOrderCopy(src, dst));
order_dst = &first;
FOR_VEHICLE_ORDERS(src, order) {
@ -2856,14 +2878,20 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, u
Order new_order;
new_order.AssignOrder(*order);
new_order.SetDestination(to_dest);
const bool wait_fixed = new_order.IsWaitFixed();
const bool wait_timetabled = wait_fixed && new_order.IsWaitTimetabled();
new_order.SetWaitTimetabled(false);
new_order.SetTravelTimetabled(false);
if (DoCommand(0, v->index | ((index + 1) << 20), new_order.Pack(), flags, CMD_INSERT_ORDER).Succeeded()) {
if (CmdInsertOrderIntl(flags, v, index + 1, new_order, true).Succeeded()) {
DoCommand(0, v->index, index, flags, CMD_DELETE_ORDER);
order = v->orders.list->GetOrderAt(index);
order->SetRefit(new_order.GetRefitCargo());
order->SetMaxSpeed(new_order.GetMaxSpeed());
if (wait_fixed) {
extern void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32 wait_time, bool wait_timetabled);
SetOrderFixedWaitTime(v, index, new_order.GetWaitTime(), wait_timetabled);
}
changed = true;
}

@ -24,6 +24,7 @@
#include "../../openttd.h"
#include "../../screenshot.h"
#include "../../debug.h"
#include "../../settings_type.h"
#if defined(WITH_DEMANGLE)
#include <cxxabi.h>
#endif
@ -483,6 +484,8 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c
/* virtual */ int CrashLogWindows::WriteCrashDump(char *filename, const char *filename_last) const
{
if (_settings_client.gui.developer == 0) return 0;
int ret = 0;
HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll"));
if (dbghelp != nullptr) {
@ -624,7 +627,7 @@ static bool _expanded;
static const TCHAR _crash_desc[] =
_T("A serious fault condition occurred in the game. The game will shut down.\n")
_T("Please send the crash information and the crash.dmp file (if any) to the patchpack developer.\n")
_T("Please send the crash information (log files and crash saves, if any) to the patchpack developer.\n")
_T("This will greatly help debugging. The correct place to do this is https://www.tt-forums.net/viewtopic.php?f=33&t=73469")
_T(" or https://github.com/JGRennison/OpenTTD-patches\n")
_T("The information contained in the report is displayed below.\n")
@ -689,7 +692,7 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
TCHAR *text = AllocaM(TCHAR, len);
_sntprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename));
if (OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != _T('\0')) {
if (_settings_client.gui.developer > 0 && OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != _T('\0')) {
_tcscat(text, _T("\n"));
_tcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename));
}

@ -14,6 +14,7 @@
#include "../debug.h"
#include "saveload.h"
#include "saveload_buffer.h"
#include "../fios.h"
#include "../safeguards.h"
@ -37,6 +38,19 @@ static void Load_DBGL()
}
}
static void Check_DBGL()
{
if (!_load_check_data.want_debug_log_data) {
SlSkipBytes(SlGetFieldLength());
return;
}
size_t length = SlGetFieldLength();
if (length) {
_load_check_data.debug_log_data.resize(length);
ReadBuffer::GetCurrent()->CopyBytes(reinterpret_cast<byte *>(const_cast<char *>(_load_check_data.debug_log_data.data())), length);
}
}
extern const ChunkHandler _debug_chunk_handlers[] = {
{ 'DBGL', Save_DBGL, Load_DBGL, nullptr, nullptr, CH_RIFF | CH_LAST},
{ 'DBGL', Save_DBGL, Load_DBGL, nullptr, Check_DBGL, CH_RIFF | CH_LAST},
};

@ -96,6 +96,14 @@ class NIHVehicle : public NIHelper {
b += seprintf(b, lastof(buffer), " Flags: ");
b = v->DumpVehicleFlags(b, lastof(buffer));
print(buffer);
if (v->IsPrimaryVehicle()) {
seprintf(buffer, lastof(buffer), " Order indices: real: %u, implicit: %u, tt: %u",
v->cur_real_order_index, v->cur_implicit_order_index, v->cur_timetable_order_index);
print(buffer);
}
seprintf(buffer, lastof(buffer), " V Cache: max speed: %u, cargo age period: %u, vis effect: %u",
v->vcache.cached_max_speed, v->vcache.cached_cargo_age_period, v->vcache.cached_vis_effect);
print(buffer);
if (v->IsGroundVehicle()) {
const GroundVehicleCache &gvc = *(v->GetGroundVehicleCache());
seprintf(buffer, lastof(buffer), " GV Cache: weight: %u, slope res: %u, max TE: %u, axle res: %u",

@ -997,3 +997,8 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
}
}
void SetOrderFixedWaitTime(Vehicle *v, VehicleOrderID order_number, uint32 wait_time, bool wait_timetabled) {
ChangeTimetable(v, order_number, wait_time, MTF_WAIT_TIME, wait_timetabled, true);
ChangeTimetable(v, order_number, 1, MTF_SET_WAIT_FIXED, false, true);
}

@ -1079,7 +1079,7 @@ static CallBackFunction PlaceLandBlockInfo()
static CallBackFunction ToolbarHelpClick(Window *w)
{
PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 13 : 10);
PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 14 : 11);
return CBF_NONE;
}
@ -1182,10 +1182,11 @@ static CallBackFunction MenuClickHelp(int index)
case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break;
case 8: ShowFramerateWindow(); break;
case 9: ShowAboutWindow(); break;
case 10: ShowSpriteAlignerWindow(); break;
case 11: ToggleBoundingBoxes(); break;
case 12: ToggleDirtyBlocks(); break;
case 9: ShowModifierKeyToggleWindow(); break;
case 10: ShowAboutWindow(); break;
case 11: ShowSpriteAlignerWindow(); break;
case 12: ToggleBoundingBoxes(); break;
case 13: ToggleDirtyBlocks(); break;
}
return CBF_NONE;
}

@ -1355,6 +1355,7 @@ static void NormaliseTrainHead(Train *head)
/* Tell the 'world' the train changed. */
head->ConsistChanged(CCF_ARRANGE);
UpdateTrainGroupID(head);
SetBit(head->flags, VRF_CONSIST_SPEED_REDUCTION);
/* Not a front engine, i.e. a free wagon chain. No need to do more. */
if (!head->IsFrontEngine()) return;

@ -499,9 +499,10 @@ void VideoDriver_Allegro::MainLoop()
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
bool old_ctrl_pressed = _ctrl_pressed;
bool old_shift_pressed = _shift_pressed;
_ctrl_pressed = !!(key_shifts & KB_CTRL_FLAG);
_shift_pressed = !!(key_shifts & KB_SHIFT_FLAG);
_ctrl_pressed = !!(key_shifts & KB_CTRL_FLAG) != _invert_ctrl;
_shift_pressed = !!(key_shifts & KB_SHIFT_FLAG) != _invert_shift;
/* determine which directional keys are down */
_dirkeys =
@ -511,6 +512,7 @@ void VideoDriver_Allegro::MainLoop()
(key[KEY_DOWN] ? 8 : 0);
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
GameLoop();

@ -695,11 +695,13 @@ void QZ_GameLoop()
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
bool old_ctrl_pressed = _ctrl_pressed;
bool old_shift_pressed = _shift_pressed;
_ctrl_pressed = !!(_current_mods & ( _settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? NSControlKeyMask : NSCommandKeyMask));
_shift_pressed = !!(_current_mods & NSShiftKeyMask);
_ctrl_pressed = !!(_current_mods & ( _settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? NSControlKeyMask : NSCommandKeyMask)) != _invert_ctrl;
_shift_pressed = !!(_current_mods & NSShiftKeyMask) != _invert_shift;
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
GameLoop();

@ -728,9 +728,10 @@ void VideoDriver_SDL::MainLoop()
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
bool old_ctrl_pressed = _ctrl_pressed;
bool old_shift_pressed = _shift_pressed;
_ctrl_pressed = !!(mod & KMOD_CTRL);
_shift_pressed = !!(mod & KMOD_SHIFT);
_ctrl_pressed = !!(mod & KMOD_CTRL) != _invert_ctrl;
_shift_pressed = !!(mod & KMOD_SHIFT) != _invert_shift;
/* determine which directional keys are down */
_dirkeys =
@ -746,6 +747,7 @@ void VideoDriver_SDL::MainLoop()
(keys[SDLK_DOWN] ? 8 : 0);
#endif
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
/* The gameloop is the part that can run asynchronously. The rest
* except sleeping can't. */

@ -1243,9 +1243,10 @@ void VideoDriver_Win32::MainLoop()
next_tick = cur_ticks + MILLISECONDS_PER_TICK;
bool old_ctrl_pressed = _ctrl_pressed;
bool old_shift_pressed = _shift_pressed;
_ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
_shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0;
_ctrl_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_CONTROL) < 0) != _invert_ctrl;
_shift_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) != _invert_shift;
/* determine which directional keys are down */
if (_wnd.has_focus) {
@ -1259,6 +1260,7 @@ void VideoDriver_Win32::MainLoop()
}
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
GdiFlush();

@ -57,4 +57,10 @@ enum TextfileWidgets {
WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right.
};
/** Widgets of the #TextfileWindow class. */
enum ModifierKeyToggleWidgets {
WID_MKT_SHIFT,
WID_MKT_CTRL,
};
#endif /* WIDGETS_MISC_WIDGET_H */

@ -2743,6 +2743,17 @@ void HandleCtrlChanged()
}
}
/**
* State of SHIFT key has changed
*/
void HandleShiftChanged()
{
Window *w;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
w->OnShiftStateChange();
}
}
/**
* Insert a text string at the cursor position into the edit box widget.
* @param wid Edit box widget.

@ -667,6 +667,10 @@ public:
*/
virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
/**
* The state of the shift key has changed
*/
virtual void OnShiftStateChange() {}
/**
* A click with the left mouse button has been made on the window.

@ -755,6 +755,11 @@ enum WindowClass {
WC_BUILD_VIRTUAL_TRAIN,
WC_CREATE_TEMPLATE,
/**
* Modifier key toggle window.
*/
WC_MODIFIER_KEY_TOGGLE,
WC_INVALID = 0xFFFF, ///< Invalid window.
};

Loading…
Cancel
Save