Files @ r17613:a9b2554a5d79
Branch filter:

Location: cpp/openttd-patchpack/source/src/engine_gui.cpp - annotation

rubidium
(svn r22387) -Fix-ish [FS#4601]: Windows' recv seems to return "graceful closed" before having passed the remaining buffer which causes OpenTTD to think all connections are "incorrectly" terminated, i.e. without the "I'm leaving" packet from the client. So let the client wait a tiny bit after sending the "I'm leaving" packet and before gracefully closing the connection
r5584:545d748cc681
r5584:545d748cc681
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r9111:983de9c5a848
r6125:eb40461cb765
r5584:545d748cc681
r8107:82461791b7a2
r8224:194097dc7288
r9070:e059c65164f3
r8116:df67d3c5e4fd
r8114:866ed489ed98
r9380:6b24883f64de
r9567:b3592d86e408
r12037:7b4fedf64d47
r12037:7b4fedf64d47
r10000:91824eb4383b
r13372:236fb191f6c2
r5584:545d748cc681
r8264:d493cb51fe8a
r5584:545d748cc681
r15610:623a23fb6560
r15610:623a23fb6560
r12827:19af93950884
r12827:19af93950884
r12827:19af93950884
r9199:7d9724de3af0
r5584:545d748cc681
r13208:40382e8abf19
r13208:40382e8abf19
r6209:f315c4c30b43
r11725:57bc99fdc1bc
r11725:57bc99fdc1bc
r11725:57bc99fdc1bc
r6259:e2dba394134b
r13208:40382e8abf19
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r11423:97fd1230114c
r11423:97fd1230114c
r13490:0caa306cf3f9
r11423:97fd1230114c
r11423:97fd1230114c
r11423:97fd1230114c
r11423:97fd1230114c
r11512:4e2f95d920fb
r11512:4e2f95d920fb
r13742:180ad925befc
r13742:180ad925befc
r11512:4e2f95d920fb
r13745:49505a0400d8
r13694:4523784084b5
r13490:0caa306cf3f9
r13694:4523784084b5
r13694:4523784084b5
r11512:4e2f95d920fb
r11512:4e2f95d920fb
r11512:4e2f95d920fb
r11512:4e2f95d920fb
r11512:4e2f95d920fb
r9302:115cfeb49cd5
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r9302:115cfeb49cd5
r13490:0caa306cf3f9
r9302:115cfeb49cd5
r5584:545d748cc681
r13695:e0bf1a35834a
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r5584:545d748cc681
r9302:115cfeb49cd5
r5584:545d748cc681
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r5584:545d748cc681
r7059:0c2dc932a6ae
r15390:44d506cb3529
r13490:0caa306cf3f9
r5584:545d748cc681
r13587:9ee7798ce808
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r13490:0caa306cf3f9
r5584:545d748cc681
r5584:545d748cc681
r14399:3f819c0da60a
r9302:115cfeb49cd5
r9302:115cfeb49cd5
r11423:97fd1230114c
r10499:570896340d7a
r15569:7f2810d85ccf
r11423:97fd1230114c
r9302:115cfeb49cd5
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r9302:115cfeb49cd5
r5584:545d748cc681
r11368:058349c3a02c
r13788:02dadd01bdbe
r5893:6c4fd9987e0f
r13739:747ed1f003e3
r13554:d1964ead02ee
r11368:058349c3a02c
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r9302:115cfeb49cd5
r5584:545d748cc681
r5584:545d748cc681
r13211:4ba95564ba64
r9567:b3592d86e408
r9567:b3592d86e408
r9567:b3592d86e408
r13211:4ba95564ba64
r12254:2375853718ac
r9567:b3592d86e408
r9567:b3592d86e408
r9567:b3592d86e408
r9567:b3592d86e408
r9567:b3592d86e408
r9567:b3592d86e408
r12828:1411e13c41d0
r5584:545d748cc681
r10927:eb69eaf0227d
r10967:2c98940d6c64
r10967:2c98940d6c64
r10967:2c98940d6c64
r13372:236fb191f6c2
r5584:545d748cc681
r10927:eb69eaf0227d
r5584:545d748cc681
r13211:4ba95564ba64
r9567:b3592d86e408
r11188:143f3c64befd
r9720:6d491d07d0a8
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r14396:0e22f6ee524f
r5584:545d748cc681
r5584:545d748cc681
r12828:1411e13c41d0
r5584:545d748cc681
r11350:df593340eca2
r13407:428d181f586b
r13407:428d181f586b
r11350:df593340eca2
r14191:bc6b1902e177
r14191:bc6b1902e177
r14191:bc6b1902e177
r14191:bc6b1902e177
r14191:bc6b1902e177
r13407:428d181f586b
r13407:428d181f586b
r13407:428d181f586b
r11712:c05ce4b83dd6
r12828:1411e13c41d0
r11350:df593340eca2
r11350:df593340eca2
r12828:1411e13c41d0
r11350:df593340eca2
r5584:545d748cc681
r5584:545d748cc681
r12828:1411e13c41d0
r5584:545d748cc681
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r11188:143f3c64befd
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r14749:107a1d25efe3
r11188:143f3c64befd
r5584:545d748cc681
r5584:545d748cc681
r12828:1411e13c41d0
r5584:545d748cc681
r10927:eb69eaf0227d
r10967:2c98940d6c64
r11188:143f3c64befd
r11403:ba31da6812eb
r10927:eb69eaf0227d
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r12828:1411e13c41d0
r5584:545d748cc681
r5584:545d748cc681
r12825:b76c82800d1a
r12825:b76c82800d1a
r13587:9ee7798ce808
r13587:9ee7798ce808
r13587:9ee7798ce808
r12825:b76c82800d1a
r12825:b76c82800d1a
r13060:e57594b0ca84
r12825:b76c82800d1a
r14309:f445232b17f6
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r13587:9ee7798ce808
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r13587:9ee7798ce808
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r13587:9ee7798ce808
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r13587:9ee7798ce808
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r12825:b76c82800d1a
r15610:623a23fb6560
r15610:623a23fb6560
r9380:6b24883f64de
r9380:6b24883f64de
r9380:6b24883f64de
r9403:e5bffa930a63
r9380:6b24883f64de
r9403:e5bffa930a63
r9380:6b24883f64de
r9380:6b24883f64de
r9380:6b24883f64de
r13022:11b36960dd16
r9380:6b24883f64de
r9380:6b24883f64de
r15610:623a23fb6560
r15610:623a23fb6560
r9380:6b24883f64de
r9380:6b24883f64de
r9380:6b24883f64de
r9380:6b24883f64de
r9380:6b24883f64de
r9403:e5bffa930a63
r9380:6b24883f64de
r9404:f74e13f5c66e
r9403:e5bffa930a63
r9403:e5bffa930a63
r13022:11b36960dd16
r9380:6b24883f64de
r9380:6b24883f64de
/* $Id$ */

/*
 * This file is part of OpenTTD.
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * 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 engine_gui.cpp GUI to show engine related information. */

#include "stdafx.h"
#include "window_gui.h"
#include "gfx_func.h"
#include "engine_base.h"
#include "command_func.h"
#include "strings_func.h"
#include "engine_gui.h"
#include "articulated_vehicles.h"
#include "vehicle_func.h"
#include "company_func.h"
#include "rail.h"
#include "settings_type.h"

#include "table/strings.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.
 */
StringID GetEngineCategoryName(EngineID engine)
{
	const Engine *e = Engine::Get(engine);
	switch (e->type) {
		default: NOT_REACHED();
		case VEH_ROAD:              return STR_ENGINE_PREVIEW_ROAD_VEHICLE;
		case VEH_AIRCRAFT:          return STR_ENGINE_PREVIEW_AIRCRAFT;
		case VEH_SHIP:              return STR_ENGINE_PREVIEW_SHIP;
		case VEH_TRAIN:
			return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco;
	}
}

/** Widgets used for the engine preview window */
enum EnginePreviewWidgets {
	EPW_QUESTION,   ///< The container for the question
	EPW_NO,         ///< No button
	EPW_YES,        ///< Yes button
};

static const NWidgetPart _nested_engine_preview_widgets[] = {
	NWidget(NWID_HORIZONTAL),
		NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
		NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
	EndContainer(),
	NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
		NWidget(WWT_EMPTY, INVALID_COLOUR, EPW_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0),
		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85),
			NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, EPW_NO), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
			NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, EPW_YES), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
		EndContainer(),
		NWidget(NWID_SPACER), SetMinimalSize(0, 8),
	EndContainer(),
};

