Changeset - r26103:316b73a1be08
[Not reviewed]
master
0 47 0
Michael Lutz - 3 years ago 2021-10-31 18:39:09
michi@icosahedron.de
Codechange: Template DoCommandP to automagically reflect the parameters of the command proc.

When finished, this will allow each command handler to take individually
different parameters, obliviating the need for bit-packing.
47 files changed with 375 insertions and 332 deletions:
0 comments (0 inline, 0 general)
src/ai/ai_gui.cpp
Show inline comments
 
@@ -19,24 +19,26 @@
 
#include "../window_func.h"
 
#include "../gfx_func.h"
 
#include "../command_func.h"
 
#include "../network/network.h"
 
#include "../settings_func.h"
 
#include "../network/network_content.h"
 
#include "../textfile_gui.h"
 
#include "../widgets/dropdown_type.h"
 
#include "../widgets/dropdown_func.h"
 
#include "../hotkeys.h"
 
#include "../core/geometry_func.hpp"
 
#include "../guitimer_func.h"
 
#include "../company_cmd.h"
 
#include "../misc_cmd.h"
 

	
 
#include "ai.hpp"
 
#include "ai_gui.hpp"
 
#include "../script/api/script_log.hpp"
 
#include "ai_config.hpp"
 
#include "ai_info.hpp"
 
#include "ai_instance.hpp"
 
#include "../game/game.hpp"
 
#include "../game/game_config.hpp"
 
#include "../game/game_info.hpp"
 
#include "../game/game_instance.hpp"
 

	
 
@@ -1281,26 +1283,26 @@ struct AIDebugWindow : public Window {
 
		if (IsInsideMM(widget, WID_AID_COMPANY_BUTTON_START, WID_AID_COMPANY_BUTTON_END + 1)) {
 
			ChangeToAI((CompanyID)(widget - WID_AID_COMPANY_BUTTON_START));
 
		}
 

	
 
		switch (widget) {
 
			case WID_AID_SCRIPT_GAME:
 
				ChangeToAI(OWNER_DEITY);
 
				break;
 

	
 
			case WID_AID_RELOAD_TOGGLE:
 
				if (ai_debug_company == OWNER_DEITY) break;
 
				/* First kill the company of the AI, then start a new one. This should start the current AI again */
 
				DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0);
 
				DoCommandP(CMD_COMPANY_CTRL, 0, CCA_NEW_AI | ai_debug_company << 16, 0);
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, {});
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | ai_debug_company << 16, 0, {});
 
				break;
 

	
 
			case WID_AID_SETTINGS:
 
				ShowAISettingsWindow(ai_debug_company);
 
				break;
 

	
 
			case WID_AID_BREAK_STR_ON_OFF_BTN:
 
				this->break_check_enabled = !this->break_check_enabled;
 
				this->InvalidateData(-1);
 
				break;
 

	
 
			case WID_AID_MATCH_CASE_BTN:
 
@@ -1321,25 +1323,25 @@ struct AIDebugWindow : public Window {
 
				/* If the last AI/Game Script is unpaused, unpause the game too. */
 
				if ((_pause_mode & PM_PAUSED_NORMAL) == PM_PAUSED_NORMAL) {
 
					bool all_unpaused = !Game::IsPaused();
 
					if (all_unpaused) {
 
						for (const Company *c : Company::Iterate()) {
 
							if (c->is_ai && AI::IsPaused(c->index)) {
 
								all_unpaused = false;
 
								break;
 
							}
 
						}
 
						if (all_unpaused) {
 
							/* All scripts have been unpaused => unpause the game. */
 
							DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 0);
 
							Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 0, {});
 
						}
 
					}
 
				}
 

	
 
				this->highlight_row = -1;
 
				this->InvalidateData(-1);
 
				break;
 
		}
 
	}
 

	
 
	void OnEditboxChanged(int wid) override
 
	{
 
@@ -1370,25 +1372,25 @@ struct AIDebugWindow : public Window {
 
				if (this->break_string_filter.GetState()) {
 
					/* Pause execution of script. */
 
					if (!this->IsDead()) {
 
						if (ai_debug_company == OWNER_DEITY) {
 
							Game::Pause();
 
						} else {
 
							AI::Pause(ai_debug_company);
 
						}
 
					}
 

	
 
					/* Pause the game. */
 
					if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) {
 
						DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
						Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 
					}
 

	
 
					/* Highlight row that matched */
 
					this->highlight_row = log->pos;
 
				}
 
			}
 
		}
 

	
 
		if (!gui_scope) return;
 

	
 
		this->SelectValidDebugCompany();
 

	
src/airport_gui.cpp
Show inline comments
 
@@ -62,25 +62,25 @@ static void PlaceAirport(TileIndex tile)
 
	SB(p2, 16, 16, INVALID_STATION); // no station to join
 

	
 
	uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex();
 
	p1 |= _selected_airport_layout << 8;
 

	
 
	auto proc = [=](bool test, StationID to_join) -> bool {
 
		if (test) {
 
			return Command<CMD_BUILD_AIRPORT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_AIRPORT>()), tile, p1, p2, {}).Succeeded();
 
		} else {
 
			uint32 p2_final = p2;
 
			if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
			return DoCommandP(CMD_BUILD_AIRPORT, STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, p1, p2_final);
 
			return Command<CMD_BUILD_AIRPORT>::Post(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, p1, p2_final, {});
 
		}
 
	};
 

	
 
	ShowSelectStationIfNeeded(TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE), proc);
 
}
 

	
 
/** Airport build toolbar window handler. */
 
struct BuildAirToolbarWindow : Window {
 
	int last_user_action; // Last started user action.
 

	
 
	BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
 
	{
src/autoreplace_gui.cpp
Show inline comments
 
@@ -16,24 +16,27 @@
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "autoreplace_func.h"
 
#include "company_func.h"
 
#include "engine_base.h"
 
#include "window_gui.h"
 
#include "engine_gui.h"
 
#include "settings_func.h"
 
#include "core/geometry_func.hpp"
 
#include "rail_gui.h"
 
#include "road_gui.h"
 
#include "widgets/dropdown_func.h"
 
#include "autoreplace_cmd.h"
 
#include "group_cmd.h"
 
#include "settings_cmd.h"
 

	
 
#include "widgets/autoreplace_widget.h"
 

	
 
#include "safeguards.h"
 

	
 
void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group);
 

	
 
static bool EngineNumberSorter(const EngineID &a, const EngineID &b)
 
{
 
	return Engine::Get(a)->list_position < Engine::Get(b)->list_position;
 
}
 

	
 
@@ -208,25 +211,25 @@ class ReplaceVehicleWindow : public Wind
 
		this->engines[1].RebuildDone();
 
		this->reset_sel_engine = false;
 
	}
 

	
 
	/**
 
	 * Handle click on the start replace button.
 
	 * @param replace_when_old Replace now or only when old?
 
	 */
 
	void ReplaceClick_StartReplace(bool replace_when_old)
 
	{
 
		EngineID veh_from = this->sel_engine[0];
 
		EngineID veh_to = this->sel_engine[1];
 
		DoCommandP(CMD_SET_AUTOREPLACE, 0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16));
 
		Command<CMD_SET_AUTOREPLACE>::Post(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), {});
 
	}
 

	
 
public:
 
	ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc)
 
	{
 
		this->sel_railtype = INVALID_RAILTYPE;
 
		this->sel_roadtype = INVALID_ROADTYPE;
 
		this->replace_engines  = true; // start with locomotives (all other vehicles will not read this bool)
 
		this->engines[0].ForceRebuild();
 
		this->engines[1].ForceRebuild();
 
		this->reset_sel_engine = true;
 
		this->details_height   = ((vehicletype == VEH_TRAIN) ? 10 : 9);
 
@@ -532,68 +535,68 @@ public:
 
						ShowDropDownList(this, GetRailTypeDropDownList(true, true), sel_railtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN);
 
						break;
 

	
 
					case VEH_ROAD:
 
						ShowDropDownList(this, GetRoadTypeDropDownList(RTTB_ROAD | RTTB_TRAM, true, true), sel_roadtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN);
 
						break;
 
				}
 
				break;
 

	
 
			case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: {
 
				const Group *g = Group::GetIfValid(this->sel_group);
 
				if (g != nullptr) {
 
					DoCommandP(CMD_SET_GROUP_FLAG, 0, this->sel_group | (GroupFlags::GF_REPLACE_WAGON_REMOVAL << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL) ? 0 : 1) | (_ctrl_pressed << 1));
 
					Command<CMD_SET_GROUP_FLAG>::Post(0, this->sel_group | (GroupFlags::GF_REPLACE_WAGON_REMOVAL << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL) ? 0 : 1) | (_ctrl_pressed << 1), {});
 
				} else {
 
					// toggle renew_keep_length
 
					DoCommandP(CMD_CHANGE_COMPANY_SETTING, 0, 0, Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, "company.renew_keep_length");
 
					Command<CMD_CHANGE_COMPANY_SETTING>::Post(0, 0, Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, "company.renew_keep_length");
 
				}
 
				break;
 
			}
 

	
 
			case WID_RV_START_REPLACE: { // Start replacing
 
				if (this->GetWidget<NWidgetLeaf>(widget)->ButtonHit(pt)) {
 
					this->HandleButtonClick(WID_RV_START_REPLACE);
 
					ReplaceClick_StartReplace(false);
 
				} else {
 
					bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group);
 
					ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0);
 
				}
 
				break;
 
			}
 

	
 
			case WID_RV_STOP_REPLACE: { // Stop replacing
 
				EngineID veh_from = this->sel_engine[0];
 
				DoCommandP(CMD_SET_AUTOREPLACE, 0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16));
 
				Command<CMD_SET_AUTOREPLACE>::Post(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), {});
 
				break;
 
			}
 

	
 
			case WID_RV_LEFT_MATRIX:
 
			case WID_RV_RIGHT_MATRIX: {
 
				byte click_side;
 
				if (widget == WID_RV_LEFT_MATRIX) {
 
					click_side = 0;
 
				} else {
 
					click_side = 1;
 
				}
 
				uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget);
 
				size_t engine_count = this->engines[click_side].size();
 

	
 
				EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE;
 

	
 
				/* If Ctrl is pressed on the left side and we don't have any engines of the selected type, stop autoreplacing.
 
				 * This is most common when we have finished autoreplacing the engine and want to remove it from the list. */
 
				if (click_side == 0 && _ctrl_pressed && e != INVALID_ENGINE &&
 
					(GetGroupNumEngines(_local_company, sel_group, e) == 0 || GetGroupNumEngines(_local_company, ALL_GROUP, e) == 0)) {
 
						EngineID veh_from = e;
 
						DoCommandP(CMD_SET_AUTOREPLACE, 0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16));
 
						Command<CMD_SET_AUTOREPLACE>::Post(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), {});
 
						break;
 
				}
 

	
 
				if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected
 
				this->sel_engine[click_side] = e;
 
				if (click_side == 0) {
 
					this->engines[1].ForceRebuild();
 
					this->reset_sel_engine = true;
 
				}
 
				this->SetDirty();
 
				break;
 
			}
src/bridge_gui.cpp
Show inline comments
 
@@ -110,26 +110,26 @@ private:
 
	static bool BridgeSpeedSorter(const BuildBridgeData &a, const BuildBridgeData &b)
 
	{
 
		return a.spec->speed < b.spec->speed;
 
	}
 

	
 
	void BuildBridge(uint8 i)
 
	{
 
		switch ((TransportType)(this->type >> 15)) {
 
			case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->at(i).index; break;
 
			case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->at(i).index; break;
 
			default: break;
 
		}
 
		DoCommandP(CMD_BUILD_BRIDGE, STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge,
 
					this->end_tile, this->start_tile, this->type | this->bridges->at(i).index);
 
		Command<CMD_BUILD_BRIDGE>::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge,
 
					this->end_tile, this->start_tile, this->type | this->bridges->at(i).index, {});
 
	}
 

	
 
	/** Sort the builable bridges */
 
	void SortBridgeList()
 
	{
 
		this->bridges->Sort();
 

	
 
		/* Display the current sort variant */
 
		this->GetWidget<NWidgetCore>(WID_BBS_DROPDOWN_CRITERIA)->widget_data = this->sorter_names[this->bridges->SortType()];
 

	
 
		/* Set the modified widgets dirty */
 
		this->SetWidgetDirty(WID_BBS_DROPDOWN_CRITERIA);
 
@@ -376,25 +376,25 @@ void ShowBuildBridgeWindow(TileIndex sta
 
	/* If Ctrl is being pressed, check whether the last bridge built is available
 
	 * If so, return this bridge type. Otherwise continue normally.
 
	 * We store bridge types for each transport type, so we have to check for
 
	 * the transport type beforehand.
 
	 */
 
	BridgeType last_bridge_type = 0;
 
	switch (transport_type) {
 
		case TRANSPORT_ROAD: last_bridge_type = _last_roadbridge_type; break;
 
		case TRANSPORT_RAIL: last_bridge_type = _last_railbridge_type; break;
 
		default: break; // water ways and air routes don't have bridge types
 
	}
 
	if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) {
 
		DoCommandP(CMD_BUILD_BRIDGE, STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, end, start, type | last_bridge_type);
 
		Command<CMD_BUILD_BRIDGE>::Post(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, CcBuildBridge, end, start, type | last_bridge_type, {});
 
		return;
 
	}
 

	
 
	/* only query bridge building possibility once, result is the same for all bridges!
 
	 * returns CMD_ERROR on failure, and price on success */
 
	StringID errmsg = INVALID_STRING_ID;
 
	CommandCost ret = Command<CMD_BUILD_BRIDGE>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_BRIDGE>()) | DC_QUERY_COST, end, start, type, {});
 

	
 
	GUIBridgeList *bl = nullptr;
 
	if (ret.Failed()) {
 
		errmsg = ret.GetErrorMessage();
 
	} else {
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -21,24 +21,25 @@
 
#include "newgrf_text.h"
 
#include "group.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "widgets/dropdown_func.h"
 
#include "engine_gui.h"
 
#include "cargotype.h"
 
#include "core/geometry_func.hpp"
 
#include "autoreplace_func.h"
 
#include "engine_cmd.h"
 
#include "train_cmd.h"
 
#include "vehicle_cmd.h"
 

	
 
#include "widgets/build_vehicle_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Get the height of a single 'entry' in the engine lists.
 
 * @param type the vehicle type to get the height of
 
@@ -1451,36 +1452,36 @@ struct BuildVehicleWindow : Window {
 

	
 
			case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
 
				DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
 
				break;
 

	
 
			case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
 
				ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0);
 
				break;
 

	
 
			case WID_BV_SHOW_HIDE: {
 
				const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
 
				if (e != nullptr) {
 
					DoCommandP(CMD_SET_VEHICLE_VISIBILITY, 0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)));
 
					Command<CMD_SET_VEHICLE_VISIBILITY>::Post(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), {});
 
				}
 
				break;
 
			}
 

	
 
			case WID_BV_BUILD: {
 
				EngineID sel_eng = this->sel_engine;
 
				if (sel_eng != INVALID_ENGINE) {
 
					CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
 
					CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
 
					if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE;
 
					DoCommandP(CMD_BUILD_VEHICLE, GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng | (cargo << 24), 0);
 
					Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), callback, this->window_number, sel_eng | (cargo << 24), 0, {});
 
				}
 
				break;
 
			}
 

	
 
			case WID_BV_RENAME: {
 
				EngineID sel_eng = this->sel_engine;
 
				if (sel_eng != INVALID_ENGINE) {
 
					this->rename_engine = sel_eng;
 
					SetDParam(0, sel_eng);
 
					ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
 
				}
 
				break;
 
@@ -1627,25 +1628,25 @@ struct BuildVehicleWindow : Window {
 
				int resize = needed_height - this->details_height;
 
				this->details_height = needed_height;
 
				this->ReInit(0, resize * FONT_HEIGHT_NORMAL);
 
				return;
 
			}
 
		}
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		DoCommandP(CMD_RENAME_ENGINE, STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, 0, this->rename_engine, 0, str);
 
		Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, 0, this->rename_engine, 0, str);
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_BV_SORT_DROPDOWN:
 
				if (this->sort_criteria != index) {
 
					this->sort_criteria = index;
 
					_engine_sort_last_criteria[this->vehicle_type] = this->sort_criteria;
 
					this->eng_list.ForceRebuild();
 
				}
 
				break;
src/cheat_gui.cpp
Show inline comments
 
@@ -19,24 +19,25 @@
 
#include "window_gui.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "rail_gui.h"
 
#include "settings_gui.h"
 
#include "company_gui.h"
 
#include "linkgraph/linkgraphschedule.h"
 
#include "map_func.h"
 
#include "tile_map.h"
 
#include "newgrf.h"
 
#include "error.h"
 
#include "misc_cmd.h"
 

	
 
#include "widgets/cheat_widget.h"
 

	
 
#include "table/sprites.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
/**
 
 * The 'amount' to cheat with.
 
 * This variable is semantically a constant value, but because the cheat
 
 * code requires to be able to write to the variable it is not constified.
 
@@ -45,25 +46,25 @@ static int32 _money_cheat_amount = 10000
 

	
 
/**
 
 * Handle cheating of money.
 
 * Note that the amount of money of a company must be changed through a command
 
 * rather than by setting a variable. Since the cheat data structure expects a
 
 * variable, the amount of given/taken money is used for this purpose.
 
 * @param p1 not used.
 
 * @param p2 is -1 or +1 (down/up)
 
 * @return Amount of money cheat.
 
 */
 
static int32 ClickMoneyCheat(int32 p1, int32 p2)
 
{
 
	DoCommandP(CMD_MONEY_CHEAT, 0, (uint32)(p2 * _money_cheat_amount), 0);
 
	Command<CMD_MONEY_CHEAT>::Post(0, (uint32)(p2 * _money_cheat_amount), 0, {});
 
	return _money_cheat_amount;
 
}
 

	
 
/**
 
 * Handle changing of company.
 
 * @param p1 company to set to
 
 * @param p2 is -1 or +1 (down/up)
 
 * @return The new company.
 
 */
 
static int32 ClickChangeCompanyCheat(int32 p1, int32 p2)
 
