Merge branch 'jgrpp' into jgrpp-nrt

This commit is contained in:
Jonathan G Rennison
2019-09-16 22:28:35 +01:00
23 changed files with 280 additions and 26 deletions

View File

@@ -48,6 +48,9 @@ struct LoadCheckData {
struct LoggedAction *gamelog_action; ///< Gamelog actions struct LoggedAction *gamelog_action; ///< Gamelog actions
uint gamelog_actions; ///< Number of 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), LoadCheckData() : error_data(nullptr), grfconfig(nullptr),
grf_compatibility(GLC_NOT_FOUND), gamelog_action(nullptr), gamelog_actions(0) grf_compatibility(GLC_NOT_FOUND), gamelog_action(nullptr), gamelog_actions(0)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@@ -490,6 +490,7 @@ STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Fully zoomed in
STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot
STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot
STR_ABOUT_MENU_SHOW_FRAMERATE :Show frame rate 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_ABOUT_OPENTTD :About 'OpenTTD'
STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner
STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes 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_L3 :{BLACK}Maximum delay of {STRING3} is allowed before the slot is skipped.
STR_SCHDISPATCH_SUMMARY_NOT_ENABLED :{BLACK}This schedule is not active. 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

View File

@@ -1339,3 +1339,88 @@ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallback
new QueryWindow(&_query_desc, caption, message, parent, callback); 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);
}

View File

@@ -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); 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; char *p = buf;
p += seprintf(p, lastof(buf), "Name: %s\n", name); p += seprintf(p, lastof(buf), "Name: %s\n", name);
const char *type = ""; const char *type = "";
@@ -323,6 +323,40 @@ static void WriteSavegameInfo(const char *name)
#endif #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 * Extract the resolution from the given string and store
@@ -612,6 +646,7 @@ static const OptionData _options[] = {
GETOPT_SHORT_VALUE('c'), GETOPT_SHORT_VALUE('c'),
GETOPT_SHORT_NOVAL('x'), GETOPT_SHORT_NOVAL('x'),
GETOPT_SHORT_VALUE('q'), GETOPT_SHORT_VALUE('q'),
GETOPT_SHORT_VALUE('K'),
GETOPT_SHORT_NOVAL('h'), GETOPT_SHORT_NOVAL('h'),
GETOPT_SHORT_VALUE('J'), GETOPT_SHORT_VALUE('J'),
GETOPT_END() GETOPT_END()
@@ -730,7 +765,8 @@ int openttd_main(int argc, char *argv[])
scanner->generation_seed = InteractiveRandom(); scanner->generation_seed = InteractiveRandom();
} }
break; break;
case 'q': { case 'q':
case 'K': {
DeterminePaths(argv[0]); DeterminePaths(argv[0]);
if (StrEmpty(mgo.opt)) { if (StrEmpty(mgo.opt)) {
ret = 1; ret = 1;
@@ -742,10 +778,12 @@ int openttd_main(int argc, char *argv[])
FiosGetSavegameListCallback(SLO_LOAD, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title)); FiosGetSavegameListCallback(SLO_LOAD, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title));
_load_check_data.Clear(); _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); SaveOrLoadResult res = SaveOrLoad(mgo.opt, SLO_CHECK, DFT_GAME_FILE, SAVE_DIR, false);
if (res != SL_OK || _load_check_data.HasErrors()) { if (res != SL_OK || _load_check_data.HasErrors()) {
fprintf(stderr, "Failed to open savegame\n"); fprintf(stderr, "Failed to open savegame\n");
if (_load_check_data.HasErrors()) { if (_load_check_data.HasErrors()) {
InitializeLanguagePacks();
char buf[256]; char buf[256];
SetDParamStr(0, _load_check_data.error_data); SetDParamStr(0, _load_check_data.error_data);
GetString(buf, _load_check_data.error, lastof(buf)); GetString(buf, _load_check_data.error, lastof(buf));
@@ -754,7 +792,11 @@ int openttd_main(int argc, char *argv[])
goto exit_noshutdown; goto exit_noshutdown;
} }
if (i == 'q') {
WriteSavegameInfo(title); WriteSavegameInfo(title);
} else {
WriteSavegameDebugData(title);
}
goto exit_noshutdown; 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 || 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)) { 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)) { 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); 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) { if (_order_destination_refcount_map_valid) {
btree::btree_map<uint32, uint32> saved_order_destination_refcount_map = std::move(_order_destination_refcount_map); 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(); IntialiseOrderDestinationRefcountMap();
if (saved_order_destination_refcount_map != _order_destination_refcount_map) CCLOG("Order destination refcount map mismatch"); 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 #undef CCLOG

View File

@@ -58,6 +58,8 @@ INSTANTIATE_POOL_METHODS(OrderList)
btree::btree_map<uint32, uint32> _order_destination_refcount_map; btree::btree_map<uint32, uint32> _order_destination_refcount_map;
bool _order_destination_refcount_map_valid = false; 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() void IntialiseOrderDestinationRefcountMap()
{ {
ClearOrderDestinationRefcountMap(); ClearOrderDestinationRefcountMap();
@@ -942,7 +944,10 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
VehicleOrderID sel_ord = GB(p1, 20, 8); VehicleOrderID sel_ord = GB(p1, 20, 8);
Order new_order(p2); 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; if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner); CommandCost ret = CheckOwnership(v->owner);
@@ -972,10 +977,16 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
/* Filter invalid load/unload types. */ /* Filter invalid load/unload types. */
switch (new_order.GetLoadType()) { switch (new_order.GetLoadType()) {
case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break; 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; default: return CMD_ERROR;
} }
switch (new_order.GetUnloadType()) { switch (new_order.GetUnloadType()) {
case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break; 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; 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); 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. * Clone/share/copy an order-list of another vehicle.
* @param tile unused * @param tile unused
@@ -1999,9 +2021,9 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
/* If the destination vehicle had a OrderList, destroy it. /* 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.) */ * (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; dst->orders.list = src->orders.list;
@@ -2086,9 +2108,9 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
Order **order_dst; Order **order_dst;
/* If the destination vehicle had an order list, destroy the chain but keep the OrderList. /* 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.) */ * (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; order_dst = &first;
FOR_VEHICLE_ORDERS(src, order) { FOR_VEHICLE_ORDERS(src, order) {
@@ -2856,14 +2878,20 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, u
Order new_order; Order new_order;
new_order.AssignOrder(*order); new_order.AssignOrder(*order);
new_order.SetDestination(to_dest); 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.SetWaitTimetabled(false);
new_order.SetTravelTimetabled(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); DoCommand(0, v->index, index, flags, CMD_DELETE_ORDER);
order = v->orders.list->GetOrderAt(index); order = v->orders.list->GetOrderAt(index);
order->SetRefit(new_order.GetRefitCargo()); order->SetRefit(new_order.GetRefitCargo());
order->SetMaxSpeed(new_order.GetMaxSpeed()); 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; changed = true;
} }

View File

@@ -24,6 +24,7 @@
#include "../../openttd.h" #include "../../openttd.h"
#include "../../screenshot.h" #include "../../screenshot.h"
#include "../../debug.h" #include "../../debug.h"
#include "../../settings_type.h"
#if defined(WITH_DEMANGLE) #if defined(WITH_DEMANGLE)
#include <cxxabi.h> #include <cxxabi.h>
#endif #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 /* virtual */ int CrashLogWindows::WriteCrashDump(char *filename, const char *filename_last) const
{ {
if (_settings_client.gui.developer == 0) return 0;
int ret = 0; int ret = 0;
HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll")); HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll"));
if (dbghelp != nullptr) { if (dbghelp != nullptr) {
@@ -624,7 +627,7 @@ static bool _expanded;
static const TCHAR _crash_desc[] = static const TCHAR _crash_desc[] =
_T("A serious fault condition occurred in the game. The game will shut down.\n") _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("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(" or https://github.com/JGRennison/OpenTTD-patches\n")
_T("The information contained in the report is displayed below.\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); TCHAR *text = AllocaM(TCHAR, len);
_sntprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename)); _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, _T("\n"));
_tcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename)); _tcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename));
} }

View File

@@ -14,6 +14,7 @@
#include "../debug.h" #include "../debug.h"
#include "saveload.h" #include "saveload.h"
#include "saveload_buffer.h" #include "saveload_buffer.h"
#include "../fios.h"
#include "../safeguards.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[] = { 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},
}; };

