Exemple #1
0
void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
{
	if (result.Failed() || !_settings_game.economy.give_money) return;

	/* Inform the company of the action of one of its clients (controllers). */
	char msg[64];
	SetDParam(0, p2);
	GetString(msg, STR_COMPANY_NAME, lastof(msg));

	if (!_network_server) {
		NetworkClientSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, p1);
	} else {
		NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER, p1);
	}
}
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		Dimension d;
		switch (widget) {
			/* Left and right should have same sizing. */
			case WID_S_LEFT:
			case WID_S_RIGHT: {
				SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR);
				d = GetStringBoundingBox(STR_WHITE_DATE_LONG);

				int64 max_money = UINT32_MAX;
				const Company *c;
				FOR_ALL_COMPANIES(c) max_money = max<int64>(c->money, max_money);
				SetDParam(0, 100LL * max_money);
				d = maxdim(d, GetStringBoundingBox(STR_COMPANY_MONEY));
				break;
			}

			case WID_S_MIDDLE:
				d = GetStringBoundingBox(STR_STATUSBAR_AUTOSAVE);
				d = maxdim(d,    GetStringBoundingBox(STR_STATUSBAR_PAUSED));

				if (Company::IsValidID(_local_company)) {
					SetDParam(0, _local_company);
					d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_COMPANY_NAME));
				}
				break;

			default:
				return;
		}

		d.width += padding.width;
		d.height += padding.height;
		*size = maxdim(d, *size);
	}
Exemple #3
0
/* Draw rail wagon specific details */
static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
{
	const Engine *e = Engine::Get(engine_number);

	/* Purchase cost */
	SetDParam(0, e->GetCost());
	DrawString(left, right, y, STR_PURCHASE_INFO_COST);
	y += FONT_HEIGHT_NORMAL;

	/* Wagon weight - (including cargo) */
	uint weight = e->GetDisplayWeight();
	SetDParam(0, weight);
	uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0);
	SetDParam(1, cargo_weight + weight);
	DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
	y += FONT_HEIGHT_NORMAL;

	/* Wagon speed limit, displayed if above zero */
	if (_settings_game.vehicle.wagon_speed_limits) {
		uint max_speed = e->GetDisplayMaxSpeed();
		if (max_speed > 0) {
			SetDParam(0, max_speed);
			DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
			y += FONT_HEIGHT_NORMAL;
		}
	}

	/* Running cost */
	if (rvi->running_cost_class != INVALID_PRICE) {
		SetDParam(0, e->GetRunningCost());
		DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
		y += FONT_HEIGHT_NORMAL;
	}

	return y;
}
Exemple #4
0
	virtual void DrawWidget(const Rect &r, int widget) const
	{
		switch (widget) {
			case MTSW_LIST_LEFT: {
				GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);

				int y = r.top + WD_FRAMERECT_TOP;
				for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
					const char *song_name = GetSongName(i);
					if (StrEmpty(song_name)) continue;

					SetDParam(0, GetTrackNumber(i));
					SetDParam(1, 2);
					SetDParamStr(2, song_name);
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME);
					y += FONT_HEIGHT_SMALL;
				}
				break;
			}

			case MTSW_LIST_RIGHT: {
				GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);

				int y = r.top + WD_FRAMERECT_TOP;
				for (const byte *p = _playlists[_settings_client.music.playlist]; *p != 0; p++) {
					uint i = *p - 1;
					SetDParam(0, GetTrackNumber(i));
					SetDParam(1, 2);
					SetDParamStr(2, GetSongName(i));
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME);
					y += FONT_HEIGHT_SMALL;
				}
				break;
			}
		}
	}
Exemple #5
0
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		if (widget == WID_MH_BACKGROUND) {
			this->line_height = FONT_HEIGHT_NORMAL + 2;
			resize->height = this->line_height;

			/* Months are off-by-one, so it's actually 8. Not using
			 * month 12 because the 1 is usually less wide. */
			SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30));
			this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width;

			size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible.
			size->width = max(200u, size->width); // At least 200 pixels wide.
		}
	}
Exemple #6
0
	virtual void SetStringParameters(int widget) const
	{
		switch (widget) {
			case WID_AP_CLASS_DROPDOWN:
				SetDParam(0, AirportClass::Get(_selected_airport_class)->name);
				break;

			case WID_AP_LAYOUT_NUM:
				SetDParam(0, STR_EMPTY);
				if (_selected_airport_index != -1) {
					const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
					StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME);
					if (string != STR_UNDEFINED) {
						SetDParam(0, string);
					} else if (as->num_table > 1) {
						SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME);
						SetDParam(1, _selected_airport_layout + 1);
					}
				}
				break;

			default: break;
		}
	}
Exemple #7
0
static void ShipArrivesAt(const Vehicle *v, Station *st)
{
	/* Check if station was ever visited before */
	if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
		st->had_vehicle_of_type |= HVOT_SHIP;

		SetDParam(0, st->index);
		AddVehicleNewsItem(
			STR_NEWS_FIRST_SHIP_ARRIVAL,
			(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
			v->index,
			st->index
		);
		AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
	}
}
Exemple #8
0
	virtual void OnClick(Point pt, int widget, int click_count)
	{
		const NWidgetBase *wid = this->GetWidget<NWidgetBase>(CW_PANEL);
		uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL);
		uint x = pt.x - wid->pos_x;
		bool rtl = _current_text_dir == TD_RTL;
		if (rtl) x = wid->current_x - x;

		if (btn >= lengthof(_cheats_ui)) return;

		const CheatEntry *ce = &_cheats_ui[btn];
		int value = (int32)ReadValue(ce->variable, ce->type);
		int oldvalue = value;

		if (btn == CHT_CHANGE_DATE && x >= 40) {
			/* Click at the date text directly. */
			SetDParam(0, value);
			ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED);
			return;
		}

		/* Not clicking a button? */
		if (!IsInsideMM(x, 20, 40)) return;

		*ce->been_used = true;

		switch (ce->type) {
			case SLE_BOOL:
				value ^= 1;
				if (ce->proc != NULL) ce->proc(value, 0);
				break;

			default:
				/* Take whatever the function returns */
				value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1);

				/* The first cheat (money), doesn't return a different value. */
				if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + ((x >= 30) != rtl ? 1 : 0);
				break;
		}

		if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value);

		this->flags4 |= WF_TIMEOUT_BEGIN;

		this->SetDirty();
	}