{
 
	while ((uint)p1 < Company::GetPoolSize()) {
src/command.cpp
Show inline comments
 
@@ -204,173 +204,83 @@ void CommandHelperBase::InternalDoAfter(
 

	
 
		if (res.Succeeded() && top_level && !(flags & DC_QUERY_COST) && !(flags & DC_BANKRUPT)) {
 
			CheckCompanyHasMoney(res); // CheckCompanyHasMoney() modifies 'res' to an error if it fails.
 
		}
 
	} else {
 
		/* If top-level, subtract the money. */
 
		if (res.Succeeded() && top_level && !(flags & DC_BANKRUPT)) {
 
			SubtractMoneyFromCompany(res);
 
		}
 
	}
 
}
 

	
 
/*!
 
 * Toplevel network safe docommand function for the current company. Must not be called recursively.
 
 * The callback is called when the command succeeded or failed. The parameters
 
 * \a tile, \a p1, and \a p2 are from the #CommandProc function. The parameter \a cmd is the command to execute.
 
 * The parameter \a my_cmd is used to indicate if the command is from a company or the server.
 
 *
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param callback A callback function to call after the command is finished
 
 * @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
 
 * @param network_command execute the command without sending it on the network
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
/**
 
 * Decide what to do with the command depending on current game state.
 
 * @param cmd Command to execute.
 
 * @param flags Command flags.
 
 * @param tile Tile of command execution.
 
 * @param err_message Message prefix to show on error.
 
 * @param network_command Does this command come from the network?
 
 * @return error state + do only cost estimation? + send to network only?
 
 */
 
static bool DoCommandP(Commands cmd, StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
std::tuple<bool, bool, bool> CommandHelperBase::InternalPostBefore(Commands cmd, CommandFlags flags, TileIndex tile, StringID err_message, bool network_command)
 
{
 
	/* Cost estimation is generally only done when the
 
	 * local user presses shift while doing something.
 
	 * However, in case of incoming network commands,
 
	 * map generation or the pause button we do want
 
	 * to execute. */
 
	bool estimate_only = _shift_pressed && IsLocalCompany() &&
 
			!_generating_world &&
 
			!network_command &&
 
			!(GetCommandFlags(cmd) & CMD_NO_EST);
 
	bool estimate_only = _shift_pressed && IsLocalCompany() && !_generating_world && !network_command && !(flags & CMD_NO_EST);
 

	
 
	/* We're only sending the command, so don't do
 
	 * fancy things for 'success'. */
 
	bool only_sending = _networking && !network_command;
 

	
 
	/* Where to show the message? */
 
	if (_pause_mode != PM_UNPAUSED && !IsCommandAllowedWhilePaused(cmd) && !estimate_only) {
 
		ShowErrorMessage(err_message, STR_ERROR_NOT_ALLOWED_WHILE_PAUSED, WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
 
		return { true, estimate_only, only_sending };
 
	} else {
 
		return { false, estimate_only, only_sending };
 
	}
 
}
 

	
 
/**
 
 * Process result of executing a command, possibly displaying any error to the player.
 
 * @param res Command result.
 
 * @param tile Tile of command execution.
 
 * @param estimate_only Is this just cost estimation?
 
 * @param only_sending Was the command only sent to network?
 
 * @param err_message Message prefix to show on error.
 
 * @param my_cmd Is the command from this client?
 
 */
 
void CommandHelperBase::InternalPostResult(const CommandCost &res, TileIndex tile, bool estimate_only, bool only_sending, StringID err_message, bool my_cmd)
 
{
 
	int x = TileX(tile) * TILE_SIZE;
 
	int y = TileY(tile) * TILE_SIZE;
 

	
 
	if (_pause_mode != PM_UNPAUSED && !IsCommandAllowedWhilePaused(cmd) && !estimate_only) {
 
		ShowErrorMessage(err_message, STR_ERROR_NOT_ALLOWED_WHILE_PAUSED, WL_INFO, x, y);
 
		return false;
 
	}
 

	
 
	/* Only set p2 when the command does not come from the network. */
 
	if (!network_command && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER;
 

	
 
	CommandCost res = DoCommandPInternal(cmd, err_message, callback, my_cmd, estimate_only, network_command, tile, p1, p2, text);
 
	if (res.Failed()) {
 
		/* Only show the error when it's for us. */
 
		if (estimate_only || (IsLocalCompany() && err_message != 0 && my_cmd)) {
 
			ShowErrorMessage(err_message, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
 
		}
 
	} else if (estimate_only) {
 
		ShowEstimatedCostOrIncome(res.GetCost(), x, y);
 
	} else if (!only_sending && res.GetCost() != 0 && tile != 0 && IsLocalCompany() && _game_mode != GM_EDITOR) {
 
		/* Only show the cost animation when we did actually
 
		 * execute the command, i.e. we're not sending it to
 
		 * the server, when it has cost the local company
 
		 * something. Furthermore in the editor there is no
 
		 * concept of cost, so don't show it there either. */
 
		ShowCostOrIncomeAnimation(x, y, GetSlopePixelZ(x, y), res.GetCost());
 
	}
 

	
 
	if (!estimate_only && !only_sending && callback != nullptr) {
 
		callback(res, cmd, tile, p1, p2, text);
 
	}
 

	
 
	return res.Succeeded();
 
}
 

	
 
/**
 
 * Shortcut for the long DoCommandP when not using a callback or error message.
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
 */
 
bool DoCommandP(Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return DoCommandP(cmd, STR_NULL, nullptr, true, false, tile, p1, p2, text);
 
}
 

	
 
/**
 
 * Shortcut for the long DoCommandP when not using an error message.
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param callback A callback function to call after the command is finished
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
 */
 
bool DoCommandP(Commands cmd, CommandCallback *callback, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return DoCommandP(cmd, STR_NULL, callback, true, false, tile, p1, p2, text);
 
}
 

	
 
/**
 
 * Shortcut for the long DoCommandP when not using a callback.
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param err_message Message prefix to show on error
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
 */
 
bool DoCommandP(Commands cmd, StringID err_message, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return DoCommandP(cmd, err_message, nullptr, true, false, tile, p1, p2, text);
 
}
 

	
 
/*!
 
 * Toplevel network safe docommand function for the current company. Must not be called recursively.
 
 * The callback is called when the command succeeded or failed. The parameters
 
 * \a tile, \a p1, and \a p2 are from the #CommandProc function. The parameter \a cmd is the command to execute.
 
 *
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param err_message Message prefix to show on error
 
 * @param callback A callback function to call after the command is finished
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
 */
 
bool DoCommandP(Commands cmd, StringID err_message, CommandCallback *callback, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return DoCommandP(cmd, err_message, callback, true, false, tile, p1, p2, text);
 
}
 

	
 
/**
 
 * Toplevel network safe docommand function for the current company. Must not be called recursively.
 
 * The callback is called when the command succeeded or failed. The parameters
 
 * \a tile, \a p1, and \a p2 are from the #CommandProc function. The parameter \a cmd is the command to execute.
 
 *
 
 * @param cmd The command to execute (a CMD_* value)
 
 * @param err_message Message prefix to show on error
 
 * @param callback A callback function to call after the command is finished
 
 * @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
 
 * @param tile The tile to perform a command on (see #CommandProc)
 
 * @param p1 Additional data for the command (see #CommandProc)
 
 * @param p2 Additional data for the command (see #CommandProc)
 
 * @param text The text to pass
 
 * @return \c true if the command succeeded, else \c false.
 
 */
 
bool InjectNetworkCommand(Commands cmd, StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return DoCommandP(cmd, err_message, callback, my_cmd, true, tile, p1, p2, text);
 
}
 

	
 
/** Helper to format command parameters into a hex string. */
 
static std::string CommandParametersToHexString(TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	return FormatArrayAsHex(EndianBufferWriter<>::FromValue(std::make_tuple(tile, p1, p2, text)));
 
}
 

	
 
/*!
 
 * Helper function for the toplevel network safe docommand function for the current company.
 
 *
 
 * @param cmd The command to execute (a CMD_* value)
src/command_func.h
Show inline comments
 
@@ -28,32 +28,24 @@ static const CommandCost CMD_ERROR = Com
 
 * Returns from a function with a specific StringID as error.
 
 *
 
 * This macro is used to return from a function. The parameter contains the
 
 * StringID which will be returned.
 
 *
 
 * @param errcode The StringID to return
 
 */
 
#define return_cmd_error(errcode) return CommandCost(errcode);
 

	
 
/** Storage buffer for serialized command data. */
 
typedef std::vector<byte> CommandDataBuffer;
 

	
 

	
 
bool DoCommandP(Commands cmd, StringID err_message, CommandCallback *callback, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
 
bool DoCommandP(Commands cmd, StringID err_message, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
 
bool DoCommandP(Commands cmd, CommandCallback *callback, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
 
bool DoCommandP(Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text = {});
 

	
 
bool InjectNetworkCommand(Commands cmd, StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text);
 

	
 
CommandCost DoCommandPInternal(Commands cmd, StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, bool network_command, TileIndex tile, uint32 p1, uint32 p2, const std::string &text);
 

	
 
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, TileIndex tile, uint32 p1, uint32 p2, const std::string &text);
 
void NetworkSendCommand(Commands cmd, StringID err_message, CommandCallback *callback, CompanyID company, TileIndex location, const CommandDataBuffer &cmd_data);
 

	
 
extern Money _additional_cash_required;
 

	
 
bool IsValidCommand(Commands cmd);
 
CommandFlags GetCommandFlags(Commands cmd);
 
const char *GetCommandName(Commands cmd);
 
Money GetAvailableMoneyForCommand();
 
bool IsCommandAllowedWhilePaused(Commands cmd);
 
@@ -87,24 +79,26 @@ struct RecursiveCommandCounter {
 
	bool IsTopLevel() const { return _counter == 1; }
 
private:
 
	static int _counter;
 
};
 

	
 

	
 
template<Commands TCmd, typename T> struct CommandHelper;
 

	
 
class CommandHelperBase {
 
protected:
 
	static void InternalDoBefore(bool top_level, bool test);
 
	static void InternalDoAfter(CommandCost &res, DoCommandFlag flags, bool top_level, bool test);
 
	static std::tuple<bool, bool, bool> InternalPostBefore(Commands cmd, CommandFlags flags, TileIndex tile, StringID err_message, bool network_command);
 
	static void InternalPostResult(const CommandCost &res, TileIndex tile, bool estimate_only, bool only_sending, StringID err_message, bool my_cmd);
 
};
 

	
 
/**
 
 * Templated wrapper that exposes the command parameter arguments
 
 * for the various Command::Do/Post calls.
 
 * @tparam Tcmd The command-id to execute.
 
 * @tparam Targs The command parameter types.
 
 */
 
template <Commands Tcmd, typename... Targs>
 
struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...)> : protected CommandHelperBase {
 
public:
 
	/**
 
@@ -138,18 +132,95 @@ public:
 

	
 
			if (res.Failed() || !(flags & DC_EXEC)) return res;
 
		}
 

	
 
		/* Execute the command here. All cost-relevant functions set the expenses type
 
		 * themselves to the cost object at some point. */
 
		InternalDoBefore(counter.IsTopLevel(), false);
 
		CommandCost res = CommandTraits<Tcmd>::proc(flags, args...);
 
		InternalDoAfter(res, flags, counter.IsTopLevel(), false);
 

	
 
		return res;
 
	}
 

	
 
	/**
 
	 * Shortcut for the long Post when not using a callback.
 
	 * @param err_message Message prefix to show on error
 
	 * @param args Parameters for the command
 
	 */
 
	static inline bool Post(StringID err_message, Targs... args) { return Post(err_message, nullptr, std::forward<Targs>(args)...); }
 
	/**
 
	 * Shortcut for the long Post when not using an error message.
 
	 * @param callback A callback function to call after the command is finished
 
	 * @param args Parameters for the command
 
	 */
 
	static inline bool Post(CommandCallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward<Targs>(args)...); }
 
	/**
 
	 * Shortcut for the long Post when not using a callback or an error message.
 
	 * @param args Parameters for the command
 
	 */
 
	static inline bool Post(Targs... args) { return Post((StringID)0, nullptr, std::forward<Targs>(args)...); }
 

	
 
	/**
 
	 * Top-level network safe command execution for the current company.
 
	 * Must not be called recursively. The callback is called when the
 
	 * command succeeded or failed.
 
	 *
 
	 * @param err_message Message prefix to show on error
 
	 * @param callback A callback function to call after the command is finished
 
	 * @param args Parameters for the command
 
	 * @return \c true if the command succeeded, else \c false.
 
	 */
 
	static bool Post(StringID err_message, CommandCallback *callback, Targs... args)
 
	{
 
		return InternalPost(err_message, callback, true, false, std::forward_as_tuple(args...));
 
	}
 

	
 
	/**
 
	 * Execute a command coming from the network.
 
	 * @param err_message Message prefix to show on error
 
	 * @param callback A callback function to call after the command is finished
 
	 * @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
 
	 * @param location Tile location for user feedback.
 
	 * @param args Parameters for the command
 
	 * @return \c true if the command succeeded, else \c false.
 
	 */
 
	static bool PostFromNet(StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex location, std::tuple<Targs...> args)
 
	{
 
		return InternalPost(err_message, callback, my_cmd, true, location, std::move(args));
 
	}
 

	
 
protected:
 
	static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
 
	{
 
		/* Where to show the message? */
 
		TileIndex tile{};
 
		if constexpr (std::is_same_v<TileIndex, std::tuple_element_t<0, decltype(args)>>) {
 
			tile = std::get<0>(args);
 
		}
 

	
 
		return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
 
	}
 

	
 
	static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple<Targs...> args)
 
	{
 
		auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), tile, err_message, network_command);
 
		if (err) return false;
 

	
 
		/* Only set p2 when the command does not come from the network. */
 
		if (!network_command && GetCommandFlags<Tcmd>() & CMD_CLIENT_ID && std::get<2>(args) == 0) std::get<2>(args) = CLIENT_ID_SERVER;
 

	
 
		CommandCost res = std::apply(DoCommandPInternal, std::tuple_cat(std::make_tuple(Tcmd, err_message, callback, my_cmd, estimate_only, network_command), args));
 
		InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd);
 

	
 
		if (!estimate_only && !only_sending && callback != nullptr) {
 
			std::apply(callback, std::tuple_cat(std::tuple<const CommandCost &, Commands>{ res, Tcmd }, args));
 
		}
 

	
 
		return res.Succeeded();
 
	}
 
};
 

	
 
template <Commands Tcmd>
 
using Command = CommandHelper<Tcmd, typename CommandTraits<Tcmd>::ProcType>;
 

	
 
#endif /* COMMAND_FUNC_H */
src/company_cmd.cpp
Show inline comments
 
@@ -595,25 +595,25 @@ static bool MaybeStartNewCompany()
 
{
 
	if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return false;
 

	
 
	/* count number of competitors */
 
	uint n = 0;
 
	for (const Company *c : Company::Iterate()) {
 
		if (c->is_ai) n++;
 
	}
 

	
 
	if (n < (uint)_settings_game.difficulty.max_no_competitors) {
 
		/* Send a command to all clients to start up a new AI.
 
		 * Works fine for Multiplayer and Singleplayer */
 
		return DoCommandP(CMD_COMPANY_CTRL, 0, CCA_NEW_AI | INVALID_COMPANY << 16, 0);
 
		return Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
 
	}
 

	
 
	return false;
 
}
 

	
 
/** Initialize the pool of companies. */
 
void InitializeCompanies()
 
{
 
	_cur_company_tick_index = 0;
 
}
 

	
 
/**
src/company_gui.cpp
Show inline comments
 
@@ -28,24 +28,29 @@
 
#include "company_base.h"
 
#include "core/geometry_func.hpp"
 
#include "object_type.h"
 
#include "rail.h"
 
#include "road.h"
 
#include "engine_base.h"
 
#include "window_func.h"
 
#include "road_func.h"
 
#include "water.h"
 
#include "station_func.h"
 
#include "zoom_func.h"
 
#include "sortlist_type.h"
 
#include "company_cmd.h"
 
#include "economy_cmd.h"
 
#include "group_cmd.h"
 
#include "misc_cmd.h"
 
#include "object_cmd.h"
 

	
 
#include "widgets/company_widget.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
/** Company GUI constants. */
 
static const uint EXP_LINESPACE  = 2;      ///< Amount of vertical space for a horizontal (sub-)total line.
 
static const uint EXP_BLOCKSPACE = 10;     ///< Amount of vertical space between two blocks of numbers.
 

	
 
static void DoSelectCompanyManagerFace(Window *parent);
 
static void ShowCompanyInfrastructure(CompanyID company);
 
@@ -426,29 +431,29 @@ struct CompanyFinancesWindow : Window {
 
				this->small = !this->small;
 
				this->SetupWidgets();
 
				if (this->IsShaded()) {
 
					/* Finances window is not resizable, so size hints given during unshading have no effect
 
					 * on the changed appearance of the window. */
 
					this->SetShaded(false);
 
				} else {
 
					this->ReInit();
 
				}
 
				break;
 

	
 
			case WID_CF_INCREASE_LOAN: // increase loan
 
				DoCommandP(CMD_INCREASE_LOAN, STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY, 0, 0, _ctrl_pressed);
 
				Command<CMD_INCREASE_LOAN>::Post(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY, 0, 0, _ctrl_pressed, {});
 
				break;
 

	
 
			case WID_CF_REPAY_LOAN: // repay loan
 
				DoCommandP(CMD_DECREASE_LOAN, STR_ERROR_CAN_T_REPAY_LOAN, 0, 0, _ctrl_pressed);
 
				Command<CMD_DECREASE_LOAN>::Post(STR_ERROR_CAN_T_REPAY_LOAN, 0, 0, _ctrl_pressed, {});
 
				break;
 

	
 
			case WID_CF_INFRASTRUCTURE: // show infrastructure details
 
				ShowCompanyInfrastructure((CompanyID)this->window_number);
 
				break;
 
		}
 
	}
 

	
 
	void OnHundredthTick() override
 
	{
 
		const Company *c = Company::Get((CompanyID)this->window_number);
 
		if (c->money > CompanyFinancesWindow::max_money) {
 
@@ -986,30 +991,30 @@ public:
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		bool local = (CompanyID)this->window_number == _local_company;
 
		if (!local) return;
 

	
 
		if (index >= COLOUR_END) index = INVALID_COLOUR;
 

	
 
		if (this->livery_class < LC_GROUP_RAIL) {
 
			/* Set company colour livery */
 
			for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
 
				/* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
 
				if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
 
					DoCommandP(CMD_SET_COMPANY_COLOUR, 0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index);
 
					Command<CMD_SET_COMPANY_COLOUR>::Post(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, {});
 
				}
 
			}
 
		} else {
 
			/* Setting group livery */
 
			DoCommandP(CMD_SET_GROUP_LIVERY, 0, this->sel, (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256) | (index << 16));
 
			Command<CMD_SET_GROUP_LIVERY>::Post(0, this->sel, (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256) | (index << 16), {});
 
		}
 
	}
 

	
 
	/**
 
	 * Some data on this window has become invalid.
 
	 * @param data Information about the changed data.
 
	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
 
	 */
 
	void OnInvalidateData(int data = 0, bool gui_scope = true) override
 
	{
 
		if (!gui_scope) return;
 

	
 
@@ -1572,25 +1577,25 @@ public:
 
	{
 
		switch (widget) {
 
			/* Toggle size, advanced/simple face selection */
 
			case WID_SCMF_TOGGLE_LARGE_SMALL:
 
			case WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON:
 
				this->advanced = !this->advanced;
 
				this->SelectDisplayPlanes(this->advanced);
 
				this->ReInit();
 
				break;
 

	
 
			/* OK button */
 
			case WID_SCMF_ACCEPT:
 
				DoCommandP(CMD_SET_COMPANY_MANAGER_FACE, 0, 0, this->face);
 
				Command<CMD_SET_COMPANY_MANAGER_FACE>::Post(0, 0, this->face, {});
 
				FALLTHROUGH;
 

	
 
			/* Cancel button */
 
			case WID_SCMF_CANCEL:
 
				this->Close();
 
				break;
 

	
 
			/* Load button */
 
			case WID_SCMF_LOAD:
 
				this->face = _company_manager_face;
 
				ScaleAllCompanyManagerFaceBits(this->face);
 
				ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
 
@@ -2567,29 +2572,29 @@ struct CompanyWindow : Window
 
				break;
 

	
 
			case WID_C_VIEW_INFRASTRUCTURE:
 
				ShowCompanyInfrastructure((CompanyID)this->window_number);
 
				break;
 

	
 
			case WID_C_GIVE_MONEY:
 
				this->query_widget = WID_C_GIVE_MONEY;
 
				ShowQueryString(STR_EMPTY, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, QSF_NONE);
 
				break;
 

	
 
			case WID_C_BUY_SHARE:
 
				DoCommandP(CMD_BUY_SHARE_IN_COMPANY, STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS, (TileIndex)0, this->window_number, 0);
 
				Command<CMD_BUY_SHARE_IN_COMPANY>::Post(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS, 0, this->window_number, 0, {});
 
				break;
 

	
 
			case WID_C_SELL_SHARE:
 
				DoCommandP(CMD_SELL_SHARE_IN_COMPANY, STR_ERROR_CAN_T_SELL_25_SHARE_IN, (TileIndex)0, this->window_number, 0);
 
				Command<CMD_SELL_SHARE_IN_COMPANY>::Post(STR_ERROR_CAN_T_SELL_25_SHARE_IN, 0, this->window_number, 0, {});
 
				break;
 

	
 
			case WID_C_COMPANY_PASSWORD:
 
				if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
 
				break;
 

	
 
			case WID_C_COMPANY_JOIN: {
 
				this->query_widget = WID_C_COMPANY_JOIN;
 
				CompanyID company = (CompanyID)this->window_number;
 
				if (_network_server) {
 
					NetworkServerDoMove(CLIENT_ID_SERVER, company);
 
					MarkWholeScreenDirty();
 
@@ -2604,56 +2609,56 @@ struct CompanyWindow : Window
 
			}
 
		}
 
	}
 

	
 
	void OnHundredthTick() override
 
	{
 
		/* redraw the window every now and then */
 
		this->SetDirty();
 
	}
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		if (DoCommandP(CMD_BUILD_OBJECT, STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
 
		if (Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0, {}) && !_shift_pressed) {
 
			ResetObjectToPlace();
 
			this->RaiseButtons();
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		this->RaiseButtons();
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		switch (this->query_widget) {
 
			default: NOT_REACHED();
 

	
 
			case WID_C_GIVE_MONEY: {
 
				Money money = (Money)(strtoull(str, nullptr, 10) / _currency->rate);
 
				uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0
 

	
 
				DoCommandP(CMD_GIVE_MONEY, STR_ERROR_CAN_T_GIVE_MONEY, 0, money_c, this->window_number);
 
				Command<CMD_GIVE_MONEY>::Post(STR_ERROR_CAN_T_GIVE_MONEY, 0, money_c, this->window_number, {});
 
				break;
 
			}
 

	
 
			case WID_C_PRESIDENT_NAME:
 
				DoCommandP(CMD_RENAME_PRESIDENT, STR_ERROR_CAN_T_CHANGE_PRESIDENT, 0, 0, 0, str);
 
				Command<CMD_RENAME_PRESIDENT>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, 0, 0, 0, str);
 
				break;
 

	
 
			case WID_C_COMPANY_NAME:
 
				DoCommandP(CMD_RENAME_COMPANY, STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, 0, 0, 0, str);
 
				Command<CMD_RENAME_COMPANY>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, 0, 0, 0, str);
 
				break;
 

	
 
			case WID_C_COMPANY_JOIN:
 
				NetworkClientRequestMove((CompanyID)this->window_number, str);
 
				break;
 
		}
 
	}
 

	
 

	
 
	/**
 
	 * Some data on this window has become invalid.
 
	 * @param data Information about the changed data.
 
@@ -2762,25 +2767,25 @@ struct BuyCompanyWindow : Window {
 
			}
 
		}
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_BC_NO:
 
				this->Close();
 
				break;
 

	
 
			case WID_BC_YES:
 
				DoCommandP(CMD_BUY_COMPANY, STR_ERROR_CAN_T_BUY_COMPANY, (TileIndex)0, this->window_number, 0);
 
				Command<CMD_BUY_COMPANY>::Post(STR_ERROR_CAN_T_BUY_COMPANY, 0, this->window_number, 0, {});
 
				break;
 
		}
 
	}
 
};
 

	
 
static const NWidgetPart _nested_buy_company_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
 
		NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
 
		NWidget(NWID_VERTICAL), SetPIP(8, 8, 8),
src/console_cmds.cpp
Show inline comments
 
@@ -33,24 +33,26 @@
 
#include "gamelog.h"
 
#include "ai/ai.hpp"
 
#include "ai/ai_config.hpp"
 
#include "newgrf.h"
 
#include "newgrf_profiling.h"
 
#include "console_func.h"
 
#include "engine_base.h"
 
#include "road.h"
 
#include "rail.h"
 
#include "game/game.hpp"
 
#include "table/strings.h"
 
#include "walltime_func.h"
 
#include "company_cmd.h"
 
#include "misc_cmd.h"
 

	
 
#include "safeguards.h"
 

	
 
/* scriptfile handling */
 
static uint _script_current_depth; ///< Depth of scripts running (used to abort execution when #ConReturn is encountered).
 

	
 
/** File list storage for the console, for caching the last 'ls' command. */
 
class ConsoleFileList : public FileList {
 
public:
 
	ConsoleFileList() : FileList()
 
	{
 
		this->file_list_valid = false;
 
@@ -621,47 +623,47 @@ DEF_CONSOLE_CMD(ConPauseGame)
 
{
 
	if (argc == 0) {
 
		IConsolePrint(CC_HELP, "Pause a network game. Usage: 'pause'.");
 
		return true;
 
	}
 

	
 
	if (_game_mode == GM_MENU) {
 
		IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
 
		return true;
 
	}
 

	
 
	if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) {
 
		DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
		Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 
		if (!_networking) IConsolePrint(CC_DEFAULT, "Game paused.");
 
	} else {
 
		IConsolePrint(CC_DEFAULT, "Game is already paused.");
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConUnpauseGame)
 
{
 
	if (argc == 0) {
 
		IConsolePrint(CC_HELP, "Unpause a network game. Usage: 'unpause'.");
 
		return true;
 
	}
 

	
 
	if (_game_mode == GM_MENU) {
 
		IConsolePrint(CC_ERROR, "This command is only available in-game and in the editor.");
 
		return true;
 
	}
 

	
 
	if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) {
 
		DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 0);
 
		Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 0, {});
 
		if (!_networking) IConsolePrint(CC_DEFAULT, "Game unpaused.");
 
	} else if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED) {
 
		IConsolePrint(CC_DEFAULT, "Game is in error state and cannot be unpaused via console.");
 
	} else if (_pause_mode != PM_UNPAUSED) {
 
		IConsolePrint(CC_DEFAULT, "Game cannot be unpaused manually; disable pause_on_join/min_active_clients.");
 
	} else {
 
		IConsolePrint(CC_DEFAULT, "Game is already unpaused.");
 
	}
 

	
 
	return true;
 
}
 

	
 
@@ -854,25 +856,25 @@ DEF_CONSOLE_CMD(ConResetCompany)
 

	
 
	if (NetworkCompanyHasClients(index)) {
 
		IConsolePrint(CC_ERROR, "Cannot remove company: a client is connected to that company.");
 
		return false;
 
	}
 
	const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
 
	if (ci->client_playas == index) {
 
		IConsolePrint(CC_ERROR, "Cannot remove company: the server is connected to that company.");
 
		return true;
 
	}
 

	
 
	/* It is safe to remove this company */
 
	DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0);
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, {});
 
	IConsolePrint(CC_DEFAULT, "Company deleted.");
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNetworkClients)
 
{
 
	if (argc == 0) {
 
		IConsolePrint(CC_HELP, "Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'.");
 
		return true;
 
	}
 

	
 
@@ -1211,25 +1213,25 @@ DEF_CONSOLE_CMD(ConStartAI)
 
		}
 

	
 
		if (!config->HasScript()) {
 
			IConsolePrint(CC_ERROR, "Failed to load the specified AI.");
 
			return true;
 
		}
 
		if (argc == 3) {
 
			config->StringToSettings(argv[2]);
 
		}
 
	}
 

	
 
	/* Start a new AI company */
 
	DoCommandP(CMD_COMPANY_CTRL, 0, CCA_NEW_AI | INVALID_COMPANY << 16, 0);
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, {});
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConReloadAI)
 
{
 
	if (argc != 2) {
 
		IConsolePrint(CC_HELP, "Reload an AI. Usage: 'reload_ai <company-id>'.");
 
		IConsolePrint(CC_HELP, "Reload the AI with the given company id. For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
 
		return true;
 
	}
 

	
 
@@ -1247,26 +1249,26 @@ DEF_CONSOLE_CMD(ConReloadAI)
 
	if (!Company::IsValidID(company_id)) {
 
		IConsolePrint(CC_ERROR, "Unknown company. Company range is between 1 and {}.", MAX_COMPANIES);
 
		return true;
 
	}
 

	
 
	/* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
 
	if (Company::IsHumanID(company_id) || company_id == _local_company) {
 
		IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
 
		return true;
 
	}
 

	
 
	/* First kill the company of the AI, then start a new one. This should start the current AI again */
 
	DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0);
 
	DoCommandP(CMD_COMPANY_CTRL, 0, CCA_NEW_AI | company_id << 16, 0);
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW_AI | company_id << 16, 0, {});
 
	IConsolePrint(CC_DEFAULT, "AI reloaded.");
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConStopAI)
 
{
 
	if (argc != 2) {
 
		IConsolePrint(CC_HELP, "Stop an AI. Usage: 'stop_ai <company-id>'.");
 
		IConsolePrint(CC_HELP, "Stop the AI with the given company id. For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc.");
 
		return true;
 
	}
 
@@ -1285,25 +1287,25 @@ DEF_CONSOLE_CMD(ConStopAI)
 
	if (!Company::IsValidID(company_id)) {
 
		IConsolePrint(CC_ERROR, "Unknown company. Company range is between 1 and {}.", MAX_COMPANIES);
 
		return true;
 
	}
 

	
 
	/* In singleplayer mode the player can be in an AI company, after cheating or loading network save with an AI in first slot. */
 
	if (Company::IsHumanID(company_id) || company_id == _local_company) {
 
		IConsolePrint(CC_ERROR, "Company is not controlled by an AI.");
 
		return true;
 
	}
 

	
 
	/* Now kill the company of the AI. */
 
	DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0);
 
	Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, {});
 
	IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConRescanAI)
 