struct EnginePreviewWindow : Window {
	static const int VEHICLE_SPACE = 40; // The space to show the vehicle image

	EnginePreviewWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
	{
		this->InitNested(desc, window_number);
	}

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

		EngineID engine = this->window_number;
		SetDParam(0, GetEngineCategoryName(engine));
		size->height = GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, size->width) + WD_PAR_VSEP_WIDE + FONT_HEIGHT_NORMAL + VEHICLE_SPACE;
		SetDParam(0, engine);
		size->height += GetStringHeight(GetEngineInfoString(engine), size->width);
	}

	virtual void DrawWidget(const Rect &r, int widget) const
	{
		if (widget != EPW_QUESTION) return;

		EngineID engine = this->window_number;
		SetDParam(0, GetEngineCategoryName(engine));
		int y = r.top + GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, r.right - r.top + 1);
		y = DrawStringMultiLine(r.left, r.right, r.top, y, STR_ENGINE_PREVIEW_MESSAGE, TC_FROMSTRING, SA_CENTER) + WD_PAR_VSEP_WIDE;

		SetDParam(0, engine);
		DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_ENGINE_NAME, TC_BLACK, SA_HOR_CENTER);
		y += FONT_HEIGHT_NORMAL;

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

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

	virtual void OnClick(Point pt, int widget, int click_count)
	{
		switch (widget) {
			case EPW_YES:
				DoCommandP(0, this->window_number, 0, CMD_WANT_ENGINE_PREVIEW);
				/* FALL THROUGH */
			case EPW_NO:
				delete this;
				break;
		}
	}
};