View File

@@ -96,6 +96,14 @@ class NIHVehicle : public NIHelper {
b += seprintf(b, lastof(buffer), " Flags: "); b += seprintf(b, lastof(buffer), " Flags: ");
b = v->DumpVehicleFlags(b, lastof(buffer)); b = v->DumpVehicleFlags(b, lastof(buffer));
print(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()) { if (v->IsGroundVehicle()) {
const GroundVehicleCache &gvc = *(v->GetGroundVehicleCache()); const GroundVehicleCache &gvc = *(v->GetGroundVehicleCache());
seprintf(buffer, lastof(buffer), " GV Cache: weight: %u, slope res: %u, max TE: %u, axle res: %u", seprintf(buffer, lastof(buffer), " GV Cache: weight: %u, slope res: %u, max TE: %u, axle res: %u",

View File

@@ -997,3 +997,8 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); 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);
}

View File

@@ -1079,7 +1079,7 @@ static CallBackFunction PlaceLandBlockInfo()
static CallBackFunction ToolbarHelpClick(Window *w) 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; return CBF_NONE;
} }
@@ -1182,10 +1182,11 @@ static CallBackFunction MenuClickHelp(int index)
case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break; case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break;
case 8: ShowFramerateWindow(); break; case 8: ShowFramerateWindow(); break;
case 9: ShowAboutWindow(); break; case 9: ShowModifierKeyToggleWindow(); break;
case 10: ShowSpriteAlignerWindow(); break; case 10: ShowAboutWindow(); break;
case 11: ToggleBoundingBoxes(); break; case 11: ShowSpriteAlignerWindow(); break;
case 12: ToggleDirtyBlocks(); break; case 12: ToggleBoundingBoxes(); break;
case 13: ToggleDirtyBlocks(); break;
} }
return CBF_NONE; return CBF_NONE;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,4 +57,10 @@ enum TextfileWidgets {
WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. 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 */ #endif /* WIDGETS_MISC_WIDGET_H */

View File

@@ -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. * Insert a text string at the cursor position into the edit box widget.
* @param wid Edit box widget. * @param wid Edit box widget.

View File

@@ -667,6 +667,10 @@ public:
*/ */
virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; } 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. * A click with the left mouse button has been made on the window.

View File

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