{
 
	if (argc == 0) {
 
		IConsolePrint(CC_HELP, "Rescan the AI dir for scripts. Usage: 'rescan_ai'.");
 
		return true;
 
	}
 

	
src/depot_gui.cpp
Show inline comments
 
@@ -17,24 +17,27 @@
 
#include "viewport_func.h"
 
#include "command_func.h"
 
#include "depot_base.h"
 
#include "spritecache.h"
 
#include "strings_func.h"
 
#include "vehicle_func.h"
 
#include "company_func.h"
 
#include "tilehighlight_func.h"
 
#include "window_gui.h"
 
#include "vehiclelist.h"
 
#include "order_backup.h"
 
#include "zoom_func.h"
 
#include "depot_cmd.h"
 
#include "train_cmd.h"
 
#include "vehicle_cmd.h"
 

	
 
#include "widgets/depot_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/*
 
 * Since all depot window sizes aren't the same, we need to modify sizes a little.
 
 * It's done with the following arrays of widget indexes. Each of them tells if a widget side should be moved and in what direction.
 
 * How long they should be moved and for what window types are controlled in ShowDepotWindow()
 
 */
 
@@ -133,25 +136,25 @@ static void TrainDepotMoveVehicle(const 
 

	
 
	if (v == wagon) return;
 

	
 
	if (wagon == nullptr) {
 
		if (head != nullptr) wagon = head->Last();
 
	} else {
 
		wagon = wagon->Previous();
 
		if (wagon == nullptr) return;
 
	}
 

	
 
	if (wagon == v) return;
 

	
 
	DoCommandP(CMD_MOVE_RAIL_VEHICLE, STR_ERROR_CAN_T_MOVE_VEHICLE, v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == nullptr ? INVALID_VEHICLE : wagon->index);
 
	Command<CMD_MOVE_RAIL_VEHICLE>::Post(STR_ERROR_CAN_T_MOVE_VEHICLE, v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == nullptr ? INVALID_VEHICLE : wagon->index, {});
 
}
 

	
 
static VehicleCellSize _base_block_sizes_depot[VEH_COMPANY_END];    ///< Cell size for vehicle images in the depot view.
 
static VehicleCellSize _base_block_sizes_purchase[VEH_COMPANY_END]; ///< Cell size for vehicle images in the purchase list.
 
static uint _consistent_train_width;                                ///< Whether trains of all lengths are consistently scaled. Either TRAININFO_DEFAULT_VEHICLE_WIDTH, VEHICLEINFO_FULL_VEHICLE_WIDTH, or 0.
 

	
 
/**
 
 * Get the GUI cell size for a vehicle image.
 
 * @param type Vehicle type to get the size for.
 
 * @param image_type Image type to get size for.
 
 * @pre image_type == EIT_IN_DEPOT || image_type == EIT_PURCHASE
 
 * @return Cell dimensions for the vehicle and image type.
 
@@ -794,59 +797,59 @@ struct DepotWindow : Window {
 
				}
 
				break;
 

	
 
			case WID_D_RENAME: // Rename button
 
				SetDParam(0, this->type);
 
				SetDParam(1, Depot::GetByTile((TileIndex)this->window_number)->index);
 
				ShowQueryString(STR_DEPOT_NAME, STR_DEPOT_RENAME_DEPOT_CAPTION, MAX_LENGTH_DEPOT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
 
				break;
 

	
 
			case WID_D_STOP_ALL:
 
			case WID_D_START_ALL: {
 
				VehicleListIdentifier vli(VL_DEPOT_LIST, this->type, this->owner);
 
				DoCommandP(CMD_MASS_START_STOP, this->window_number, (widget == WID_D_START_ALL ? (1 << 0) : 0), vli.Pack());
 
				Command<CMD_MASS_START_STOP>::Post(this->window_number, (widget == WID_D_START_ALL ? (1 << 0) : 0), vli.Pack(), {});
 
				break;
 
			}
 

	
 
			case WID_D_SELL_ALL:
 
				/* Only open the confirmation window if there are anything to sell */
 
				if (this->vehicle_list.size() != 0 || this->wagon_list.size() != 0) {
 
					SetDParam(0, this->type);
 
					SetDParam(1, this->GetDepotIndex());
 
					ShowQuery(
 
						STR_DEPOT_CAPTION,
 
						STR_DEPOT_SELL_CONFIRMATION_TEXT,
 
						this,
 
						DepotSellAllConfirmationCallback
 
					);
 
				}
 
				break;
 

	
 
			case WID_D_VEHICLE_LIST:
 
				ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
 
				break;
 

	
 
			case WID_D_AUTOREPLACE:
 
				DoCommandP(CMD_DEPOT_MASS_AUTOREPLACE, this->window_number, this->type, 0);
 
				Command<CMD_DEPOT_MASS_AUTOREPLACE>::Post(this->window_number, this->type, 0, {});
 
				break;
 

	
 
		}
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		/* Do depot renaming */
 
		DoCommandP(CMD_RENAME_DEPOT, STR_ERROR_CAN_T_RENAME_DEPOT, 0, this->GetDepotIndex(), 0, str);
 
		Command<CMD_RENAME_DEPOT>::Post(STR_ERROR_CAN_T_RENAME_DEPOT, 0, this->GetDepotIndex(), 0, str);
 
	}
 

	
 
	bool OnRightClick(Point pt, int widget) override
 
	{
 
		if (widget != WID_D_MATRIX) return false;
 

	
 
		GetDepotVehiclePtData gdvp = { nullptr, nullptr };
 
		const Vehicle *v = nullptr;
 
		NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_D_MATRIX);
 
		DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp);
 

	
 
		if (this->type == VEH_TRAIN) v = gdvp.wagon;
 
@@ -896,28 +899,28 @@ struct DepotWindow : Window {
 
		return true;
 
	}
 

	
 
	/**
 
	 * Clones a vehicle
 
	 * @param v the original vehicle to clone
 
	 * @return Always true.
 
	 */
 
	bool OnVehicleSelect(const Vehicle *v) override
 
	{
 
		if (_ctrl_pressed) {
 
			/* Share-clone, do not open new viewport, and keep tool active */
 
			DoCommandP(CMD_CLONE_VEHICLE, STR_ERROR_CAN_T_BUY_TRAIN + v->type, this->window_number, v->index, 1);
 
			Command<CMD_CLONE_VEHICLE>::Post(STR_ERROR_CAN_T_BUY_TRAIN + v->type, this->window_number, v->index, 1, {});
 
		} else {
 
			/* Copy-clone, open viewport for new vehicle, and deselect the tool (assume player wants to changs things on new vehicle) */
 
			if (DoCommandP(CMD_CLONE_VEHICLE, STR_ERROR_CAN_T_BUY_TRAIN + v->type, CcCloneVehicle, this->window_number, v->index, 0)) {
 
			/* Copy-clone, open viewport for new vehicle, and deselect the tool (assume player wants to change things on new vehicle) */
 
			if (Command<CMD_CLONE_VEHICLE>::Post(STR_ERROR_CAN_T_BUY_TRAIN + v->type, CcCloneVehicle, this->window_number, v->index, 0, {})) {
 
				ResetObjectToPlace();
 
			}
 
		}
 

	
 
		return true;
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		/* abort clone */
 
		this->RaiseWidget(WID_D_CLONE);
 
		this->SetWidgetDirty(WID_D_CLONE);
 
@@ -993,50 +996,50 @@ struct DepotWindow : Window {
 
				const Vehicle *v = nullptr;
 
				VehicleID sel = this->sel;
 

	
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 

	
 
				NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_D_MATRIX);
 
				if (this->type == VEH_TRAIN) {
 
					GetDepotVehiclePtData gdvp = { nullptr, nullptr };
 

	
 
					if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) {
 
						if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && _ctrl_pressed) {
 
							DoCommandP(CMD_REVERSE_TRAIN_DIRECTION, STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true);
 
							Command<CMD_REVERSE_TRAIN_DIRECTION>::Post(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true, {});
 
						} else if (gdvp.wagon == nullptr || gdvp.wagon->index != sel) {
 
							this->vehicle_over = INVALID_VEHICLE;
 
							TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
 
						} else if (gdvp.head != nullptr && gdvp.head->IsFrontEngine()) {
 
							ShowVehicleViewWindow(gdvp.head);
 
						}
 
					}
 
				} else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) {
 
					ShowVehicleViewWindow(v);
 
				}
 
				break;
 
			}
 

	
 
			case WID_D_SELL: case WID_D_SELL_CHAIN: {
 
				if (this->IsWidgetDisabled(widget)) return;
 
				if (this->sel == INVALID_VEHICLE) return;
 

	
 
				this->HandleButtonClick(widget);
 

	
 
				const Vehicle *v = Vehicle::Get(this->sel);
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 

	
 
				int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
 
				DoCommandP(CMD_SELL_VEHICLE, GetCmdSellVehMsg(v->type), v->tile, v->index | sell_cmd << 20 | MAKE_ORDER_BACKUP_FLAG, 0);
 
				Command<CMD_SELL_VEHICLE>::Post(GetCmdSellVehMsg(v->type), v->tile, v->index | sell_cmd << 20 | MAKE_ORDER_BACKUP_FLAG, 0, {});
 
				break;
 
			}
 

	
 
			default:
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 
				break;
 
		}
 
		this->hovered_widget = -1;
 
		_cursor.vehchain = false;
 
	}
 

	
 
@@ -1082,25 +1085,25 @@ struct DepotWindow : Window {
 
	inline uint16 GetDepotIndex() const
 
	{
 
		return (this->type == VEH_AIRCRAFT) ? ::GetStationIndex(this->window_number) : ::GetDepotIndex(this->window_number);
 
	}
 
};
 

	
 
static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
 
{
 
	if (confirmed) {
 
		DepotWindow *w = (DepotWindow*)win;
 
		TileIndex tile = w->window_number;
 
		byte vehtype = w->type;
 
		DoCommandP(CMD_DEPOT_SELL_ALL_VEHICLES, tile, vehtype, 0);
 
		Command<CMD_DEPOT_SELL_ALL_VEHICLES>::Post(tile, vehtype, 0, {});
 
	}
 
}
 

	
 
/**
 
 * Opens a depot window
 
 * @param tile The tile where the depot/hangar is located
 
 * @param type The type of vehicles in the depot
 
 */
 
void ShowDepotWindow(TileIndex tile, VehicleType type)
 
{
 
	if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != nullptr) return;
 

	
src/dock_gui.cpp
Show inline comments
 
@@ -19,24 +19,26 @@
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "company_func.h"
 
#include "slope_func.h"
 
#include "tilehighlight_func.h"
 
#include "company_base.h"
 
#include "hotkeys.h"
 
#include "gui.h"
 
#include "zoom_func.h"
 
#include "tunnelbridge_cmd.h"
 
#include "dock_cmd.h"
 
#include "station_cmd.h"
 
#include "water_cmd.h"
 
#include "waypoint_cmd.h"
 

	
 
#include "widgets/dock_widget.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
static void ShowBuildDockStationPicker(Window *parent);
 
static void ShowBuildDocksDepotPicker(Window *parent);
 

	
 
static Axis _ship_depot_direction;
 
@@ -185,91 +187,91 @@ struct BuildDocksToolbarWindow : Window 
 
		}
 
		this->last_clicked_widget = (DockToolbarWidgets)widget;
 
	}
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		switch (this->last_clicked_widget) {
 
			case WID_DT_CANAL: // Build canal button
 
				VpStartPlaceSizing(tile, (_game_mode == GM_EDITOR) ? VPM_X_AND_Y : VPM_X_OR_Y, DDSP_CREATE_WATER);
 
				break;
 

	
 
			case WID_DT_LOCK: // Build lock button
 
				DoCommandP(CMD_BUILD_LOCK, STR_ERROR_CAN_T_BUILD_LOCKS, CcBuildDocks, tile, 0, 0);
 
				Command<CMD_BUILD_LOCK>::Post(STR_ERROR_CAN_T_BUILD_LOCKS, CcBuildDocks, tile, 0, 0, {});
 
				break;
 

	
 
			case WID_DT_DEMOLISH: // Demolish aka dynamite button
 
				PlaceProc_DemolishArea(tile);
 
				break;
 

	
 
			case WID_DT_DEPOT: // Build depot button
 
				DoCommandP(CMD_BUILD_SHIP_DEPOT, STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, tile, _ship_depot_direction, 0);
 
				Command<CMD_BUILD_SHIP_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT, CcBuildDocks, tile, _ship_depot_direction, 0, {});
 
				break;
 

	
 
			case WID_DT_STATION: { // Build station button
 
				/* Determine the watery part of the dock. */
 
				DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
 
				TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile);
 

	
 
				uint32 p1 = _ctrl_pressed;
 
				uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join
 

	
 
				auto proc = [=](bool test, StationID to_join) -> bool {
 
					if (test) {
 
						return Command<CMD_BUILD_DOCK>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_DOCK>()), tile, p1, p2, {}).Succeeded();
 
					} else {
 
						uint32 p2_final = p2;
 
						if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
						return DoCommandP(CMD_BUILD_DOCK, STR_ERROR_CAN_T_BUILD_DOCK_HERE, CcBuildDocks, tile, p1, p2_final);
 
						return Command<CMD_BUILD_DOCK>::Post(STR_ERROR_CAN_T_BUILD_DOCK_HERE, CcBuildDocks, tile, p1, p2_final, {});
 
					}
 
				};
 

	
 
				ShowSelectStationIfNeeded(TileArea(tile, tile_to), proc);
 
				break;
 
			}
 

	
 
			case WID_DT_BUOY: // Build buoy button
 
				DoCommandP(CMD_BUILD_BUOY, STR_ERROR_CAN_T_POSITION_BUOY_HERE, CcBuildDocks, tile, 0, 0);
 
				Command<CMD_BUILD_BUOY>::Post(STR_ERROR_CAN_T_POSITION_BUOY_HERE, CcBuildDocks, tile, 0, 0, {});
 
				break;
 

	
 
			case WID_DT_RIVER: // Build river button (in scenario editor)
 
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_RIVER);
 
				break;
 

	
 
			case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button
 
				DoCommandP(CMD_BUILD_BRIDGE, STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER << 15);
 
				Command<CMD_BUILD_BRIDGE>::Post(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE, CcBuildBridge, tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER << 15, {});
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
 
	{
 
		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
 
	}
 

	
 
	void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
 
	{
 
		if (pt.x != -1) {
 
			switch (select_proc) {
 
				case DDSP_DEMOLISH_AREA:
 
					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 
					break;
 
				case DDSP_CREATE_WATER:
 
					DoCommandP(CMD_BUILD_CANAL, STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL);
 
					Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, {});
 
					break;
 
				case DDSP_CREATE_RIVER:
 
					DoCommandP(CMD_BUILD_CANAL, STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER | (_ctrl_pressed ? 1 << 2 : 0));
 
					Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER | (_ctrl_pressed ? 1 << 2 : 0), {});
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		if (_game_mode != GM_EDITOR && this->IsWidgetLowered(WID_DT_STATION)) SetViewportCatchmentStation(nullptr, true);
 

	
 
		this->RaiseButtons();
src/economy.cpp
Show inline comments
 
@@ -39,24 +39,25 @@
 
#include "station_base.h"
 
#include "waypoint_base.h"
 
#include "economy_base.h"
 
#include "core/pool_func.hpp"
 
#include "core/backup_type.hpp"
 
#include "cargo_type.h"
 
#include "water.h"
 
#include "game/game.hpp"
 
#include "cargomonitor.h"
 
#include "goal_base.h"
 
#include "story_base.h"
 
#include "linkgraph/refresh.h"
 
#include "company_cmd.h"
 
#include "economy_cmd.h"
 
#include "vehicle_cmd.h"
 

	
 
#include "table/strings.h"
 
#include "table/pricebase.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
/* Initialize the cargo payment-pool */
 
CargoPaymentPool _cargo_payment_pool("CargoPayment");
 
INSTANTIATE_POOL_METHODS(CargoPayment)
 
@@ -620,25 +621,25 @@ static void CompanyCheckBankrupt(Company
 
			}
 

	
 
			/* Actually remove the company, but not when we're a network client.
 
			 * In case of network clients we will be getting a command from the
 
			 * server. It is done in this way as we are called from the
 
			 * StateGameLoop which can't change the current company, and thus
 
			 * updating the local company triggers an assert later on. In the
 
			 * case of a network game the command will be processed at a time
 
			 * that changing the current company is okay. In case of single
 
			 * player we are sure (the above check) that we are not the local
 
			 * company and thus we won't be moved. */
 
			if (!_networking || _network_server) {
 
				DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0);
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, {});
 
				return;
 
			}
 
			break;
 
		}
 
	}
 

	
 
	if (CeilDiv(c->months_of_bankruptcy, 3) != CeilDiv(c->months_of_bankruptcy - 1, 3)) CompanyAdminUpdate(c);
 
}
 

	
 
/**
 
 * Update the finances of all companies.
 
 * Pay for the stations, update the history graph, update ratings and company values, and deal with bankruptcy.
src/engine_gui.cpp
Show inline comments
 
@@ -14,24 +14,25 @@
 
#include "strings_func.h"
 
#include "engine_gui.h"
 
#include "articulated_vehicles.h"
 
#include "vehicle_func.h"
 
#include "company_func.h"
 
#include "rail.h"
 
#include "road.h"
 
#include "settings_type.h"
 
#include "train.h"
 
#include "roadveh.h"
 
#include "ship.h"
 
#include "aircraft.h"
 
#include "engine_cmd.h"
 

	
 
#include "widgets/engine_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Return the category of an engine.
 
 * @param engine Engine to examine.
 
 * @return String describing the category ("road veh", "train". "airplane", or "ship") of the engine.
 
 */
 
@@ -116,25 +117,25 @@ struct EnginePreviewWindow : Window {
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		DrawVehicleEngine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, this->width >> 1, y + this->vehicle_space / 2, engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
 

	
 
		y += this->vehicle_space;
 
		DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_EP_YES:
 
				DoCommandP(CMD_WANT_ENGINE_PREVIEW, 0, this->window_number, 0);
 
				Command<CMD_WANT_ENGINE_PREVIEW>::Post(0, this->window_number, 0, {});
 
				FALLTHROUGH;
 
			case WID_EP_NO:
 
				if (!_shift_pressed) this->Close();
 
				break;
 
		}
 
	}
 

	
 
	void OnInvalidateData(int data = 0, bool gui_scope = true) override
 
	{
 
		if (!gui_scope) return;
 

	
 
		EngineID engine = this->window_number;
src/fios_gui.cpp
Show inline comments
 
@@ -18,24 +18,25 @@
 
#include "strings_func.h"
 
#include "fileio_func.h"
 
#include "fios.h"
 
#include "window_func.h"
 
#include "tilehighlight_func.h"
 
#include "querystring_gui.h"
 
#include "engine_func.h"
 
#include "landscape_type.h"
 
#include "date_func.h"
 
#include "core/geometry_func.hpp"
 
#include "gamelog.h"
 
#include "stringfilter_type.h"
 
#include "misc_cmd.h"
 

	
 
#include "widgets/fios_widget.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
LoadCheckData _load_check_data;    ///< Data loaded from save during SL_LOAD_CHECK.
 

	
 
static bool _fios_path_changed;
 
static bool _savegame_sort_dirty;
 
@@ -349,25 +350,25 @@ public:
 
		this->GetWidget<NWidgetCore>(WID_SL_CAPTION)->widget_data = caption_string;
 

	
 
		this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR);
 
		this->FinishInitNested(0);
 

	
 
		this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST);
 
		this->querystrings[WID_SL_FILTER] = &this->filter_editbox;
 
		this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
 

	
 
		/* pause is only used in single-player, non-editor mode, non-menu mode. It
 
		 * will be unpaused in the WE_DESTROY event handler. */
 
		if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) {
 
			DoCommandP(CMD_PAUSE, 0, PM_PAUSED_SAVELOAD, 1);
 
			Command<CMD_PAUSE>::Post(0, PM_PAUSED_SAVELOAD, 1, {});
 
		}
 
		SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
 

	
 
		this->OnInvalidateData(SLIWD_RESCAN_FILES);
 

	
 
		ResetObjectToPlace();
 

	
 
		/* Select the initial directory. */
 
		o_dir.type = FIOS_TYPE_DIRECT;
 
		std::string dir;
 
		switch (this->abstract_filetype) {
 
			case FT_SAVEGAME:
 
@@ -393,25 +394,25 @@ public:
 
				this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
 
				break;
 

	
 
			default:
 
				this->SetFocusedWidget(WID_SL_FILTER);
 
		}
 
	}
 

	
 
	void Close() override
 
	{
 
		/* pause is only used in single-player, non-editor mode, non menu mode */
 
		if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
 
			DoCommandP(CMD_PAUSE, 0, PM_PAUSED_SAVELOAD, 0);
 
			Command<CMD_PAUSE>::Post(0, PM_PAUSED_SAVELOAD, 0, {});
 
		}
 
		this->Window::Close();
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_SL_SORT_BYNAME:
 
			case WID_SL_SORT_BYDATE:
 
				if (((_savegame_sort_order & SORT_BY_NAME) != 0) == (widget == WID_SL_SORT_BYNAME)) {
 
					this->DrawSortButtonState(widget, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
 
				}
src/goal_gui.cpp
Show inline comments
 
@@ -14,24 +14,25 @@
 
#include "strings_func.h"
 
#include "date_func.h"
 
#include "viewport_func.h"
 
#include "gui.h"
 
#include "goal_base.h"
 
#include "core/geometry_func.hpp"
 
#include "company_func.h"
 
#include "company_base.h"
 
#include "company_gui.h"
 
#include "story_base.h"
 
#include "command_func.h"
 
#include "string_func.h"
 
#include "goal_cmd.h"
 

	
 
#include "widgets/goal_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/** Goal list columns. */
 
enum GoalColumn {
 
	GC_GOAL = 0, ///< Goal text column.
 
	GC_PROGRESS, ///< Goal progress column.
 
};
 
@@ -373,35 +374,35 @@ struct GoalQuestionWindow : public Windo
 
				break;
 

	
 
			case WID_GQ_BUTTON_3:
 
				SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[2]);
 
				break;
 
		}
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_GQ_BUTTON_1:
 
				DoCommandP(CMD_GOAL_QUESTION_ANSWER, 0, this->window_number, this->button[0]);
 
				Command<CMD_GOAL_QUESTION_ANSWER>::Post(0, this->window_number, this->button[0], {});
 
				this->Close();
 
				break;
 

	
 
			case WID_GQ_BUTTON_2:
 
				DoCommandP(CMD_GOAL_QUESTION_ANSWER, 0, this->window_number, this->button[1]);
 
				Command<CMD_GOAL_QUESTION_ANSWER>::Post(0, this->window_number, this->button[1], {});
 
				this->Close();
 
				break;
 

	
 
			case WID_GQ_BUTTON_3:
 
				DoCommandP(CMD_GOAL_QUESTION_ANSWER, 0, this->window_number, this->button[2]);
 
				Command<CMD_GOAL_QUESTION_ANSWER>::Post(0, this->window_number, this->button[2], {});
 
				this->Close();
 
				break;
 
		}
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		if (widget != WID_GQ_QUESTION) return;
 

	
 
		SetDParamStr(0, this->question);
 
		size->height = GetStringHeight(STR_JUST_RAW_STRING, size->width) + WD_PAR_VSEP_WIDE;
 
	}
src/group_gui.cpp
Show inline comments
 
@@ -17,24 +17,25 @@
 
#include "window_func.h"
 
#include "vehicle_func.h"
 
#include "autoreplace_gui.h"
 
#include "company_func.h"
 
#include "widgets/dropdown_func.h"
 
#include "tilehighlight_func.h"
 
#include "vehicle_gui_base.h"
 
#include "core/geometry_func.hpp"
 
#include "company_base.h"
 
#include "company_gui.h"
 
#include "gui.h"
 
#include "group_cmd.h"
 
#include "vehicle_cmd.h"
 

	
 
#include "widgets/group_widget.h"
 

	
 
#include "table/sprites.h"
 

	
 
#include "safeguards.h"
 

	
 
static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels
 

	
 
typedef GUIList<const Group*> GUIGroupList;
 

	
 
static const NWidgetPart _nested_group_widgets[] = {
 
@@ -632,25 +633,25 @@ public:
 
				}
 

	
 
				this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
 
				break;
 
		}
 
	}
 

	
 
	static void DeleteGroupCallback(Window *win, bool confirmed)
 
	{
 
		if (confirmed) {
 
			VehicleGroupWindow *w = (VehicleGroupWindow*)win;
 
			w->vli.index = ALL_GROUP;
 
			DoCommandP(CMD_DELETE_GROUP, STR_ERROR_GROUP_CAN_T_DELETE, (TileIndex)0, w->group_confirm, 0);
 
			Command<CMD_DELETE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_DELETE, 0, w->group_confirm, 0, {});
 
		}
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
 
				this->vehgroups.ToggleSortOrder();
 
				this->SetDirty();
 
				break;
 

	
 
			case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
 
@@ -763,25 +764,25 @@ public:
 
						SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
 
						SetMouseCursorVehicle(v, EIT_IN_LIST);
 
						_cursor.vehchain = true;
 

	
 
						this->SetDirty();
 
					}
 
				}
 

	
 
				break;
 
			}
 

	
 
			case WID_GL_CREATE_GROUP: { // Create a new group
 
				DoCommandP(CMD_CREATE_GROUP, STR_ERROR_GROUP_CAN_T_CREATE, CcCreateGroup, 0, this->vli.vtype, this->vli.index);
 
				Command<CMD_CREATE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_CREATE, CcCreateGroup, 0, this->vli.vtype, this->vli.index, {});
 
				break;
 
			}
 

	
 
			case WID_GL_DELETE_GROUP: { // Delete the selected group
 
				this->group_confirm = this->vli.index;
 
				ShowQuery(STR_QUERY_GROUP_DELETE_CAPTION, STR_GROUP_DELETE_QUERY_TEXT, this, DeleteGroupCallback);
 
				break;
 
			}
 

	
 
			case WID_GL_RENAME_GROUP: // Rename the selected roup
 
				this->ShowRenameGroupWindow(this->vli.index, false);
 
				break;
 