Exemple #9
0
	virtual void DrawWidget(const Rect &r, int widget) const
	{
		switch (widget) {
			case AIL_WIDGET_LIST: {
				/* Draw a list of all available AIs. */
				int y = this->GetWidget<NWidgetBase>(AIL_WIDGET_LIST)->pos_y;
				/* First AI in the list is hardcoded to random */
				if (this->vscroll->IsVisible(0)) {
					DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_BLACK);
					y += this->line_height;
				}
				AIInfoList::const_iterator it = this->ai_info_list->begin();
				for (int i = 1; it != this->ai_info_list->end(); i++, it++) {
					if (this->vscroll->IsVisible(i)) {
						DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_BLACK);
						y += this->line_height;
					}
				}
				break;
			}
			case AIL_WIDGET_INFO_BG: {
				AIInfo *selected_info = NULL;
				AIInfoList::const_iterator it = this->ai_info_list->begin();
				for (int i = 1; selected_info == NULL && it != this->ai_info_list->end(); i++, it++) {
					if (this->selected == i - 1) selected_info = (*it).second;
				}
				/* Some info about the currently selected AI. */
				if (selected_info != NULL) {
					int y = r.top + WD_FRAMERECT_TOP;
					SetDParamStr(0, selected_info->GetAuthor());
					DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_AUTHOR);
					y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
					SetDParam(0, selected_info->GetVersion());
					DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_VERSION);
					y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
					if (selected_info->GetURL() != NULL) {
						SetDParamStr(0, selected_info->GetURL());
						DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_URL);
						y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
					}
					SetDParamStr(0, selected_info->GetDescription());
					DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, STR_JUST_RAW_STRING, TC_BLACK);
				}
				break;
			}
		}
	}
/* Draw ship specific details */
static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
{
	const Engine *e = Engine::Get(engine_number);

	/* Purchase cost - Max speed */
	uint raw_speed = e->GetDisplayMaxSpeed();
	uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
	uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);

	SetDParam(0, e->GetCost());
	if (ocean_speed == canal_speed) {
		SetDParam(1, ocean_speed);
		DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
		y += FONT_HEIGHT_NORMAL;
	} else {
		DrawString(left, right, y, STR_PURCHASE_INFO_COST);
		y += FONT_HEIGHT_NORMAL;

		SetDParam(0, ocean_speed);
		DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN);
		y += FONT_HEIGHT_NORMAL;

		SetDParam(0, canal_speed);
		DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL);
		y += FONT_HEIGHT_NORMAL;
	}

	/* Cargo type + capacity */
	SetDParam(0, e->GetDefaultCargoType());
	SetDParam(1, e->GetDisplayDefaultCapacity());
	SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
	DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
	y += FONT_HEIGHT_NORMAL;

	/* Running cost */
	SetDParam(0, e->GetRunningCost());
	DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
	y += FONT_HEIGHT_NORMAL;

	return y;
}
Exemple #11
0
static StringID GetAircraftEngineInfoString(const Engine *e)
{
	CargoID cargo = e->GetDefaultCargoType();
	uint16 mail_capacity;
	uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
	uint16 range = e->GetRange();

	uint i = 0;
	SetDParam(i++, e->GetCost());
	SetDParam(i++, e->GetDisplayMaxSpeed());
	if (range > 0) SetDParam(i++, range);
	SetDParam(i++, cargo);
	SetDParam(i++, capacity);

	if (mail_capacity > 0) {
		SetDParam(i++, CT_MAIL);
		SetDParam(i++, mail_capacity);
		SetDParam(i++, e->GetRunningCost());
		return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST;
	} else {
		SetDParam(i++, e->GetRunningCost());
		return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
	}
}
Exemple #12
0
void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr)
{
	/* Just a fail-safe.. should never happen */
	if (!_network_udp_server) return;

	Packet packet(PACKET_UDP_SERVER_DETAIL_INFO);

	/* Send the amount of active companies */
	packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
	packet.Send_uint8 ((uint8)Company::GetNumItems());

	/* Fetch the latest version of the stats */
	NetworkCompanyStats company_stats[MAX_COMPANIES];
	NetworkPopulateCompanyStats(company_stats);

	/* The minimum company information "blob" size. */
	static const uint MIN_CI_SIZE = 54;
	uint max_cname_length = NETWORK_COMPANY_NAME_LENGTH;

	if (Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH) >= (uint)SEND_MTU - packet.size) {
		/* Assume we can at least put the company information in the packets. */
		assert(Company::GetNumItems() * MIN_CI_SIZE < (uint)SEND_MTU - packet.size);

		/* At this moment the company names might not fit in the
		 * packet. Check whether that is really the case. */

		for (;;) {
			int free = SEND_MTU - packet.size;
			Company *company;
			FOR_ALL_COMPANIES(company) {
				char company_name[NETWORK_COMPANY_NAME_LENGTH];
				SetDParam(0, company->index);
				GetString(company_name, STR_COMPANY_NAME, company_name + max_cname_length - 1);
				free -= MIN_CI_SIZE;
				free -= (int)strlen(company_name);
			}
			if (free >= 0) break;

			/* Try again, with slightly shorter strings. */
			assert(max_cname_length > 0);
			max_cname_length--;
		}
	}
Exemple #13
0
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		switch (widget) {
			case WID_SGI_TRANSLATION: {
				SetDParam(0, _current_language->missing);
				int height = GetStringHeight(STR_INTRO_TRANSLATION, size->width);
				if (height > 3 * FONT_HEIGHT_NORMAL) {
					/* Don't let the window become too high. */
					Dimension textdim = GetStringBoundingBox(STR_INTRO_TRANSLATION);
					textdim.height *= 3;
					textdim.width -= textdim.width / 2;
					*size = maxdim(*size, textdim);
				} else {
					size->height = height + padding.height;
				}
				break;
			}
		}
	}
Exemple #14
0
	void UpdateSignEditWindow(const Sign *si)
	{
		char *last_of = &this->edit_str_buf[this->edit_str_size - 1]; // points to terminating '\0'

		/* Display an empty string when the sign hasnt been edited yet */
		if (si->name != NULL) {
			SetDParam(0, si->index);
			GetString(this->edit_str_buf, STR_SIGN_NAME, last_of);
		} else {
			GetString(this->edit_str_buf, STR_EMPTY, last_of);
		}
		*last_of = '\0';

		this->cur_sign = si->index;
		InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, this->max_chars);

		this->SetWidgetDirty(WID_QES_TEXT);
		this->SetFocusedWidget(WID_QES_TEXT);
	}