static const WindowDesc _engine_preview_desc(
	WDP_CENTER, 0, 0,
	WC_ENGINE_PREVIEW, WC_NONE,
	WDF_CONSTRUCTION,
	_nested_engine_preview_widgets, lengthof(_nested_engine_preview_widgets)
);


void ShowEnginePreviewWindow(EngineID engine)
{
	AllocateWindowDescFront<EnginePreviewWindow>(&_engine_preview_desc, engine);
}

uint GetTotalCapacityOfArticulatedParts(EngineID engine)
{
	uint total = 0;

	CargoArray cap = GetCapacityOfArticulatedParts(engine);
	for (CargoID c = 0; c < NUM_CARGO; c++) {
		total += cap[c];
	}

	return total;
}

static StringID GetTrainEngineInfoString(const Engine *e)
{
	SetDParam(0, e->GetCost());
	SetDParam(2, e->GetDisplayMaxSpeed());
	SetDParam(3, e->GetPower());
	SetDParam(1, e->GetDisplayWeight());
	SetDParam(7, e->GetDisplayMaxTractiveEffort());

	SetDParam(4, e->GetRunningCost());

	uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
	if (capacity != 0) {
		SetDParam(5, e->GetDefaultCargoType());
		SetDParam(6, capacity);
	} else {
		SetDParam(5, CT_INVALID);
	}
	return (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e->u.rail.railtype)->acceleration_type != 2) ? STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE : STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER;
}

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;
	}
}