@@ -792,92 +793,92 @@ public:
 

	
 
			case WID_GL_AVAILABLE_VEHICLES:
 
				ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
 
				break;
 

	
 
			case WID_GL_MANAGE_VEHICLES_DROPDOWN: {
 
				ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)), 0, WID_GL_MANAGE_VEHICLES_DROPDOWN);
 
				break;
 
			}
 

	
 
			case WID_GL_START_ALL:
 
			case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
 
				DoCommandP(CMD_MASS_START_STOP, 0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack());
 
				Command<CMD_MASS_START_STOP>::Post(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack(), {});
 
				break;
 
			}
 

	
 
			case WID_GL_REPLACE_PROTECTION: {
 
				const Group *g = Group::GetIfValid(this->vli.index);
 
				if (g != nullptr) {
 
					DoCommandP(CMD_SET_GROUP_FLAG, 0, this->vli.index | (GroupFlags::GF_REPLACE_PROTECTION << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION) ? 0 : 1) | (_ctrl_pressed << 1));
 
					Command<CMD_SET_GROUP_FLAG>::Post(0, this->vli.index | (GroupFlags::GF_REPLACE_PROTECTION << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION) ? 0 : 1) | (_ctrl_pressed << 1), {});
 
				}
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnDragDrop_Group(Point pt, int widget)
 
	{
 
		const Group *g = Group::Get(this->group_sel);
 

	
 
		switch (widget) {
 
			case WID_GL_ALL_VEHICLES: // All vehicles
 
			case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
 
				if (g->parent != INVALID_GROUP) {
 
					DoCommandP(CMD_ALTER_GROUP, STR_ERROR_GROUP_CAN_T_SET_PARENT, 0, this->group_sel | (1 << 16), INVALID_GROUP);
 
					Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, 0, this->group_sel | (1 << 16), INVALID_GROUP, {});
 
				}
 

	
 
				this->group_sel = INVALID_GROUP;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 
				break;
 

	
 
			case WID_GL_LIST_GROUP: { // Matrix group
 
				uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
 
				GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index;
 

	
 
				if (this->group_sel != new_g && g->parent != new_g) {
 
					DoCommandP(CMD_ALTER_GROUP, STR_ERROR_GROUP_CAN_T_SET_PARENT, 0, this->group_sel | (1 << 16), new_g);
 
					Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, 0, this->group_sel | (1 << 16), new_g, {});
 
				}
 

	
 
				this->group_sel = INVALID_GROUP;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnDragDrop_Vehicle(Point pt, int widget)
 
	{
 
		switch (widget) {
 
			case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
 
				DoCommandP(CMD_ADD_VEHICLE_GROUP, STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, 0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0));
 
				Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, 0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), {});
 

	
 
				this->vehicle_sel = INVALID_VEHICLE;
 
				this->group_over = INVALID_GROUP;
 

	
 
				this->SetDirty();
 
				break;
 

	
 
			case WID_GL_LIST_GROUP: { // Matrix group
 
				const VehicleID vindex = this->vehicle_sel;
 
				this->vehicle_sel = INVALID_VEHICLE;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 

	
 
				uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
 
				GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
 

	
 
				DoCommandP(CMD_ADD_VEHICLE_GROUP, STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, 0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0));
 
				Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, 0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), {});
 
				break;
 
			}
 

	
 
			case WID_GL_LIST_VEHICLE: { // Matrix vehicle
 
				const VehicleID vindex = this->vehicle_sel;
 
				this->vehicle_sel = INVALID_VEHICLE;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 

	
 
				uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
 
				if (id_v >= this->vehgroups.size()) return; // click out of list bound
 

	
 
@@ -914,25 +915,25 @@ public:
 
	}
 

	
 
	void OnDragDrop(Point pt, int widget) override
 
	{
 
		if (this->vehicle_sel != INVALID_VEHICLE) OnDragDrop_Vehicle(pt, widget);
 
		if (this->group_sel != INVALID_GROUP) OnDragDrop_Group(pt, widget);
 

	
 
		_cursor.vehchain = false;
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str != nullptr) DoCommandP(CMD_ALTER_GROUP, STR_ERROR_GROUP_CAN_T_RENAME, 0, this->group_rename, 0, str);
 
		if (str != nullptr) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, 0, this->group_rename, 0, str);
 
		this->group_rename = INVALID_GROUP;
 
	}
 

	
 
	void OnResize() override
 
	{
 
		this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
 
		this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE);
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
@@ -944,37 +945,37 @@ public:
 
				this->vehgroups.SetSortType(index);
 
				break;
 

	
 
			case WID_GL_MANAGE_VEHICLES_DROPDOWN:
 
				assert(this->vehicles.size() != 0);
 

	
 
				switch (index) {
 
					case ADI_REPLACE: // Replace window
 
						ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype);
 
						break;
 
					case ADI_SERVICE: // Send for servicing
 
					case ADI_DEPOT: { // Send to Depots
 
						DoCommandP(CMD_SEND_VEHICLE_TO_DEPOT, GetCmdSendToDepotMsg(this->vli.vtype), 0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack());
 
						Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), 0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack(), {});
 
						break;
 
					}
 

	
 
					case ADI_ADD_SHARED: // Add shared Vehicles
 
						assert(Group::IsValidID(this->vli.index));
 

	
 
						DoCommandP(CMD_ADD_SHARED_VEHICLE_GROUP, STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE, 0, this->vli.index, this->vli.vtype);
 
						Command<CMD_ADD_SHARED_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE, 0, this->vli.index, this->vli.vtype, {});
 
						break;
 
					case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group
 
						assert(Group::IsValidID(this->vli.index));
 

	
 
						DoCommandP(CMD_REMOVE_ALL_VEHICLES_GROUP, STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES, (TileIndex)0, this->vli.index, 0);
 
						Command<CMD_REMOVE_ALL_VEHICLES_GROUP>::Post(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES, 0, this->vli.index, 0, {});
 
						break;
 
					default: NOT_REACHED();
 
				}
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 

	
 
		this->SetDirty();
 
	}
 

	
 
	void OnGameTick() override
src/highscore_gui.cpp
Show inline comments
 
@@ -12,24 +12,25 @@
 
#include "table/strings.h"
 
#include "gfx_func.h"
 
#include "table/sprites.h"
 
#include "window_gui.h"
 
#include "window_func.h"
 
#include "network/network.h"
 
#include "command_func.h"
 
#include "company_func.h"
 
#include "company_base.h"
 
#include "strings_func.h"
 
#include "hotkeys.h"
 
#include "zoom_func.h"
 
#include "misc_cmd.h"
 

	
 
#include "widgets/highscore_widget.h"
 

	
 
#include "safeguards.h"
 

	
 
struct EndGameHighScoreBaseWindow : Window {
 
	uint32 background_img;
 
	int8 rank;
 

	
 
	EndGameHighScoreBaseWindow(WindowDesc *desc) : Window(desc)
 
	{
 
		this->InitNested();
 
@@ -87,25 +88,25 @@ struct EndGameHighScoreBaseWindow : Wind
 
				 * the background to open. Especially the ones that do
 
				 * locate themselves based on the status-/toolbars. */
 
				return ES_HANDLED;
 
		}
 
	}
 
};
 

	
 
/** End game window shown at the end of the game */
 
struct EndGameWindow : EndGameHighScoreBaseWindow {
 
	EndGameWindow(WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
 
	{
 
		/* Pause in single-player to have a look at the highscore at your own leisure */
 
		if (!_networking) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
		if (!_networking) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 

	
 
		this->background_img = SPR_TYCOON_IMG1_BEGIN;
 

	
 
		if (_local_company != COMPANY_SPECTATOR) {
 
			const Company *c = Company::Get(_local_company);
 
			if (c->old_economy[0].performance_history == SCORE_MAX) {
 
				this->background_img = SPR_TYCOON_IMG2_BEGIN;
 
			}
 
		}
 

	
 
		/* In a network game show the endscores of the custom difficulty 'network' which is
 
		 * a TOP5 of that game, and not an all-time TOP5. */
 
@@ -115,25 +116,25 @@ struct EndGameWindow : EndGameHighScoreB
 
		} else {
 
			/* in singleplayer mode _local company is always valid */
 
			const Company *c = Company::Get(_local_company);
 
			this->window_number = SP_CUSTOM;
 
			this->rank = SaveHighScoreValue(c);
 
		}
 

	
 
		MarkWholeScreenDirty();
 
	}
 

	
 
	void Close() override
 
	{
 
		if (!_networking) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 0); // unpause
 
		if (!_networking) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 0, {}); // unpause
 
		ShowHighscoreTable(this->window_number, this->rank);
 
		this->EndGameHighScoreBaseWindow::Close();
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		this->SetupHighScoreEndWindow();
 
		Point pt = this->GetTopLeft(ScaleGUITrad(640), ScaleGUITrad(480));
 

	
 
		const Company *c = Company::GetIfValid(_local_company);
 
		if (c == nullptr) return;
 

	
 
@@ -150,40 +151,40 @@ struct EndGameWindow : EndGameHighScoreB
 
			DrawStringMultiLine(pt.x + ScaleGUITrad(36), pt.x + ScaleGUITrad(640), pt.y + ScaleGUITrad(140), pt.y + ScaleGUITrad(206), STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS, TC_FROMSTRING, SA_CENTER);
 
		}
 
	}
 
};
 

	
 
struct HighScoreWindow : EndGameHighScoreBaseWindow {
 
	bool game_paused_by_player; ///< True if the game was paused by the player when the highscore window was opened.
 

	
 
	HighScoreWindow(WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
 
	{
 
		/* pause game to show the chart */
 
		this->game_paused_by_player = _pause_mode == PM_PAUSED_NORMAL;
 
		if (!_networking && !this->game_paused_by_player) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
		if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 

	
 
		/* Close all always on-top windows to get a clean screen */
 
		if (_game_mode != GM_MENU) HideVitalWindows();
 

	
 
		MarkWholeScreenDirty();
 
		this->window_number = difficulty; // show highscore chart for difficulty...
 
		this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
 
		this->rank = ranking;
 
	}
 

	
 
	void Close() override
 
	{
 
		if (_game_mode != GM_MENU) ShowVitalWindows();
 

	
 
		if (!_networking && !this->game_paused_by_player) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 0); // unpause
 
		if (!_networking && !this->game_paused_by_player) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 0, {}); // unpause
 

	
 
		this->EndGameHighScoreBaseWindow::Close();
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		const HighScore *hs = _highscore_table[this->window_number];
 

	
 
		this->SetupHighScoreEndWindow();
 
		Point pt = this->GetTopLeft(ScaleGUITrad(640), ScaleGUITrad(480));
 

	
 
		SetDParam(0, _settings_game.game_creation.ending_year);
src/industry_gui.cpp
Show inline comments
 
@@ -30,24 +30,25 @@
 
#include "sortlist_type.h"
 
#include "widgets/dropdown_func.h"
 
#include "company_base.h"
 
#include "core/geometry_func.hpp"
 
#include "core/random_func.hpp"
 
#include "core/backup_type.hpp"
 
#include "genworld.h"
 
#include "smallmap_gui.h"
 
#include "widgets/dropdown_type.h"
 
#include "widgets/industry_widget.h"
 
#include "clear_map.h"
 
#include "zoom_func.h"
 
#include "industry_cmd.h"
 

	
 
#include "table/strings.h"
 

	
 
#include <bitset>
 

	
 
#include "safeguards.h"
 

	
 
bool _ignore_restrictions;
 
std::bitset<NUM_INDUSTRYTYPES> _displayed_industries; ///< Communication from the industry chain window to the smallmap window about what industries to display.
 

	
 
/** Cargo suffix type (for which window is it requested) */
 
enum CargoSuffixType {
 
@@ -670,25 +671,25 @@ public:
 
					if (this->enabled[this->selected_index] && click_count > 1) this->OnClick(pt, WID_DPI_FUND_WIDGET, 1);
 
				}
 
				break;
 
			}
 

	
 
			case WID_DPI_DISPLAY_WIDGET:
 
				if (this->selected_type != INVALID_INDUSTRYTYPE) ShowIndustryCargoesWindow(this->selected_type);
 
				break;
 

	
 
			case WID_DPI_FUND_WIDGET: {
 
				if (this->selected_type != INVALID_INDUSTRYTYPE) {
 
					if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) {
 
						DoCommandP(CMD_BUILD_INDUSTRY, STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, 0, this->selected_type, InteractiveRandom());
 
						Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, 0, this->selected_type, InteractiveRandom(), {});
 
						this->HandleButtonClick(WID_DPI_FUND_WIDGET);
 
					} else {
 
						HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT);
 
					}
 
				}
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnResize() override
 
	{
 
@@ -707,31 +708,31 @@ public:
 
		if (_game_mode == GM_EDITOR) {
 
			/* Show error if no town exists at all */
 
			if (Town::GetNumItems() == 0) {
 
				SetDParam(0, indsp->name);
 
				ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y);
 
				return;
 
			}
 

	
 
			Backup<CompanyID> cur_company(_current_company, OWNER_NONE, FILE_LINE);
 
			Backup<bool> old_generating_world(_generating_world, true, FILE_LINE);
 
			_ignore_restrictions = true;
 

	
 
			DoCommandP(CMD_BUILD_INDUSTRY, STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, (layout_index << 8) | this->selected_type, seed);
 
			Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, (layout_index << 8) | this->selected_type, seed, {});
 

	
 
			cur_company.Restore();
 
			old_generating_world.Restore();
 
			_ignore_restrictions = false;
 
		} else {
 
			success = DoCommandP(CMD_BUILD_INDUSTRY, STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, (layout_index << 8) | this->selected_type, seed);
 
			success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, (layout_index << 8) | this->selected_type, seed, {});
 
		}
 

	
 
		/* If an industry has been built, just reset the cursor and the system */
 
		if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
 
	}
 

	
 
	void OnHundredthTick() override
 
	{
 
		if (_game_mode == GM_EDITOR) return;
 
		const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
 

	
 
		if (indsp->enabled) {
src/linkgraph/linkgraphschedule.cpp
Show inline comments
 
@@ -7,24 +7,25 @@
 

	
 
/** @file linkgraphschedule.cpp Definition of link graph schedule used for cargo distribution. */
 

	
 
#include "../stdafx.h"
 
#include "linkgraphschedule.h"
 
#include "init.h"
 
#include "demands.h"
 
#include "mcf.h"
 
#include "flowmapper.h"
 
#include "../framerate_type.h"
 
#include "../command_func.h"
 
#include "../network/network.h"
 
#include "../misc_cmd.h"
 

	
 
#include "../safeguards.h"
 

	
 
/**
 
 * Static instance of LinkGraphSchedule.
 
 * Note: This instance is created on task start.
 
 *       Lazy creation on first usage results in a data race between the CDist threads.
 
 */
 
/* static */ LinkGraphSchedule LinkGraphSchedule::instance;
 

	
 
/**
 
 * Start the next job in the schedule.
 
@@ -164,33 +165,33 @@ LinkGraphSchedule::~LinkGraphSchedule()
 
/**
 
 * Pause the game if in 2 _date_fract ticks, we would do a join with the next
 
 * link graph job, but it is still running.
 
 * The check is done 2 _date_fract ticks early instead of 1, as in multiplayer
 
 * calls to DoCommandP are executed after a delay of 1 _date_fract tick.
 
 * If we previously paused, unpause if the job is now ready to be joined with.
 
 */
 
void StateGameLoop_LinkGraphPauseControl()
 
{
 
	if (_pause_mode & PM_PAUSED_LINK_GRAPH) {
 
		/* We are paused waiting on a job, check the job every tick. */
 
		if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
			DoCommandP(CMD_PAUSE, 0, PM_PAUSED_LINK_GRAPH, 0);
 
			Command<CMD_PAUSE>::Post(0, PM_PAUSED_LINK_GRAPH, 0, {});
 
		}
 
	} else if (_pause_mode == PM_UNPAUSED &&
 
			_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
 
			_date % _settings_game.linkgraph.recalc_interval == _settings_game.linkgraph.recalc_interval / 2 &&
 
			LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
		/* Perform check two _date_fract ticks before we would join, to make
 
		 * sure it also works in multiplayer. */
 
		DoCommandP(CMD_PAUSE, 0, PM_PAUSED_LINK_GRAPH, 1);
 
		Command<CMD_PAUSE>::Post(0, PM_PAUSED_LINK_GRAPH, 1, {});
 
	}
 
}
 

	
 
/**
 
 * Pause the game on load if we would do a join with the next link graph job,
 
 * but it is still running, and it would not be caught by a call to
 
 * StateGameLoop_LinkGraphPauseControl().
 
 */
 
void AfterLoad_LinkGraphPauseControl()
 
{
 
	if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
		_pause_mode |= PM_PAUSED_LINK_GRAPH;
src/main_gui.cpp
Show inline comments
 
@@ -24,24 +24,25 @@
 
#include "strings_func.h"
 
#include "zoom_func.h"
 
#include "company_base.h"
 
#include "company_func.h"
 
#include "toolbar_gui.h"
 
#include "statusbar_gui.h"
 
#include "linkgraph/linkgraph_gui.h"
 
#include "tilehighlight_func.h"
 
#include "hotkeys.h"
 
#include "guitimer_func.h"
 
#include "error.h"
 
#include "news_gui.h"
 
#include "misc_cmd.h"
 

	
 
#include "saveload/saveload.h"
 

	
 
#include "widgets/main_widget.h"
 

	
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "network/network_gui.h"
 
#include "network/network_base.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 
@@ -317,25 +318,25 @@ struct MainWindow : Window
 
			case GHK_RESET_OBJECT_TO_PLACE: ResetObjectToPlace(); break;
 
			case GHK_DELETE_WINDOWS: CloseNonVitalWindows(); break;
 
			case GHK_DELETE_NONVITAL_WINDOWS: CloseAllNonVitalWindows(); break;
 
			case GHK_DELETE_ALL_MESSAGES: DeleteAllMessages(); break;
 
			case GHK_REFRESH_SCREEN: MarkWholeScreenDirty(); break;
 

	
 
			case GHK_CRASH: // Crash the game
 
				*(volatile byte *)nullptr = 0;
 
				break;
 

	
 
			case GHK_MONEY: // Gimme money
 
				/* You can only cheat for money in singleplayer mode. */
 
				if (!_networking) DoCommandP(CMD_MONEY_CHEAT, 0, 10000000, 0);
 
				if (!_networking) Command<CMD_MONEY_CHEAT>::Post(0, 10000000, 0, {});
 
				break;
 

	
 
			case GHK_UPDATE_COORDS: // Update the coordinates of all station signs
 
				UpdateAllVirtCoords();
 
				break;
 

	
 
			case GHK_TOGGLE_TRANSPARENCY:
 
			case GHK_TOGGLE_TRANSPARENCY + 1:
 
			case GHK_TOGGLE_TRANSPARENCY + 2:
 
			case GHK_TOGGLE_TRANSPARENCY + 3:
 
			case GHK_TOGGLE_TRANSPARENCY + 4:
 
			case GHK_TOGGLE_TRANSPARENCY + 5:
src/misc_cmd.cpp
Show inline comments
 
@@ -126,25 +126,25 @@ CommandCost CmdDecreaseLoan(DoCommandFla
 
	return CommandCost();
 
}
 

	
 
/**
 
 * In case of an unsafe unpause, we want the
 
 * user to confirm that it might crash.
 
 * @param w         unused
 
 * @param confirmed whether the user confirmed their action
 
 */
 
static void AskUnsafeUnpauseCallback(Window *w, bool confirmed)
 
{
 
	if (confirmed) {
 
		DoCommandP(CMD_PAUSE, 0, PM_PAUSED_ERROR, 0);
 
		Command<CMD_PAUSE>::Post(0, PM_PAUSED_ERROR, 0, {});
 
	}
 
}
 

	
 
/**
 
 * Pause/Unpause the game (server-only).
 
 * Set or unset a bit in the pause mode. If pause mode is zero the game is
 
 * unpaused. A bitset is used instead of a boolean value/counter to have
 
 * more control over the game when saving/loading, etc.
 
 * @param flags operation to perform
 
 * @param tile unused
 
 * @param p1 the pause mode to change
 
 * @param p2 1 pauses, 0 unpauses this mode
src/network/network.cpp
Show inline comments
 
@@ -386,25 +386,25 @@ void NetworkHandlePauseChange(PauseMode 
 
/**
 
 * Helper function for the pause checkers. If pause is true and the
 
 * current pause mode isn't set the game will be paused, if it it false
 
 * and the pause mode is set the game will be unpaused. In the other
 
 * cases nothing happens to the pause state.
 
 * @param pause whether we'd like to pause
 
 * @param pm the mode which we would like to pause with
 
 */
 
static void CheckPauseHelper(bool pause, PauseMode pm)
 
{
 
	if (pause == ((_pause_mode & pm) != PM_UNPAUSED)) return;
 

	
 
	DoCommandP(CMD_PAUSE, 0, pm, pause ? 1 : 0);
 
	Command<CMD_PAUSE>::Post(0, pm, pause ? 1 : 0, {});
 
}
 

	
 
/**
 
 * Counts the number of active clients connected.
 
 * It has to be in STATUS_ACTIVE and not a spectator
 
 * @return number of active clients
 
 */
 
static uint NetworkCountActiveClients()
 
{
 
	uint count = 0;
 

	
 
	for (const NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
src/network/network_command.cpp
Show inline comments
 
@@ -442,14 +442,14 @@ static inline void SanitizeStringsHelper
 
template <Commands Tcmd>
 
CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data)
 
{
 
	auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(data);
 
	SanitizeStringsHelper(CommandTraits<Tcmd>::flags, args, std::make_index_sequence<std::tuple_size_v<typename CommandTraits<Tcmd>::Args>>{});
 
	return EndianBufferWriter<CommandDataBuffer>::FromValue(args);
 
}
 

	
 
template <Commands Tcmd>
 
void UnpackNetworkCommand(const CommandPacket *cp)
 
{
 
	auto args = EndianBufferReader::ToValue<typename CommandTraits<Tcmd>::Args>(cp->data);
 
	std::apply(&InjectNetworkCommand, std::tuple_cat(std::make_tuple(Tcmd, cp->err_msg, cp->callback, cp->my_cmd), args));
 
	Command<Tcmd>::PostFromNet(cp->err_msg, cp->callback, cp->my_cmd, cp->tile, args);
 
}
src/network/network_gui.cpp
Show inline comments
 
@@ -27,24 +27,25 @@
 
#include "../widgets/dropdown_func.h"
 
#include "../querystring_gui.h"
 
#include "../sortlist_type.h"
 
#include "../company_func.h"
 
#include "../command_func.h"
 
#include "../core/geometry_func.hpp"
 
#include "../genworld.h"
 
#include "../map_type.h"
 
#include "../guitimer_func.h"
 
#include "../zoom_func.h"
 
#include "../sprite.h"
 
#include "../settings_internal.h"
 
#include "../company_cmd.h"
 

	
 
#include "../widgets/network_widget.h"
 

	
 
#include "table/strings.h"
 
#include "../table/sprites.h"
 

	
 
#include "../stringfilter_type.h"
 

	
 
#ifdef __EMSCRIPTEN__
 
#	include <emscripten.h>
 
#endif
 

	
 
@@ -1386,25 +1387,25 @@ static void AdminClientBanCallback(Windo
 
	if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, {});
 
}
 

	
 
/**
 
 * Callback function for admin command to reset company.
 
 * @param w The window which initiated the confirmation dialog.
 
 * @param confirmed Iff the user pressed Yes.
 
 */
 
static void AdminCompanyResetCallback(Window *w, bool confirmed)
 
{
 
	if (confirmed) {
 
		if (NetworkCompanyHasClients(_admin_company_id)) return;
 
		DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0);
 
		Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0, {});
 
	}
 
}
 

	
 
/**
 
 * Callback function for admin command to unlock company.
 
 * @param w The window which initiated the confirmation dialog.
 
 * @param confirmed Iff the user pressed Yes.
 
 */
 
static void AdminCompanyUnlockCallback(Window *w, bool confirmed)
 
{
 
	if (confirmed) NetworkServerSetCompanyPassword(_admin_company_id, "", false);
 
}
 
@@ -1526,25 +1527,25 @@ private:
 
		}
 
	}
 

	
 
	/**
 
	 * Crete new company button is clicked.
 
	 * @param w The instance of this window.
 
	 * @param pt The point where this button was clicked.
 
	 * @param company_id The company this button was assigned to.
 
	 */
 
	static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID company_id)
 
	{
 
		if (_network_server) {
 
			DoCommandP(CMD_COMPANY_CTRL, 0, CCA_NEW, _network_own_client_id);
 
			Command<CMD_COMPANY_CTRL>::Post(0, CCA_NEW, _network_own_client_id, {});
 
		} else {
 
			NetworkSendCommand(CMD_COMPANY_CTRL, STR_NULL, nullptr, _local_company, 0, CCA_NEW, 0, {});
 
		}
 
	}
 

	
 
	/**
 
	 * Admin button on a Client is clicked.
 
	 * @param w The instance of this window.
 
	 * @param pt The point where this button was clicked.
 
	 * @param client_id The client this button was assigned to.
 
	 */
 
	static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id)
src/network/network_server.cpp
Show inline comments
 
@@ -20,24 +20,25 @@
 
#include "../command_func.h"
 
#include "../saveload/saveload.h"
 