Exemple #15
0
static StringID GetAircraftEngineInfoString(const Engine *e)
{
	CargoID cargo = e->GetDefaultCargoType();
	uint16 mail_capacity;
	uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);

	SetDParam(0, e->GetCost());
	SetDParam(1, e->GetDisplayMaxSpeed());
	SetDParam(2, cargo);
	SetDParam(3, capacity);

	if (mail_capacity > 0) {
		SetDParam(4, CT_MAIL);
		SetDParam(5, mail_capacity);
		SetDParam(6, e->GetRunningCost());
		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST;
	} else {
		SetDParam(4, e->GetRunningCost());
		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
	}
}
Exemple #16
0
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		if (widget != CW_PANEL) return;

		uint width = 0;
		for (int i = 0; i != lengthof(_cheats_ui); i++) {
			const CheatEntry *ce = &_cheats_ui[i];
			switch (ce->type) {
				case SLE_BOOL:
					SetDParam(0, STR_CONFIG_SETTING_ON);
					width = max(width, GetStringBoundingBox(ce->str).width);
					SetDParam(0, STR_CONFIG_SETTING_OFF);
					width = max(width, GetStringBoundingBox(ce->str).width);
					break;

				default:
					switch (ce->str) {
						/* Display date for change date cheat */
						case STR_CHEAT_CHANGE_DATE:
							SetDParam(0, ConvertYMDToDate(MAX_YEAR, 11, 31));
							width = max(width, GetStringBoundingBox(ce->str).width);
							break;

						/* Draw coloured flag for change company cheat */
						case STR_CHEAT_CHANGE_COMPANY:
							SetDParam(0, 15);
							width = max(width, GetStringBoundingBox(ce->str).width + 10 + 10);
							break;

						/* Set correct string for switch climate cheat */
						case STR_CHEAT_SWITCH_CLIMATE:
							for (StringID i = STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE; i <= STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE; i++) {
								SetDParam(0, i);
								width = max(width, GetStringBoundingBox(ce->str).width);
							}
							break;

						default:
							SetDParam(0, INT64_MAX);
							width = max(width, GetStringBoundingBox(ce->str).width);
							break;
					}
					break;
			}
		}

		size->width = width + 50 /* stuff on the left */ + 10 /* extra spacing on right */;
		this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE;
		size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL) * lengthof(_cheats_ui);
	}
/* Draw locomotive specific details */
static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
{
	const Engine *e = Engine::Get(engine_number);

	/* Purchase Cost - Engine weight */
	SetDParam(0, e->GetCost());
	SetDParam(1, e->GetDisplayWeight());
	DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
	y += FONT_HEIGHT_NORMAL;

	/* Max speed - Engine power */
	SetDParam(0, e->GetDisplayMaxSpeed());
	SetDParam(1, e->GetPower());
	DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
	y += FONT_HEIGHT_NORMAL;

	/* Max tractive effort - not applicable if old acceleration or maglev */
	if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
		SetDParam(0, e->GetDisplayMaxTractiveEffort());
		DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
		y += FONT_HEIGHT_NORMAL;
	}

	/* Running cost */
	if (rvi->running_cost_class != INVALID_PRICE) {
		SetDParam(0, e->GetRunningCost());
		DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
		y += FONT_HEIGHT_NORMAL;
	}

	/* Powered wagons power - Powered wagons extra weight */
	if (rvi->pow_wag_power != 0) {
		SetDParam(0, rvi->pow_wag_power);
		SetDParam(1, rvi->pow_wag_weight);
		DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT);
		y += FONT_HEIGHT_NORMAL;
	}

	return y;
}
Exemple #18
0
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		switch (widget) {
			case TTV_ARRIVAL_DEPARTURE_PANEL:
				SetDParam(0, MAX_YEAR * DAYS_IN_YEAR);
				this->deparr_time_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width;
				this->deparr_abbr_width = max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width);
				size->width = WD_FRAMERECT_LEFT + this->deparr_abbr_width + 10 + this->deparr_time_width + WD_FRAMERECT_RIGHT;
				/* fall through */
			case TTV_ARRIVAL_DEPARTURE_SELECTION:
			case TTV_TIMETABLE_PANEL:
				resize->height = FONT_HEIGHT_NORMAL;
				size->height = WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM;
				break;

			case TTV_SUMMARY_PANEL:
				size->height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
				break;
		}
	}
Exemple #19
0
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
	{
		switch (widget) {
			case WID_SIL_LIST: {
				Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON);
				this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text.
				resize->height = max<uint>(FONT_HEIGHT_NORMAL, spr_dim.height);
				Dimension d = {this->text_offset + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM};
				*size = maxdim(*size, d);
				break;
			}

			case WID_SIL_CAPTION:
				SetDParam(0, max<size_t>(1000, Sign::GetPoolSize()));
				*size = GetStringBoundingBox(STR_SIGN_LIST_CAPTION);
				size->height += padding.height;
				size->width  += padding.width;
				break;
		}
	}
/**
 * Call a given command as an ingredient of a paste operation.
 *
 * Costs and possible errors will be aggregated. After return, call PastingState::IsInterrupted to
 * test if the paste operation is disallowed to be continued.
 *
 * @param tile The tile to apply the command on.
 * @param p1 Additional data for the command.
 * @param p2 Additional data for the command.
 * @param cmd The command-id to execute (a value of the CMD_* enums) and the error summary message (CMD_MSG).
 * @return The cost of this operation or an error.
 *
 * @pre The command is not flagged with CMD_NO_TEST.
 * @pre The type of the command is CMDT_LANDSCAPE_CONSTRUCTION.
 *
 * @see PastingState::IsInterrupted
 * @see PastingState::CollectCost
 * @see PastingState::CollectError
 */