static StringID GetRoadVehEngineInfoString(const Engine *e)
{
	if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
		SetDParam(0, e->GetCost());
		SetDParam(1, e->GetDisplayMaxSpeed());
		uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
		if (capacity != 0) {
			SetDParam(2, e->GetDefaultCargoType());
			SetDParam(3, capacity);
		} else {
			SetDParam(2, CT_INVALID);
		}
		SetDParam(4, e->GetRunningCost());
		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
	} else {
		SetDParam(0, e->GetCost());
		SetDParam(2, e->GetDisplayMaxSpeed());
		SetDParam(3, e->GetPower());
		SetDParam(1, e->GetDisplayWeight());
		SetDParam(7, e->GetDisplayMaxTractiveEffort());

		SetDParam(4, e->GetRunningCost());

		uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
		if (capacity != 0) {
			SetDParam(5, e->GetDefaultCargoType());
			SetDParam(6, capacity);
		} else {
			SetDParam(5, CT_INVALID);
		}
		return STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE;
	}
}

static StringID GetShipEngineInfoString(const Engine *e)
{
	SetDParam(0, e->GetCost());
	SetDParam(1, e->GetDisplayMaxSpeed());
	SetDParam(2, e->GetDefaultCargoType());
	SetDParam(3, e->GetDisplayDefaultCapacity());
	SetDParam(4, e->GetRunningCost());
	return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
}


/**
 * Get a multi-line string with some technical data, describing the engine.
 * @param engine Engine to describe.
 * @return String describing the engine.
 * @post \c DParam array is set up for printing the string.
 */
StringID GetEngineInfoString(EngineID engine)
{
	const Engine *e = Engine::Get(engine);

	switch (e->type) {
		case VEH_TRAIN:
			return GetTrainEngineInfoString(e);

		case VEH_ROAD:
			return GetRoadVehEngineInfoString(e);

		case VEH_SHIP:
			return GetShipEngineInfoString(e);

		case VEH_AIRCRAFT:
			return GetAircraftEngineInfoString(e);

		default: NOT_REACHED();
	}
}

/**
 * Draw an engine.
 * @param left   Minimum horizontal position to use for drawing the engine
 * @param right  Maximum horizontal position to use for drawing the engine
 * @param preferred_x Horizontal position to use for drawing the engine.
 * @param y      Vertical position to use for drawing the engine.
 * @param engine Engine to draw.
 * @param pal    Palette to use for drawing.
 */
void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal)
{
	const Engine *e = Engine::Get(engine);

	switch (e->type) {
		case VEH_TRAIN:
			DrawTrainEngine(left, right, preferred_x, y, engine, pal);
			break;

		case VEH_ROAD:
			DrawRoadVehEngine(left, right, preferred_x, y, engine, pal);
			break;

		case VEH_SHIP:
			DrawShipEngine(left, right, preferred_x, y, engine, pal);
			break;

		case VEH_AIRCRAFT:
			DrawAircraftEngine(left, right, preferred_x, y, engine, pal);
			break;

		default: NOT_REACHED();
	}
}

/**
 * Sort all items using quick sort and given 'CompareItems' function
 * @param el list to be sorted
 * @param compare function for evaluation of the quicksort
 */
void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
{
	uint size = el->Length();
	/* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
	 * generally, do not sort if there are less than 2 items */
	if (size < 2) return;
	QSortT(el->Begin(), size, compare);
}

/**
 * Sort selected range of items (on indices @ <begin, begin+num_items-1>)
 * @param el list to be sorted
 * @param compare function for evaluation of the quicksort
 * @param begin start of sorting
 * @param num_items count of items to be sorted
 */
void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items)
{
	if (num_items < 2) return;
	assert(begin < el->Length());
	assert(begin + num_items <= el->Length());
	QSortT(el->Get(begin), num_items, compare);
}