#include "../saveload/saveload_filter.h"
 
#include "../station_base.h"
 
#include "../genworld.h"
 
#include "../company_func.h"
 
#include "../company_gui.h"
 
#include "../company_cmd.h"
 
#include "../roadveh.h"
 
#include "../order_backup.h"
 
#include "../core/pool_func.hpp"
 
#include "../core/random_func.hpp"
 
#include "../company_cmd.h"
 
#include "../rev.h"
 
#include <mutex>
 
#include <condition_variable>
 

	
 
#include "../safeguards.h"
 

	
 

	
 
/* This file handles all the server-commands */
 

	
 
DECLARE_POSTFIX_INCREMENT(ClientID)
 
/** The identifier counter for new clients (is never decreased) */
 
static ClientID _network_client_id = CLIENT_ID_FIRST;
 
@@ -1546,39 +1547,39 @@ static void NetworkAutoCleanCompanies()
 
	/* Go through all the companies */
 
	for (const Company *c : Company::Iterate()) {
 
		/* Skip the non-active once */
 
		if (c->is_ai) continue;
 

	
 
		if (!clients_in_company[c->index]) {
 
			/* The company is empty for one month more */
 
			_network_company_states[c->index].months_empty++;
 

	
 
			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
 
			if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && _network_company_states[c->index].password.empty()) {
 
				/* Shut the company down */
 
				DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0);
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no password.", c->index + 1);
 
			}
 
			/* Is the company empty for autoclean_protected-months, and there is a protection? */
 
			if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !_network_company_states[c->index].password.empty()) {
 
				/* Unprotect the company */
 
				_network_company_states[c->index].password.clear();
 
				IConsolePrint(CC_INFO, "Auto-removed protection from company #{}.", c->index + 1);
 
				_network_company_states[c->index].months_empty = 0;
 
				NetworkServerUpdateCompanyPassworded(c->index, false);
 
			}
 
			/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
 
			if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) {
 
				/* Shut the company down */
 
				DoCommandP(CMD_COMPANY_CTRL, 0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0);
 
				Command<CMD_COMPANY_CTRL>::Post(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, {});
 
				IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
 
			}
 
		} else {
 
			/* It is not empty, reset the date */
 
			_network_company_states[c->index].months_empty = 0;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Check whether a name is unique, and otherwise try to make it unique.
 
 * @param new_name The name to check/modify.
src/object_gui.cpp
Show inline comments
 
@@ -16,24 +16,25 @@
 
#include "object.h"
 
#include "querystring_gui.h"
 
#include "sortlist_type.h"
 
#include "stringfilter_type.h"
 
#include "string_func.h"
 
#include "strings_func.h"
 
#include "viewport_func.h"
 
#include "tilehighlight_func.h"
 
#include "window_gui.h"
 
#include "window_func.h"
 
#include "zoom_func.h"
 
#include "terraform_cmd.h"
 
#include "object_cmd.h"
 

	
 
#include "widgets/object_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
static ObjectClassID _selected_object_class; ///< Currently selected available object class.
 
static int _selected_object_index;           ///< Index of the currently selected object if existing, else \c -1.
 
static uint8 _selected_object_view;          ///< the view of the selected object
 

	
 
/** Enum referring to the Hotkeys in the build object window */
 
@@ -533,26 +534,26 @@ public:
 
			case WID_BO_OBJECT_SPRITE:
 
				if (_selected_object_index != -1) {
 
					_selected_object_view = GB(widget, 16, 16);
 
					this->SelectOtherObject(_selected_object_index); // Re-select the object for a different view.
 
				}
 
				break;
 
		}
 
	}
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
 
		DoCommandP(CMD_BUILD_OBJECT, STR_ERROR_CAN_T_BUILD_OBJECT, CcTerraform,
 
				tile, objclass->GetSpec(_selected_object_index)->Index(), _selected_object_view);
 
		Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_OBJECT, CcTerraform,
 
				tile, objclass->GetSpec(_selected_object_index)->Index(), _selected_object_view, {});
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		this->UpdateButtons(_selected_object_class, -1, _selected_object_view);
 
	}
 

	
 
	EventState OnHotkey(int hotkey) override
 
	{
 
		switch (hotkey) {
 
			case BOHK_FOCUS_FILTER_BOX:
 
				this->SetFocusedWidget(WID_BO_FILTER);
src/openttd.cpp
Show inline comments
 
@@ -57,24 +57,25 @@
 
#include "newgrf.h"
 
#include "misc/getoptdata.h"
 
#include "game/game.hpp"
 
#include "game/game_config.hpp"
 
#include "town.h"
 
#include "subsidy_func.h"
 
#include "gfx_layout.h"
 
#include "viewport_func.h"
 
#include "viewport_sprite_sorter.h"
 
#include "framerate_type.h"
 
#include "industry.h"
 
#include "network/network_gui.h"
 
#include "misc_cmd.h"
 

	
 
#include "linkgraph/linkgraphschedule.h"
 

	
 
#include <stdarg.h>
 
#include <system_error>
 

	
 
#include "safeguards.h"
 

	
 
#ifdef __EMSCRIPTEN__
 
#	include <emscripten.h>
 
#	include <emscripten/html5.h>
 
#endif
 
@@ -842,25 +843,25 @@ static void OnStartGame(bool dedicated_s
 
	NetworkServerUpdateGameInfo();
 
	/* Execute the game-start script */
 
	IConsoleCmdExec("exec scripts/game_start.scr 0");
 
}
 

	
 
static void MakeNewGameDone()
 
{
 
	SettingsDisableElrail(_settings_game.vehicle.disable_elrails);
 

	
 
	/* In a dedicated server, the server does not play */
 
	if (!VideoDriver::GetInstance()->HasGUI()) {
 
		OnStartGame(true);
 
		if (_settings_client.gui.pause_on_newgame) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
		if (_settings_client.gui.pause_on_newgame) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 
		return;
 
	}
 

	
 
	/* Create a single company */
 
	DoStartupNewCompany(false);
 

	
 
	Company *c = Company::Get(COMPANY_FIRST);
 
	c->settings = _settings_client.company;
 

	
 
	/* Overwrite color from settings if needed
 
	 * COLOUR_END corresponds to Random colour */
 
	if (_settings_client.gui.starting_colour != COLOUR_END) {
 
@@ -871,25 +872,25 @@ static void MakeNewGameDone()
 

	
 
	OnStartGame(false);
 

	
 
	InitializeRailGUI();
 
	InitializeRoadGUI();
 

	
 
	/* We are the server, we start a new company (not dedicated),
 
	 * so set the default password *if* needed. */
 
	if (_network_server && !_settings_client.network.default_company_pass.empty()) {
 
		NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass);
 
	}
 

	
 
	if (_settings_client.gui.pause_on_newgame) DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, 1);
 
	if (_settings_client.gui.pause_on_newgame) Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, 1, {});
 

	
 
	CheckEngines();
 
	CheckIndustries();
 
	MarkWholeScreenDirty();
 

	
 
	if (_network_server && !_network_dedicated) ShowClientList();
 
}
 

	
 
static void MakeNewGame(bool from_heightmap, bool reset_settings)
 
{
 
	_game_mode = GM_NORMAL;
 
	if (!from_heightmap) {
 
@@ -1036,47 +1037,47 @@ void SwitchToMode(SwitchMode new_mode)
 
			ResetWindowSystem();
 

	
 
			if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, NO_DIRECTORY)) {
 
				SetDParamStr(0, GetSaveLoadErrorString());
 
				ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
			} else {
 
				if (_file_to_saveload.abstract_ftype == FT_SCENARIO) {
 
					/* Reset engine pool to simplify changing engine NewGRFs in scenario editor. */
 
					EngineOverrideManager::ResetToCurrentNewGRFConfig();
 
				}
 
				OnStartGame(_network_dedicated);
 
				/* Decrease pause counter (was increased from opening load dialog) */
 
				DoCommandP(CMD_PAUSE, 0, PM_PAUSED_SAVELOAD, 0);
 
				Command<CMD_PAUSE>::Post(0, PM_PAUSED_SAVELOAD, 0, {});
 
			}
 
			break;
 
		}
 

	
 
		case SM_RESTART_HEIGHTMAP: // Load a heightmap and start a new game from it with current settings
 
		case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it
 
			MakeNewGame(true, new_mode == SM_START_HEIGHTMAP);
 
			break;
 

	
 
		case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor
 
			SetLocalCompany(OWNER_NONE);
 

	
 
			GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y);
 
			MarkWholeScreenDirty();
 
			break;
 

	
 
		case SM_LOAD_SCENARIO: { // Load scenario from scenario editor
 
			if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_EDITOR, NO_DIRECTORY)) {
 
				SetLocalCompany(OWNER_NONE);
 
				_settings_newgame.game_creation.starting_year = _cur_year;
 
				/* Cancel the saveload pausing */
 
				DoCommandP(CMD_PAUSE, 0, PM_PAUSED_SAVELOAD, 0);
 
				Command<CMD_PAUSE>::Post(0, PM_PAUSED_SAVELOAD, 0, {});
 
			} else {
 
				SetDParamStr(0, GetSaveLoadErrorString());
 
				ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
 
			}
 
			break;
 
		}
 

	
 
		case SM_JOIN_GAME: // Join a multiplayer game
 
			LoadIntroGame();
 
			NetworkClientJoinGame();
 
			break;
 

	
src/order_backup.cpp
Show inline comments
 
@@ -162,25 +162,25 @@ CommandCost CmdClearOrderBackup(DoComman
 
 * @param user The user associated with the OrderBackup.
 
 * @pre _network_server.
 
 * @note Must not be used from a command.
 
 */
 
/* static */ void OrderBackup::ResetUser(uint32 user)
 
{
 
	assert(_network_server);
 

	
 
	for (OrderBackup *ob : OrderBackup::Iterate()) {
 
		/* If it's not a backup of us, ignore it. */
 
		if (ob->user != user) continue;
 

	
 
		DoCommandP(CMD_CLEAR_ORDER_BACKUP, 0, 0, user);
 
		Command<CMD_CLEAR_ORDER_BACKUP>::Post(0, 0, user, {});
 
		return;
 
	}
 
}
 

	
 
/**
 
 * Reset the OrderBackups from GUI/game logic.
 
 * @param t        The tile of the order backup.
 
 * @param from_gui Whether the call came from the GUI, i.e. whether
 
 *                 it must be synced over the network.
 
 */
 
/* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
 
{
src/order_gui.cpp
Show inline comments
 
@@ -20,24 +20,25 @@
 
#include "textbuf_gui.h"
 
#include "string_func.h"
 
#include "tilehighlight_func.h"
 
#include "network/network.h"
 
#include "station_base.h"
 
#include "industry.h"
 
#include "waypoint_base.h"
 
#include "core/geometry_func.hpp"
 
#include "hotkeys.h"
 
#include "aircraft.h"
 
#include "engine_func.h"
 
#include "vehicle_func.h"
 
#include "order_cmd.h"
 

	
 
#include "widgets/order_widget.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
/** Order load types that could be given to station orders. */
 
static const StringID _station_load_types[][5][5] = {
 
	{
 
		/* No refitting. */
 
		{
 
			STR_EMPTY,
 
@@ -582,171 +583,171 @@ private:
 
	void OrderClick_FullLoad(OrderLoadFlags load_type, bool toggle = false)
 
	{
 
		VehicleOrderID sel_ord = this->OrderGetSel();
 
		const Order *order = this->vehicle->GetOrder(sel_ord);
 

	
 
		if (order == nullptr) return;
 

	
 
		if (toggle && order->GetLoadType() == load_type) {
 
			load_type = OLF_LOAD_IF_POSSIBLE; // reset to 'default'
 
		}
 
		if (order->GetLoadType() == load_type) return; // If we still match, do nothing
 

	
 
		DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (load_type << 4));
 
		Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (load_type << 4), {});
 
	}
 

	
 
	/**
 
	 * Handle the click on the service.
 
	 */
 
	void OrderClick_Service(int i)
 
	{
 
		VehicleOrderID sel_ord = this->OrderGetSel();
 

	
 
		if (i < 0) {
 
			const Order *order = this->vehicle->GetOrder(sel_ord);
 
			if (order == nullptr) return;
 
			i = (order->GetDepotOrderType() & ODTFB_SERVICE) ? DA_ALWAYS_GO : DA_SERVICE;
 
		}
 
		DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_DEPOT_ACTION | (i << 4));
 
		Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_DEPOT_ACTION | (i << 4), {});
 
	}
 

	
 
	/**
 
	 * Handle the click on the service in nearest depot button.
 
	 */
 
	void OrderClick_NearestDepot()
 
	{
 
		Order order;
 
		order.next = nullptr;
 
		order.index = 0;
 
		order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS,
 
				_settings_client.gui.new_nonstop && this->vehicle->IsGroundVehicle() ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
 
		order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
 

	
 
		DoCommandP(CMD_INSERT_ORDER, STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack());
 
		Command<CMD_INSERT_ORDER>::Post(STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), {});
 
	}
 

	
 
	/**
 
	 * Handle the click on the unload button.
 
	 * @param unload_type Unload flag to apply. If matches existing unload type, toggles to default of 'unload if possible'.
 
	 * @param toggle If we toggle or not (used for hotkey behavior)
 
	 */
 
	void OrderClick_Unload(OrderUnloadFlags unload_type, bool toggle = false)
 
	{
 
		VehicleOrderID sel_ord = this->OrderGetSel();
 
		const Order *order = this->vehicle->GetOrder(sel_ord);
 

	
 
		if (order == nullptr) return;
 

	
 
		if (toggle && order->GetUnloadType() == unload_type) {
 
			unload_type = OUF_UNLOAD_IF_POSSIBLE;
 
		}
 
		if (order->GetUnloadType() == unload_type) return; // If we still match, do nothing
 

	
 
		DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_UNLOAD | (unload_type << 4));
 
		Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_UNLOAD | (unload_type << 4), {});
 

	
 
		/* Transfer and unload orders with leave empty as default */
 
		if (unload_type == OUFB_TRANSFER || unload_type == OUFB_UNLOAD) {
 
			DoCommandP(CMD_MODIFY_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (OLFB_NO_LOAD << 4));
 
			Command<CMD_MODIFY_ORDER>::Post(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (OLFB_NO_LOAD << 4), {});
 
			this->SetWidgetDirty(WID_O_FULL_LOAD);
 
		}
 
	}
 

	
 
	/**
 
	 * Handle the click on the nonstop button.
 
	 * @param non_stop what non-stop type to use; -1 to use the 'next' one.
 
	 */
 
	void OrderClick_Nonstop(int non_stop)
 
	{
 
		if (!this->vehicle->IsGroundVehicle()) return;
 

	
 
		VehicleOrderID sel_ord = this->OrderGetSel();
 
		const Order *order = this->vehicle->GetOrder(sel_ord);
 

	
 
		if (order == nullptr || order->GetNonStopType() == non_stop) return;
 

	
 
		/* Keypress if negative, so 'toggle' to the next */
 
		if (non_stop < 0) {
 
			non_stop = order->GetNonStopType() ^ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS;
 
		}
 

	
 
		this->SetWidgetDirty(WID_O_NON_STOP);
 
		DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_NON_STOP | non_stop << 4);
 
		Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_NON_STOP | non_stop << 4, {});
 
	}
 

	
 
	/**
 
	 * Handle the click on the skip button.
 
	 * If ctrl is pressed, skip to selected order, else skip to current order + 1
 
	 */
 
	void OrderClick_Skip()
 
	{
 
		/* Don't skip when there's nothing to skip */
 
		if (_ctrl_pressed && this->vehicle->cur_implicit_order_index == this->OrderGetSel()) return;
 
		if (this->vehicle->GetNumOrders() <= 1) return;
 

	
 
		DoCommandP(CMD_SKIP_TO_ORDER, _ctrl_pressed ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER,
 
				this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_implicit_order_index + 1) % this->vehicle->GetNumOrders()));
 
		Command<CMD_SKIP_TO_ORDER>::Post(_ctrl_pressed ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER,
 
				this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_implicit_order_index + 1) % this->vehicle->GetNumOrders()), {});
 
	}
 

	
 
	/**
 
	 * Handle the click on the delete button.
 
	 */
 
	void OrderClick_Delete()
 
	{
 
		/* When networking, move one order lower */
 
		int selected = this->selected_order + (int)_networking;
 

	
 
		if (DoCommandP(CMD_DELETE_ORDER, STR_ERROR_CAN_T_DELETE_THIS_ORDER, this->vehicle->tile, this->vehicle->index, this->OrderGetSel())) {
 
		if (Command<CMD_DELETE_ORDER>::Post(STR_ERROR_CAN_T_DELETE_THIS_ORDER, this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), {})) {
 
			this->selected_order = selected >= this->vehicle->GetNumOrders() ? -1 : selected;
 
			this->UpdateButtonState();
 
		}
 
	}
 

	
 
	/**
 
	 * Handle the click on the 'stop sharing' button.
 
	 * If 'End of Shared Orders' isn't selected, do nothing. If Ctrl is pressed, call OrderClick_Delete and exit.
 
	 * To stop sharing this vehicle order list, we copy the orders of a vehicle that share this order list. That way we
 
	 * exit the group of shared vehicles while keeping the same order list.
 
	 */
 
	void OrderClick_StopSharing()
 
	{
 
		/* Don't try to stop sharing orders if 'End of Shared Orders' isn't selected. */
 
		if (!this->vehicle->IsOrderListShared() || this->selected_order != this->vehicle->GetNumOrders()) return;
 
		/* If Ctrl is pressed, delete the order list as if we clicked the 'Delete' button. */
 
		if (_ctrl_pressed) {
 
			this->OrderClick_Delete();
 
			return;
 
		}
 

	
 
		/* Get another vehicle that share orders with this vehicle. */
 
		Vehicle *other_shared = (this->vehicle->FirstShared() == this->vehicle) ? this->vehicle->NextShared() : this->vehicle->PreviousShared();
 
		/* Copy the order list of the other vehicle. */
 
		if (DoCommandP(CMD_CLONE_ORDER, STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST, this->vehicle->tile, this->vehicle->index | CO_COPY << 30, other_shared->index)) {
 
		if (Command<CMD_CLONE_ORDER>::Post(STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST, this->vehicle->tile, this->vehicle->index | CO_COPY << 30, other_shared->index, {})) {
 
			this->UpdateButtonState();
 
		}
 
	}
 

	
 
	/**
 
	 * Handle the click on the refit button.
 
	 * If ctrl is pressed, cancel refitting, else show the refit window.
 
	 * @param i Selected refit command.
 
	 * @param auto_refit Select refit for auto-refitting.
 
	 */
 
	void OrderClick_Refit(int i, bool auto_refit)
 
	{
 
		if (_ctrl_pressed) {
 
			/* Cancel refitting */
 
			DoCommandP(CMD_ORDER_REFIT, this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT);
 
			Command<CMD_ORDER_REFIT>::Post(this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, {});
 
		} else {
 
			if (i == 1) { // Auto-refit to available cargo type.
 
				DoCommandP(CMD_ORDER_REFIT, this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | CT_AUTO_REFIT);
 
				Command<CMD_ORDER_REFIT>::Post(this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | CT_AUTO_REFIT, {});
 
			} else {
 
				ShowVehicleRefitWindow(this->vehicle, this->OrderGetSel(), this, auto_refit);
 
			}
 
		}
 
	}
 

	
 
	/** Cache auto-refittability of the vehicle chain. */
 
	void UpdateAutoRefitState()
 
	{
 
		this->can_do_refit = false;
 
		this->can_do_autorefit = false;
 
		for (const Vehicle *w = this->vehicle; w != nullptr; w = w->IsGroundVehicle() ? w->Next() : nullptr) {
 
@@ -1150,50 +1151,50 @@ public:
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_O_ORDER_LIST: {
 
				if (this->goto_type == OPOS_CONDITIONAL) {
 
					VehicleOrderID order_id = this->GetOrderFromPt(_cursor.pos.y - this->top);
 
					if (order_id != INVALID_VEH_ORDER_ID) {
 
						Order order;
 
						order.next = nullptr;
 
						order.index = 0;
 
						order.MakeConditional(order_id);
 

	
 
						DoCommandP(CMD_INSERT_ORDER, STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack());
 
						Command<CMD_INSERT_ORDER>::Post(STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), {});
 
					}
 
					ResetObjectToPlace();
 
					break;
 
				}
 

	
 
				VehicleOrderID sel = this->GetOrderFromPt(pt.y);
 

	
 
				if (_ctrl_pressed && sel < this->vehicle->GetNumOrders()) {
 
					TileIndex xy = this->vehicle->GetOrder(sel)->GetLocation(this->vehicle);
 
					if (xy != INVALID_TILE) ScrollMainWindowToTile(xy);
 
					return;
 
				}
 

	
 
				/* This order won't be selected any more, close all child windows and dropdowns */
 
				this->CloseChildWindows();
 
				HideDropDownMenu(this);
 

	
 
				if (sel == INVALID_VEH_ORDER_ID || this->vehicle->owner != _local_company) {
 
					/* Deselect clicked order */
 
					this->selected_order = -1;
 
				} else if (sel == this->selected_order) {
 
					if (this->vehicle->type == VEH_TRAIN && sel < this->vehicle->GetNumOrders()) {
 
						DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER,
 
						Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER,
 
								this->vehicle->tile, this->vehicle->index + (sel << 20),
 
								MOF_STOP_LOCATION | ((this->vehicle->GetOrder(sel)->GetStopLocation() + 1) % OSL_END) << 4);
 
								MOF_STOP_LOCATION | ((this->vehicle->GetOrder(sel)->GetStopLocation() + 1) % OSL_END) << 4, {});
 
					}
 
				} else {
 
					/* Select clicked order */
 
					this->selected_order = sel;
 

	
 
					if (this->vehicle->owner == _local_company) {
 
						/* Activate drag and drop */
 
						SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
 
					}
 
				}
 

	
 
				this->UpdateButtonState();
 
@@ -1322,25 +1323,25 @@ public:
 
				case OCV_MAX_SPEED:
 
					value = ConvertDisplaySpeedToSpeed(value);
 
					break;
 

	
 
				case OCV_RELIABILITY:
 
				case OCV_LOAD_PERCENTAGE:
 
					value = Clamp(value, 0, 100);
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
			DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel << 20), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4);
 
			Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (sel << 20), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, {});
 
		}
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_O_NON_STOP:
 
				this->OrderClick_Nonstop(index);
 
				break;
 

	
 
			case WID_O_FULL_LOAD:
 
				this->OrderClick_FullLoad((OrderLoadFlags)index);
 
@@ -1360,42 +1361,42 @@ public:
 
				}
 
				break;
 

	
 
			case WID_O_SERVICE:
 
				this->OrderClick_Service(index);
 
				break;
 

	
 
			case WID_O_REFIT_DROPDOWN:
 
				this->OrderClick_Refit(index, true);
 
				break;
 

	
 
			case WID_O_COND_VARIABLE:
 
				DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_VARIABLE | index << 4);
 
				Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_VARIABLE | index << 4, {});
 
				break;
 

	
 
			case WID_O_COND_COMPARATOR:
 
				DoCommandP(CMD_MODIFY_ORDER, STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_COMPARATOR | index << 4);
 
				Command<CMD_MODIFY_ORDER>::Post(STR_ERROR_CAN_T_MODIFY_THIS_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_COMPARATOR | index << 4, {});
 
				break;
 
		}
 
	}
 

	
 
	void OnDragDrop(Point pt, int widget) override
 
	{
 
		switch (widget) {
 
			case WID_O_ORDER_LIST: {
 
				VehicleOrderID from_order = this->OrderGetSel();
 
				VehicleOrderID to_order = this->GetOrderFromPt(pt.y);
 

	
 
				if (!(from_order == to_order || from_order == INVALID_VEH_ORDER_ID || from_order > this->vehicle->GetNumOrders() || to_order == INVALID_VEH_ORDER_ID || to_order > this->vehicle->GetNumOrders()) &&
 
						DoCommandP(CMD_MOVE_ORDER, STR_ERROR_CAN_T_MOVE_THIS_ORDER, this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16))) {
 
						Command<CMD_MOVE_ORDER>::Post(STR_ERROR_CAN_T_MOVE_THIS_ORDER, this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16), {})) {
 
					this->selected_order = -1;
 
					this->UpdateButtonState();
 
				}
 
				break;
 
			}
 

	
 
			case WID_O_DELETE:
 
				this->OrderClick_Delete();
 
				break;
 

	
 
			case WID_O_STOP_SHARING:
 
				this->OrderClick_StopSharing();
 