void PastingState::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
{
	/* make sure we are still allowed to paste */
	if (this->IsInterrupted()) {
		this->last_result = CMD_ERROR; // mark that the command didn't succeed
		return;
	}

	/* PastingState::DoCommand can handle only fully predictable commands, those without
	 * CMD_NO_TEST flag. Unpredictable command have to be handled separately. */
	assert(!(GetCommandFlags(cmd) & CMD_NO_TEST));

	/* ignore some of the given flags, instead use those from the command proc table */
	DoCommandFlag flags = this->dc_flags;
	flags &= ~DC_AUTO & ~DC_NO_WATER & ~DC_ALL_TILES;
	flags |= CommandFlagsToDCFlags(GetCommandFlags(cmd));

	/* use given error message or the default one */
	StringID summary_error_msg = GB(cmd, 16, 16);
	if (summary_error_msg == 0) summary_error_msg = STR_ERROR_CAN_T_PASTE_HERE;

	/* test the command, output is the return value */
	CommandCost ret = ::DoCommand(tile, p1, p2, flags & ~DC_EXEC, cmd);

	/* apply if exec'ing */
	if (ret.Succeeded() && (flags & DC_EXEC)) {
		/* check if there is enough money */
		if (ret.GetCost() > 0 && this->GetAvailableMoney() < ret.GetCost()) {
			SetDParam(0, ret.GetCost());
			ret = CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
		} else {
			CommandCost ret2 = ::DoCommand(tile, p1, p2, flags, cmd);
			assert(ret == ret2);
		}
	}

	/* aggregate costs */
	this->CollectCost(ret, tile, summary_error_msg);
}
Exemple #21
0
	virtual void DrawWidget(const Rect &r, int widget) const
	{
		if (widget != AIS_WIDGET_BACKGROUND) return;

		AIConfig *config = this->ai_config;
		AIConfigItemList::const_iterator it = config->GetConfigList()->begin();
		int i = 0;
		for (; !this->vscroll.IsVisible(i); i++) it++;

		bool rtl = _dynlang.text_dir == TD_RTL;
		uint buttons_left = rtl ? r.right - 23 : r.left + 4;
		uint value_left   = r.left + (rtl ? WD_FRAMERECT_LEFT : 28);
		uint value_right  = r.right - (rtl ? 28 : WD_FRAMERECT_RIGHT);
		uint text_left    = r.left + (rtl ? WD_FRAMERECT_LEFT : 54);
		uint text_right   = r.right - (rtl ? 54 : WD_FRAMERECT_RIGHT);


		int y = r.top;
		for (; this->vscroll.IsVisible(i) && it != config->GetConfigList()->end(); i++, it++) {
			int current_value = config->GetSetting((*it).name);
			bool editable = (_game_mode == GM_MENU) || ((it->flags & AICONFIG_INGAME) != 0);

			uint x = rtl ? r.right : r.left;
			if (((*it).flags & AICONFIG_BOOLEAN) != 0) {
				DrawFrameRect(buttons_left, y  + 2, buttons_left + 19, y + 10, (current_value != 0) ? COLOUR_GREEN : COLOUR_RED, (current_value != 0) ? FR_LOWERED : FR_NONE);
			} else {
				DrawArrowButtons(buttons_left, y + 2, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > (*it).min_value, editable && current_value < (*it).max_value);
				if (it->labels != NULL && it->labels->Find(current_value) != it->labels->End()) {
					x = DrawString(value_left, value_right, y + WD_MATRIX_TOP, it->labels->Find(current_value)->second, TC_ORANGE);
				} else {
					SetDParam(0, current_value);
					x = DrawString(value_left, value_right, y + WD_MATRIX_TOP, STR_JUST_INT, TC_ORANGE);
				}
			}

			DrawString(max(rtl ? 0U : x + 3, text_left), min(rtl ? x - 3 : r.right, text_right), y + WD_MATRIX_TOP, (*it).description, TC_LIGHT_BLUE);
			y += this->line_height;
		}
	}
Exemple #22
0
	virtual void DrawWidget(const Rect &r, int widget) const
	{
		switch (widget) {
			case WID_AP_AIRPORT_LIST: {
				int y = r.top;
				AirportClass *apclass = AirportClass::Get(_selected_airport_class);
				for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) {
					const AirportSpec *as = apclass->GetSpec(i);
					if (!as->IsAvailable()) {
						GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER);
					}

					DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, Center(y, this->line_height), as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK);

					y += this->line_height;
				}
				break;
			}

			case WID_AP_AIRPORT_SPRITE:
				if (this->preview_sprite != 0) {
					Dimension d = GetSpriteSize(this->preview_sprite);
					DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2);
				}
				break;

			case WID_AP_EXTRA_TEXT:
				if (_selected_airport_index != -1) {
					const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
					StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT);
					if (string != STR_UNDEFINED) {
						SetDParam(0, string);
						DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING);
					}
				}
				break;
		}
	}
Exemple #23
0
Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
{
	NewsReferenceType reftype1 = NR_NONE;
	NewsReferenceType reftype2 = NR_NONE;

	/* if mode is false, use the singular form */
	const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
	SetDParam(0, mode ? cs->name : cs->name_single);

	switch (s->src_type) {
		case ST_INDUSTRY:
			reftype1 = NR_INDUSTRY;
			SetDParam(1, STR_INDUSTRY_NAME);
			break;
		case ST_TOWN:
			reftype1 = NR_TOWN;
			SetDParam(1, STR_TOWN_NAME);
			break;
		default: NOT_REACHED();
	}
	SetDParam(2, s->src);

	switch (s->dst_type) {
		case ST_INDUSTRY:
			reftype2 = NR_INDUSTRY;
			SetDParam(4, STR_INDUSTRY_NAME);
			break;
		case ST_TOWN:
			reftype2 = NR_TOWN;
			SetDParam(4, STR_TOWN_NAME);
			break;
		default: NOT_REACHED();
	}
	SetDParam(5, s->dst);

	Pair p;
	p.a = reftype1;
	p.b = reftype2;
	return p;
}
/**
 * Set the right DParams to get the name of an owner.
 * @param owner the owner to get the name of.
 * @param tile  optional tile to get the right town.
 * @pre if tile == 0, then owner can't be OWNER_TOWN.
 */
void GetNameOfOwner(Owner owner, TileIndex tile)
{
	SetDParam(2, owner);

	if (owner != OWNER_TOWN) {
		if (!Company::IsValidID(owner)) {
			SetDParam(0, STR_COMPANY_SOMEONE);
		} else {
			SetDParam(0, STR_COMPANY_NAME);
			SetDParam(1, owner);
		}
	} else {
		assert(tile != 0);
		const Town *t = ClosestTownFromTile(tile, UINT_MAX);

		SetDParam(0, STR_TOWN_NAME);
		SetDParam(1, t->index);
	}
}
/**
 * Sets the arrival or departure string and parameters.
 * @param param1 the first DParam to fill
 * @param param2 the second DParam to fill
 * @param ticks  the number of ticks to 'draw'
 */