@@ -1429,43 +1430,43 @@ public:
 
			case OHK_NO_LOAD:        this->OrderClick_FullLoad(OLFB_NO_LOAD, true); break;
 
			default: return ES_NOT_HANDLED;
 
		}
 
		return ES_HANDLED;
 
	}
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		if (this->goto_type == OPOS_GOTO) {
 
			const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
 
			if (cmd.IsType(OT_NOTHING)) return;
 

	
 
			if (DoCommandP(CMD_INSERT_ORDER, STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack())) {
 
			if (Command<CMD_INSERT_ORDER>::Post(STR_ERROR_CAN_T_INSERT_NEW_ORDER, this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), {})) {
 
				/* With quick goto the Go To button stays active */
 
				if (!_settings_client.gui.quick_goto) ResetObjectToPlace();
 
			}
 
		}
 
	}
 

	
 
	bool OnVehicleSelect(const Vehicle *v) override
 
	{
 
		/* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet.
 
		 * We disallow copying orders of other vehicles if we already have at least one order entry
 
		 * ourself as it easily copies orders of vehicles within a station when we mean the station.
 
		 * Obviously if you press CTRL on a non-empty orders vehicle you know what you are doing
 
		 * TODO: give a warning message */
 
		bool share_order = _ctrl_pressed || this->goto_type == OPOS_SHARE;
 
		if (this->vehicle->GetNumOrders() != 0 && !share_order) return false;
 

	
 
		if (DoCommandP(CMD_CLONE_ORDER, share_order ? STR_ERROR_CAN_T_SHARE_ORDER_LIST : STR_ERROR_CAN_T_COPY_ORDER_LIST,
 
				this->vehicle->tile, this->vehicle->index | (share_order ? CO_SHARE : CO_COPY) << 30, v->index)) {
 
		if (Command<CMD_CLONE_ORDER>::Post(share_order ? STR_ERROR_CAN_T_SHARE_ORDER_LIST : STR_ERROR_CAN_T_COPY_ORDER_LIST,
 
				this->vehicle->tile, this->vehicle->index | (share_order ? CO_SHARE : CO_COPY) << 30, v->index, {})) {
 
			this->selected_order = -1;
 
			ResetObjectToPlace();
 
		}
 
		return true;
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		this->goto_type = OPOS_NONE;
 
		this->SetWidgetDirty(WID_O_GOTO);
 

	
 
		/* Remove drag highlighting if it exists. */
src/rail_gui.cpp
Show inline comments
 
@@ -30,24 +30,25 @@
 
#include "hotkeys.h"
 
#include "engine_base.h"
 
#include "vehicle_func.h"
 
#include "zoom_func.h"
 
#include "rail_gui.h"
 
#include "querystring_gui.h"
 
#include "sortlist_type.h"
 
#include "stringfilter_type.h"
 
#include "string_func.h"
 
#include "station_cmd.h"
 
#include "tunnelbridge_cmd.h"
 
#include "waypoint_cmd.h"
 
#include "rail_cmd.h"
 

	
 
#include "station_map.h"
 
#include "tunnelbridge_map.h"
 

	
 
#include "widgets/rail_widget.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
static RailType _cur_railtype;               ///< Rail type of the current build-rail toolbar.
 
static bool _remove_button_clicked;          ///< Flag whether 'remove' toggle-button is currently enabled
 
static DiagDirection _build_depot_direction; ///< Currently selected depot direction
 
@@ -86,44 +87,47 @@ static bool IsStationAvailable(const Sta
 
	if (cb_res == CALLBACK_FAILED) return true;
 

	
 
	return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res);
 
}
 

	
 
void CcPlaySound_CONSTRUCTION_RAIL(const CommandCost &result, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, tile);
 
}
 

	
 
static void GenericPlaceRail(TileIndex tile, int cmd)
 
{
 
	DoCommandP(_remove_button_clicked ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL,
 
			_remove_button_clicked ? STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK : STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK,
 
			CcPlaySound_CONSTRUCTION_RAIL,
 
			tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3));
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3), {});
 
	} else {
 
		Command<CMD_BUILD_SINGLE_RAIL>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				tile, _cur_railtype, cmd | (_settings_client.gui.auto_remove_signals << 3), {});
 
	}
 
}
 

	
 
/**
 
 * Try to add an additional rail-track at the entrance of a depot
 
 * @param tile  Tile to use for adding the rail-track
 
 * @param dir   Direction to check for already present tracks
 
 * @param track Track to add
 
 * @see CcRailDepot()
 
 */
 
static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track)
 
{
 
	if (GetRailTileType(tile) == RAIL_TILE_DEPOT) return;
 
	if (GetRailTileType(tile) == RAIL_TILE_SIGNALS && !_settings_client.gui.auto_remove_signals) return;
 
	if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
 

	
 
	DoCommandP(CMD_BUILD_SINGLE_RAIL, tile, _cur_railtype, track | (_settings_client.gui.auto_remove_signals << 3));
 
	Command<CMD_BUILD_SINGLE_RAIL>::Post(tile, _cur_railtype, track | (_settings_client.gui.auto_remove_signals << 3), {});
 
}
 

	
 
/** Additional pieces of track to add at the entrance of a depot. */
 
static const Track _place_depot_extra_track[12] = {
 
	TRACK_LEFT,  TRACK_UPPER, TRACK_UPPER, TRACK_RIGHT, // First additional track for directions 0..3
 
	TRACK_X,     TRACK_Y,     TRACK_X,     TRACK_Y,     // Second additional track
 
	TRACK_LOWER, TRACK_LEFT,  TRACK_RIGHT, TRACK_LOWER, // Third additional track
 
};
 

	
 
/** Direction to check for existing track pieces. */
 
static const DiagDirection _place_depot_extra_dir[12] = {
 
	DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_SW,
 
@@ -159,25 +163,25 @@ static void PlaceRail_Waypoint(TileIndex
 
		VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
 
		return;
 
	}
 

	
 
	Axis axis = GetAxisForNewWaypoint(tile);
 
	if (IsValidAxis(axis)) {
 
		/* Valid tile for waypoints */
 
		VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_STATION);
 
		VpSetPlaceSizingLimit(_settings_game.station.station_spread);
 
	} else {
 
		/* Tile where we can't build rail waypoints. This is always going to fail,
 
		 * but provides the user with a proper error message. */
 
		DoCommandP(CMD_BUILD_RAIL_WAYPOINT, STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT, tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16);
 
		Command<CMD_BUILD_RAIL_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT, tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, {});
 
	}
 
}
 

	
 
void CcStation(const CommandCost &result, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	if (result.Failed()) return;
 

	
 
	if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_CONSTRUCTION_RAIL, tile);
 
	/* Only close the station builder window if the default station and non persistent building is chosen. */
 
	if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
 
}
 

	
 
@@ -199,25 +203,25 @@ static void PlaceRail_Station(TileIndex 
 

	
 
		int w = _settings_client.gui.station_numtracks;
 
		int h = _settings_client.gui.station_platlength;
 
		if (!_railstation.orientation) Swap(w, h);
 

	
 
		auto proc = [=](bool test, StationID to_join) -> bool {
 
			if (test) {
 
				return Command<CMD_BUILD_RAIL_STATION>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_STATION>()), tile, p1, p2, {}).Succeeded();
 
			} else {
 
				uint32 p2_final = p2;
 
				if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
				return DoCommandP(CMD_BUILD_RAIL_STATION, STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, tile, p1, p2_final);
 
				return Command<CMD_BUILD_RAIL_STATION>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, tile, p1, p2_final, {});
 
			}
 
		};
 

	
 
		ShowSelectStationIfNeeded(TileArea(tile, w, h), proc);
 
	}
 
}
 

	
 
/**
 
 * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp
 
 *
 
 * @param tile The tile where the signal will build or edit
 
 */
 
@@ -227,25 +231,25 @@ static void GenericPlaceSignals(TileInde
 

	
 
	if (trackbits & TRACK_BIT_VERT) { // N-S direction
 
		trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
 
	}
 

	
 
	if (trackbits & TRACK_BIT_HORZ) { // E-W direction
 
		trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
 
	}
 

	
 
	Track track = FindFirstTrack(trackbits);
 

	
 
	if (_remove_button_clicked) {
 
		DoCommandP(CMD_REMOVE_SIGNALS, STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL,  tile, track, 0);
 
		Command<CMD_REMOVE_SIGNALS>::Post(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL, tile, track, 0, {});
 
	} else {
 
		const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
 

	
 
		/* various bitstuffed elements for CmdBuildSingleSignal() */
 
		uint32 p1 = track;
 

	
 
		/* Which signals should we cycle through? */
 
		uint8 cycle_types;
 

	
 
		if (_settings_client.gui.cycle_signal_types == SIGNAL_CYCLE_ALL && _settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL) {
 
			cycle_types = SIGTYPE_NORMAL | (SIGTYPE_LAST << 3);
 
		} else {
 
@@ -258,26 +262,26 @@ static void GenericPlaceSignals(TileInde
 
			SB(p1, 4, 1, _cur_signal_variant);
 
			SB(p1, 5, 3, _cur_signal_type);
 
			SB(p1, 8, 1, _convert_signal_button);
 
			SB(p1, 9, 6, cycle_types);
 
		} else {
 
			SB(p1, 3, 1, _ctrl_pressed);
 
			SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
			SB(p1, 5, 3, SIGTYPE_PBS_ONEWAY);
 
			SB(p1, 8, 1, 0);
 
			SB(p1, 9, 6, cycle_types);
 
		}
 

	
 
		DoCommandP(CMD_BUILD_SIGNALS, (w != nullptr && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE,
 
				CcPlaySound_CONSTRUCTION_RAIL, tile, p1, 0);
 
		Command<CMD_BUILD_SIGNALS>::Post((w != nullptr && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE,
 
				CcPlaySound_CONSTRUCTION_RAIL, tile, p1, 0, {});
 
	}
 
}
 

	
 
/**
 
 * Start placing a rail bridge.
 
 * @param tile Position of the first tile of the bridge.
 
 * @param w    Rail toolbar window.
 
 */
 
static void PlaceRail_Bridge(TileIndex tile, Window *w)
 
{
 
	if (IsBridgeTile(tile)) {
 
		TileIndex other_tile = GetOtherTunnelBridgeEnd(tile);
 
@@ -361,28 +365,31 @@ static void BuildRailClick_Remove(Window
 
				if (_railstation.orientation == 0) Swap(x, y);
 
				SetTileSelectSize(x, y);
 
			} else {
 
				VpSetPlaceSizingLimit(_settings_game.station.station_spread);
 
			}
 
		}
 
	}
 
}
 

	
 
static void DoRailroadTrack(int mode)
 
{
 
	uint32 p2 = _cur_railtype | (mode << 6) | (_settings_client.gui.auto_remove_signals << 11);
 
	DoCommandP(_remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK : CMD_BUILD_RAILROAD_TRACK,
 
			_remove_button_clicked ? STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK : STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK,
 
			CcPlaySound_CONSTRUCTION_RAIL,
 
			TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2);
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
	} else {
 
		Command<CMD_BUILD_RAILROAD_TRACK>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
	}
 
}
 

	
 
static void HandleAutodirPlacement()
 
{
 
	int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5
 

	
 
	if (_thd.drawstyle & HT_RAIL) { // one tile case
 
		GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat);
 
		return;
 
	}
 

	
 
	DoRailroadTrack(trackstat);
 
@@ -415,28 +422,31 @@ static void HandleAutoSignalPlacement()
 
		SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance);
 
	} else {
 
		SB(p2,  3, 1, 0);
 
		SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
		SB(p2,  6, 1, _ctrl_pressed);
 
		SB(p2,  7, 3, SIGTYPE_PBS_ONEWAY);
 
		SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
 
		SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance);
 
	}
 

	
 
	/* _settings_client.gui.drag_signals_density is given as a parameter such that each user
 
	 * in a network game can specify their own signal density */
 
	DoCommandP(_remove_button_clicked ? CMD_REMOVE_SIGNAL_TRACK : CMD_BUILD_SIGNAL_TRACK,
 
			_remove_button_clicked ? STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE,
 
			CcPlaySound_CONSTRUCTION_RAIL,
 
			TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2);
 
	if (_remove_button_clicked) {
 
		Command<CMD_REMOVE_SIGNAL_TRACK>::Post(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
	} else {
 
		Command<CMD_BUILD_SIGNAL_TRACK>::Post(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE, CcPlaySound_CONSTRUCTION_RAIL,
 
				TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, {});
 
	}
 
}
 

	
 

	
 
/** Rail toolbar management class. */
 
struct BuildRailToolbarWindow : Window {
 
	RailType railtype;    ///< Rail type to build.
 
	int last_user_action; ///< Last started user action.
 

	
 
	BuildRailToolbarWindow(WindowDesc *desc, RailType railtype) : Window(desc)
 
	{
 
		this->InitNested(TRANSPORT_RAIL);
 
		this->SetupRailToolbar(railtype);
 
@@ -644,46 +654,45 @@ struct BuildRailToolbarWindow : Window {
 
				VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL);
 
				break;
 

	
 
			case WID_RAT_AUTORAIL:
 
				VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
 
				break;
 

	
 
			case WID_RAT_DEMOLISH:
 
				PlaceProc_DemolishArea(tile);
 
				break;
 

	
 
			case WID_RAT_BUILD_DEPOT:
 
				DoCommandP(CMD_BUILD_TRAIN_DEPOT, STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT,
 
						CcRailDepot, tile, _cur_railtype, _build_depot_direction);
 
				Command<CMD_BUILD_TRAIN_DEPOT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT, CcRailDepot, tile, _cur_railtype, _build_depot_direction, {});
 
				break;
 

	
 
			case WID_RAT_BUILD_WAYPOINT:
 
				PlaceRail_Waypoint(tile);
 
				break;
 

	
 
			case WID_RAT_BUILD_STATION:
 
				PlaceRail_Station(tile);
 
				break;
 

	
 
			case WID_RAT_BUILD_SIGNALS:
 
				VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
 
				break;
 

	
 
			case WID_RAT_BUILD_BRIDGE:
 
				PlaceRail_Bridge(tile, this);
 
				break;
 

	
 
			case WID_RAT_BUILD_TUNNEL:
 
				DoCommandP(CMD_BUILD_TUNNEL, STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRailTunnel, tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0);
 
				Command<CMD_BUILD_TUNNEL>::Post(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRailTunnel, tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, {});
 
				break;
 

	
 
			case WID_RAT_CONVERT_RAIL:
 
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
 
	{
 
@@ -707,53 +716,53 @@ struct BuildRailToolbarWindow : Window {
 
					HandleAutodirPlacement();
 
					break;
 

	
 
				case DDSP_BUILD_SIGNALS:
 
					HandleAutoSignalPlacement();
 
					break;
 

	
 
				case DDSP_DEMOLISH_AREA:
 
					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 
					break;
 

	
 
				case DDSP_CONVERT_RAIL:
 
					DoCommandP(CMD_CONVERT_RAIL, STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 1 << 6 : 0));
 
					Command<CMD_CONVERT_RAIL>::Post(STR_ERROR_CAN_T_CONVERT_RAIL, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 1 << 6 : 0), {});
 
					break;
 

	
 
				case DDSP_REMOVE_STATION:
 
				case DDSP_BUILD_STATION:
 
					if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) {
 
						/* Station */
 
						if (_remove_button_clicked) {
 
							DoCommandP(CMD_REMOVE_FROM_RAIL_STATION, STR_ERROR_CAN_T_REMOVE_PART_OF_STATION, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _ctrl_pressed ? 0 : 1);
 
							Command<CMD_REMOVE_FROM_RAIL_STATION>::Post(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _ctrl_pressed ? 0 : 1, {});
 
						} else {
 
							HandleStationPlacement(start_tile, end_tile);
 
						}
 
					} else {
 
						/* Waypoint */
 
						if (_remove_button_clicked) {
 
							DoCommandP(CMD_REMOVE_FROM_RAIL_WAYPOINT, STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _ctrl_pressed ? 0 : 1);
 
							Command<CMD_REMOVE_FROM_RAIL_WAYPOINT>::Post(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, end_tile, start_tile, _ctrl_pressed ? 0 : 1, {});
 
						} else {
 
							TileArea ta(start_tile, end_tile);
 
							uint32 p1 = _cur_railtype | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 6 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24;
 
							uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16;
 

	
 
							auto proc = [=](bool test, StationID to_join) -> bool {
 
								if (test) {
 
									return Command<CMD_BUILD_RAIL_WAYPOINT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_WAYPOINT>()), ta.tile, p1, p2, {}).Succeeded();
 
								} else {
 
									uint32 p2_final = p2;
 
									if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
									return DoCommandP(CMD_BUILD_RAIL_WAYPOINT, STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, ta.tile, p1, p2_final);
 
									return Command<CMD_BUILD_RAIL_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT, CcPlaySound_CONSTRUCTION_RAIL, ta.tile, p1, p2_final, {});
 
								}
 
							};
 

	
 
							ShowSelectWaypointIfNeeded(ta, proc);
 
						}
 
					}
 
					break;
 
			}
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
@@ -904,25 +913,25 @@ static void HandleStationPlacement(TileI
 
	if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength);
 

	
 
	uint32 p1 = _cur_railtype | _railstation.orientation << 6 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24;
 
	uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
 

	
 
	auto proc = [=](bool test, StationID to_join) -> bool {
 
		if (test) {
 
			return Command<CMD_BUILD_RAIL_STATION>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_RAIL_STATION>()), ta.tile, p1, p2, {}).Succeeded();
 
		} else {
 
			uint32 p2_final = p2;
 
			if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
			return DoCommandP(CMD_BUILD_RAIL_STATION, STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, ta.tile, p1, p2_final);
 
			return Command<CMD_BUILD_RAIL_STATION>::Post(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION, CcStation, ta.tile, p1, p2_final, {});
 
		}
 
	};
 

	
 
	ShowSelectStationIfNeeded(ta, proc);
 
}
 

	
 
/** Enum referring to the Hotkeys in the build rail station window */
 
enum BuildRalStationHotkeys {
 
	BRASHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string
 
};
 

	
 
struct BuildRailStationWindow : public PickerWindowBase {
src/road_gui.cpp
Show inline comments
 
@@ -23,24 +23,25 @@
 
#include "tunnelbridge.h"
 
#include "tunnelbridge_map.h"
 
#include "tilehighlight_func.h"
 
#include "company_base.h"
 
#include "hotkeys.h"
 
#include "road_gui.h"
 
#include "zoom_func.h"
 
#include "engine_base.h"
 
#include "strings_func.h"
 
#include "core/geometry_func.hpp"
 
#include "date_func.h"
 
#include "station_cmd.h"
 
#include "road_cmd.h"
 
#include "tunnelbridge_cmd.h"
 

	
 
#include "widgets/road_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
static void ShowRVStationPicker(Window *parent, RoadStopType rs);
 
static void ShowRoadDepotPicker(Window *parent);
 

	
 
static bool _remove_button_clicked;
 
@@ -118,25 +119,25 @@ void CcBuildRoadTunnel(const CommandCost
 

	
 
/**
 
 * If required, connects a new structure to an existing road or tram by building the missing roadbit.
 
 * @param tile Tile containing the structure to connect.
 
 * @param direction Direction to check.
 
 */
 
void ConnectRoadToStructure(TileIndex tile, DiagDirection direction)
 
{
 
	tile += TileOffsByDiagDir(direction);
 
	/* if there is a roadpiece just outside of the station entrance, build a connecting route */
 
	if (IsNormalRoadTile(tile)) {
 
		if (GetRoadBits(tile, GetRoadTramType(_cur_roadtype)) != ROAD_NONE) {
 
			DoCommandP(CMD_BUILD_ROAD, tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0);
 
			Command<CMD_BUILD_ROAD>::Post(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, {});
 
		}
 
	}
 
}
 

	
 
void CcRoadDepot(const CommandCost &result, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	if (result.Failed()) return;
 

	
 
	DiagDirection dir = (DiagDirection)GB(p1, 0, 2);
 
	if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
 
	if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
 
	ConnectRoadToStructure(tile, dir);
 
@@ -196,25 +197,25 @@ static void PlaceRoadStop(TileIndex star
 
		SetBit(p2, 1); // It's a drive-through stop.
 
		ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
 
	}
 
	p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4.
 

	
 
	auto proc = [=](bool test, StationID to_join) -> bool {
 
		if (test) {
 
			return Command<CMD_BUILD_ROAD_STOP>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_ROAD_STOP>()), ta.tile, p1, p2, {}).Succeeded();
 
		} else {
 
			uint32 p2_final = p2;
 
			if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join);
 

	
 
			return DoCommandP(CMD_BUILD_ROAD_STOP, err_msg, CcRoadStop, ta.tile, p1, p2_final);
 
			return Command<CMD_BUILD_ROAD_STOP>::Post(err_msg, CcRoadStop, ta.tile, p1, p2_final, {});
 
		}
 
	};
 

	
 
	ShowSelectStationIfNeeded(ta, proc);
 
}
 

	
 
/**
 
 * Callback for placing a bus station.
 
 * @param tile Position to place the station.
 
 */
 
static void PlaceRoad_BusStation(TileIndex tile)
 
{
 
@@ -557,43 +558,43 @@ struct BuildRoadToolbarWindow : Window {
 
			case WID_ROT_AUTOROAD:
 
				_place_road_flag = RF_NONE;
 
				if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
 
				if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
 
				VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
 
				break;
 

	
 
			case WID_ROT_DEMOLISH:
 
				PlaceProc_DemolishArea(tile);
 
				break;
 

	
 
			case WID_ROT_DEPOT:
 
				DoCommandP(CMD_BUILD_ROAD_DEPOT, this->rti->strings.err_depot, CcRoadDepot,
 
						tile, _cur_roadtype << 2 | _road_depot_orientation, 0);
 
				Command<CMD_BUILD_ROAD_DEPOT>::Post(this->rti->strings.err_depot, CcRoadDepot,
 
						tile, _cur_roadtype << 2 | _road_depot_orientation, 0, {});
 
				break;
 

	
 
			case WID_ROT_BUS_STATION:
 
				PlaceRoad_BusStation(tile);
 
				break;
 

	
 
			case WID_ROT_TRUCK_STATION:
 
				PlaceRoad_TruckStation(tile);
 
				break;
 

	
 
			case WID_ROT_BUILD_BRIDGE:
 
				PlaceRoad_Bridge(tile, this);
 
				break;
 

	
 
			case WID_ROT_BUILD_TUNNEL:
 
				DoCommandP(CMD_BUILD_TUNNEL, STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRoadTunnel,
 
						tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0);
 
				Command<CMD_BUILD_TUNNEL>::Post(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE, CcBuildRoadTunnel,
 
						tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, {});
 
				break;
 

	
 
			case WID_ROT_CONVERT_ROAD:
 
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_ROAD);
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
@@ -676,55 +677,59 @@ struct BuildRoadToolbarWindow : Window {
 
				case DDSP_PLACE_ROAD_Y_DIR:
 
				case DDSP_PLACE_AUTOROAD:
 
					/* Flag description:
 
					 * Use the first three bits (0x07) if dir == Y
 
					 * else use the last 2 bits (X dir has
 
					 * not the 3rd bit set) */
 

	
 
					/* Even if _cur_roadtype_id is a uint8 we only use 5 bits so
 
					 * we could ignore the last 3 bits and reuse them for other
 
					 * flags */
 
					_place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
 

	
 
					DoCommandP(_remove_button_clicked ? CMD_REMOVE_LONG_ROAD : CMD_BUILD_LONG_ROAD,
 
							_remove_button_clicked ? this->rti->strings.err_remove_road : this->rti->strings.err_build_road, CcPlaySound_CONSTRUCTION_OTHER,
 
							start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 10));
 
					if (_remove_button_clicked) {
 
						Command<CMD_REMOVE_LONG_ROAD>::Post(this->rti->strings.err_remove_road, CcPlaySound_CONSTRUCTION_OTHER,
 
								start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 10), {});
 
					} else {
 
						Command<CMD_BUILD_LONG_ROAD>::Post(this->rti->strings.err_build_road, CcPlaySound_CONSTRUCTION_OTHER,
 
								start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 10), {});
 
					}
 
					break;
 

	
 
				case DDSP_BUILD_BUSSTOP:
 
				case DDSP_REMOVE_BUSSTOP:
 
					if (this->IsWidgetLowered(WID_ROT_BUS_STATION)) {
 
						if (_remove_button_clicked) {
 
							TileArea ta(start_tile, end_tile);
 
							DoCommandP(CMD_REMOVE_ROAD_STOP, this->rti->strings.err_remove_station[ROADSTOP_BUS], CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS);
 
							Command<CMD_REMOVE_ROAD_STOP>::Post(this->rti->strings.err_remove_station[ROADSTOP_BUS], CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, {});
 
						} else {
 
							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_BUS, this->rti->strings.err_build_station[ROADSTOP_BUS]);
 
						}
 
					}
 
					break;
 

	
 
				case DDSP_BUILD_TRUCKSTOP:
 
				case DDSP_REMOVE_TRUCKSTOP:
 
					if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION)) {
 
						if (_remove_button_clicked) {
 
							TileArea ta(start_tile, end_tile);
 
							DoCommandP(CMD_REMOVE_ROAD_STOP, this->rti->strings.err_remove_station[ROADSTOP_TRUCK], CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK);
 
							Command<CMD_REMOVE_ROAD_STOP>::Post(this->rti->strings.err_remove_station[ROADSTOP_TRUCK], CcPlaySound_CONSTRUCTION_OTHER, ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, {});
 
						} else {
 
							PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, this->rti->strings.err_build_station[ROADSTOP_TRUCK]);
 
						}
 
					}
 
					break;
 

	
 
				case DDSP_CONVERT_ROAD:
 
					DoCommandP(CMD_CONVERT_ROAD, rti->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype);
 
					Command<CMD_CONVERT_ROAD>::Post(rti->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype, {});
 
					break;
 
			}
 
		}
 
	}
 

	
 
	void OnPlacePresize(Point pt, TileIndex tile) override
 
	{
 
		Command<CMD_BUILD_TUNNEL>::Do(DC_AUTO, tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, {});
 
		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
 
	}
 

	
 
	EventState OnCTRLStateChange() override
src/settings.cpp
Show inline comments
 
@@ -1541,25 +1541,25 @@ CommandCost CmdChangeCompanySetting(DoCo
 
/**
 
 * Top function to save the new value of an element of the Settings struct
 
 * @param index offset in the SettingDesc array of the Settings struct which
 
 * identifies the setting member we want to change
 
 * @param value new value of the setting
 
 * @param force_newgame force the newgame settings
 
 */
 
bool SetSettingValue(const IntSettingDesc *sd, int32 value, bool force_newgame)
 
{
 
	const IntSettingDesc *setting = sd->AsIntSetting();
 
	if ((setting->flags & SF_PER_COMPANY) != 0) {
 
		if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
 
			return DoCommandP(CMD_CHANGE_COMPANY_SETTING, 0, 0, value, setting->GetName());
 
			return Command<CMD_CHANGE_COMPANY_SETTING>::Post(0, 0, value, setting->GetName());
 
		}
 

	
 
		setting->ChangeValue(&_settings_client.company, value);
 
		return true;
 
	}
 

	
 
	/* If an item is company-based, we do not send it over the network
 
	 * (if any) to change. Also *hack*hack* we update the _newgame version
 
	 * of settings because changing a company-based setting in a game also
 
	 * changes its defaults. At least that is the convention we have chosen */
 
	if (setting->flags & SF_NO_NETWORK_SYNC) {
 
		if (_game_mode != GM_MENU) {
 
@@ -1567,25 +1567,25 @@ bool SetSettingValue(const IntSettingDes
 
		}
 
		setting->ChangeValue(&GetGameSettings(), value);
 
		return true;
 
	}
 

	
 
	if (force_newgame) {
 
		setting->ChangeValue(&_settings_newgame, value);
 
		return true;
 
	}
 

	
 
	/* send non-company-based settings over the network */
 
	if (!_networking || (_networking && _network_server)) {
 
		return DoCommandP(CMD_CHANGE_SETTING, 0, 0, value, setting->GetName());
 
		return Command<CMD_CHANGE_SETTING>::Post(0, 0, value, setting->GetName());
 
	}
 
	return false;
 
}
 

	
 
/**
 
 * Set the company settings for a new company to their default values.
 
 */
 
void SetDefaultCompanySettings(CompanyID cid)
 
{
 
	Company *c = Company::Get(cid);
 
	for (auto &desc : _company_settings) {
 
		const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
src/signs_cmd.cpp
Show inline comments
 
@@ -123,14 +123,14 @@ void CcPlaceSign(const CommandCost &resu
 
	ShowRenameSignWindow(Sign::Get(_new_sign_id));
 
	ResetObjectToPlace();
 
}
 

	
 
/**
 
 *
 
 * PlaceProc function, called when someone pressed the button if the
 
 *  sign-tool is selected
 
 * @param tile on which to place the sign
 
 */
 
void PlaceProc_Sign(TileIndex tile)
 
{
 
	DoCommandP(CMD_PLACE_SIGN, STR_ERROR_CAN_T_PLACE_SIGN_HERE, CcPlaceSign, tile, 0, 0);
 
	Command<CMD_PLACE_SIGN>::Post(STR_ERROR_CAN_T_PLACE_SIGN_HERE, CcPlaceSign, tile, 0, 0, {});
 
}
src/signs_gui.cpp
Show inline comments
 
@@ -17,24 +17,25 @@
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "map_func.h"
 
#include "viewport_func.h"
 
#include "querystring_gui.h"
 
#include "sortlist_type.h"
 
#include "stringfilter_type.h"
 
#include "string_func.h"
 
#include "core/geometry_func.hpp"
 
#include "hotkeys.h"
 
#include "transparency.h"
 
#include "gui.h"
 
#include "signs_cmd.h"
 

	
 
#include "widgets/sign_widget.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
#include "safeguards.h"
 

	
 
struct SignList {
 
	/**
 
	 * A GUIList contains signs and uses a StringFilter for filtering.
 
	 */
 
@@ -404,25 +405,25 @@ Window *ShowSignList()
 
	return AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
 
}
 

	
 
/**
 
 * Actually rename the sign.
 
 * @param index the sign to rename.
 
 * @param text  the new name.
 
 * @return true if the window will already be removed after returning.
 
 */
 
static bool RenameSign(SignID index, const char *text)
 
{
 
	bool remove = StrEmpty(text);
 
	DoCommandP(CMD_RENAME_SIGN, StrEmpty(text) ? STR_ERROR_CAN_T_DELETE_SIGN : STR_ERROR_CAN_T_CHANGE_SIGN_NAME, 0, index, 0, text);
 
	Command<CMD_RENAME_SIGN>::Post(StrEmpty(text) ? STR_ERROR_CAN_T_DELETE_SIGN : STR_ERROR_CAN_T_CHANGE_SIGN_NAME, 0, index, 0, text);
 
	return remove;
 
}
 

	
 
struct SignWindow : Window, SignList {
 
	QueryString name_editbox;
 
	SignID cur_sign;
 

	
 
	SignWindow(WindowDesc *desc, const Sign *si) : Window(desc), name_editbox(MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_SIGN_NAME_CHARS)
 
	{
 
		this->querystrings[WID_QES_TEXT] = &this->name_editbox;
 
		this->name_editbox.caption = STR_EDIT_SIGN_CAPTION;
 
		this->name_editbox.cancel_button = WID_QES_CANCEL;
src/station_gui.cpp
Show inline comments
 
@@ -22,24 +22,25 @@
 
#include "viewport_func.h"
 
#include "widgets/dropdown_func.h"
 
#include "station_base.h"
 
#include "waypoint_base.h"
 
#include "tilehighlight_func.h"
 
#include "company_base.h"
 
#include "sortlist_type.h"
 
#include "core/geometry_func.hpp"
 
#include "vehiclelist.h"
 
#include "town.h"
 
#include "linkgraph/linkgraph.h"
 
#include "zoom_func.h"
 
#include "station_cmd.h"
 

	
 
#include "widgets/station_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include <set>
 
#include <vector>
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Calculates and draws the accepted or supplied cargo around the selected tile(s)
 
@@ -1938,25 +1939,25 @@ struct StationViewWindow : public Window
 
				}
 
				this->ReInit(0, height_change * FONT_HEIGHT_NORMAL);
 
				break;
 
			}
 

	
 
			case WID_SV_RENAME:
 
				SetDParam(0, this->window_number);
 
				ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS,
 
						this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
 
				break;
 

	
 
			case WID_SV_CLOSE_AIRPORT:
 
				DoCommandP(CMD_OPEN_CLOSE_AIRPORT, 0, this->window_number, 0);
 
				Command<CMD_OPEN_CLOSE_AIRPORT>::Post(0, this->window_number, 0, {});
 
				break;
 

	
 
			case WID_SV_TRAINS:   // Show list of scheduled trains to this station
 
			case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station
 
			case WID_SV_SHIPS:    // Show list of scheduled ships to this station
 
			case WID_SV_PLANES: { // Show list of scheduled aircraft to this station
 
				Owner owner = Station::Get(this->window_number)->owner;
 
				ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number);
 
				break;
 
			}
 

	
 
			case WID_SV_SORT_BY: {
 
@@ -2075,25 +2076,25 @@ struct StationViewWindow : public Window
 
	{
 
		if (widget == WID_SV_SORT_BY) {
 
			this->SelectSortBy(index);
 
		} else {
 
			this->SelectGroupBy(index);
 
		}
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		DoCommandP(CMD_RENAME_STATION, STR_ERROR_CAN_T_RENAME_STATION, 0, this->window_number, 0, str);
 
		Command<CMD_RENAME_STATION>::Post(STR_ERROR_CAN_T_RENAME_STATION, 0, this->window_number, 0, str);
 
	}
 

	
 
	void OnResize() override
 
	{
 
		this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
 
	}
 

	
 
	/**
 
	 * Some data on this window has become invalid. Invalidate the cache for the given cargo if necessary.
 
	 * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo data.
 
	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
 
	 */
src/story_gui.cpp
Show inline comments
 
@@ -16,24 +16,25 @@
 
#include "core/geometry_func.hpp"
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "widgets/dropdown_type.h"
 
#include "widgets/dropdown_func.h"
 
#include "sortlist_type.h"
 
#include "goal_base.h"
 
#include "viewport_func.h"
 
#include "window_func.h"
 
#include "company_base.h"
 
#include "tilehighlight_func.h"
 
#include "vehicle_base.h"
 
#include "story_cmd.h"
 

	
 
#include "widgets/story_widget.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
#include <numeric>
 

	
 
#include "safeguards.h"
 

	
 
static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor);
 

	
 
@@ -557,25 +558,25 @@ protected:
 
				break;
 

	
 
			case SPET_GOAL:
 
				ShowGoalsList((CompanyID)this->window_number);
 
				break;
 

	
 
			case SPET_BUTTON_PUSH:
 
				if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
 
				this->active_button_id = pe.index;
 
				this->SetTimeout();
 
				this->SetWidgetDirty(WID_SB_PAGE_PANEL);
 

	
 
				DoCommandP(CMD_STORY_PAGE_BUTTON, 0, pe.index, 0);
 
				Command<CMD_STORY_PAGE_BUTTON>::Post(0, pe.index, 0, {});
 
				break;
 

	
 
			case SPET_BUTTON_TILE:
 
				if (this->active_button_id == pe.index) {
 
					ResetObjectToPlace();
 
					this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
 
				} else {
 
					CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
 
					SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
 
					this->active_button_id = pe.index;
 
				}
 
				this->SetWidgetDirty(WID_SB_PAGE_PANEL);
 
@@ -912,44 +913,44 @@ public:
 
	}
 

	
 
	void OnPlaceObject(Point pt, TileIndex tile) override
 
	{
 
		const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
 
		if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
 
			ResetObjectToPlace();
 
			this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
 
			this->SetWidgetDirty(WID_SB_PAGE_PANEL);
 
			return;
 
		}
 

	
 
		DoCommandP(CMD_STORY_PAGE_BUTTON, tile, pe->index, 0);
 
		Command<CMD_STORY_PAGE_BUTTON>::Post(tile, pe->index, 0, {});
 
		ResetObjectToPlace();
 
	}
 

	
 
	bool OnVehicleSelect(const Vehicle *v) override
 
	{
 
		const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
 
		if (pe == nullptr || pe->type != SPET_BUTTON_VEHICLE) {
 
			ResetObjectToPlace();
 
			this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
 
			this->SetWidgetDirty(WID_SB_PAGE_PANEL);
 
			return false;
 
		}
 

	
 
		/* Check that the vehicle matches the requested type */
 
		StoryPageButtonData data{ pe->referenced_id };
 
		VehicleType wanted_vehtype = data.GetVehicleType();
 
		if (wanted_vehtype != VEH_INVALID && wanted_vehtype != v->type) return false;
 

	
 
		DoCommandP(CMD_STORY_PAGE_BUTTON, 0, pe->index, v->index);
 
		Command<CMD_STORY_PAGE_BUTTON>::Post(0, pe->index, v->index, {});
 
		ResetObjectToPlace();
 
		return true;
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
 
		this->SetWidgetDirty(WID_SB_PAGE_PANEL);
 
	}
 
};
 

	
 
GUIStoryPageList::SortFunction * const StoryBookWindow::page_sorter_funcs[] = {
src/terraform_gui.cpp
Show inline comments
 
@@ -26,24 +26,26 @@
 
#include "landscape_type.h"
 
#include "tilehighlight_func.h"
 
#include "strings_func.h"
 
#include "newgrf_object.h"
 
#include "object.h"
 
#include "hotkeys.h"
 
#include "engine_base.h"
 
#include "terraform_gui.h"
 
#include "terraform_cmd.h"
 
#include "zoom_func.h"
 
#include "rail_cmd.h"
 
#include "landscape_cmd.h"
 
#include "terraform_cmd.h"
 
#include "object_cmd.h"
 

	
 
#include "widgets/terraform_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
void CcTerraform(const CommandCost &result, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
{
 
	if (result.Succeeded()) {
 
		if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
 
	} else {
 
@@ -54,25 +56,25 @@ void CcTerraform(const CommandCost &resu
 

	
 

	
 
/** Scenario editor command that generates desert areas */
 
static void GenerateDesertArea(TileIndex end, TileIndex start)
 
{
 
	if (_game_mode != GM_EDITOR) return;
 

	
 
	Backup<bool> old_generating_world(_generating_world, true, FILE_LINE);
 

	
 
	TileArea ta(start, end);
 
	for (TileIndex tile : ta) {
 
		SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_NORMAL : TROPICZONE_DESERT);
 
		DoCommandP(CMD_LANDSCAPE_CLEAR, tile, 0, 0);
 
		Command<CMD_LANDSCAPE_CLEAR>::Post(tile, 0, 0, {});
 
		MarkTileDirtyByTile(tile);
 
	}
 
	old_generating_world.Restore();
 
	InvalidateWindowClassesData(WC_TOWN_VIEW, 0);
 
}
 

	
 
/** Scenario editor command that generates rocky areas */
 
static void GenerateRockyArea(TileIndex end, TileIndex start)
 
{
 
	if (_game_mode != GM_EDITOR) return;
 

	
 
	bool success = false;
 
@@ -109,34 +111,34 @@ static void GenerateRockyArea(TileIndex 
 
 */
 
bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
 
{
 
	if (!_settings_game.construction.freeform_edges) {
 
		/* When end_tile is MP_VOID, the error tile will not be visible to the
 
		 * user. This happens when terraforming at the southern border. */
 
		if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0);
 
		if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1);
 
	}
 

	
 
	switch (proc) {
 
		case DDSP_DEMOLISH_AREA:
 
			DoCommandP(CMD_CLEAR_AREA, STR_ERROR_CAN_T_CLEAR_THIS_AREA, CcPlaySound_EXPLOSION, end_tile, start_tile, _ctrl_pressed ? 1 : 0);
 
			Command<CMD_CLEAR_AREA>::Post(STR_ERROR_CAN_T_CLEAR_THIS_AREA, CcPlaySound_EXPLOSION, end_tile, start_tile, _ctrl_pressed ? 1 : 0, {});
 
			break;
 
		case DDSP_RAISE_AND_LEVEL_AREA:
 
			DoCommandP(CMD_LEVEL_LAND, STR_ERROR_CAN_T_RAISE_LAND_HERE, CcTerraform, end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0));
 
			Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_RAISE_LAND_HERE, CcTerraform, end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), {});
 
			break;
 
		case DDSP_LOWER_AND_LEVEL_AREA:
 
			DoCommandP(CMD_LEVEL_LAND, STR_ERROR_CAN_T_LOWER_LAND_HERE, CcTerraform, end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0));
 
			Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LOWER_LAND_HERE, CcTerraform, end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), {});
 
			break;
 
		case DDSP_LEVEL_AREA:
 
			DoCommandP(CMD_LEVEL_LAND, STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0));
 
			Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), {});
 
			break;
 
		case DDSP_CREATE_ROCKS:
 
			GenerateRockyArea(end_tile, start_tile);
 
			break;
 
		case DDSP_CREATE_DESERT:
 
			GenerateDesertArea(end_tile, start_tile);
 
			break;
 
		default:
 
			return false;
 
	}
 

	
 
	return true;
 
@@ -232,25 +234,25 @@ struct TerraformToolbarWindow : Window {
 
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA);
 
				break;
 

	
 
			case WID_TT_LEVEL_LAND: // Level land button
 
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
 
				break;
 

	
 
			case WID_TT_DEMOLISH: // Demolish aka dynamite button
 
				PlaceProc_DemolishArea(tile);
 
				break;
 

	
 
			case WID_TT_BUY_LAND: // Buy land button
 
				DoCommandP(CMD_BUILD_OBJECT, STR_ERROR_CAN_T_PURCHASE_THIS_LAND, CcPlaySound_CONSTRUCTION_RAIL, tile, OBJECT_OWNED_LAND, 0);
 
				Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_PURCHASE_THIS_LAND, CcPlaySound_CONSTRUCTION_RAIL, tile, OBJECT_OWNED_LAND, 0, {});
 
				break;
 

	
 
			case WID_TT_PLACE_SIGN: // Place sign button
 
				PlaceProc_Sign(tile);
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
 
	{
 
@@ -389,25 +391,25 @@ static byte _terraform_size = 1;
 
 * tiles in the selection to that height.
 
 * @todo : Incorporate into game itself to allow for ingame raising/lowering of
 
 *         larger chunks at the same time OR remove altogether, as we have 'level land' ?
 
 * @param tile The top-left tile where the terraforming will start
 
 * @param mode 1 for raising, 0 for lowering land
 
 */
 
static void CommonRaiseLowerBigLand(TileIndex tile, int mode)
 
{
 
	if (_terraform_size == 1) {
 
		StringID msg =
 
			mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE;
 

	
 
		DoCommandP(CMD_TERRAFORM_LAND, msg, CcTerraform, tile, SLOPE_N, (uint32)mode);
 
		Command<CMD_TERRAFORM_LAND>::Post(msg, CcTerraform, tile, SLOPE_N, (uint32)mode, {});
 
	} else {
 
		assert(_terraform_size != 0);
 
		TileArea ta(tile, _terraform_size, _terraform_size);
 
		ta.ClampToMap();
 

	
 
		if (ta.w == 0 || ta.h == 0) return;
 

	
 
		if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
 

	
 
		uint h;
 
		if (mode != 0) {
 
			/* Raise land */
 
@@ -416,25 +418,25 @@ static void CommonRaiseLowerBigLand(Tile
 
				h = std::min(h, TileHeight(tile2));
 
			}
 
		} else {
 
			/* Lower land */
 
			h = 0;
 
			for (TileIndex tile2 : ta) {
 
				h = std::max(h, TileHeight(tile2));
 
			}
 
		}
 

	
 
		for (TileIndex tile2 : ta) {
 
			if (TileHeight(tile2) == h) {
 
				DoCommandP(CMD_TERRAFORM_LAND, tile2, SLOPE_N, (uint32)mode);
 
				Command<CMD_TERRAFORM_LAND>::Post(tile2, SLOPE_N, (uint32)mode, {});
 
			}
 
		}
 
	}
 
}
 

	
 
static const int8 _multi_terraform_coords[][2] = {
 
	{  0, -2},
 
	{  4,  0}, { -4,  0}, {  0,  2},
 
	{ -8,  2}, { -4,  4}, {  0,  6}, {  4,  4}, {  8,  2},
 
	{-12,  0}, { -8, -2}, { -4, -4}, {  0, -6}, {  4, -4}, {  8, -2}, { 12,  0},
 
	{-16,  2}, {-12,  4}, { -8,  6}, { -4,  8}, {  0, 10}, {  4,  8}, {  8,  6}, { 12,  4}, { 16,  2},
 
	{-20,  0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, {  0,-10}, {  4, -8}, {  8, -6}, { 12, -4}, { 16, -2}, { 20,  0},
src/timetable_gui.cpp
Show inline comments
 
@@ -13,24 +13,25 @@
 
#include "window_gui.h"
 
#include "window_func.h"
 
#include "textbuf_gui.h"
 
#include "strings_func.h"
 
#include "vehicle_base.h"
 
#include "string_func.h"
 
#include "gfx_func.h"
 
#include "company_func.h"
 
#include "date_func.h"
 
#include "date_gui.h"
 
#include "vehicle_gui.h"
 
#include "settings_type.h"
 
#include "timetable_cmd.h"
 

	
 
#include "widgets/timetable_widget.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/** Container for the arrival/departure dates of a vehicle */
 
struct TimetableArrivalDeparture {
 
	Ticks arrival;   ///< The arrival time
 
	Ticks departure; ///< The departure time
 
@@ -133,25 +134,25 @@ static void FillTimetableArrivalDepartur
 
		table[i].arrival = sum;
 
	}
 
}
 

	
 

	
 
/**
 
 * Callback for when a time has been chosen to start the time table
 
 * @param w the window related to the setting of the date
 
 * @param date the actually chosen date
 
 */
 
static void ChangeTimetableStartCallback(const Window *w, Date date)
 
{
 
	DoCommandP(CMD_SET_TIMETABLE_START, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, w->window_number, date);
 
	Command<CMD_SET_TIMETABLE_START>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, w->window_number, date, {});
 
}
 

	
 

	
 
struct TimetableWindow : Window {
 
	int sel_index;
 
	const Vehicle *vehicle; ///< Vehicle monitored by the window.
 
	bool show_expected;     ///< Whether we show expected arrival or scheduled
 
	uint deparr_time_width; ///< The width of the departure/arrival time
 
	uint deparr_abbr_width; ///< The width of the departure/arrival abbreviation
 
	Scrollbar *vscroll;
 
	bool query_is_speed_query; ///< The currently open query window is a speed query and not a time query.
 

	
 
@@ -569,43 +570,43 @@ struct TimetableWindow : Window {
 
						SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->GetMaxSpeed()));
 
						current = STR_JUST_INT;
 
					}
 
				}
 

	
 
				this->query_is_speed_query = true;
 
				ShowQueryString(current, STR_TIMETABLE_CHANGE_SPEED, 31, this, CS_NUMERAL, QSF_NONE);
 
				break;
 
			}
 

	
 
			case WID_VT_CLEAR_TIME: { // Clear waiting time.
 
				uint32 p1 = PackTimetableArgs(v, this->sel_index, false);
 
				DoCommandP(CMD_CHANGE_TIMETABLE, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (TileIndex)0, p1, 0);
 
				Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, 0, {});
 
				break;
 
			}
 

	
 
			case WID_VT_CLEAR_SPEED: { // Clear max speed button.
 
				uint32 p1 = PackTimetableArgs(v, this->sel_index, true);
 
				DoCommandP(CMD_CHANGE_TIMETABLE, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (TileIndex)0, p1, UINT16_MAX);
 
				Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, UINT16_MAX, {});
 
				break;
 
			}
 

	
 
			case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter.
 
				DoCommandP(CMD_SET_VEHICLE_ON_TIME, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (TileIndex)0, v->index, 0);
 
				Command<CMD_SET_VEHICLE_ON_TIME>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, v->index, 0, {});
 
				break;
 

	
 
			case WID_VT_AUTOFILL: { // Autofill the timetable.
 
				uint32 p2 = 0;
 
				if (!HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(p2, 0);
 
				if (_ctrl_pressed) SetBit(p2, 1);
 
				DoCommandP(CMD_AUTOFILL_TIMETABLE, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (TileIndex)0, v->index, p2);
 
				Command<CMD_AUTOFILL_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, v->index, p2, {});
 
				break;
 
			}
 

	
 
			case WID_VT_EXPECTED:
 
				this->show_expected = !this->show_expected;
 
				break;
 

	
 
			case WID_VT_SHARED_ORDER_LIST:
 
				ShowVehicleListWindow(v);
 
				break;
 
		}
 

	
 
@@ -620,25 +621,25 @@ struct TimetableWindow : Window {
 

	
 
		uint32 p1 = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query);
 

	
 
		uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10);
 
		if (this->query_is_speed_query) {
 
			val = ConvertDisplaySpeedToKmhishSpeed(val);
 
		} else {
 
			if (!_settings_client.gui.timetable_in_ticks) val *= DAY_TICKS;
 
		}
 

	
 
		uint32 p2 = std::min<uint32>(val, UINT16_MAX);
 

	
 
		DoCommandP(CMD_CHANGE_TIMETABLE, STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, p2);
 
		Command<CMD_CHANGE_TIMETABLE>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, 0, p1, p2, {});
 
	}
 

	
 
	void OnResize() override
 
	{
 
		/* Update the scroll bar */
 
		this->vscroll->SetCapacityFromWidget(this, WID_VT_TIMETABLE_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
 
	}
 

	
 
	/**
 
	 * Update the selection state of the arrival/departure data
 
	 */
 
	void UpdateSelectionStates()
src/toolbar_gui.cpp
Show inline comments
 
@@ -40,24 +40,25 @@
 
#include "linkgraph/linkgraph_gui.h"
 
#include "newgrf_debug.h"
 
#include "hotkeys.h"
 
#include "engine_base.h"
 
#include "highscore.h"
 
#include "game/game.hpp"
 
#include "goal_base.h"
 
#include "story_base.h"
 
#include "toolbar_gui.h"
 
#include "framerate_type.h"
 
#include "guitimer_func.h"
 
#include "screenshot_gui.h"
 
#include "misc_cmd.h"
 

	
 
#include "widgets/toolbar_widget.h"
 

	
 
#include "network/network.h"
 
#include "network/network_gui.h"
 
#include "network/network_func.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
/** Width of the toolbar, shared by statusbar. */
 
uint _toolbar_width = 0;
 
@@ -256,25 +257,25 @@ static CallBackFunction SelectSignTool()
 
	} else {
 
		SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
 
		return CBF_PLACE_SIGN;
 
	}
 
}
 

	
 