static void SetArrivalDepartParams(int param1, int param2, Ticks ticks)
{
	SetDParam(param1, STR_JUST_DATE_TINY);
	SetDParam(param2, _date + (ticks / DAY_TICKS));
}
	virtual void OnClick(Point pt, int widget, int click_count)
	{
		const Vehicle *v = this->vehicle;

		switch (widget) {
			case WID_VT_ORDER_VIEW: // Order view button
				ShowOrdersWindow(v);
				break;

			case WID_VT_TIMETABLE_PANEL: { // Main panel.
				int selected = GetOrderFromTimetableWndPt(pt.y, v);

				this->DeleteChildWindows();
				this->sel_index = (selected == INVALID_ORDER || selected == this->sel_index) ? -1 : selected;
				break;
			}

			case WID_VT_START_DATE: // Change the date that the timetable starts.
				ShowSetDateWindow(this, v->index, _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback);
				break;

			case WID_VT_CHANGE_TIME: { // "Wait For" button.
				int selected = this->sel_index;
				VehicleOrderID real = (selected + 1) / 2;

				if (real >= v->GetNumOrders()) real = 0;

				const Order *order = v->GetOrder(real);
				StringID current = STR_EMPTY;

				if (order != NULL) {
					uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
					if (!_settings_client.gui.timetable_in_ticks) time /= DAY_TICKS;

					if (time != 0) {
						SetDParam(0, time);
						current = STR_JUST_INT;
					}
				}

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

			case WID_VT_CHANGE_SPEED: { // Change max speed button.
				int selected = this->sel_index;
				VehicleOrderID real = (selected + 1) / 2;

				if (real >= v->GetNumOrders()) real = 0;

				StringID current = STR_EMPTY;
				const Order *order = v->GetOrder(real);
				if (order != NULL) {
					if (order->max_speed != UINT16_MAX) {
						SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->max_speed));
						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(0, p1, 0, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
				break;
			}

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

			case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter.
				DoCommandP(0, v->index, 0, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
				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(0, v->index, p2, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
				break;
			}

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

			case WID_VT_SHARED_ORDER_LIST:
				ShowVehicleListWindow(v);
				break;
		}

		this->SetDirty();
	}
	virtual void DrawWidget(const Rect &r, int widget) const
	{
		const Vehicle *v = this->vehicle;
		int selected = this->sel_index;

		switch (widget) {
			case WID_VT_TIMETABLE_PANEL: {
				int y = r.top + WD_FRAMERECT_TOP;
				int i = this->vscroll->GetPosition();
				VehicleOrderID order_id = (i + 1) / 2;
				bool final_order = false;

				bool rtl = _current_text_dir == TD_RTL;
				SetDParamMaxValue(0, v->GetNumOrders(), 2);
				int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3;
				int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width;

				const Order *order = v->GetOrder(order_id);
				while (order != NULL) {
					/* Don't draw anything if it extends past the end of the window. */
					if (!this->vscroll->IsVisible(i)) break;

					if (i % 2 == 0) {
						DrawOrderString(v, order, order_id, y, i == selected, true, r.left + WD_FRAMERECT_LEFT, middle, r.right - WD_FRAMERECT_RIGHT);

						order_id++;

						if (order_id >= v->GetNumOrders()) {
							order = v->GetOrder(0);
							final_order = true;
						} else {
							order = order->next;
						}
					} else {
						StringID string;
						TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK;
						if (order->IsType(OT_CONDITIONAL)) {
							string = STR_TIMETABLE_NO_TRAVEL;
						} else if (order->IsType(OT_IMPLICIT)) {
							string = STR_TIMETABLE_NOT_TIMETABLEABLE;
							colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
						} else if (order->travel_time == 0) {
							string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED : STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
						} else {
							SetTimetableParams(0, 1, order->travel_time);
							string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR;
						}
						SetDParam(2, order->max_speed);

						DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour);

						if (final_order) break;
					}

					i++;
					y += FONT_HEIGHT_NORMAL;
				}
				break;
			}

			case WID_VT_ARRIVAL_DEPARTURE_PANEL: {
				/* Arrival and departure times are handled in an all-or-nothing approach,
				 * i.e. are only shown if we can calculate all times.
				 * Excluding order lists with only one order makes some things easier.
				 */
				Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0;
				if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break;

				TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders());
				const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders();

				VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID;

				int y = r.top + WD_FRAMERECT_TOP;

				bool show_late = this->show_expected && v->lateness_counter > DAY_TICKS;
				Ticks offset = show_late ? 0 : -v->lateness_counter;

				bool rtl = _current_text_dir == TD_RTL;
				int abbr_left  = rtl ? r.right - WD_FRAMERECT_RIGHT - this->deparr_abbr_width : r.left + WD_FRAMERECT_LEFT;
				int abbr_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->deparr_abbr_width;
				int time_left  = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_RIGHT - this->deparr_time_width;
				int time_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->deparr_time_width : r.right - WD_FRAMERECT_RIGHT;

				for (int i = this->vscroll->GetPosition(); i / 2 < v->GetNumOrders(); ++i) { // note: i is also incremented in the loop
					/* Don't draw anything if it extends past the end of the window. */
					if (!this->vscroll->IsVisible(i)) break;

					if (i % 2 == 0) {
						if (arr_dep[i / 2].arrival != INVALID_TICKS) {
							DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_ARRIVAL_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK);
							if (this->show_expected && i / 2 == earlyID) {
								SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival);
								DrawString(time_left, time_right, y, STR_GREEN_STRING, i == selected ? TC_WHITE : TC_BLACK);
							} else {
								SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival + offset);
								DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK);
							}
						}
					} else {
						if (arr_dep[i / 2].departure != INVALID_TICKS) {
							DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK);
							SetArrivalDepartParams(0, 1, arr_dep[i/2].departure + offset);
							DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK);
						}
					}
					y += FONT_HEIGHT_NORMAL;
				}
				break;
			}

			case WID_VT_SUMMARY_PANEL: {
				int y = r.top + WD_FRAMERECT_TOP;

				Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0;
				if (total_time != 0) {
					SetTimetableParams(0, 1, total_time);
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE);
				}
				y += FONT_HEIGHT_NORMAL;

				if (v->timetable_start != 0) {
					/* We are running towards the first station so we can start the
					 * timetable at the given time. */
					SetDParam(0, STR_JUST_DATE_TINY);
					SetDParam(1, v->timetable_start);
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_START_AT);
				} else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) {
					/* We aren't running on a timetable yet, so how can we be "on time"
					 * when we aren't even "on service"/"on duty"? */
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_NOT_STARTED);
				} else if (v->lateness_counter == 0 || (!_settings_client.gui.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_ON_TIME);
				} else {
					SetTimetableParams(0, 1, abs(v->lateness_counter));
					DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE);
				}
				break;
			}
		}
	}
/**
 * Draw the purchase info details of a vehicle at a given location.
 * @param left,right,y location where to draw the info
 * @param engine_number the engine of which to draw the info of
 * @return y after drawing all the text
 */
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number)
{
	const Engine *e = Engine::Get(engine_number);
	YearMonthDay ymd;
	ConvertDateToYMD(e->intro_date, &ymd);
	bool refittable = IsArticulatedVehicleRefittable(engine_number);
	bool articulated_cargo = false;

	switch (e->type) {
		default: NOT_REACHED();
		case VEH_TRAIN:
			if (e->u.rail.railveh_type == RAILVEH_WAGON) {
				y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail);
			} else {
				y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail);
			}
			articulated_cargo = true;
			break;

		case VEH_ROAD:
			y = DrawRoadVehPurchaseInfo(left, right, y, engine_number);
			articulated_cargo = true;
			break;

		case VEH_SHIP:
			y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable);
			break;

		case VEH_AIRCRAFT:
			y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable);
			break;
	}

	if (articulated_cargo) {
		/* Cargo type + capacity, or N/A */
		int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, refittable);

		if (new_y == y) {
			SetDParam(0, CT_INVALID);
			SetDParam(2, STR_EMPTY);
			DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
			y += FONT_HEIGHT_NORMAL;
		} else {
			y = new_y;
		}
	}

	/* Draw details that apply to all types except rail wagons. */
	if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
		/* Design date - Life length */
		SetDParam(0, ymd.year);
		SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR);
		DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
		y += FONT_HEIGHT_NORMAL;

		/* Reliability */
		SetDParam(0, ToPercent16(e->reliability));
		DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
		y += FONT_HEIGHT_NORMAL;
	}

	if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);

	/* Additional text from NewGRF */
	y = ShowAdditionalText(left, right, y, engine_number);

	return y;
}
/* Draw aircraft specific details */
static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
{
	const Engine *e = Engine::Get(engine_number);
	CargoID cargo = e->GetDefaultCargoType();

	/* Purchase cost - Max speed */
	SetDParam(0, e->GetCost());
	SetDParam(1, e->GetDisplayMaxSpeed());
	DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
	y += FONT_HEIGHT_NORMAL;

	/* Cargo capacity */
	uint16 mail_capacity;
	uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
	if (mail_capacity > 0) {
		SetDParam(0, cargo);
		SetDParam(1, capacity);
		SetDParam(2, CT_MAIL);
		SetDParam(3, mail_capacity);
		DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
	} else {
		/* Note, if the default capacity is selected by the refit capacity
		 * callback, then the capacity shown is likely to be incorrect. */
		SetDParam(0, cargo);
		SetDParam(1, capacity);
		SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
		DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
	}
	y += FONT_HEIGHT_NORMAL;

	/* Running cost */
	SetDParam(0, e->GetRunningCost());
	DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
	y += FONT_HEIGHT_NORMAL;

	uint16 range = e->GetRange();
	if (range != 0) {
		SetDParam(0, range);
		DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE);
		y += FONT_HEIGHT_NORMAL;
	}

	return y;
}
void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const
{
	int left = r.left + WD_MATRIX_LEFT;
	int right = r.right - WD_MATRIX_RIGHT;

	bool rtl = _current_text_dir == TD_RTL;
	bool ltr = !rtl;

	int text_offset = WD_FRAMERECT_RIGHT;
	int text_left  = left  + (rtl ?           0 : text_offset);
	int text_right = right - (rtl ? text_offset :           0);

	int y = r.top + 1;
	uint max_departures = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->departures->Length() + this->arrivals->Length());

	if (max_departures > _settings_client.gui.max_departures) {
		max_departures = _settings_client.gui.max_departures;
	}

	byte small_font_size = _settings_client.gui.departure_larger_font ? FONT_HEIGHT_NORMAL : FONT_HEIGHT_SMALL;

	/* Draw the black background. */
	GfxFillRect(r.left + 1, r.top, r.right - 1, r.bottom, PC_BLACK);

	/* Nothing selected? Then display the information text. */
	bool none_selected[2] = {true, true};
	for (uint i = 0; i < 4; ++i)
	{
		if (this->show_types[i]) {
			none_selected[0] = false;
			break;
		}
	}

	for (uint i = 0; i < 2; ++i)
	{
		if (this->departure_types[i]) {
			none_selected[1] = false;
			break;
		}
	}

	if (none_selected[0] || none_selected[1]) {
		DrawString(text_left, text_right, y + 1, STR_DEPARTURES_NONE_SELECTED);
		return;
	}

	/* No scheduled departures? Then display the information text. */
	if (max_departures == 0) {
		DrawString(text_left, text_right, y + 1, STR_DEPARTURES_EMPTY);
		return;
	}

	/* Find the maximum possible width of the departure time and "Expt <time>" fields. */
	int time_width = cached_date_width;

	if (!_settings_client.gui.departure_show_both) {
		time_width += (departure_types[0] && departure_types[1] ? cached_date_arrow_width : 0);
	}

	/* Vehicle type icon */
	int type_width = _settings_client.gui.departure_show_vehicle_type ? (GetStringBoundingBox(STR_DEPARTURES_TYPE_PLANE)).width : 0;

	/* Find the maximum width of the status field */
	int status_width = cached_status_width;

	/* Find the width of the "Calling at:" field. */
	int calling_at_width = (GetStringBoundingBox(_settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)).width;

	/* Find the maximum company name width. */
	int toc_width = 0;

	/* Find the maximum group name width. */
	int group_width = 0;

	/* Find the maximum vehicle name width. */
	int veh_width = 0;

	if (_settings_client.gui.departure_show_vehicle || _settings_client.gui.departure_show_company || _settings_client.gui.departure_show_group) {
		for (uint i = 0; i < 4; ++i) {
			VehicleList vehicles;

			/* MAX_COMPANIES is probably the wrong thing to put here, but it works. GenerateVehicleSortList doesn't check the company when the type of list is VL_STATION_LIST (r20801). */
			if (!GenerateVehicleSortList(&vehicles, VehicleListIdentifier(VL_STATION_LIST, (VehicleType)(VEH_TRAIN + i), MAX_COMPANIES, station).Pack())) {
				/* Something went wrong: panic! */
				continue;
			}

			for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) {
				SetDParam(0, (uint64)((*v)->index));
				int width = (GetStringBoundingBox(STR_DEPARTURES_VEH)).width;
				if (_settings_client.gui.departure_show_vehicle && width > veh_width) veh_width = width;

				if ((*v)->group_id != INVALID_GROUP && (*v)->group_id != DEFAULT_GROUP) {
					SetDParam(0, (uint64)((*v)->group_id));
					width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width;
					if (_settings_client.gui.departure_show_group && width > group_width) group_width = width;
				}

				SetDParam(0, (uint64)((*v)->owner));
				width = (GetStringBoundingBox(STR_DEPARTURES_TOC)).width;
				if (_settings_client.gui.departure_show_company && width > toc_width) toc_width = width;
			}
		}
	}

	uint departure = 0;
	uint arrival = 0;

	/* Draw each departure. */
	for (uint i = 0; i < max_departures; ++i) {
		const Departure *d;

		if (arrival == this->arrivals->Length()) {
			d = (*(this->departures))[departure++];
		} else if (departure == this->departures->Length()) {
			d = (*(this->arrivals))[arrival++];
		} else {
			d = (*(this->departures))[departure];
			const Departure *a = (*(this->arrivals))[arrival];

			if (a->scheduled_date < d->scheduled_date) {
				d = a;
				arrival++;
			} else {
				departure++;
			}
		}

		if (i < this->vscroll->GetPosition()) {
			continue;
		}

		/* If for some reason the departure is too far in the future or is at a negative time, skip it. */
		if ((d->scheduled_date / DAY_TICKS) > (_date + _settings_client.gui.max_departure_time) ||
			d->scheduled_date < 0) {
			continue;
		}

		if (d->terminus == INVALID_STATION) continue;

		StringID time_str = (departure_types[0] && departure_types[1]) ? (d->type == D_DEPARTURE ? STR_DEPARTURES_TIME_DEP : STR_DEPARTURES_TIME_ARR) : STR_DEPARTURES_TIME;

		if (_settings_client.gui.departure_show_both) time_str = STR_DEPARTURES_TIME_BOTH;

		/* Time */
		SetDParam(0, d->scheduled_date);
		SetDParam(1, d->scheduled_date - d->order->wait_time);
		ltr ? DrawString(              text_left, text_left + time_width, y + 1, time_str)
			: DrawString(text_right - time_width,             text_right, y + 1, time_str);

		/* Vehicle type icon, with thanks to sph */
		if (_settings_client.gui.departure_show_vehicle_type) {
			StringID type = STR_DEPARTURES_TYPE_TRAIN;
			int offset = (_settings_client.gui.departure_show_vehicle_color ? 1 : 0);

			switch (d->vehicle->type) {
				case VEH_TRAIN:
					type = STR_DEPARTURES_TYPE_TRAIN;
					break;
				case VEH_ROAD:
					type = IsCargoInClass(d->vehicle->cargo_type, CC_PASSENGERS) ? STR_DEPARTURES_TYPE_BUS : STR_DEPARTURES_TYPE_LORRY;
					break;
				case VEH_SHIP:
					type = STR_DEPARTURES_TYPE_SHIP;
					break;
				case VEH_AIRCRAFT:
					type = STR_DEPARTURES_TYPE_PLANE;
					break;
				default:
					break;
			}

			type += offset;

			DrawString(text_left + time_width + 3, text_left + time_width + type_width + 3, y, type);
		}

		/* The icons to show with the destination and via stations. */
		StringID icon = STR_DEPARTURES_STATION_NONE;
		StringID icon_via = STR_DEPARTURES_STATION_NONE;

		if (_settings_client.gui.departure_destination_type) {
			Station *t = Station::Get(d->terminus.station);

			if (t->facilities & FACIL_DOCK &&
					t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_SHIP &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon = STR_DEPARTURES_STATION_PORTAIRPORT;
			} else if (t->facilities & FACIL_DOCK &&
					d->vehicle->type != VEH_SHIP) {
				icon = STR_DEPARTURES_STATION_PORT;
			} else if (t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon = STR_DEPARTURES_STATION_AIRPORT;
			}
		}

		if (_settings_client.gui.departure_destination_type && d->via != INVALID_STATION) {
			Station *t = Station::Get(d->via);

			if (t->facilities & FACIL_DOCK &&
					t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_SHIP &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon_via = STR_DEPARTURES_STATION_PORTAIRPORT;
			} else if (t->facilities & FACIL_DOCK &&
					d->vehicle->type != VEH_SHIP) {
				icon_via = STR_DEPARTURES_STATION_PORT;
			} else if (t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon_via = STR_DEPARTURES_STATION_AIRPORT;
			}
		}

		/* Destination */
		if (d->via == INVALID_STATION) {
			/* Only show the terminus. */
			SetDParam(0, d->terminus.station);
			SetDParam(1, icon);
			ltr ? DrawString(              text_left + time_width + type_width + 6,   text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS)
				: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,                 text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS);
		} else {
			/* Show the terminus and the via station. */
			SetDParam(0, d->terminus.station);
			SetDParam(1, icon);
			SetDParam(2, d->via);
			SetDParam(3, icon_via);
			int text_width = (GetStringBoundingBox(STR_DEPARTURES_TERMINUS_VIA_STATION)).width;

			if (text_width < text_right - status_width - (toc_width + veh_width + group_width + 2) - 2 - (text_left + time_width + type_width + 6)) {
				/* They will both fit, so show them both. */
				SetDParam(0, d->terminus.station);
				SetDParam(1, icon);
				SetDParam(2, d->via);
				SetDParam(3, icon_via);
				ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION)
					: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION);
			} else {
				/* They won't both fit, so switch between showing the terminus and the via station approximately every 4 seconds. */
				if (this->tick_count & (1 << 7)) {
					SetDParam(0, d->via);
					SetDParam(1, icon_via);
					ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_VIA)
						: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_VIA);
				} else {
					SetDParam(0, d->terminus.station);
					SetDParam(1, icon);
					ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA)
						: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA);
				}
			}
		}

		/* Status */
		{
			int status_left = ltr ? text_right - status_width - 2 - (toc_width + veh_width + group_width + 2) : text_left + (toc_width + veh_width + group_width + 2) + 7;
			int status_right = ltr ? text_right - (toc_width + veh_width + group_width + 2) + 2 : text_left + status_width + 2 + (toc_width + veh_width + group_width + 7);

			if (d->status == D_ARRIVED) {
				/* The vehicle has arrived. */
				DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ARRIVED);
			} else if(d->status == D_CANCELLED) {
				/* The vehicle has been cancelled. */
				DrawString(status_left, status_right, y + 1, STR_DEPARTURES_CANCELLED);
			} else{
				if (d->lateness <= DAY_TICKS && d->scheduled_date > ((_date * DAY_TICKS) + _date_fract)) {
					/* We have no evidence that the vehicle is late, so assume it is on time. */
					DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ON_TIME);
				} else {
					if ((d->scheduled_date + d->lateness) < ((_date * DAY_TICKS) + _date_fract)) {
						/* The vehicle was expected to have arrived by now, even if we knew it was going to be late. */
						/* We assume that the train stays at least a day at a station so it won't accidentally be marked as delayed for a fraction of a day. */
						DrawString(status_left, status_right, y + 1, STR_DEPARTURES_DELAYED);
					} else {
						/* The vehicle is expected to be late and is not yet due to arrive. */
						SetDParam(0, d->scheduled_date + d->lateness);
						DrawString(status_left, status_right, y + 1, STR_DEPARTURES_EXPECTED);
					}
				}
			}
		}

		/* Vehicle name */

		if (_settings_client.gui.departure_show_vehicle) {
			SetDParam(0, (uint64)(d->vehicle->index));
			ltr ? DrawString(text_right - (toc_width + veh_width + group_width + 2),              text_right - toc_width - group_width - 2, y + 1, STR_DEPARTURES_VEH)
				: DrawString(               text_left + toc_width + group_width + 2, text_left + (toc_width + veh_width + group_width + 2), y + 1, STR_DEPARTURES_VEH);
		}

		/* Group name */

		if (_settings_client.gui.departure_show_group && d->vehicle->group_id != INVALID_GROUP && d->vehicle->group_id != DEFAULT_GROUP) {
			SetDParam(0, (uint64)(d->vehicle->group_id));
			ltr ? DrawString(text_right - (toc_width + group_width + 2),              text_right - toc_width - 2, y + 1, STR_DEPARTURES_GROUP)
				: DrawString(               text_left + toc_width + 2, text_left + (toc_width + group_width + 2), y + 1, STR_DEPARTURES_GROUP);
		}

		/* Operating company */
		if (_settings_client.gui.departure_show_company) {
			SetDParam(0, (uint64)(d->vehicle->owner));
			ltr ? DrawString(text_right - toc_width,            text_right, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_RIGHT)
				: DrawString(             text_left, text_left + toc_width, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_LEFT);
		}

		int bottom_y = y + this->entry_height - small_font_size - (_settings_client.gui.departure_larger_font ? 1 : 3);

		/* Calling at */
		ltr ? DrawString(                    text_left,  text_left + calling_at_width, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)
			: DrawString(text_right - calling_at_width,                    text_right, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT);

		/* List of stations */
		/* RTL languages can be handled in the language file, e.g. by having the following: */
		/* STR_DEPARTURES_CALLING_AT_STATION      :{STATION}, {RAW_STRING} */
		/* STR_DEPARTURES_CALLING_AT_LAST_STATION :{STATION} & {RAW_STRING}*/
		char buffer[512], scratch[512];

		if (d->calling_at.Length() != 0) {
			SetDParam(0, (uint64)(*d->calling_at.Get(0)).station);
			GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch));

			StationID continuesTo = INVALID_STATION;

			if (d->calling_at.Get(0)->station == d->terminus.station && d->calling_at.Length() > 1) {
				continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station;
			} else if (d->calling_at.Length() > 1) {
				/* There's more than one stop. */

				uint i;
				/* For all but the last station, write out ", <station>". */
				for (i = 1; i < d->calling_at.Length() - 1; ++i) {
					StationID s = d->calling_at.Get(i)->station;
					if (s == d->terminus.station) {
						continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station;
						break;
					}
					SetDParam(0, (uint64)scratch);
					SetDParam(1, (uint64)s);
					GetString(buffer, STR_DEPARTURES_CALLING_AT_STATION, lastof(buffer));
					strncpy(scratch, buffer, sizeof(scratch));
				}

				/* Finally, finish off with " and <station>". */
				SetDParam(0, (uint64)scratch);
				SetDParam(1, (uint64)d->calling_at.Get(i)->station);
				GetString(buffer, STR_DEPARTURES_CALLING_AT_LAST_STATION, lastof(buffer));
				strncpy(scratch, buffer, sizeof(scratch));
			}

			SetDParam(0, (uint64)scratch);
			StringID string;
			if (continuesTo == INVALID_STATION) {
				string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_LARGE : STR_DEPARTURES_CALLING_AT_LIST;
			} else {
				SetDParam(1, continuesTo);
				string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS_LARGE : STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS;
			}
			GetString(buffer, string, lastof(buffer));
		} else {
			buffer[0] = 0;
			//SetDParam(0, d->terminus);
			//GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch));
		}

		int list_width = (GetStringBoundingBox(buffer, _settings_client.gui.departure_larger_font ? FS_NORMAL : FS_SMALL)).width;

		/* Draw the whole list if it will fit. Otherwise scroll it. */
		if (list_width < text_right - (text_left + calling_at_width + 2)) {
			ltr ? DrawString(text_left + calling_at_width + 2,                        text_right, bottom_y, buffer)
				: DrawString(                       text_left, text_right - calling_at_width - 2, bottom_y, buffer);
		} else {
			DrawPixelInfo tmp_dpi;
			if (ltr
				? !FillDrawPixelInfo(&tmp_dpi, text_left + calling_at_width + 2, bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)
				: !FillDrawPixelInfo(&tmp_dpi, text_left                       , bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)) {
				y += this->entry_height;
				continue;
			}
			DrawPixelInfo *old_dpi = _cur_dpi;
			_cur_dpi = &tmp_dpi;

			/* The scrolling text starts out of view at the right of the screen and finishes when it is out of view at the left of the screen. */
			int pos = ltr
				? text_right - (this->tick_count % (list_width + text_right - text_left))
				:  text_left + (this->tick_count % (list_width + text_right - text_left));

			ltr ? DrawString(       pos, INT16_MAX, 0, buffer, TC_FROMSTRING,  SA_LEFT | SA_FORCE)
				: DrawString(-INT16_MAX,       pos, 0, buffer, TC_FROMSTRING, SA_RIGHT | SA_FORCE);

			_cur_dpi = old_dpi;
		}

		y += this->entry_height;
	}
}