/* --- Pausing --- */
 

	
 
static CallBackFunction ToolbarPauseClick(Window *w)
 
{
 
	if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
 

	
 
	if (DoCommandP(CMD_PAUSE, 0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED)) {
 
	if (Command<CMD_PAUSE>::Post(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, {})) {
 
		if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
 
	}
 
	return CBF_NONE;
 
}
 

	
 
/**
 
 * Toggle fast forward mode.
 
 *
 
 * @param w Unused.
 
 * @return #CBF_NONE
 
 */
 
static CallBackFunction ToolbarFastForwardClick(Window *w)
src/town_gui.cpp
Show inline comments
 
@@ -24,24 +24,25 @@
 
#include "sortlist_type.h"
 
#include "road_cmd.h"
 
#include "landscape.h"
 
#include "querystring_gui.h"
 
#include "window_func.h"
 
#include "townname_func.h"
 
#include "core/backup_type.hpp"
 
#include "core/geometry_func.hpp"
 
#include "genworld.h"
 
#include "stringfilter_type.h"
 
#include "widgets/dropdown_func.h"
 
#include "town_kdtree.h"
 
#include "town_cmd.h"
 

	
 
#include "widgets/town_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc);
 

	
 
typedef GUIList<const Town*> GUITownList;
 

	
 
static const NWidgetPart _nested_town_authority_widgets[] = {
 
@@ -278,25 +279,25 @@ public:
 

	
 
				y = GetNthSetBit(GetMaskOfTownActions(nullptr, _local_company, this->town), y + this->vscroll->GetPosition() - 1);
 
				if (y >= 0) {
 
					this->sel_index = y;
 
					this->SetDirty();
 
				}
 
				/* When double-clicking, continue */
 
				if (click_count == 1 || y < 0) break;
 
				FALLTHROUGH;
 
			}
 

	
 
			case WID_TA_EXECUTE:
 
				DoCommandP(CMD_DO_TOWN_ACTION, STR_ERROR_CAN_T_DO_THIS, this->town->xy, this->window_number, this->sel_index);
 
				Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, this->window_number, this->sel_index, {});
 
				break;
 
		}
 
	}
 

	
 
	void OnHundredthTick() override
 
	{
 
		this->SetDirty();
 
	}
 
};
 

	
 
static WindowDesc _town_authority_desc(
 
	WDP_AUTO, "view_town_authority", 317, 222,
 
@@ -465,30 +466,30 @@ public:
 
				SetViewportCatchmentTown(Town::Get(this->window_number), !this->IsWidgetLowered(WID_TV_CATCHMENT));
 
				break;
 

	
 
			case WID_TV_EXPAND: { // expand town - only available on Scenario editor
 
				/* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */
 
				static bool _warn_town_no_roads = false;
 

	
 
				if (!_settings_game.economy.allow_town_roads && !_warn_town_no_roads) {
 
					ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, WL_WARNING);
 
					_warn_town_no_roads = true;
 
				}
 

	
 
				DoCommandP(CMD_EXPAND_TOWN, STR_ERROR_CAN_T_EXPAND_TOWN, (TileIndex)0, this->window_number, 0);
 
				Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, 0, this->window_number, 0, {});
 
				break;
 
			}
 

	
 
			case WID_TV_DELETE: // delete town - only available on Scenario editor
 
				DoCommandP(CMD_DELETE_TOWN, STR_ERROR_TOWN_CAN_T_DELETE, (TileIndex)0, this->window_number, 0);
 
				Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, 0, this->window_number, 0, {});
 
				break;
 
		}
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		switch (widget) {
 
			case WID_TV_INFO:
 
				size->height = GetDesiredInfoHeight(size->width);
 
				break;
 
		}
 
	}
 
@@ -552,25 +553,25 @@ public:
 
	void OnInvalidateData(int data = 0, bool gui_scope = true) override
 
	{
 
		if (!gui_scope) return;
 
		/* Called when setting station noise or required cargoes have changed, in order to resize the window */
 
		this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
 
		this->ResizeWindowAsNeeded();
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		DoCommandP(CMD_RENAME_TOWN, STR_ERROR_CAN_T_RENAME_TOWN, 0, this->window_number, 0, str);
 
		Command<CMD_RENAME_TOWN>::Post(STR_ERROR_CAN_T_RENAME_TOWN, 0, this->window_number, 0, str);
 
	}
 
};
 

	
 
static const NWidgetPart _nested_town_game_view_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
 
		NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
 
		NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
		NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
 
		NWidget(WWT_SHADEBOX, COLOUR_BROWN),
 
		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
 
		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
 
@@ -1153,25 +1154,25 @@ public:
 
	{
 
		std::string name;
 

	
 
		if (!this->townnamevalid) {
 
			name = this->townname_editbox.text.buf;
 
		} else {
 
			/* If user changed the name, send it */
 
			char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH];
 
			GetTownName(buf, &this->params, this->townnameparts, lastof(buf));
 
			if (strcmp(buf, this->townname_editbox.text.buf) != 0) name = this->townname_editbox.text.buf;
 
		}
 

	
 
		bool success = DoCommandP(CMD_FOUND_TOWN, errstr, cc,
 
		bool success = Command<CMD_FOUND_TOWN>::Post(errstr, cc,
 
				tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6, townnameparts, name);
 

	
 
		/* Rerandomise name, if success and no cost-estimation. */
 
		if (success && !_shift_pressed) this->RandomTownName();
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_TF_NEW_TOWN:
 
				HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT);
 
				break;
src/train_cmd.cpp
Show inline comments
 
@@ -26,24 +26,25 @@
 
#include "newgrf_station.h"
 
#include "effectvehicle_func.h"
 
#include "network/network.h"
 
#include "spritecache.h"
 
#include "core/random_func.hpp"
 
#include "company_base.h"
 
#include "newgrf.h"
 
#include "order_backup.h"
 
#include "zoom_func.h"
 
#include "newgrf_debug.h"
 
#include "framerate_type.h"
 
#include "train_cmd.h"
 
#include "misc_cmd.h"
 

	
 
#include "table/strings.h"
 
#include "table/train_sprites.h"
 

	
 
#include "safeguards.h"
 

	
 
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
 
static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
 
bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
 
static TileIndex TrainApproachingCrossingTile(const Train *v);
 
static void CheckIfTrainNeedsService(Train *v);
 
static void CheckNextTrainTile(Train *v);
 
@@ -78,25 +79,25 @@ void CheckTrainsLengths()
 
		if (v->First() == v && !(v->vehstatus & VS_CRASHED)) {
 
			for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) {
 
				if (u->track != TRACK_BIT_DEPOT) {
 
					if ((w->track != TRACK_BIT_DEPOT &&
 
							std::max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
 
							(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
 
						SetDParam(0, v->index);
 
						SetDParam(1, v->owner);
 
						ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL);
 

	
 
						if (!_networking && first) {
 
							first = false;
 
							DoCommandP(CMD_PAUSE, 0, PM_PAUSED_ERROR, 1);
 
							Command<CMD_PAUSE>::Post(0, PM_PAUSED_ERROR, 1, {});
 
						}
 
						/* Break so we warn only once for each train. */
 
						break;
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Recalculates the cached stuff of a train. Should be called each time a vehicle is added
src/train_gui.cpp
Show inline comments
 
@@ -5,24 +5,25 @@
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file train_gui.cpp GUI for trains. */
 

	
 
#include "stdafx.h"
 
#include "window_gui.h"
 
#include "command_func.h"
 
#include "train.h"
 
#include "strings_func.h"
 
#include "vehicle_func.h"
 
#include "zoom_func.h"
 
#include "train_cmd.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Callback for building wagons.
 
 * @param result The result of the command.
 
 * @param cmd Unused.
 
 * @param tile   The tile the command was executed on.
 
 * @param p1 Additional data for the command (for the #CommandProc)
 
 * @param p2 Additional data for the command (for the #CommandProc)
 
@@ -36,25 +37,25 @@ void CcBuildWagon(const CommandCost &res
 
	const Vehicle *found = nullptr;
 
	for (const Train *t : Train::Iterate()) {
 
		if (t->IsFrontEngine() && t->tile == tile && t->IsStoppedInDepot()) {
 
			if (found != nullptr) return; // must be exactly one.
 
			found = t;
 
		}
 
	}
 

	
 
	/* if we found a loco, */
 
	if (found != nullptr) {
 
		found = found->Last();
 
		/* put the new wagon at the end of the loco. */
 
		DoCommandP(CMD_MOVE_RAIL_VEHICLE, 0, _new_vehicle_id, found->index);
 
		Command<CMD_MOVE_RAIL_VEHICLE>::Post(0, _new_vehicle_id, found->index, {});
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	}
 
}
 

	
 
/**
 
 * Highlight the position where a rail vehicle is dragged over by drawing a light gray background.
 
 * @param px        The current x position to draw from.
 
 * @param max_width The maximum space available to draw.
 
 * @param selection Selected vehicle that is dragged.
 
 * @param chain     Whether a whole chain is dragged.
 
 * @return The width of the highlight mark.
 
 */
src/tree_gui.cpp
Show inline comments
 
@@ -10,24 +10,25 @@
 
#include "stdafx.h"
 
#include "window_gui.h"
 
#include "gfx_func.h"
 
#include "tilehighlight_func.h"
 
#include "company_func.h"
 
#include "company_base.h"
 
#include "command_func.h"
 
#include "core/random_func.hpp"
 
#include "sound_func.h"
 
#include "strings_func.h"
 
#include "zoom_func.h"
 
#include "tree_map.h"
 
#include "tree_cmd.h"
 

	
 
#include "widgets/tree_widget.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 
#include "table/tree_land.h"
 

	
 
#include "safeguards.h"
 

	
 
void PlaceTreesRandomly();
 
uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone);
 

	
 
@@ -221,35 +222,35 @@ public:
 
			VpStartDragging(DDSP_PLANT_TREES);
 
		}
 
	}
 

	
 
	void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
 
	{
 
		if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL) {
 
			VpSelectTilesWithMethod(pt.x, pt.y, select_method);
 
		} else {
 
			TileIndex tile = TileVirtXY(pt.x, pt.y);
 

	
 
			if (this->mode == PM_NORMAL) {
 
				DoCommandP(CMD_PLANT_TREE, tile, this->tree_to_plant, tile);
 
				Command<CMD_PLANT_TREE>::Post(tile, this->tree_to_plant, tile, {});
 
			} else {
 
				this->DoPlantForest(tile);
 
			}
 
		}
 
	}
 

	
 
	void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
 
	{
 
		if (_game_mode != GM_EDITOR && this->mode == PM_NORMAL && pt.x != -1 && select_proc == DDSP_PLANT_TREES) {
 
			DoCommandP(CMD_PLANT_TREE, STR_ERROR_CAN_T_PLANT_TREE_HERE, end_tile, this->tree_to_plant, start_tile);
 
			Command<CMD_PLANT_TREE>::Post(STR_ERROR_CAN_T_PLANT_TREE_HERE, end_tile, this->tree_to_plant, start_tile, {});
 
		}
 
	}
 

	
 
	void OnPlaceObjectAbort() override
 
	{
 
		this->tree_to_plant = -1;
 
		this->UpdateMode();
 
	}
 
};
 

	
 
/**
 
 * Make widgets for the current available tree types.
src/vehicle_gui.cpp
Show inline comments
 
@@ -29,24 +29,27 @@
 
#include "widgets/dropdown_func.h"
 
#include "timetable.h"
 
#include "articulated_vehicles.h"
 
#include "spritecache.h"
 
#include "core/geometry_func.hpp"
 
#include "company_base.h"
 
#include "engine_func.h"
 
#include "station_base.h"
 
#include "tilehighlight_func.h"
 
#include "zoom_func.h"
 
#include "depot_cmd.h"
 
#include "vehicle_cmd.h"
 
#include "order_cmd.h"
 
#include "roadveh_cmd.h"
 
#include "train_cmd.h"
 

	
 
#include "safeguards.h"
 

	
 

	
 
BaseVehicleListWindow::GroupBy _grouping[VLT_END][VEH_COMPANY_END];
 
Sorting _sorting[BaseVehicleListWindow::GB_END];
 

	
 
static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNumberSorter;
 
static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNameSorter;
 
static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleAgeSorter;
 
static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleProfitThisYearSorter;
 
static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleProfitLastYearSorter;
 
@@ -1026,27 +1029,27 @@ struct RefitWindow : public Window {
 
				this->InvalidateData(1);
 

	
 
				if (click_count == 1) break;
 
				FALLTHROUGH;
 
			}
 

	
 
			case WID_VR_REFIT: // refit button
 
				if (this->cargo != nullptr) {
 
					const Vehicle *v = Vehicle::Get(this->window_number);
 

	
 
					if (this->order == INVALID_VEH_ORDER_ID) {
 
						bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX;
 
						if (DoCommandP(CMD_REFIT_VEHICLE, GetCmdRefitVehMsg(v), v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16) && delete_window) this->Close();
 
						if (Command<CMD_REFIT_VEHICLE>::Post(GetCmdRefitVehMsg(v), v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16, {}) && delete_window) this->Close();
 
					} else {
 
						if (DoCommandP(CMD_ORDER_REFIT, v->tile, v->index, this->cargo->cargo | this->order << 16)) this->Close();
 
						if (Command<CMD_ORDER_REFIT>::Post(v->tile, v->index, this->cargo->cargo | this->order << 16, {})) this->Close();
 
					}
 
				}
 
				break;
 
		}
 
	}
 

	
 
	void OnMouseDrag(Point pt, int widget) override
 
	{
 
		switch (widget) {
 
			case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image.
 
				if (this->order != INVALID_VEH_ORDER_ID) break;
 
				NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_VR_VEHICLE_PANEL_DISPLAY);
 
@@ -1887,50 +1890,50 @@ public:
 

	
 
			case WID_VL_AVAILABLE_VEHICLES:
 
				ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
 
				break;
 

	
 
			case WID_VL_MANAGE_VEHICLES_DROPDOWN: {
 
				ShowDropDownList(this, this->BuildActionDropdownList(VehicleListIdentifier::UnPack(this->window_number).type == VL_STANDARD, false), 0, WID_VL_MANAGE_VEHICLES_DROPDOWN);
 
				break;
 
			}
 

	
 
			case WID_VL_STOP_ALL:
 
			case WID_VL_START_ALL:
 
				DoCommandP(CMD_MASS_START_STOP, 0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number);
 
				Command<CMD_MASS_START_STOP>::Post(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number, {});
 
				break;
 
		}
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_VL_GROUP_BY_PULLDOWN:
 
				this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
 
				break;
 

	
 
			case WID_VL_SORT_BY_PULLDOWN:
 
				this->vehgroups.SetSortType(index);
 
				break;
 

	
 
			case WID_VL_MANAGE_VEHICLES_DROPDOWN:
 
				assert(this->vehicles.size() != 0);
 

	
 
				switch (index) {
 
					case ADI_REPLACE: // Replace window
 
						ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype);
 
						break;
 
					case ADI_SERVICE: // Send for servicing
 
					case ADI_DEPOT: // Send to Depots
 
						DoCommandP(CMD_SEND_VEHICLE_TO_DEPOT, GetCmdSendToDepotMsg(this->vli.vtype), 0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number);
 
						Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), 0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, {});
 
						break;
 

	
 
					default: NOT_REACHED();
 
				}
 
				break;
 

	
 
			default: NOT_REACHED();
 
		}
 
		this->SetDirty();
 
	}
 

	
 
	void OnGameTick() override
 
@@ -2415,25 +2418,25 @@ struct VehicleDetailsWindow : Window {
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
			case WID_VD_INCREASE_SERVICING_INTERVAL:   // increase int
 
			case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int
 
				int mod = _ctrl_pressed ? 5 : 10;
 
				const Vehicle *v = Vehicle::Get(this->window_number);
 

	
 
				mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
 
				mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent());
 
				if (mod == v->GetServiceInterval()) return;
 

	
 
				DoCommandP(CMD_CHANGE_SERVICE_INT, STR_ERROR_CAN_T_CHANGE_SERVICING, v->tile, v->index, mod | (1 << 16) | (v->ServiceIntervalIsPercent() << 17));
 
				Command<CMD_CHANGE_SERVICE_INT>::Post(STR_ERROR_CAN_T_CHANGE_SERVICING, v->tile, v->index, mod | (1 << 16) | (v->ServiceIntervalIsPercent() << 17), {});
 
				break;
 
			}
 

	
 
			case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
 
				const Vehicle *v = Vehicle::Get(this->window_number);
 
				ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0);
 
				break;
 
			}
 

	
 
			case WID_VD_DETAILS_CARGO_CARRIED:
 
			case WID_VD_DETAILS_TRAIN_VEHICLES:
 
			case WID_VD_DETAILS_CAPACITY_OF_EACH:
 
@@ -2451,25 +2454,25 @@ struct VehicleDetailsWindow : Window {
 
				break;
 
		}
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
 
				const Vehicle *v = Vehicle::Get(this->window_number);
 
				bool iscustom = index != 0;
 
				bool ispercent = iscustom ? (index == 2) : Company::Get(v->owner)->settings.vehicle.servint_ispercent;
 
				uint16 interval = GetServiceIntervalClamped(v->GetServiceInterval(), ispercent);
 
				DoCommandP(CMD_CHANGE_SERVICE_INT, STR_ERROR_CAN_T_CHANGE_SERVICING, v->tile, v->index, interval | (iscustom << 16) | (ispercent << 17));
 
				Command<CMD_CHANGE_SERVICE_INT>::Post(STR_ERROR_CAN_T_CHANGE_SERVICING, v->tile, v->index, interval | (iscustom << 16) | (ispercent << 17), {});
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnResize() override
 
	{
 
		NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_VD_MATRIX);
 
		if (nwi != nullptr) {
 
			this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX);
 
		}
 
	}
 
@@ -2634,25 +2637,25 @@ void CcStartStopVehicle(const CommandCos
 
	Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos);
 
	AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING);
 
}
 

	
 
/**
 
 * Executes #CMD_START_STOP_VEHICLE for given vehicle.
 
 * @param v Vehicle to start/stop
 
 * @param texteffect Should a texteffect be shown?
 
 */
 
void StartStopVehicle(const Vehicle *v, bool texteffect)
 
{
 
	assert(v->IsPrimaryVehicle());
 
	DoCommandP(CMD_START_STOP_VEHICLE, _vehicle_msg_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : nullptr, v->tile, v->index, 0);
 
	Command<CMD_START_STOP_VEHICLE>::Post(_vehicle_msg_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : nullptr, v->tile, v->index, 0, {});
 
}
 

	
 
/** Checks whether the vehicle may be refitted at the moment.*/
 
static bool IsVehicleRefitable(const Vehicle *v)
 
{
 
	if (!v->IsStoppedInDepot()) return false;
 

	
 
	do {
 
		if (IsEngineRefittable(v->engine_type)) return true;
 
	} while (v->IsGroundVehicle() && (v = v->Next()) != nullptr);
 

	
 
	return false;
 
@@ -2958,72 +2961,72 @@ public:
 
				} else {
 
					const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
 
					if (click_count > 1 && mainwindow->viewport->zoom <= ZOOM_LVL_OUT_4X) {
 
						/* main window 'follows' vehicle */
 
						mainwindow->viewport->follow_vehicle = v->index;
 
					} else {
 
						ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
 
					}
 
				}
 
				break;
 

	
 
			case WID_VV_GOTO_DEPOT: // goto hangar
 
				DoCommandP(CMD_SEND_VEHICLE_TO_DEPOT, GetCmdSendToDepotMsg(v), v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0);
 
				Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(v), v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, {});
 
				break;
 
			case WID_VV_REFIT: // refit
 
				ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this);
 
				break;
 
			case WID_VV_SHOW_ORDERS: // show orders
 
				if (_ctrl_pressed) {
 
					ShowTimetableWindow(v);
 
				} else {
 
					ShowOrdersWindow(v);
 
				}
 
				break;
 
			case WID_VV_SHOW_DETAILS: // show details
 
				if (_ctrl_pressed) {
 
					ShowCompanyGroupForVehicle(v);
 
				} else {
 
					ShowVehicleDetailsWindow(v);
 
				}
 
				break;
 
			case WID_VV_CLONE: // clone vehicle
 
				/* Suppress the vehicle GUI when share-cloning.
 
				 * There is no point to it except for starting the vehicle.
 
				 * For starting the vehicle the player has to open the depot GUI, which is
 
				 * most likely already open, but is also visible in the vehicle viewport. */
 
				DoCommandP(CMD_CLONE_VEHICLE, _vehicle_msg_translation_table[VCT_CMD_CLONE_VEH][v->type],
 
				Command<CMD_CLONE_VEHICLE>::Post(_vehicle_msg_translation_table[VCT_CMD_CLONE_VEH][v->type],
 
										_ctrl_pressed ? nullptr : CcCloneVehicle,
 
										v->tile, v->index, _ctrl_pressed ? 1 : 0);
 
										v->tile, v->index, _ctrl_pressed ? 1 : 0, {});
 
				break;
 
			case WID_VV_TURN_AROUND: // turn around
 
				assert(v->IsGroundVehicle());
 
				if (v->type == VEH_ROAD) {
 
					DoCommandP(CMD_TURN_ROADVEH, _vehicle_msg_translation_table[VCT_CMD_TURN_AROUND][v->type], v->tile, v->index, 0);
 
					Command<CMD_TURN_ROADVEH>::Post(_vehicle_msg_translation_table[VCT_CMD_TURN_AROUND][v->type], v->tile, v->index, 0, {});
 
				} else {
 
					DoCommandP(CMD_REVERSE_TRAIN_DIRECTION, _vehicle_msg_translation_table[VCT_CMD_TURN_AROUND][v->type], v->tile, v->index, 0);
 
					Command<CMD_REVERSE_TRAIN_DIRECTION>::Post(_vehicle_msg_translation_table[VCT_CMD_TURN_AROUND][v->type], v->tile, v->index, 0, {});
 
				}
 
				break;
 
			case WID_VV_FORCE_PROCEED: // force proceed
 
				assert(v->type == VEH_TRAIN);
 
				DoCommandP(CMD_FORCE_TRAIN_PROCEED, STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL, v->tile, v->index, 0);
 
				Command<CMD_FORCE_TRAIN_PROCEED>::Post(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL, v->tile, v->index, 0, {});
 
				break;
 
		}
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		DoCommandP(CMD_RENAME_VEHICLE, STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type, 0, this->window_number, 0, str);
 
		Command<CMD_RENAME_VEHICLE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type, 0, this->window_number, 0, str);
 
	}
 

	
 
	void OnMouseOver(Point pt, int widget) override
 
	{
 
		bool start_stop = widget == WID_VV_START_STOP;
 
		if (start_stop != mouse_over_start_stop) {
 
			mouse_over_start_stop = start_stop;
 
			this->SetWidgetDirty(WID_VV_START_STOP);
 
		}
 
	}
 

	
 
	void OnResize() override
src/waypoint_gui.cpp
Show inline comments
 
@@ -11,24 +11,25 @@
 
#include "window_gui.h"
 
#include "gui.h"
 
#include "textbuf_gui.h"
 
#include "vehiclelist.h"
 
#include "vehicle_gui.h"
 
#include "viewport_func.h"
 
#include "strings_func.h"
 
#include "command_func.h"
 
#include "company_func.h"
 
#include "company_base.h"
 
#include "window_func.h"
 
#include "waypoint_base.h"
 
#include "waypoint_cmd.h"
 

	
 
#include "widgets/waypoint_widget.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
/** GUI for accessing waypoints and buoys. */
 
struct WaypointWindow : Window {
 
private:
 
	VehicleType vt; ///< Vehicle type using the waypoint.
 
	Waypoint *wp;   ///< Waypoint displayed by the window.
 
@@ -129,25 +130,25 @@ public:
 
			NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_W_VIEWPORT);
 
			nvp->UpdateViewportCoordinates(this);
 
			this->wp->UpdateVirtCoord();
 

	
 
			ScrollWindowToTile(this->GetCenterTile(), this, true); // Re-center viewport.
 
		}
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		DoCommandP(CMD_RENAME_WAYPOINT, STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME, 0, this->window_number, 0, str);
 
		Command<CMD_RENAME_WAYPOINT>::Post(STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME, 0, this->window_number, 0, str);
 
	}
 

	
 
};
 

	
 
/** The widgets of the waypoint view. */
 
static const NWidgetPart _nested_waypoint_view_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
 
		NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_W_RENAME), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_BUOY_VIEW_CHANGE_BUOY_NAME),
 
		NWidget(WWT_CAPTION, COLOUR_GREY, WID_W_CAPTION), SetDataTip(STR_WAYPOINT_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
		NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_W_CENTER_VIEW), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_BUOY_VIEW_CENTER_TOOLTIP),
 
		NWidget(WWT_SHADEBOX, COLOUR_GREY),
0 comments (0 inline, 0 general)