2009-08-21 22:21:05 +02:00
/*
* 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/>.
*/
2008-05-06 17:11:33 +02:00
/** @file build_vehicle_gui.cpp GUI for building vehicles. */
2007-02-23 12:50:43 +01:00
2010-01-15 17:41:15 +01:00
# include "stdafx.h"
# include "engine_base.h"
# include "engine_func.h"
2009-06-24 19:39:54 +02:00
# include "station_base.h"
2013-06-11 20:24:01 +02:00
# include "network/network.h"
2007-06-01 13:41:02 +02:00
# include "articulated_vehicles.h"
2007-12-19 21:45:46 +01:00
# include "textbuf_gui.h"
2007-12-21 22:50:46 +01:00
# include "command_func.h"
2008-09-30 22:51:04 +02:00
# include "company_func.h"
2006-10-10 17:02:38 +02:00
# include "vehicle_gui.h"
# include "newgrf_engine.h"
2009-05-22 21:47:26 +02:00
# include "newgrf_text.h"
2007-05-19 11:40:18 +02:00
# include "group.h"
2011-04-30 16:24:23 +02:00
# include "string_func.h"
2007-12-21 20:49:27 +01:00
# include "strings_func.h"
2007-12-25 12:26:07 +01:00
# include "window_func.h"
2023-05-04 15:14:12 +02:00
# include "timer/timer_game_calendar.h"
2007-12-27 14:35:39 +01:00
# include "vehicle_func.h"
2024-03-31 18:31:47 +02:00
# include "dropdown_type.h"
2024-03-31 20:37:16 +02:00
# include "dropdown_func.h"
2008-05-27 14:24:23 +02:00
# include "engine_gui.h"
2009-06-24 23:33:11 +02:00
# include "cargotype.h"
2010-11-12 17:29:09 +01:00
# include "core/geometry_func.hpp"
2012-04-17 21:44:08 +02:00
# include "autoreplace_func.h"
2021-10-31 19:39:09 +01:00
# include "engine_cmd.h"
2021-10-10 02:35:06 +02:00
# include "train_cmd.h"
# include "vehicle_cmd.h"
2022-10-21 20:58:43 +02:00
# include "zoom_func.h"
2023-05-01 19:02:16 +02:00
# include "querystring_gui.h"
# include "stringfilter_type.h"
# include "hotkeys.h"
2006-10-10 17:02:38 +02:00
2011-12-15 23:22:55 +01:00
# include "widgets/build_vehicle_widget.h"
2008-01-13 02:21:35 +01:00
# include "table/strings.h"
2014-04-23 22:13:33 +02:00
# include "safeguards.h"
2009-11-16 17:22:14 +01:00
/**
* Get the height of a single ' entry ' in the engine lists .
* @ param type the vehicle type to get the height of
* @ return the height for the entry
*/
uint GetEngineListHeight ( VehicleType type )
{
2023-11-21 20:04:24 +01:00
return std : : max < uint > ( GetCharacterHeight ( FS_NORMAL ) + WidgetDimensions : : scaled . matrix . Vertical ( ) , GetVehicleImageCellSize ( type , EIT_PURCHASE ) . height ) ;
2009-11-16 17:22:14 +01:00
}
2024-01-15 23:49:24 +01:00
static constexpr NWidgetPart _nested_build_vehicle_widgets [ ] = {
2009-03-22 22:16:57 +01:00
NWidget ( NWID_HORIZONTAL ) ,
2009-11-24 19:05:55 +01:00
NWidget ( WWT_CLOSEBOX , COLOUR_GREY ) ,
2023-04-25 11:03:48 +02:00
NWidget ( WWT_CAPTION , COLOUR_GREY , WID_BV_CAPTION ) , SetDataTip ( STR_JUST_STRING , STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS ) , SetTextStyle ( TC_WHITE ) ,
2009-12-21 17:24:29 +01:00
NWidget ( WWT_SHADEBOX , COLOUR_GREY ) ,
2013-05-26 21:30:07 +02:00
NWidget ( WWT_DEFSIZEBOX , COLOUR_GREY ) ,
2009-12-09 18:10:57 +01:00
NWidget ( WWT_STICKYBOX , COLOUR_GREY ) ,
2009-03-22 22:16:57 +01:00
EndContainer ( ) ,
2023-05-08 19:21:29 +02:00
NWidget ( NWID_VERTICAL ) ,
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_BV_SORT_ASCENDING_DESCENDING ) , SetDataTip ( STR_BUTTON_SORT_BY , STR_TOOLTIP_SORT_ORDER ) ,
NWidget ( WWT_DROPDOWN , COLOUR_GREY , WID_BV_SORT_DROPDOWN ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) , SetDataTip ( STR_JUST_STRING , STR_TOOLTIP_SORT_CRITERIA ) ,
EndContainer ( ) ,
NWidget ( NWID_HORIZONTAL ) ,
NWidget ( WWT_TEXTBTN , COLOUR_GREY , WID_BV_SHOW_HIDDEN_ENGINES ) ,
NWidget ( WWT_DROPDOWN , COLOUR_GREY , WID_BV_CARGO_FILTER_DROPDOWN ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) , SetDataTip ( STR_JUST_STRING , STR_TOOLTIP_FILTER_CRITERIA ) ,
EndContainer ( ) ,
NWidget ( WWT_PANEL , COLOUR_GREY ) ,
NWidget ( WWT_EDITBOX , COLOUR_GREY , WID_BV_FILTER ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) , SetPadding ( 2 ) , SetDataTip ( STR_LIST_FILTER_OSKTITLE , STR_LIST_FILTER_TOOLTIP ) ,
2009-04-12 19:38:01 +02:00
EndContainer ( ) ,
2009-03-22 22:16:57 +01:00
EndContainer ( ) ,
/* Vehicle list. */
NWidget ( NWID_HORIZONTAL ) ,
2013-06-30 16:36:31 +02:00
NWidget ( WWT_MATRIX , COLOUR_GREY , WID_BV_LIST ) , SetResize ( 1 , 1 ) , SetFill ( 1 , 0 ) , SetMatrixDataTip ( 1 , 0 , STR_NULL ) , SetScrollbar ( WID_BV_SCROLLBAR ) ,
2011-12-16 17:27:45 +01:00
NWidget ( NWID_VSCROLLBAR , COLOUR_GREY , WID_BV_SCROLLBAR ) ,
2009-03-22 22:16:57 +01:00
EndContainer ( ) ,
/* Panel with details. */
2011-12-16 17:27:45 +01:00
NWidget ( WWT_PANEL , COLOUR_GREY , WID_BV_PANEL ) , SetMinimalSize ( 240 , 122 ) , SetResize ( 1 , 0 ) , EndContainer ( ) ,
2009-03-22 22:16:57 +01:00
/* Build/rename buttons, resize button. */
NWidget ( NWID_HORIZONTAL ) ,
2011-12-16 17:27:45 +01:00
NWidget ( NWID_SELECTION , INVALID_COLOUR , WID_BV_BUILD_SEL ) ,
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_BV_BUILD ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) ,
2009-10-25 02:26:40 +02:00
EndContainer ( ) ,
2014-09-07 18:14:06 +02:00
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_BV_SHOW_HIDE ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) , SetDataTip ( STR_JUST_STRING , STR_NULL ) ,
2011-12-16 17:27:45 +01:00
NWidget ( WWT_PUSHTXTBTN , COLOUR_GREY , WID_BV_RENAME ) , SetResize ( 1 , 0 ) , SetFill ( 1 , 0 ) ,
2009-11-24 19:05:55 +01:00
NWidget ( WWT_RESIZEBOX , COLOUR_GREY ) ,
2009-03-22 22:16:57 +01:00
EndContainer ( ) ,
} ;
2009-03-10 22:17:00 +01:00
2009-04-12 19:38:01 +02:00
2014-09-07 18:10:27 +02:00
bool _engine_sort_direction ; ///< \c false = descending, \c true = ascending.
2024-03-16 23:59:32 +01:00
uint8_t _engine_sort_last_criteria [ ] = { 0 , 0 , 0 , 0 } ; ///< Last set sort criteria, for each vehicle type.
2014-09-07 18:10:27 +02:00
bool _engine_sort_last_order [ ] = { false , false , false , false } ; ///< Last set direction of the sort order, for each vehicle type.
2014-09-07 18:14:06 +02:00
bool _engine_sort_show_hidden_engines [ ] = { false , false , false , false } ; ///< Last set 'show hidden engines' setting for each vehicle type.
2024-01-06 16:29:48 +01:00
static CargoID _engine_sort_last_cargo_criteria [ ] = { CargoFilterCriteria : : CF_ANY , CargoFilterCriteria : : CF_ANY , CargoFilterCriteria : : CF_ANY , CargoFilterCriteria : : CF_ANY } ; ///< Last set filter criteria, for each vehicle type.
2006-10-10 17:02:38 +02:00
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by engineID
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineNumberSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2006-10-10 17:02:38 +02:00
{
2019-02-27 08:04:17 +01:00
int r = Engine : : Get ( a . engine_id ) - > list_position - Engine : : Get ( b . engine_id ) - > list_position ;
2006-10-10 17:02:38 +02:00
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2006-10-10 17:02:38 +02:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by introduction date
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineIntroDateSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2006-10-10 17:02:38 +02:00
{
2023-08-11 14:18:32 +02:00
const auto va = Engine : : Get ( a . engine_id ) - > intro_date ;
const auto vb = Engine : : Get ( b . engine_id ) - > intro_date ;
const auto r = va - vb ;
2006-10-10 17:02:38 +02:00
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2006-10-10 17:02:38 +02:00
}
2020-06-15 19:36:33 +02:00
/* cached values for EngineNameSorter to spare many GetString() calls */
static EngineID _last_engine [ 2 ] = { INVALID_ENGINE , INVALID_ENGINE } ;
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by name
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineNameSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2006-10-10 17:02:38 +02:00
{
2023-05-31 18:02:50 +02:00
static std : : string last_name [ 2 ] = { { } , { } } ;
2006-10-10 17:46:03 +02:00
2019-02-27 08:04:17 +01:00
if ( a . engine_id ! = _last_engine [ 0 ] ) {
_last_engine [ 0 ] = a . engine_id ;
2023-01-22 22:06:48 +01:00
SetDParam ( 0 , PackEngineNameDParam ( a . engine_id , EngineNameContext : : PurchaseList ) ) ;
2023-05-31 18:02:50 +02:00
last_name [ 0 ] = GetString ( STR_ENGINE_NAME ) ;
2006-10-10 17:46:03 +02:00
}
2006-10-10 17:02:38 +02:00
2019-02-27 08:04:17 +01:00
if ( b . engine_id ! = _last_engine [ 1 ] ) {
_last_engine [ 1 ] = b . engine_id ;
2023-01-22 22:06:48 +01:00
SetDParam ( 0 , PackEngineNameDParam ( b . engine_id , EngineNameContext : : PurchaseList ) ) ;
2023-05-31 18:02:50 +02:00
last_name [ 1 ] = GetString ( STR_ENGINE_NAME ) ;
2006-10-10 17:02:38 +02:00
}
2023-04-27 15:39:10 +02:00
int r = StrNaturalCompare ( last_name [ 0 ] , last_name [ 1 ] ) ; // Sort by name (natural sorting).
2006-10-10 17:02:38 +02:00
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2006-10-10 17:02:38 +02:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by reliability
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineReliabilitySorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2006-10-10 17:02:38 +02:00
{
2019-02-27 08:04:17 +01:00
const int va = Engine : : Get ( a . engine_id ) - > reliability ;
const int vb = Engine : : Get ( b . engine_id ) - > reliability ;
2006-10-10 17:02:38 +02:00
const int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2006-10-10 17:02:38 +02:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by purchase cost
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineCostSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
Money va = Engine : : Get ( a . engine_id ) - > GetCost ( ) ;
Money vb = Engine : : Get ( b . engine_id ) - > GetCost ( ) ;
2023-04-29 09:25:51 +02:00
int r = ClampTo < int32_t > ( va - vb ) ;
2007-01-21 23:50:43 +01:00
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-01-21 23:50:43 +01:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by speed
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineSpeedSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
int va = Engine : : Get ( a . engine_id ) - > GetDisplayMaxSpeed ( ) ;
int vb = Engine : : Get ( b . engine_id ) - > GetDisplayMaxSpeed ( ) ;
2007-01-21 23:50:43 +01:00
int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-01-21 23:50:43 +01:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by power
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EnginePowerSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
int va = Engine : : Get ( a . engine_id ) - > GetPower ( ) ;
int vb = Engine : : Get ( b . engine_id ) - > GetPower ( ) ;
2007-01-21 23:50:43 +01:00
int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-01-21 23:50:43 +01:00
}
2010-11-06 21:20:03 +01:00
/**
* Determines order of engines by tractive effort
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:20:03 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineTractiveEffortSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2010-11-06 21:20:03 +01:00
{
2019-02-27 08:04:17 +01:00
int va = Engine : : Get ( a . engine_id ) - > GetDisplayMaxTractiveEffort ( ) ;
int vb = Engine : : Get ( b . engine_id ) - > GetDisplayMaxTractiveEffort ( ) ;
2010-11-06 21:20:03 +01:00
int r = va - vb ;
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2010-11-06 21:20:03 +01:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by running costs
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EngineRunningCostSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
Money va = Engine : : Get ( a . engine_id ) - > GetRunningCost ( ) ;
Money vb = Engine : : Get ( b . engine_id ) - > GetRunningCost ( ) ;
2023-04-29 09:25:51 +02:00
int r = ClampTo < int32_t > ( va - vb ) ;
2007-01-21 23:50:43 +01:00
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-01-21 23:50:43 +01:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of engines by running costs
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool EnginePowerVsRunningCostSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
const Engine * e_a = Engine : : Get ( a . engine_id ) ;
const Engine * e_b = Engine : : Get ( b . engine_id ) ;
2019-05-05 23:02:06 +02:00
uint p_a = e_a - > GetPower ( ) ;
uint p_b = e_b - > GetPower ( ) ;
Money r_a = e_a - > GetRunningCost ( ) ;
Money r_b = e_b - > GetRunningCost ( ) ;
/* Check if running cost is zero in one or both engines.
* If only one of them is zero then that one has higher value ,
* else if both have zero cost then compare powers . */
if ( r_a = = 0 ) {
if ( r_b = = 0 ) {
/* If it is ambiguous which to return go with their ID */
if ( p_a = = p_b ) return EngineNumberSorter ( a , b ) ;
return _engine_sort_direction ! = ( p_a < p_b ) ;
}
return ! _engine_sort_direction ;
}
if ( r_b = = 0 ) return _engine_sort_direction ;
/* Using double for more precision when comparing close values.
* This shouldn ' t have any major effects in performance nor in keeping
* the game in sync between players since it ' s used in GUI only in client side */
double v_a = ( double ) p_a / ( double ) r_a ;
double v_b = ( double ) p_b / ( double ) r_b ;
/* Use EngineID to sort if both have same power/running cost,
* since we want consistent sorting .
* Also if both have no power then sort with reverse of running cost to simulate
* previous sorting behaviour for wagons . */
2023-04-23 12:59:58 +02:00
if ( v_a = = 0 & & v_b = = 0 ) return EngineRunningCostSorter ( b , a ) ;
2019-05-05 23:02:06 +02:00
if ( v_a = = v_b ) return EngineNumberSorter ( a , b ) ;
return _engine_sort_direction ! = ( v_a < v_b ) ;
2007-01-21 23:50:43 +01:00
}
2010-03-06 14:03:17 +01:00
/* Train sorting functions */
2010-11-06 21:12:20 +01:00
/**
* Determines order of train engines by capacity
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool TrainEngineCapacitySorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-06-02 17:41:37 +02:00
{
2019-02-27 08:04:17 +01:00
const RailVehicleInfo * rvi_a = RailVehInfo ( a . engine_id ) ;
const RailVehicleInfo * rvi_b = RailVehInfo ( b . engine_id ) ;
2008-09-03 20:05:02 +02:00
2019-02-27 08:04:17 +01:00
int va = GetTotalCapacityOfArticulatedParts ( a . engine_id ) * ( rvi_a - > railveh_type = = RAILVEH_MULTIHEAD ? 2 : 1 ) ;
int vb = GetTotalCapacityOfArticulatedParts ( b . engine_id ) * ( rvi_b - > railveh_type = = RAILVEH_MULTIHEAD ? 2 : 1 ) ;
2007-06-02 17:41:37 +02:00
int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-06-02 17:41:37 +02:00
}
2010-11-06 21:12:20 +01:00
/**
* Determines order of train engines by engine / wagon
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool TrainEnginesThenWagonsSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-01-21 23:50:43 +01:00
{
2019-02-27 08:04:17 +01:00
int val_a = ( RailVehInfo ( a . engine_id ) - > railveh_type = = RAILVEH_WAGON ? 1 : 0 ) ;
int val_b = ( RailVehInfo ( b . engine_id ) - > railveh_type = = RAILVEH_WAGON ? 1 : 0 ) ;
2007-01-21 23:50:43 +01:00
int r = val_a - val_b ;
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-01-21 23:50:43 +01:00
}
2007-12-27 16:47:08 +01:00
/* Road vehicle sorting functions */
2010-11-06 21:12:20 +01:00
/**
* Determines order of road vehicles by capacity
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool RoadVehEngineCapacitySorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-06-02 17:41:37 +02:00
{
2019-02-27 08:04:17 +01:00
int va = GetTotalCapacityOfArticulatedParts ( a . engine_id ) ;
int vb = GetTotalCapacityOfArticulatedParts ( b . engine_id ) ;
2007-12-27 16:47:08 +01:00
int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-12-27 16:47:08 +01:00
}
2009-03-10 22:17:00 +01:00
/* Ship vehicle sorting functions */
2010-11-06 21:12:20 +01:00
/**
* Determines order of ships by capacity
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool ShipEngineCapacitySorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2007-06-02 17:41:37 +02:00
{
2019-02-27 08:04:17 +01:00
const Engine * e_a = Engine : : Get ( a . engine_id ) ;
const Engine * e_b = Engine : : Get ( b . engine_id ) ;
2009-03-18 20:32:13 +01:00
int va = e_a - > GetDisplayDefaultCapacity ( ) ;
int vb = e_b - > GetDisplayDefaultCapacity ( ) ;
2007-06-02 17:41:37 +02:00
int r = va - vb ;
2009-03-10 22:17:00 +01:00
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2007-06-02 17:41:37 +02:00
}
2006-10-10 17:02:38 +02:00
/* Aircraft sorting functions */
2010-11-06 21:12:20 +01:00
/**
* Determines order of aircraft by cargo
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2010-11-06 21:12:20 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool AircraftEngineCargoSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2006-10-10 17:02:38 +02:00
{
2019-02-27 08:04:17 +01:00
const Engine * e_a = Engine : : Get ( a . engine_id ) ;
const Engine * e_b = Engine : : Get ( b . engine_id ) ;
2009-03-14 00:49:12 +01:00
2023-05-08 19:01:06 +02:00
uint16_t mail_a , mail_b ;
2009-10-31 18:48:09 +01:00
int va = e_a - > GetDisplayDefaultCapacity ( & mail_a ) ;
int vb = e_b - > GetDisplayDefaultCapacity ( & mail_b ) ;
2007-06-02 17:47:38 +02:00
int r = va - vb ;
2006-10-10 17:02:38 +02:00
if ( r = = 0 ) {
2009-10-31 18:48:09 +01:00
/* The planes have the same passenger capacity. Check mail capacity instead */
r = mail_a - mail_b ;
2007-06-02 17:47:38 +02:00
if ( r = = 0 ) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter ( a , b ) ;
}
2006-10-10 17:02:38 +02:00
}
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2006-10-10 17:02:38 +02:00
}
2011-12-13 02:18:40 +01:00
/**
* Determines order of aircraft by range .
2019-04-11 22:17:30 +02:00
* @ param a first engine to compare
* @ param b second engine to compare
* @ return for descending order : returns true if a < b . Vice versa for ascending order
2011-12-13 02:18:40 +01:00
*/
2019-02-27 08:04:17 +01:00
static bool AircraftRangeSorter ( const GUIEngineListItem & a , const GUIEngineListItem & b )
2011-12-13 02:18:40 +01:00
{
2023-05-08 19:01:06 +02:00
uint16_t r_a = Engine : : Get ( a . engine_id ) - > GetRange ( ) ;
uint16_t r_b = Engine : : Get ( b . engine_id ) - > GetRange ( ) ;
2011-12-13 02:18:40 +01:00
int r = r_a - r_b ;
/* Use EngineID to sort instead since we want consistent sorting */
if ( r = = 0 ) return EngineNumberSorter ( a , b ) ;
2019-04-11 22:17:30 +02:00
return _engine_sort_direction ? r > 0 : r < 0 ;
2011-12-13 02:18:40 +01:00
}
2014-09-07 18:10:27 +02:00
/** Sort functions for the vehicle sort criteria, for each vehicle type. */
EngList_SortTypeFunction * const _engine_sort_functions [ ] [ 11 ] = { {
2007-01-22 15:08:14 +01:00
/* Trains */
2008-07-20 23:21:51 +02:00
& EngineNumberSorter ,
2009-03-10 22:17:00 +01:00
& EngineCostSorter ,
& EngineSpeedSorter ,
& EnginePowerSorter ,
2010-11-06 21:20:03 +01:00
& EngineTractiveEffortSorter ,
2007-01-21 23:50:43 +01:00
& EngineIntroDateSorter ,
& EngineNameSorter ,
2009-03-10 22:17:00 +01:00
& EngineRunningCostSorter ,
2010-03-06 14:03:17 +01:00
& EnginePowerVsRunningCostSorter ,
2007-01-21 23:50:43 +01:00
& EngineReliabilitySorter ,
2007-06-02 17:41:37 +02:00
& TrainEngineCapacitySorter ,
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Road vehicles */
2007-01-22 02:35:53 +01:00
& EngineNumberSorter ,
2009-03-10 22:17:00 +01:00
& EngineCostSorter ,
& EngineSpeedSorter ,
2010-11-06 21:11:36 +01:00
& EnginePowerSorter ,
2010-11-06 21:20:03 +01:00
& EngineTractiveEffortSorter ,
2007-01-22 02:35:53 +01:00
& EngineIntroDateSorter ,
& EngineNameSorter ,
2009-03-10 22:17:00 +01:00
& EngineRunningCostSorter ,
2010-11-06 21:11:36 +01:00
& EnginePowerVsRunningCostSorter ,
2007-01-22 02:35:53 +01:00
& EngineReliabilitySorter ,
2007-06-02 17:41:37 +02:00
& RoadVehEngineCapacitySorter ,
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Ships */
2007-01-22 02:35:53 +01:00
& EngineNumberSorter ,
2009-03-10 22:17:00 +01:00
& EngineCostSorter ,
& EngineSpeedSorter ,
2007-01-22 02:35:53 +01:00
& EngineIntroDateSorter ,
& EngineNameSorter ,
2009-03-10 22:17:00 +01:00
& EngineRunningCostSorter ,
2007-01-22 02:35:53 +01:00
& EngineReliabilitySorter ,
2007-06-02 17:41:37 +02:00
& ShipEngineCapacitySorter ,
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Aircraft */
2007-01-22 02:35:53 +01:00
& EngineNumberSorter ,
2009-03-10 22:17:00 +01:00
& EngineCostSorter ,
& EngineSpeedSorter ,
2007-01-22 02:35:53 +01:00
& EngineIntroDateSorter ,
& EngineNameSorter ,
2009-03-10 22:17:00 +01:00
& EngineRunningCostSorter ,
2007-01-22 02:35:53 +01:00
& EngineReliabilitySorter ,
& AircraftEngineCargoSorter ,
2011-12-13 02:18:40 +01:00
& AircraftRangeSorter ,
2007-01-22 02:35:53 +01:00
} } ;
2007-01-21 23:50:43 +01:00
2014-09-07 18:10:27 +02:00
/** Dropdown menu strings for the vehicle sort criteria. */
const StringID _engine_sort_listing [ ] [ 12 ] = { {
2007-01-22 15:08:14 +01:00
/* Trains */
2009-07-23 00:44:56 +02:00
STR_SORT_BY_ENGINE_ID ,
STR_SORT_BY_COST ,
2007-01-21 23:50:43 +01:00
STR_SORT_BY_MAX_SPEED ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_POWER ,
2010-11-06 21:20:03 +01:00
STR_SORT_BY_TRACTIVE_EFFORT ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_INTRO_DATE ,
2009-07-23 21:31:50 +02:00
STR_SORT_BY_NAME ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_RUNNING_COST ,
STR_SORT_BY_POWER_VS_RUNNING_COST ,
2007-01-21 23:50:43 +01:00
STR_SORT_BY_RELIABILITY ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_CARGO_CAPACITY ,
2007-01-21 23:50:43 +01:00
INVALID_STRING_ID
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Road vehicles */
2009-07-23 00:44:56 +02:00
STR_SORT_BY_ENGINE_ID ,
STR_SORT_BY_COST ,
2007-12-27 16:47:08 +01:00
STR_SORT_BY_MAX_SPEED ,
2010-11-06 21:11:36 +01:00
STR_SORT_BY_POWER ,
2010-11-06 21:20:03 +01:00
STR_SORT_BY_TRACTIVE_EFFORT ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_INTRO_DATE ,
2009-07-23 21:31:50 +02:00
STR_SORT_BY_NAME ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_RUNNING_COST ,
2010-11-06 21:11:36 +01:00
STR_SORT_BY_POWER_VS_RUNNING_COST ,
2007-01-22 01:26:46 +01:00
STR_SORT_BY_RELIABILITY ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_CARGO_CAPACITY ,
2007-01-22 01:26:46 +01:00
INVALID_STRING_ID
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Ships */
2009-07-23 00:44:56 +02:00
STR_SORT_BY_ENGINE_ID ,
STR_SORT_BY_COST ,
2007-12-27 16:47:08 +01:00
STR_SORT_BY_MAX_SPEED ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_INTRO_DATE ,
2009-07-23 21:31:50 +02:00
STR_SORT_BY_NAME ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_RUNNING_COST ,
2007-01-22 02:35:53 +01:00
STR_SORT_BY_RELIABILITY ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_CARGO_CAPACITY ,
2007-01-22 02:35:53 +01:00
INVALID_STRING_ID
2007-04-19 00:10:36 +02:00
} , {
2007-01-22 15:08:14 +01:00
/* Aircraft */
2009-07-23 00:44:56 +02:00
STR_SORT_BY_ENGINE_ID ,
STR_SORT_BY_COST ,
2006-10-10 17:02:38 +02:00
STR_SORT_BY_MAX_SPEED ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_INTRO_DATE ,
2009-07-23 21:31:50 +02:00
STR_SORT_BY_NAME ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_RUNNING_COST ,
2006-10-10 17:02:38 +02:00
STR_SORT_BY_RELIABILITY ,
2009-07-23 00:44:56 +02:00
STR_SORT_BY_CARGO_CAPACITY ,
2011-12-13 02:18:40 +01:00
STR_SORT_BY_RANGE ,
2006-10-10 17:02:38 +02:00
INVALID_STRING_ID
2007-01-22 02:35:53 +01:00
} } ;
2006-10-10 17:02:38 +02:00
2021-03-08 12:03:11 +01:00
/** Filters vehicles by cargo and engine (in case of rail vehicle). */
2019-02-27 08:04:17 +01:00
static bool CDECL CargoAndEngineFilter ( const GUIEngineListItem * item , const CargoID cid )
2009-04-12 19:38:01 +02:00
{
2024-01-06 16:29:48 +01:00
if ( cid = = CargoFilterCriteria : : CF_ANY ) {
2021-03-08 12:03:11 +01:00
return true ;
2024-01-06 16:29:48 +01:00
} else if ( cid = = CargoFilterCriteria : : CF_ENGINES ) {
2019-02-27 08:04:17 +01:00
return Engine : : Get ( item - > engine_id ) - > GetPower ( ) ! = 0 ;
2021-03-08 12:03:11 +01:00
} else {
2019-02-27 08:04:17 +01:00
CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks ( item - > engine_id , true ) & _standard_cargo_mask ;
2024-01-06 16:29:48 +01:00
return ( cid = = CargoFilterCriteria : : CF_NONE ? refit_mask = = 0 : HasBit ( refit_mask , cid ) ) ;
2021-03-08 12:03:11 +01:00
}
2009-04-12 19:38:01 +02:00
}
static GUIEngineList : : FilterFunction * const _filter_funcs [ ] = {
2021-03-08 12:03:11 +01:00
& CargoAndEngineFilter ,
2009-04-12 19:38:01 +02:00
} ;
2023-01-06 21:21:27 +01:00
static uint GetCargoWeight ( const CargoArray & cap , VehicleType vtype )
2008-02-14 08:25:24 +01:00
{
2023-01-06 21:21:27 +01:00
uint weight = 0 ;
for ( CargoID c = 0 ; c < NUM_CARGO ; c + + ) {
if ( cap [ c ] ! = 0 ) {
if ( vtype = = VEH_TRAIN ) {
weight + = CargoSpec : : Get ( c ) - > WeightOfNUnitsInTrain ( cap [ c ] ) ;
} else {
weight + = CargoSpec : : Get ( c ) - > WeightOfNUnits ( cap [ c ] ) ;
}
}
}
return weight ;
}
2008-02-14 08:25:24 +01:00
2023-01-06 21:21:27 +01:00
static int DrawCargoCapacityInfo ( int left , int right , int y , TestedEngineDetails & te , bool refittable )
{
2023-10-20 18:32:17 +02:00
for ( const CargoSpec * cs : _sorted_cargo_specs ) {
CargoID cid = cs - > Index ( ) ;
if ( te . all_capacities [ cid ] = = 0 ) continue ;
2008-02-14 08:25:24 +01:00
2023-10-20 18:32:17 +02:00
SetDParam ( 0 , cid ) ;
SetDParam ( 1 , te . all_capacities [ cid ] ) ;
2023-01-06 21:21:27 +01:00
SetDParam ( 2 , refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_CAPACITY ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2008-02-14 08:25:24 +01:00
}
return y ;
}
2007-01-21 23:50:43 +01:00
/* Draw rail wagon specific details */
2019-03-23 22:06:46 +01:00
static int DrawRailWagonPurchaseInfo ( int left , int right , int y , EngineID engine_number , const RailVehicleInfo * rvi , TestedEngineDetails & te )
2007-01-21 23:50:43 +01:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2009-01-25 01:57:03 +01:00
2007-01-21 23:50:43 +01:00
/* Purchase cost */
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
/* Wagon weight - (including cargo) */
2009-02-01 17:10:06 +01:00
uint weight = e - > GetDisplayWeight ( ) ;
2007-05-07 18:38:21 +02:00
SetDParam ( 0 , weight ) ;
2023-01-06 21:21:27 +01:00
SetDParam ( 1 , GetCargoWeight ( te . all_capacities , VEH_TRAIN ) + weight ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_WEIGHT_CWEIGHT ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
/* Wagon speed limit, displayed if above zero */
2008-05-29 17:13:28 +02:00
if ( _settings_game . vehicle . wagon_speed_limits ) {
2009-02-01 17:10:06 +01:00
uint max_speed = e - > GetDisplayMaxSpeed ( ) ;
2007-05-07 18:38:21 +02:00
if ( max_speed > 0 ) {
2023-04-08 18:26:13 +02:00
SetDParam ( 0 , PackVelocity ( max_speed , e - > type ) ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_SPEED ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-05-07 18:38:21 +02:00
}
2007-01-21 23:50:43 +01:00
}
2008-02-21 20:09:10 +01:00
/* Running cost */
2009-11-07 23:47:54 +01:00
if ( rvi - > running_cost_class ! = INVALID_PRICE ) {
2009-01-25 01:57:03 +01:00
SetDParam ( 0 , e - > GetRunningCost ( ) ) ;
2024-01-26 21:05:09 +01:00
DrawString ( left , right , y , TimerGameEconomy : : UsingWallclockUnits ( ) ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2008-02-21 20:09:10 +01:00
}
2007-01-21 23:50:43 +01:00
return y ;
}
/* Draw locomotive specific details */
2019-03-23 22:06:46 +01:00
static int DrawRailEnginePurchaseInfo ( int left , int right , int y , EngineID engine_number , const RailVehicleInfo * rvi , TestedEngineDetails & te )
2007-01-21 23:50:43 +01:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2007-01-21 23:50:43 +01:00
/* Purchase Cost - Engine weight */
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
SetDParam ( 2 , e - > GetDisplayWeight ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT_WEIGHT ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
SetDParam ( 1 , e - > GetDisplayWeight ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_WEIGHT ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
/* Max speed - Engine power */
2023-04-08 18:26:13 +02:00
SetDParam ( 0 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2009-02-01 17:10:06 +01:00
SetDParam ( 1 , e - > GetPower ( ) ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_SPEED_POWER ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
/* Max tractive effort - not applicable if old acceleration or maglev */
2010-01-30 17:27:35 +01:00
if ( _settings_game . vehicle . train_acceleration_model ! = AM_ORIGINAL & & GetRailTypeInfo ( rvi - > railtype ) - > acceleration_type ! = 2 ) {
2009-02-19 10:45:44 +01:00
SetDParam ( 0 , e - > GetDisplayMaxTractiveEffort ( ) ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_MAX_TE ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
}
/* Running cost */
2009-11-07 23:47:54 +01:00
if ( rvi - > running_cost_class ! = INVALID_PRICE ) {
2009-01-25 01:57:03 +01:00
SetDParam ( 0 , e - > GetRunningCost ( ) ) ;
2024-01-26 21:05:09 +01:00
DrawString ( left , right , y , TimerGameEconomy : : UsingWallclockUnits ( ) ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2008-02-21 20:09:10 +01:00
}
2007-01-21 23:50:43 +01:00
/* 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 ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-01-15 16:36:58 +01:00
}
2007-01-21 23:50:43 +01:00
return y ;
}
2007-01-22 03:09:51 +01:00
/* Draw road vehicle specific details */
2019-03-23 22:06:46 +01:00
static int DrawRoadVehPurchaseInfo ( int left , int right , int y , EngineID engine_number , TestedEngineDetails & te )
2007-01-22 03:09:51 +01:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2009-01-25 01:57:03 +01:00
2010-03-06 13:59:28 +01:00
if ( _settings_game . vehicle . roadveh_acceleration_model ! = AM_ORIGINAL ) {
/* Purchase Cost */
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2010-03-06 13:59:28 +01:00
/* Road vehicle weight - (including cargo) */
2023-05-08 19:01:06 +02:00
int16_t weight = e - > GetDisplayWeight ( ) ;
2010-03-06 13:59:28 +01:00
SetDParam ( 0 , weight ) ;
2023-01-06 21:21:27 +01:00
SetDParam ( 1 , GetCargoWeight ( te . all_capacities , VEH_ROAD ) + weight ) ;
2010-03-06 13:59:28 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_WEIGHT_CWEIGHT ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2010-03-06 13:59:28 +01:00
/* Max speed - Engine power */
2023-04-08 18:26:13 +02:00
SetDParam ( 0 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2010-03-06 13:59:28 +01:00
SetDParam ( 1 , e - > GetPower ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_SPEED_POWER ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2010-03-06 13:59:28 +01:00
/* Max tractive effort */
SetDParam ( 0 , e - > GetDisplayMaxTractiveEffort ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_MAX_TE ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2010-03-06 13:59:28 +01:00
} else {
/* Purchase cost - Max speed */
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 2 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT_SPEED ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 1 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_SPEED ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2010-03-06 13:59:28 +01:00
}
2007-01-22 03:09:51 +01:00
/* Running cost */
2009-01-25 01:57:03 +01:00
SetDParam ( 0 , e - > GetRunningCost ( ) ) ;
2024-01-26 21:05:09 +01:00
DrawString ( left , right , y , TimerGameEconomy : : UsingWallclockUnits ( ) ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-22 03:09:51 +01:00
2009-02-27 21:40:39 +01:00
return y ;
2007-01-22 03:09:51 +01:00
}
2007-01-22 01:26:46 +01:00
/* Draw ship specific details */
2019-03-23 22:06:46 +01:00
static int DrawShipPurchaseInfo ( int left , int right , int y , EngineID engine_number , bool refittable , TestedEngineDetails & te )
2007-01-22 01:26:46 +01:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2009-01-25 01:57:03 +01:00
2007-01-22 01:26:46 +01:00
/* Purchase cost - Max speed */
2011-08-27 12:34:31 +02:00
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 ) ;
if ( ocean_speed = = canal_speed ) {
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 2 , PackVelocity ( ocean_speed , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT_SPEED ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 1 , PackVelocity ( ocean_speed , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_SPEED ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-08-27 12:34:31 +02:00
} else {
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_COST ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-08-27 12:34:31 +02:00
2023-04-08 18:26:13 +02:00
SetDParam ( 0 , PackVelocity ( ocean_speed , e - > type ) ) ;
2011-08-27 12:34:31 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_SPEED_OCEAN ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-08-27 12:34:31 +02:00
2023-04-08 18:26:13 +02:00
SetDParam ( 0 , PackVelocity ( canal_speed , e - > type ) ) ;
2011-08-27 12:34:31 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_SPEED_CANAL ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-08-27 12:34:31 +02:00
}
2007-01-22 01:26:46 +01:00
/* Cargo type + capacity */
2019-03-23 22:06:46 +01:00
SetDParam ( 0 , te . cargo ) ;
SetDParam ( 1 , te . capacity ) ;
2009-08-05 19:59:21 +02:00
SetDParam ( 2 , refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_CAPACITY ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-22 01:26:46 +01:00
/* Running cost */
2009-01-25 01:57:03 +01:00
SetDParam ( 0 , e - > GetRunningCost ( ) ) ;
2024-01-26 21:05:09 +01:00
DrawString ( left , right , y , TimerGameEconomy : : UsingWallclockUnits ( ) ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-22 01:26:46 +01:00
return y ;
}
2017-03-18 21:46:15 +01:00
/**
* Draw aircraft specific details in the buy window .
* @ param left Left edge of the window to draw in .
* @ param right Right edge of the window to draw in .
* @ param y Top of the area to draw in .
* @ param engine_number Engine to display .
* @ param refittable If set , the aircraft can be refitted .
* @ return Bottom of the used area .
*/
2019-03-23 22:06:46 +01:00
static int DrawAircraftPurchaseInfo ( int left , int right , int y , EngineID engine_number , bool refittable , TestedEngineDetails & te )
2006-10-10 17:02:38 +02:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2006-10-10 17:02:38 +02:00
/* Purchase cost - Max speed */
2019-03-23 22:06:46 +01:00
if ( te . cost ! = 0 ) {
SetDParam ( 0 , e - > GetCost ( ) + te . cost ) ;
SetDParam ( 1 , te . cost ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 2 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_REFIT_SPEED ) ;
} else {
SetDParam ( 0 , e - > GetCost ( ) ) ;
2023-04-08 18:26:13 +02:00
SetDParam ( 1 , PackVelocity ( e - > GetDisplayMaxSpeed ( ) , e - > type ) ) ;
2019-03-23 22:06:46 +01:00
DrawString ( left , right , y , STR_PURCHASE_INFO_COST_SPEED ) ;
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2006-10-10 17:02:38 +02:00
/* Cargo capacity */
2019-03-23 22:06:46 +01:00
if ( te . mail_capacity > 0 ) {
SetDParam ( 0 , te . cargo ) ;
SetDParam ( 1 , te . capacity ) ;
2024-02-04 11:16:08 +01:00
SetDParam ( 2 , GetCargoIDByLabel ( CT_MAIL ) ) ;
2019-03-23 22:06:46 +01:00
SetDParam ( 3 , te . mail_capacity ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_AIRCRAFT_CAPACITY ) ;
2006-10-10 17:02:38 +02:00
} else {
/* Note, if the default capacity is selected by the refit capacity
2009-03-14 19:16:29 +01:00
* callback , then the capacity shown is likely to be incorrect . */
2019-03-23 22:06:46 +01:00
SetDParam ( 0 , te . cargo ) ;
SetDParam ( 1 , te . capacity ) ;
2009-08-05 19:59:21 +02:00
SetDParam ( 2 , refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_CAPACITY ) ;
2006-10-10 17:02:38 +02:00
}
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2006-10-10 17:02:38 +02:00
/* Running cost */
2009-01-25 01:57:03 +01:00
SetDParam ( 0 , e - > GetRunningCost ( ) ) ;
2024-01-26 21:05:09 +01:00
DrawString ( left , right , y , TimerGameEconomy : : UsingWallclockUnits ( ) ? STR_PURCHASE_INFO_RUNNINGCOST_PERIOD : STR_PURCHASE_INFO_RUNNINGCOST_YEAR ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2006-10-10 17:02:38 +02:00
2017-03-18 21:46:15 +01:00
/* Aircraft type */
SetDParam ( 0 , e - > GetAircraftTypeText ( ) ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_AIRCRAFT_TYPE ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2017-03-18 21:46:15 +01:00
/* Aircraft range, if available. */
2023-05-08 19:01:06 +02:00
uint16_t range = e - > GetRange ( ) ;
2011-12-13 01:43:35 +01:00
if ( range ! = 0 ) {
SetDParam ( 0 , range ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_AIRCRAFT_RANGE ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2011-12-13 01:43:35 +01:00
}
2007-01-21 23:50:43 +01:00
return y ;
}
2006-10-10 17:02:38 +02:00
2023-05-01 19:02:16 +02:00
2009-05-22 21:47:26 +02:00
/**
2023-05-01 19:02:16 +02:00
* Try to get the NewGRF engine additional text callback as an optional std : : string .
* @ param engine The engine whose additional text to get .
* @ return The std : : string if present , otherwise std : : nullopt .
2009-05-22 21:47:26 +02:00
*/
2023-05-01 19:02:16 +02:00
static std : : optional < std : : string > GetNewGRFAdditionalText ( EngineID engine )
2009-05-22 21:47:26 +02:00
{
2023-05-08 19:01:06 +02:00
uint16_t callback = GetVehicleCallback ( CBID_VEHICLE_ADDITIONAL_TEXT , 0 , 0 , engine , nullptr ) ;
2023-05-01 19:02:16 +02:00
if ( callback = = CALLBACK_FAILED | | callback = = 0x400 ) return std : : nullopt ;
2014-01-12 19:00:39 +01:00
const GRFFile * grffile = Engine : : Get ( engine ) - > GetGRF ( ) ;
2023-01-06 23:43:50 +01:00
assert ( grffile ! = nullptr ) ;
2011-11-08 18:24:43 +01:00
if ( callback > 0x400 ) {
2014-01-12 19:00:39 +01:00
ErrorUnknownCallbackResult ( grffile - > grfid , CBID_VEHICLE_ADDITIONAL_TEXT , callback ) ;
2023-05-01 19:02:16 +02:00
return std : : nullopt ;
2011-11-08 18:24:43 +01:00
}
2009-05-22 21:47:26 +02:00
2014-01-12 19:00:39 +01:00
StartTextRefStackUsage ( grffile , 6 ) ;
2023-05-01 19:02:16 +02:00
std : : string result = GetString ( GetGRFStringID ( grffile - > grfid , 0xD000 + callback ) ) ;
2009-05-22 21:47:26 +02:00
StopTextRefStackUsage ( ) ;
return result ;
}
2023-05-01 19:02:16 +02:00
/**
* Display additional text from NewGRF in the purchase information window
* @ param left Left border of text bounding box
* @ param right Right border of text bounding box
* @ param y Top border of text bounding box
* @ param engine Engine to query the additional purchase information for
* @ return Bottom border of text bounding box
*/
static uint ShowAdditionalText ( int left , int right , int y , EngineID engine )
{
auto text = GetNewGRFAdditionalText ( engine ) ;
if ( ! text ) return y ;
return DrawStringMultiLine ( left , right , y , INT32_MAX , * text , TC_BLACK ) ;
}
2023-01-06 21:21:27 +01:00
void TestedEngineDetails : : FillDefaultCapacities ( const Engine * e )
{
this - > cargo = e - > GetDefaultCargoType ( ) ;
if ( e - > type = = VEH_TRAIN | | e - > type = = VEH_ROAD ) {
this - > all_capacities = GetCapacityOfArticulatedParts ( e - > index ) ;
this - > capacity = this - > all_capacities [ this - > cargo ] ;
this - > mail_capacity = 0 ;
} else {
this - > capacity = e - > GetDisplayDefaultCapacity ( & this - > mail_capacity ) ;
this - > all_capacities [ this - > cargo ] = this - > capacity ;
2024-02-04 11:16:08 +01:00
if ( IsValidCargoID ( GetCargoIDByLabel ( CT_MAIL ) ) ) {
this - > all_capacities [ GetCargoIDByLabel ( CT_MAIL ) ] = this - > mail_capacity ;
} else {
this - > mail_capacity = 0 ;
}
2023-01-06 21:21:27 +01:00
}
2024-01-06 16:15:37 +01:00
if ( this - > all_capacities . GetCount ( ) = = 0 ) this - > cargo = INVALID_CARGO ;
2023-01-06 21:21:27 +01:00
}
2007-01-21 23:50:43 +01:00
/**
* Draw the purchase info details of a vehicle at a given location .
2009-03-22 12:06:25 +01:00
* @ param left , right , y location where to draw the info
2007-01-21 23:50:43 +01:00
* @ param engine_number the engine of which to draw the info of
2007-03-26 13:41:14 +02:00
* @ return y after drawing all the text
2007-01-21 23:50:43 +01:00
*/
2019-03-23 22:06:46 +01:00
int DrawVehiclePurchaseInfo ( int left , int right , int y , EngineID engine_number , TestedEngineDetails & te )
2007-01-21 23:50:43 +01:00
{
2009-05-17 01:34:14 +02:00
const Engine * e = Engine : : Get ( engine_number ) ;
2023-12-28 22:34:08 +01:00
TimerGameCalendar : : YearMonthDay ymd = TimerGameCalendar : : ConvertDateToYMD ( e - > intro_date ) ;
2009-02-27 21:40:39 +01:00
bool refittable = IsArticulatedVehicleRefittable ( engine_number ) ;
2009-10-06 21:56:43 +02:00
bool articulated_cargo = false ;
2007-01-21 23:50:43 +01:00
switch ( e - > type ) {
2007-05-18 19:31:41 +02:00
default : NOT_REACHED ( ) ;
2009-10-06 21:56:43 +02:00
case VEH_TRAIN :
2009-10-06 21:17:07 +02:00
if ( e - > u . rail . railveh_type = = RAILVEH_WAGON ) {
2019-03-23 22:06:46 +01:00
y = DrawRailWagonPurchaseInfo ( left , right , y , engine_number , & e - > u . rail , te ) ;
2007-01-21 23:50:43 +01:00
} else {
2019-03-23 22:06:46 +01:00
y = DrawRailEnginePurchaseInfo ( left , right , y , engine_number , & e - > u . rail , te ) ;
2007-01-21 23:50:43 +01:00
}
2009-10-06 21:56:43 +02:00
articulated_cargo = true ;
2007-01-21 23:50:43 +01:00
break ;
2009-02-27 21:40:39 +01:00
2009-10-06 21:56:43 +02:00
case VEH_ROAD :
2019-03-23 22:06:46 +01:00
y = DrawRoadVehPurchaseInfo ( left , right , y , engine_number , te ) ;
2009-10-06 21:56:43 +02:00
articulated_cargo = true ;
2007-01-22 03:09:51 +01:00
break ;
2009-10-06 21:56:43 +02:00
2008-12-16 23:02:12 +01:00
case VEH_SHIP :
2019-03-23 22:06:46 +01:00
y = DrawShipPurchaseInfo ( left , right , y , engine_number , refittable , te ) ;
2008-12-16 23:02:12 +01:00
break ;
2009-10-06 21:56:43 +02:00
2007-03-08 17:27:54 +01:00
case VEH_AIRCRAFT :
2019-03-23 22:06:46 +01:00
y = DrawAircraftPurchaseInfo ( left , right , y , engine_number , refittable , te ) ;
2007-01-21 23:50:43 +01:00
break ;
}
2009-10-06 21:56:43 +02:00
if ( articulated_cargo ) {
/* Cargo type + capacity, or N/A */
2023-01-06 21:21:27 +01:00
int new_y = DrawCargoCapacityInfo ( left , right , y , te , refittable ) ;
2009-10-06 21:56:43 +02:00
if ( new_y = = y ) {
2024-01-06 16:15:37 +01:00
SetDParam ( 0 , INVALID_CARGO ) ;
2009-10-06 21:56:43 +02:00
SetDParam ( 2 , STR_EMPTY ) ;
DrawString ( left , right , y , STR_PURCHASE_INFO_CAPACITY ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2009-10-06 21:56:43 +02:00
} else {
y = new_y ;
}
}
2010-10-30 19:51:07 +02:00
/* Draw details that apply to all types except rail wagons. */
2009-10-06 21:17:07 +02:00
if ( e - > type ! = VEH_TRAIN | | e - > u . rail . railveh_type ! = RAILVEH_WAGON ) {
2007-01-21 23:50:43 +01:00
/* Design date - Life length */
SetDParam ( 0 , ymd . year ) ;
2023-08-16 15:43:31 +02:00
SetDParam ( 1 , TimerGameCalendar : : DateToYear ( e - > GetLifeLengthInDays ( ) ) ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_DESIGNED_LIFE ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
/* Reliability */
2009-08-27 15:31:26 +02:00
SetDParam ( 0 , ToPercent16 ( e - > reliability ) ) ;
2009-04-26 16:52:56 +02:00
DrawString ( left , right , y , STR_PURCHASE_INFO_RELIABILITY ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2007-01-21 23:50:43 +01:00
}
2006-10-10 17:02:38 +02:00
2012-01-12 20:23:00 +01:00
if ( refittable ) y = ShowRefitOptionsList ( left , right , y , engine_number ) ;
2006-10-10 17:02:38 +02:00
/* Additional text from NewGRF */
2009-03-22 12:06:25 +01:00
y = ShowAdditionalText ( left , right , y , engine_number ) ;
2007-03-26 13:41:14 +02:00
2019-04-04 23:06:38 +02:00
/* The NewGRF's name which the vehicle comes from */
const GRFConfig * config = GetGRFConfig ( e - > GetGRFID ( ) ) ;
if ( _settings_client . gui . show_newgrf_name & & config ! = nullptr )
{
DrawString ( left , right , y , config - > GetName ( ) , TC_BLACK ) ;
2023-11-21 20:04:24 +01:00
y + = GetCharacterHeight ( FS_NORMAL ) ;
2019-04-04 23:06:38 +02:00
}
2007-03-26 13:41:14 +02:00
return y ;
2006-10-10 17:02:38 +02:00
}
2010-08-01 21:22:34 +02:00
/**
* Engine drawing loop
2007-01-23 00:23:30 +01:00
* @ param type Type of vehicle ( VEH_ * )
2022-10-21 20:58:43 +02:00
* @ param r The Rect of the list
2007-01-23 00:23:30 +01:00
* @ param eng_list What engines to draw
2024-02-25 22:33:11 +01:00
* @ param sb Scrollbar of list .
2007-01-23 00:23:30 +01:00
* @ param selected_id what engine to highlight as selected , if any
2009-11-16 16:11:54 +01:00
* @ param show_count Whether to show the amount of engines or not
2009-09-19 11:51:14 +02:00
* @ param selected_group the group to list the engines of
2007-01-23 00:23:30 +01:00
*/
2024-02-25 22:33:11 +01:00
void DrawEngineList ( VehicleType type , const Rect & r , const GUIEngineList & eng_list , const Scrollbar & sb , EngineID selected_id , bool show_count , GroupID selected_group )
2007-01-23 00:23:30 +01:00
{
2009-11-16 17:22:14 +01:00
static const int sprite_y_offsets [ ] = { - 1 , - 1 , - 2 , - 2 } ;
2007-01-23 00:23:30 +01:00
2024-02-25 22:33:11 +01:00
auto [ first , last ] = sb . GetVisibleRangeIterators ( eng_list ) ;
2007-01-23 02:00:56 +01:00
2010-11-13 10:56:25 +01:00
bool rtl = _current_text_dir = = TD_RTL ;
2009-11-16 17:22:14 +01:00
int step_size = GetEngineListHeight ( type ) ;
2012-12-23 02:00:25 +01:00
int sprite_left = GetVehicleImageCellSize ( type , EIT_PURCHASE ) . extend_left ;
int sprite_right = GetVehicleImageCellSize ( type , EIT_PURCHASE ) . extend_right ;
int sprite_width = sprite_left + sprite_right ;
2022-12-05 20:54:41 +01:00
int circle_width = std : : max ( GetScaledSpriteSize ( SPR_CIRCLE_FOLDED ) . width , GetScaledSpriteSize ( SPR_CIRCLE_UNFOLDED ) . width ) ;
2023-12-28 11:04:55 +01:00
int linecolour = GetColourGradient ( COLOUR_ORANGE , SHADE_NORMAL ) ;
2009-11-16 17:22:14 +01:00
2022-09-23 10:36:22 +02:00
Rect ir = r . WithHeight ( step_size ) . Shrink ( WidgetDimensions : : scaled . matrix ) ;
2022-09-05 22:05:18 +02:00
int sprite_y_offset = ScaleSpriteTrad ( sprite_y_offsets [ type ] ) + ir . Height ( ) / 2 ;
2009-11-16 17:22:14 +01:00
2012-04-17 21:44:08 +02:00
Dimension replace_icon = { 0 , 0 } ;
2012-05-05 21:27:47 +02:00
int count_width = 0 ;
if ( show_count ) {
replace_icon = GetSpriteSize ( SPR_GROUP_REPLACE_ACTIVE ) ;
2023-09-13 17:19:44 +02:00
uint biggest_num_engines = 0 ;
2024-02-25 22:33:11 +01:00
for ( auto it = first ; it ! = last ; + + it ) {
const uint num_engines = GetGroupNumEngines ( _local_company , selected_group , it - > engine_id ) ;
2023-09-13 17:19:44 +02:00
biggest_num_engines = std : : max ( biggest_num_engines , num_engines ) ;
}
SetDParam ( 0 , biggest_num_engines ) ;
2023-04-25 10:45:05 +02:00
count_width = GetStringBoundingBox ( STR_JUST_COMMA , FS_SMALL ) . width ;
2012-05-05 21:27:47 +02:00
}
2012-04-17 21:44:08 +02:00
2022-12-05 20:54:41 +01:00
Rect tr = ir . Indent ( circle_width + WidgetDimensions : : scaled . hsep_normal + sprite_width + WidgetDimensions : : scaled . hsep_wide , rtl ) ; // Name position
2022-09-23 10:36:22 +02:00
Rect cr = tr . Indent ( replace_icon . width + WidgetDimensions : : scaled . hsep_wide , ! rtl ) . WithWidth ( count_width , ! rtl ) ; // Count position
Rect rr = tr . WithWidth ( replace_icon . width , ! rtl ) ; // Replace icon position
if ( show_count ) tr = tr . Indent ( count_width + WidgetDimensions : : scaled . hsep_normal + replace_icon . width + WidgetDimensions : : scaled . hsep_wide , ! rtl ) ;
2009-11-16 17:22:14 +01:00
2023-11-21 20:04:24 +01:00
int normal_text_y_offset = ( ir . Height ( ) - GetCharacterHeight ( FS_NORMAL ) ) / 2 ;
int small_text_y_offset = ir . Height ( ) - GetCharacterHeight ( FS_SMALL ) ;
2022-10-21 20:58:43 +02:00
int replace_icon_y_offset = ( ir . Height ( ) - replace_icon . height ) / 2 ;
2007-01-23 00:23:30 +01:00
2024-04-09 09:35:12 +02:00
const int offset = ( rtl ? - circle_width : circle_width ) / 2 ;
const int level_width = rtl ? - WidgetDimensions : : scaled . hsep_indent : WidgetDimensions : : scaled . hsep_indent ;
2022-10-21 20:58:43 +02:00
int y = ir . top ;
2024-02-25 22:33:11 +01:00
for ( auto it = first ; it ! = last ; + + it ) {
const auto & item = * it ;
2022-12-05 20:54:41 +01:00
uint indent = item . indent * WidgetDimensions : : scaled . hsep_indent ;
bool has_variants = ( item . flags & EngineDisplayFlags : : HasVariants ) ! = EngineDisplayFlags : : None ;
bool is_folded = ( item . flags & EngineDisplayFlags : : IsFolded ) ! = EngineDisplayFlags : : None ;
bool shaded = ( item . flags & EngineDisplayFlags : : Shaded ) ! = EngineDisplayFlags : : None ;
2024-04-09 09:35:12 +02:00
if ( item . indent > 0 ) {
/* Draw tree continuation lines. */
int tx = ( rtl ? ir . right : ir . left ) + offset ;
int ty = y - WidgetDimensions : : scaled . matrix . top ;
for ( uint lvl = 1 ; lvl < = item . indent ; + + lvl ) {
if ( HasBit ( item . level_mask , lvl ) ) GfxDrawLine ( tx , ty , tx , ty + step_size - 1 , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
if ( lvl < item . indent ) tx + = level_width ;
}
/* Draw our node in the tree. */
int ycentre = y + normal_text_y_offset + GetCharacterHeight ( FS_NORMAL ) / 2 - 1 ;
if ( ! HasBit ( item . level_mask , item . indent ) ) GfxDrawLine ( tx , ty , tx , ycentre , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
GfxDrawLine ( tx , ycentre , tx + offset - ( rtl ? - 1 : 1 ) , ycentre , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
}
2008-09-30 22:39:50 +02:00
/* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
2022-12-05 20:54:41 +01:00
const uint num_engines = GetGroupNumEngines ( _local_company , selected_group , item . engine_id ) ;
2007-01-23 00:23:30 +01:00
2022-12-05 20:54:41 +01:00
const Engine * e = Engine : : Get ( item . engine_id ) ;
2014-09-07 18:14:06 +02:00
bool hidden = HasBit ( e - > company_hidden , _local_company ) ;
StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME ;
2023-04-28 22:16:13 +02:00
TextColour tc = ( item . engine_id = = selected_id ) ? TC_WHITE : ( ( hidden | shaded ) ? ( TC_GREY | TC_FORCED | TC_NO_SHADE ) : TC_BLACK ) ;
2014-09-07 18:14:06 +02:00
2023-04-17 00:02:32 +02:00
if ( show_count ) {
/* relies on show_count to find 'Vehicle in use' panel of autoreplace window */
SetDParam ( 0 , PackEngineNameDParam ( item . engine_id , EngineNameContext : : AutoreplaceVehicleInUse , item . indent ) ) ;
} else {
SetDParam ( 0 , PackEngineNameDParam ( item . engine_id , EngineNameContext : : PurchaseList , item . indent ) ) ;
}
2022-12-05 20:54:41 +01:00
Rect itr = tr . Indent ( indent , rtl ) ;
DrawString ( itr . left , itr . right , y + normal_text_y_offset , str , tc ) ;
int sprite_x = ir . Indent ( indent + circle_width + WidgetDimensions : : scaled . hsep_normal , rtl ) . WithWidth ( sprite_width , rtl ) . left + sprite_left ;
DrawVehicleEngine ( r . left , r . right , sprite_x , y + sprite_y_offset , item . engine_id , ( show_count & & num_engines = = 0 ) ? PALETTE_CRASH : GetEnginePalette ( item . engine_id , _local_company ) , EIT_PURCHASE ) ;
2009-11-16 16:11:54 +01:00
if ( show_count ) {
2007-05-19 11:40:18 +02:00
SetDParam ( 0 , num_engines ) ;
2023-04-25 10:45:05 +02:00
DrawString ( cr . left , cr . right , y + small_text_y_offset , STR_JUST_COMMA , TC_BLACK , SA_RIGHT | SA_FORCE , false , FS_SMALL ) ;
2022-12-05 20:54:41 +01:00
if ( EngineHasReplacementForCompany ( Company : : Get ( _local_company ) , item . engine_id , selected_group ) ) DrawSprite ( SPR_GROUP_REPLACE_ACTIVE , num_engines = = 0 ? PALETTE_CRASH : PAL_NONE , rr . left , y + replace_icon_y_offset ) ;
}
if ( has_variants ) {
Rect fr = ir . Indent ( indent , rtl ) . WithWidth ( circle_width , rtl ) ;
2023-12-04 19:19:55 +01:00
DrawSpriteIgnorePadding ( is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED , PAL_NONE , { fr . left , y , fr . right , y + ir . Height ( ) - 1 } , SA_CENTER ) ;
2022-12-05 20:54:41 +01:00
}
2024-02-25 22:33:11 +01:00
y + = step_size ;
2007-01-23 00:23:30 +01:00
}
}
2014-09-07 18:10:27 +02:00
/**
* Display the dropdown for the vehicle sort criteria .
* @ param w Parent window ( holds the dropdown button ) .
* @ param vehicle_type % Vehicle type being sorted .
* @ param selected Currently selected sort criterium .
* @ param button Widget button .
*/
2024-01-14 17:47:10 +01:00
void DisplayVehicleSortDropDown ( Window * w , VehicleType vehicle_type , int selected , WidgetID button )
2014-09-07 18:10:27 +02:00
{
2023-05-08 19:01:06 +02:00
uint32_t hidden_mask = 0 ;
2014-09-07 18:10:27 +02:00
/* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
if ( vehicle_type = = VEH_ROAD & & _settings_game . vehicle . roadveh_acceleration_model = = AM_ORIGINAL ) {
SetBit ( hidden_mask , 3 ) ; // power
SetBit ( hidden_mask , 4 ) ; // tractive effort
SetBit ( hidden_mask , 8 ) ; // power by running costs
}
/* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
if ( vehicle_type = = VEH_TRAIN & & _settings_game . vehicle . train_acceleration_model = = AM_ORIGINAL ) {
SetBit ( hidden_mask , 4 ) ; // tractive effort
}
ShowDropDownMenu ( w , _engine_sort_listing [ vehicle_type ] , selected , button , 0 , hidden_mask ) ;
}
2006-10-10 17:02:38 +02:00
2024-04-09 09:35:12 +02:00
/**
* Add children to GUI engine list to build a hierarchical tree .
* @ param dst Destination list .
* @ param src Source list .
* @ param parent Current tree parent ( set by self with recursion ) .
* @ param indent Current tree indentation level ( set by self with recursion ) .
*/
void GUIEngineListAddChildren ( GUIEngineList & dst , const GUIEngineList & src , EngineID parent , uint8_t indent )
{
for ( const auto & item : src ) {
if ( item . variant_id ! = parent | | item . engine_id = = parent ) continue ;
const Engine * e = Engine : : Get ( item . engine_id ) ;
EngineDisplayFlags flags = item . flags ;
if ( e - > display_last_variant ! = INVALID_ENGINE ) flags & = ~ EngineDisplayFlags : : Shaded ;
dst . emplace_back ( e - > display_last_variant = = INVALID_ENGINE ? item . engine_id : e - > display_last_variant , item . engine_id , flags , indent ) ;
/* Add variants if not folded */
if ( ( item . flags & ( EngineDisplayFlags : : HasVariants | EngineDisplayFlags : : IsFolded ) ) = = EngineDisplayFlags : : HasVariants ) {
/* Add this engine again as a child */
if ( ( item . flags & EngineDisplayFlags : : Shaded ) = = EngineDisplayFlags : : None ) {
dst . emplace_back ( item . engine_id , item . engine_id , EngineDisplayFlags : : None , indent + 1 ) ;
}
GUIEngineListAddChildren ( dst , src , item . engine_id , indent + 1 ) ;
}
}
if ( indent > 0 | | dst . empty ( ) ) return ;
/* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
uint16_t level_mask = 0 ;
for ( auto it = std : : rbegin ( dst ) ; std : : next ( it ) ! = std : : rend ( dst ) ; + + it ) {
auto next_it = std : : next ( it ) ;
SB ( level_mask , it - > indent , 1 , it - > indent < = next_it - > indent ) ;
next_it - > level_mask = level_mask ;
}
}
2023-05-01 19:02:16 +02:00
/** Enum referring to the Hotkeys in the build vehicle window */
enum BuildVehicleHotkeys {
BVHK_FOCUS_FILTER_BOX , ///< Focus the edit box for editing the filter string
} ;
2014-09-07 18:10:27 +02:00
/** GUI for building vehicles. */
2008-05-13 16:28:27 +02:00
struct BuildVehicleWindow : Window {
2014-09-07 18:13:29 +02:00
VehicleType vehicle_type ; ///< Type of vehicles shown in the window.
2008-05-13 16:28:27 +02:00
union {
2019-04-06 08:46:15 +02:00
RailType railtype ; ///< Rail type to show, or #INVALID_RAILTYPE.
RoadType roadtype ; ///< Road type to show, or #INVALID_ROADTYPE.
2014-09-07 18:13:29 +02:00
} filter ; ///< Filter to apply.
bool descending_sort_order ; ///< Sort direction, @see _engine_sort_direction
2024-03-16 23:59:32 +01:00
uint8_t sort_criteria ; ///< Current sort criterium.
2014-09-07 18:14:06 +02:00
bool show_hidden_engines ; ///< State of the 'show hidden engines' button.
2014-09-07 18:13:29 +02:00
bool listview_mode ; ///< If set, only display the available vehicles and do not show a 'build' button.
EngineID sel_engine ; ///< Currently selected engine, or #INVALID_ENGINE
EngineID rename_engine ; ///< Engine being renamed.
2008-05-28 19:29:27 +02:00
GUIEngineList eng_list ;
2023-11-12 22:32:12 +01:00
CargoID cargo_filter_criteria ; ///< Selected cargo filter
2021-04-25 20:34:16 +02:00
int details_height ; ///< Minimal needed height of the details panels, in text lines (found so far).
2010-08-12 10:37:01 +02:00
Scrollbar * vscroll ;
2019-03-23 22:06:46 +01:00
TestedEngineDetails te ; ///< Tested cost and capacity after refit.
2008-05-13 16:28:27 +02:00
2023-05-01 19:02:16 +02:00
StringFilter string_filter ; ///< Filter for vehicle name
QueryString vehicle_editbox ; ///< Filter editbox
2019-02-28 22:32:08 +01:00
void SetBuyVehicleText ( )
{
NWidgetCore * widget = this - > GetWidget < NWidgetCore > ( WID_BV_BUILD ) ;
2024-01-12 00:00:07 +01:00
bool refit = this - > sel_engine ! = INVALID_ENGINE & & this - > cargo_filter_criteria ! = CargoFilterCriteria : : CF_ANY & & this - > cargo_filter_criteria ! = CargoFilterCriteria : : CF_NONE & & this - > cargo_filter_criteria ! = CargoFilterCriteria : : CF_ENGINES ;
2023-11-12 22:32:12 +01:00
if ( refit ) refit = Engine : : Get ( this - > sel_engine ) - > GetDefaultCargoType ( ) ! = this - > cargo_filter_criteria ;
2019-02-28 22:32:08 +01:00
if ( refit ) {
widget - > widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this - > vehicle_type ;
widget - > tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this - > vehicle_type ;
} else {
widget - > widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this - > vehicle_type ;
widget - > tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this - > vehicle_type ;
}
}
2023-05-01 19:02:16 +02:00
BuildVehicleWindow ( WindowDesc * desc , TileIndex tile , VehicleType type ) : Window ( desc ) , vehicle_editbox ( MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH , MAX_LENGTH_VEHICLE_NAME_CHARS )
2008-05-13 16:28:27 +02:00
{
this - > vehicle_type = type ;
2019-04-06 08:46:15 +02:00
this - > listview_mode = tile = = INVALID_TILE ;
2023-11-06 21:29:35 +01:00
this - > window_number = this - > listview_mode ? ( int ) type : tile . base ( ) ;
2008-05-13 16:28:27 +02:00
2014-09-07 18:09:48 +02:00
this - > sel_engine = INVALID_ENGINE ;
2008-05-13 16:28:27 +02:00
2014-09-07 18:10:27 +02:00
this - > sort_criteria = _engine_sort_last_criteria [ type ] ;
this - > descending_sort_order = _engine_sort_last_order [ type ] ;
2014-09-07 18:14:06 +02:00
this - > show_hidden_engines = _engine_sort_show_hidden_engines [ type ] ;
2008-05-13 16:28:27 +02:00
2019-04-06 08:46:15 +02:00
this - > UpdateFilterByTile ( ) ;
2009-10-25 02:26:40 +02:00
2013-05-26 21:23:42 +02:00
this - > CreateNestedTree ( ) ;
2009-10-25 02:26:40 +02:00
2011-12-16 17:27:45 +01:00
this - > vscroll = this - > GetScrollbar ( WID_BV_SCROLLBAR ) ;
2010-08-12 10:37:01 +02:00
2008-07-13 04:43:46 +02:00
/* If we are just viewing the list of vehicles, we do not need the Build button.
2013-01-08 23:46:42 +01:00
* So we just hide it , and enlarge the Rename button by the now vacant place . */
2011-12-16 17:27:45 +01:00
if ( this - > listview_mode ) this - > GetWidget < NWidgetStacked > ( WID_BV_BUILD_SEL ) - > SetDisplayedPlane ( SZSP_NONE ) ;
2009-10-25 02:26:40 +02:00
2011-12-16 17:27:45 +01:00
NWidgetCore * widget = this - > GetWidget < NWidgetCore > ( WID_BV_LIST ) ;
2009-10-25 02:26:40 +02:00
widget - > tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type ;
2014-09-07 18:14:06 +02:00
widget = this - > GetWidget < NWidgetCore > ( WID_BV_SHOW_HIDE ) ;
widget - > tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type ;
2011-12-16 17:27:45 +01:00
widget = this - > GetWidget < NWidgetCore > ( WID_BV_RENAME ) ;
2009-10-25 02:26:40 +02:00
widget - > widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type ;
widget - > tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type ;
2014-09-07 18:14:06 +02:00
widget = this - > GetWidget < NWidgetCore > ( WID_BV_SHOW_HIDDEN_ENGINES ) ;
widget - > widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type ;
widget - > tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type ;
widget - > SetLowered ( this - > show_hidden_engines ) ;
2021-04-25 20:34:16 +02:00
this - > details_height = ( ( this - > vehicle_type = = VEH_TRAIN ) ? 10 : 9 ) ;
2009-10-25 02:26:40 +02:00
2023-08-15 18:12:05 +02:00
if ( tile = = INVALID_TILE ) {
this - > FinishInitNested ( type ) ;
} else {
this - > FinishInitNested ( tile ) ;
}
2008-05-13 16:28:27 +02:00
2023-05-01 19:02:16 +02:00
this - > querystrings [ WID_BV_FILTER ] = & this - > vehicle_editbox ;
this - > vehicle_editbox . cancel_button = QueryString : : ACTION_CLEAR ;
2009-12-11 21:37:24 +01:00
this - > owner = ( tile ! = INVALID_TILE ) ? GetTileOwner ( tile ) : _local_company ;
2009-04-12 16:12:17 +02:00
this - > eng_list . ForceRebuild ( ) ;
2008-05-13 16:28:27 +02:00
this - > GenerateBuildList ( ) ; // generate the list, since we need it in the next line
2023-01-24 01:05:42 +01:00
/* Select the first unshaded engine in the list as default when opening the window */
EngineID engine = INVALID_ENGINE ;
2024-04-16 18:44:55 +02:00
auto it = std : : find_if ( this - > eng_list . begin ( ) , this - > eng_list . end ( ) , [ & ] ( GUIEngineListItem & item ) { return ( item . flags & EngineDisplayFlags : : Shaded ) = = EngineDisplayFlags : : None ; } ) ;
2023-01-24 01:05:42 +01:00
if ( it ! = this - > eng_list . end ( ) ) engine = it - > engine_id ;
this - > SelectEngine ( engine ) ;
2008-05-13 16:28:27 +02:00
}
2006-10-10 17:02:38 +02:00
2019-04-06 08:46:15 +02:00
/** Set the filter type according to the depot type */
void UpdateFilterByTile ( )
{
switch ( this - > vehicle_type ) {
default : NOT_REACHED ( ) ;
case VEH_TRAIN :
if ( this - > listview_mode ) {
this - > filter . railtype = INVALID_RAILTYPE ;
} else {
this - > filter . railtype = GetRailType ( this - > window_number ) ;
}
break ;
case VEH_ROAD :
if ( this - > listview_mode ) {
this - > filter . roadtype = INVALID_ROADTYPE ;
} else {
this - > filter . roadtype = GetRoadTypeRoad ( this - > window_number ) ;
if ( this - > filter . roadtype = = INVALID_ROADTYPE ) {
this - > filter . roadtype = GetRoadTypeTram ( this - > window_number ) ;
}
}
break ;
case VEH_SHIP :
case VEH_AIRCRAFT :
break ;
}
}
2023-11-12 22:32:12 +01:00
StringID GetCargoFilterLabel ( CargoID cid ) const
2010-04-01 21:52:13 +02:00
{
2023-11-12 22:32:12 +01:00
switch ( cid ) {
2024-01-06 16:29:48 +01:00
case CargoFilterCriteria : : CF_ANY : return STR_PURCHASE_INFO_ALL_TYPES ;
case CargoFilterCriteria : : CF_ENGINES : return STR_PURCHASE_INFO_ENGINES_ONLY ;
case CargoFilterCriteria : : CF_NONE : return STR_PURCHASE_INFO_NONE ;
2023-11-12 22:32:12 +01:00
default : return CargoSpec : : Get ( cid ) - > name ;
2010-04-01 21:52:13 +02:00
}
2023-11-12 22:32:12 +01:00
}
2010-04-01 21:52:13 +02:00
2023-11-12 22:32:12 +01:00
/** Populate the filter list and set the cargo filter criteria. */
void SetCargoFilterArray ( )
{
/* Set the last cargo filter criteria. */
this - > cargo_filter_criteria = _engine_sort_last_cargo_criteria [ this - > vehicle_type ] ;
2024-01-06 16:29:48 +01:00
if ( this - > cargo_filter_criteria < NUM_CARGO & & ! HasBit ( _standard_cargo_mask , this - > cargo_filter_criteria ) ) this - > cargo_filter_criteria = CargoFilterCriteria : : CF_ANY ;
2010-04-01 21:52:13 +02:00
this - > eng_list . SetFilterFuncs ( _filter_funcs ) ;
2024-01-06 16:29:48 +01:00
this - > eng_list . SetFilterState ( this - > cargo_filter_criteria ! = CargoFilterCriteria : : CF_ANY ) ;
2010-04-01 21:52:13 +02:00
}
2019-03-23 22:06:46 +01:00
void SelectEngine ( EngineID engine )
{
2023-11-12 22:32:12 +01:00
CargoID cargo = this - > cargo_filter_criteria ;
2024-01-06 16:29:48 +01:00
if ( cargo = = CargoFilterCriteria : : CF_ANY | | cargo = = CargoFilterCriteria : : CF_ENGINES | | cargo = = CargoFilterCriteria : : CF_NONE ) cargo = INVALID_CARGO ;
2019-03-23 22:06:46 +01:00
this - > sel_engine = engine ;
this - > SetBuyVehicleText ( ) ;
if ( this - > sel_engine = = INVALID_ENGINE ) return ;
const Engine * e = Engine : : Get ( this - > sel_engine ) ;
if ( ! this - > listview_mode ) {
/* Query for cost and refitted capacity */
2023-01-06 21:21:27 +01:00
auto [ ret , veh_id , refit_capacity , refit_mail , cargo_capacities ] = Command < CMD_BUILD_VEHICLE > : : Do ( DC_QUERY_COST , this - > window_number , this - > sel_engine , true , cargo , INVALID_CLIENT_ID ) ;
2019-03-23 22:06:46 +01:00
if ( ret . Succeeded ( ) ) {
this - > te . cost = ret . GetCost ( ) - e - > GetCost ( ) ;
2021-11-30 23:21:16 +01:00
this - > te . capacity = refit_capacity ;
this - > te . mail_capacity = refit_mail ;
2023-05-04 12:29:21 +02:00
this - > te . cargo = ! IsValidCargoID ( cargo ) ? e - > GetDefaultCargoType ( ) : cargo ;
2023-01-06 21:21:27 +01:00
this - > te . all_capacities = cargo_capacities ;
2019-03-23 22:06:46 +01:00
return ;
}
}
/* Purchase test was not possible or failed, fill in the defaults instead. */
this - > te . cost = 0 ;
2023-01-06 21:21:27 +01:00
this - > te . FillDefaultCapacities ( e ) ;
2019-03-23 22:06:46 +01:00
}
2019-03-04 08:49:37 +01:00
void OnInit ( ) override
2010-04-01 21:52:13 +02:00
{
this - > SetCargoFilterArray ( ) ;
}
2009-04-12 19:38:01 +02:00
/** Filter the engine list against the currently selected cargo filter */
void FilterEngineList ( )
{
2023-11-12 22:32:12 +01:00
this - > eng_list . Filter ( this - > cargo_filter_criteria ) ;
2018-09-23 13:23:54 +02:00
if ( 0 = = this - > eng_list . size ( ) ) { // no engine passed through the filter, invalidate the previously selected engine
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( INVALID_ENGINE ) ;
2019-02-12 23:59:12 +01:00
} else if ( std : : find ( this - > eng_list . begin ( ) , this - > eng_list . end ( ) , this - > sel_engine ) = = this - > eng_list . end ( ) ) { // previously selected engine didn't pass the filter, select the first engine of the list
2019-02-27 08:04:17 +01:00
this - > SelectEngine ( this - > eng_list [ 0 ] . engine_id ) ;
2009-04-12 19:38:01 +02:00
}
}
/** Filter a single engine */
bool FilterSingleEngine ( EngineID eid )
{
2019-02-27 08:04:17 +01:00
GUIEngineListItem item = { eid , eid , EngineDisplayFlags : : None , 0 } ;
2023-11-12 22:32:12 +01:00
return CargoAndEngineFilter ( & item , this - > cargo_filter_criteria ) ;
2009-04-12 19:38:01 +02:00
}
2023-05-01 19:02:16 +02:00
/** Filter by name and NewGRF extra text */
bool FilterByText ( const Engine * e )
{
/* Do not filter if the filter text box is empty */
if ( this - > string_filter . IsEmpty ( ) ) return true ;
/* Filter engine name */
this - > string_filter . ResetState ( ) ;
2023-06-19 01:03:32 +02:00
SetDParam ( 0 , PackEngineNameDParam ( e - > index , EngineNameContext : : PurchaseList ) ) ;
this - > string_filter . AddLine ( GetString ( STR_ENGINE_NAME ) ) ;
2023-05-01 19:02:16 +02:00
/* Filter NewGRF extra text */
auto text = GetNewGRFAdditionalText ( e - > index ) ;
if ( text ) this - > string_filter . AddLine ( * text ) ;
return this - > string_filter . GetState ( ) ;
}
2008-05-13 16:28:27 +02:00
/* Figure out what train EngineIDs to put in the list */
2019-02-27 08:04:17 +01:00
void GenerateBuildTrainList ( GUIEngineList & list )
2008-05-13 16:28:27 +02:00
{
2019-02-27 08:04:17 +01:00
std : : vector < EngineID > variants ;
2008-05-13 16:28:27 +02:00
EngineID sel_id = INVALID_ENGINE ;
2023-01-19 20:07:10 +01:00
size_t num_engines = 0 ;
2008-01-17 19:49:39 +01:00
2019-02-27 08:04:17 +01:00
list . clear ( ) ;
2006-10-10 17:02:38 +02:00
2008-05-13 16:28:27 +02:00
/* Make list of all available train engines and wagons.
2009-03-14 19:16:29 +01:00
* Also check to see if the previously selected engine is still available ,
* and if not , reset selection to INVALID_ENGINE . This could be the case
* when engines become obsolete and are removed */
2019-12-15 22:45:18 +01:00
for ( const Engine * e : Engine : : IterateType ( VEH_TRAIN ) ) {
2023-04-25 21:34:10 +02:00
if ( ! this - > show_hidden_engines & & e - > IsVariantHidden ( _local_company ) ) continue ;
2008-05-13 16:28:27 +02:00
EngineID eid = e - > index ;
const RailVehicleInfo * rvi = & e - > u . rail ;
2006-10-10 17:02:38 +02:00
2019-04-06 08:46:15 +02:00
if ( this - > filter . railtype ! = INVALID_RAILTYPE & & ! HasPowerOnRail ( rvi - > railtype , this - > filter . railtype ) ) continue ;
2008-09-30 22:39:50 +02:00
if ( ! IsEngineBuildable ( eid , VEH_TRAIN , _local_company ) ) continue ;
2007-03-26 13:41:14 +02:00
2009-04-12 19:38:01 +02:00
/* Filter now! So num_engines and num_wagons is valid */
if ( ! FilterSingleEngine ( eid ) ) continue ;
2023-05-01 19:02:16 +02:00
/* Filter by name or NewGRF extra text */
if ( ! FilterByText ( e ) ) continue ;
2019-02-27 08:04:17 +01:00
list . emplace_back ( eid , e - > info . variant_id , e - > display_flags , 0 ) ;
2008-05-28 19:29:27 +02:00
2023-01-19 20:07:10 +01:00
if ( rvi - > railveh_type ! = RAILVEH_WAGON ) num_engines + + ;
2023-10-03 14:43:15 +02:00
/* Add all parent variants of this engine to the variant list */
EngineID parent = e - > info . variant_id ;
while ( parent ! = INVALID_ENGINE ) {
variants . push_back ( parent ) ;
parent = Engine : : Get ( parent ) - > info . variant_id ;
}
2008-05-13 16:28:27 +02:00
if ( eid = = this - > sel_engine ) sel_id = eid ;
2008-01-26 21:55:04 +01:00
}
2008-05-13 16:28:27 +02:00
2019-02-27 08:04:17 +01:00
/* ensure primary engine of variant group is in list */
for ( const auto & variant : variants ) {
if ( std : : find ( list . begin ( ) , list . end ( ) , variant ) = = list . end ( ) ) {
const Engine * e = Engine : : Get ( variant ) ;
list . emplace_back ( variant , e - > info . variant_id , e - > display_flags | EngineDisplayFlags : : Shaded , 0 ) ;
2023-01-19 20:07:10 +01:00
if ( e - > u . rail . railveh_type ! = RAILVEH_WAGON ) num_engines + + ;
2019-02-27 08:04:17 +01:00
}
}
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( sel_id ) ;
2008-05-13 16:28:27 +02:00
2020-06-15 19:36:33 +02:00
/* invalidate cached values for name sorter - engine names could change */
_last_engine [ 0 ] = _last_engine [ 1 ] = INVALID_ENGINE ;
2012-06-03 17:07:27 +02:00
/* make engines first, and then wagons, sorted by selected sort_criteria */
2014-09-07 18:10:27 +02:00
_engine_sort_direction = false ;
2023-05-14 10:17:44 +02:00
EngList_Sort ( list , TrainEnginesThenWagonsSorter ) ;
2008-05-13 16:28:27 +02:00
/* and then sort engines */
2014-09-07 18:10:27 +02:00
_engine_sort_direction = this - > descending_sort_order ;
2023-05-14 10:17:44 +02:00
EngList_SortPartial ( list , _engine_sort_functions [ 0 ] [ this - > sort_criteria ] , 0 , num_engines ) ;
2008-05-13 16:28:27 +02:00
/* and finally sort wagons */
2023-05-14 10:17:44 +02:00
EngList_SortPartial ( list , _engine_sort_functions [ 0 ] [ this - > sort_criteria ] , num_engines , list . size ( ) - num_engines ) ;
2007-01-21 23:50:43 +01:00
}
2007-01-23 00:23:30 +01:00
2008-05-13 16:28:27 +02:00
/* Figure out what road vehicle EngineIDs to put in the list */
void GenerateBuildRoadVehList ( )
{
EngineID sel_id = INVALID_ENGINE ;
2006-10-10 17:02:38 +02:00
2018-09-21 00:44:14 +02:00
this - > eng_list . clear ( ) ;
2006-10-10 17:02:38 +02:00
2019-12-15 22:45:18 +01:00
for ( const Engine * e : Engine : : IterateType ( VEH_ROAD ) ) {
2023-04-25 21:34:10 +02:00
if ( ! this - > show_hidden_engines & & e - > IsVariantHidden ( _local_company ) ) continue ;
2008-05-13 16:28:27 +02:00
EngineID eid = e - > index ;
2008-09-30 22:39:50 +02:00
if ( ! IsEngineBuildable ( eid , VEH_ROAD , _local_company ) ) continue ;
2019-04-06 08:46:15 +02:00
if ( this - > filter . roadtype ! = INVALID_ROADTYPE & & ! HasPowerOnRoad ( e - > u . road . roadtype , this - > filter . roadtype ) ) continue ;
2023-05-01 19:02:16 +02:00
/* Filter by name or NewGRF extra text */
if ( ! FilterByText ( e ) ) continue ;
2019-02-27 08:04:17 +01:00
this - > eng_list . emplace_back ( eid , e - > info . variant_id , e - > display_flags , 0 ) ;
2008-05-13 16:28:27 +02:00
if ( eid = = this - > sel_engine ) sel_id = eid ;
2006-11-30 17:03:12 +01:00
}
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( sel_id ) ;
2008-05-13 16:28:27 +02:00
}
2006-10-10 17:02:38 +02:00
2008-05-13 16:28:27 +02:00
/* Figure out what ship EngineIDs to put in the list */
void GenerateBuildShipList ( )
{
EngineID sel_id = INVALID_ENGINE ;
2018-09-21 00:44:14 +02:00
this - > eng_list . clear ( ) ;
2008-05-13 16:28:27 +02:00
2019-12-15 22:45:18 +01:00
for ( const Engine * e : Engine : : IterateType ( VEH_SHIP ) ) {
2023-04-25 21:34:10 +02:00
if ( ! this - > show_hidden_engines & & e - > IsVariantHidden ( _local_company ) ) continue ;
2008-05-13 16:28:27 +02:00
EngineID eid = e - > index ;
2008-09-30 22:39:50 +02:00
if ( ! IsEngineBuildable ( eid , VEH_SHIP , _local_company ) ) continue ;
2023-05-01 19:02:16 +02:00
/* Filter by name or NewGRF extra text */
if ( ! FilterByText ( e ) ) continue ;
2019-02-27 08:04:17 +01:00
this - > eng_list . emplace_back ( eid , e - > info . variant_id , e - > display_flags , 0 ) ;
2008-05-13 16:28:27 +02:00
if ( eid = = this - > sel_engine ) sel_id = eid ;
}
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( sel_id ) ;
2008-05-13 16:28:27 +02:00
}
/* Figure out what aircraft EngineIDs to put in the list */
void GenerateBuildAircraftList ( )
{
EngineID sel_id = INVALID_ENGINE ;
2018-09-21 00:44:14 +02:00
this - > eng_list . clear ( ) ;
2008-05-13 16:28:27 +02:00
2019-04-10 23:07:06 +02:00
const Station * st = this - > listview_mode ? nullptr : Station : : GetByTile ( this - > window_number ) ;
2009-01-10 10:51:14 +01:00
2008-05-13 16:28:27 +02:00
/* Make list of all available planes.
2009-03-14 19:16:29 +01:00
* Also check to see if the previously selected plane is still available ,
* and if not , reset selection to INVALID_ENGINE . This could be the case
* when planes become obsolete and are removed */
2019-12-15 22:45:18 +01:00
for ( const Engine * e : Engine : : IterateType ( VEH_AIRCRAFT ) ) {
2023-04-25 21:34:10 +02:00
if ( ! this - > show_hidden_engines & & e - > IsVariantHidden ( _local_company ) ) continue ;
2008-05-13 16:28:27 +02:00
EngineID eid = e - > index ;
2008-09-30 22:39:50 +02:00
if ( ! IsEngineBuildable ( eid , VEH_AIRCRAFT , _local_company ) ) continue ;
2008-05-13 16:28:27 +02:00
/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
2009-01-10 10:51:14 +01:00
if ( ! this - > listview_mode & & ! CanVehicleUseStation ( eid , st ) ) continue ;
2008-05-13 16:28:27 +02:00
2023-05-01 19:02:16 +02:00
/* Filter by name or NewGRF extra text */
if ( ! FilterByText ( e ) ) continue ;
2019-02-27 08:04:17 +01:00
this - > eng_list . emplace_back ( eid , e - > info . variant_id , e - > display_flags , 0 ) ;
2023-05-01 19:02:16 +02:00
2008-05-13 16:28:27 +02:00
if ( eid = = this - > sel_engine ) sel_id = eid ;
}
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( sel_id ) ;
2008-05-13 16:28:27 +02:00
}
2006-10-10 17:02:38 +02:00
2008-05-13 16:28:27 +02:00
/* Generate the list of vehicles */
void GenerateBuildList ( )
{
2009-04-12 16:12:17 +02:00
if ( ! this - > eng_list . NeedRebuild ( ) ) return ;
2019-04-06 08:46:15 +02:00
/* Update filter type in case the road/railtype of the depot got converted */
this - > UpdateFilterByTile ( ) ;
2019-02-27 08:04:17 +01:00
this - > eng_list . clear ( ) ;
GUIEngineList list ;
2008-05-13 16:28:27 +02:00
switch ( this - > vehicle_type ) {
default : NOT_REACHED ( ) ;
case VEH_TRAIN :
2019-02-27 08:04:17 +01:00
this - > GenerateBuildTrainList ( list ) ;
2024-04-09 09:35:12 +02:00
GUIEngineListAddChildren ( this - > eng_list , list ) ;
2018-09-21 23:45:44 +02:00
this - > eng_list . shrink_to_fit ( ) ;
2009-04-12 16:12:17 +02:00
this - > eng_list . RebuildDone ( ) ;
2019-02-27 08:04:17 +01:00
return ;
2008-05-13 16:28:27 +02:00
case VEH_ROAD :
this - > GenerateBuildRoadVehList ( ) ;
break ;
case VEH_SHIP :
this - > GenerateBuildShipList ( ) ;
break ;
case VEH_AIRCRAFT :
this - > GenerateBuildAircraftList ( ) ;
break ;
}
2009-04-12 19:38:01 +02:00
this - > FilterEngineList ( ) ;
2019-02-27 08:04:17 +01:00
/* ensure primary engine of variant group is in list after filtering */
std : : vector < EngineID > variants ;
for ( const auto & item : this - > eng_list ) {
2023-10-03 14:43:15 +02:00
EngineID parent = item . variant_id ;
while ( parent ! = INVALID_ENGINE ) {
variants . push_back ( parent ) ;
parent = Engine : : Get ( parent ) - > info . variant_id ;
}
2019-02-27 08:04:17 +01:00
}
2023-10-03 14:43:15 +02:00
2019-02-27 08:04:17 +01:00
for ( const auto & variant : variants ) {
if ( std : : find ( this - > eng_list . begin ( ) , this - > eng_list . end ( ) , variant ) = = this - > eng_list . end ( ) ) {
const Engine * e = Engine : : Get ( variant ) ;
2022-12-31 11:10:25 +01:00
this - > eng_list . emplace_back ( variant , e - > info . variant_id , e - > display_flags | EngineDisplayFlags : : Shaded , 0 ) ;
2019-02-27 08:04:17 +01:00
}
}
2014-09-07 18:10:27 +02:00
_engine_sort_direction = this - > descending_sort_order ;
2023-05-14 10:17:44 +02:00
EngList_Sort ( this - > eng_list , _engine_sort_functions [ this - > vehicle_type ] [ this - > sort_criteria ] ) ;
2009-04-12 16:12:17 +02:00
2019-02-27 08:04:17 +01:00
this - > eng_list . swap ( list ) ;
2024-04-09 09:35:12 +02:00
GUIEngineListAddChildren ( this - > eng_list , list , INVALID_ENGINE , 0 ) ;
2018-09-21 23:45:44 +02:00
this - > eng_list . shrink_to_fit ( ) ;
2009-04-12 16:12:17 +02:00
this - > eng_list . RebuildDone ( ) ;
2008-05-13 16:28:27 +02:00
}
2023-11-12 22:32:12 +01:00
DropDownList BuildCargoDropDownList ( ) const
{
DropDownList list ;
/* Add item for disabling filtering. */
2024-03-31 18:31:47 +02:00
list . push_back ( MakeDropDownListStringItem ( this - > GetCargoFilterLabel ( CargoFilterCriteria : : CF_ANY ) , CargoFilterCriteria : : CF_ANY ) ) ;
2023-11-12 22:32:12 +01:00
/* Specific filters for trains. */
if ( this - > vehicle_type = = VEH_TRAIN ) {
/* Add item for locomotives only in case of trains. */
2024-03-31 18:31:47 +02:00
list . push_back ( MakeDropDownListStringItem ( this - > GetCargoFilterLabel ( CargoFilterCriteria : : CF_ENGINES ) , CargoFilterCriteria : : CF_ENGINES ) ) ;
2023-11-12 22:32:12 +01:00
/* Add item for vehicles not carrying anything, e.g. train engines.
* This could also be useful for eyecandy vehicles of other types , but is likely too confusing for joe , */
2024-03-31 18:31:47 +02:00
list . push_back ( MakeDropDownListStringItem ( this - > GetCargoFilterLabel ( CargoFilterCriteria : : CF_NONE ) , CargoFilterCriteria : : CF_NONE ) ) ;
2023-11-12 22:32:12 +01:00
}
/* Add cargos */
2023-11-15 02:33:50 +01:00
Dimension d = GetLargestCargoIconSize ( ) ;
2023-11-12 22:32:12 +01:00
for ( const CargoSpec * cs : _sorted_standard_cargo_specs ) {
2024-03-31 18:31:47 +02:00
list . push_back ( MakeDropDownListIconItem ( d , cs - > GetCargoIcon ( ) , PAL_NONE , cs - > name , cs - > Index ( ) ) ) ;
2023-11-12 22:32:12 +01:00
}
return list ;
}
2023-12-29 20:11:59 +01:00
void OnClick ( [[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count ) override
2008-05-13 16:28:27 +02:00
{
switch ( widget ) {
2014-09-11 19:10:38 +02:00
case WID_BV_SORT_ASCENDING_DESCENDING :
2008-05-13 16:28:27 +02:00
this - > descending_sort_order ^ = true ;
2014-09-07 18:10:27 +02:00
_engine_sort_last_order [ this - > vehicle_type ] = this - > descending_sort_order ;
2009-04-12 16:12:17 +02:00
this - > eng_list . ForceRebuild ( ) ;
2008-05-13 16:28:27 +02:00
this - > SetDirty ( ) ;
break ;
2014-09-07 18:14:06 +02:00
case WID_BV_SHOW_HIDDEN_ENGINES :
this - > show_hidden_engines ^ = true ;
_engine_sort_show_hidden_engines [ this - > vehicle_type ] = this - > show_hidden_engines ;
this - > eng_list . ForceRebuild ( ) ;
this - > SetWidgetLoweredState ( widget , this - > show_hidden_engines ) ;
this - > SetDirty ( ) ;
break ;
2011-12-16 17:27:45 +01:00
case WID_BV_LIST : {
2022-12-05 20:54:41 +01:00
EngineID e = INVALID_ENGINE ;
2023-05-12 13:58:31 +02:00
const auto it = this - > vscroll - > GetScrolledItemFromWidget ( this - > eng_list , pt . y , this , WID_BV_LIST ) ;
if ( it ! = this - > eng_list . end ( ) ) {
const auto & item = * it ;
2022-12-05 20:54:41 +01:00
const Rect r = this - > GetWidget < NWidgetBase > ( widget ) - > GetCurrentRect ( ) . Shrink ( WidgetDimensions : : scaled . matrix ) . WithWidth ( WidgetDimensions : : scaled . hsep_indent * ( item . indent + 1 ) , _current_text_dir = = TD_RTL ) ;
if ( ( item . flags & EngineDisplayFlags : : HasVariants ) ! = EngineDisplayFlags : : None & & IsInsideMM ( r . left , r . right , pt . x ) ) {
/* toggle folded flag on engine */
assert ( item . variant_id ! = INVALID_ENGINE ) ;
Engine * engine = Engine : : Get ( item . variant_id ) ;
engine - > display_flags ^ = EngineDisplayFlags : : IsFolded ;
InvalidateWindowData ( WC_REPLACE_VEHICLE , this - > vehicle_type , 0 ) ; // Update the autoreplace window
InvalidateWindowClassesData ( WC_BUILD_VEHICLE ) ; // The build windows needs updating as well
return ;
}
if ( ( item . flags & EngineDisplayFlags : : Shaded ) = = EngineDisplayFlags : : None ) e = item . engine_id ;
}
this - > SelectEngine ( e ) ;
2008-05-13 16:28:27 +02:00
this - > SetDirty ( ) ;
2014-09-07 18:14:06 +02:00
if ( _ctrl_pressed ) {
this - > OnClick ( pt , WID_BV_SHOW_HIDE , 1 ) ;
} else if ( click_count > 1 & & ! this - > listview_mode ) {
this - > OnClick ( pt , WID_BV_BUILD , 1 ) ;
}
2008-05-13 16:28:27 +02:00
break ;
}
2014-09-07 18:10:27 +02:00
case WID_BV_SORT_DROPDOWN : // Select sorting criteria dropdown menu
DisplayVehicleSortDropDown ( this , this - > vehicle_type , this - > sort_criteria , WID_BV_SORT_DROPDOWN ) ;
2010-08-01 20:53:30 +02:00
break ;
2008-05-13 16:28:27 +02:00
2011-12-16 17:27:45 +01:00
case WID_BV_CARGO_FILTER_DROPDOWN : // Select cargo filtering criteria dropdown menu
2023-11-12 22:32:12 +01:00
ShowDropDownList ( this , this - > BuildCargoDropDownList ( ) , this - > cargo_filter_criteria , widget ) ;
2009-04-12 19:38:01 +02:00
break ;
2014-09-07 18:14:06 +02:00
case WID_BV_SHOW_HIDE : {
2019-04-10 23:07:06 +02:00
const Engine * e = ( this - > sel_engine = = INVALID_ENGINE ) ? nullptr : Engine : : Get ( this - > sel_engine ) ;
if ( e ! = nullptr ) {
2021-11-05 23:55:23 +01:00
Command < CMD_SET_VEHICLE_VISIBILITY > : : Post ( this - > sel_engine , ! e - > IsHidden ( _current_company ) ) ;
2014-09-07 18:14:06 +02:00
}
break ;
}
2011-12-16 17:27:45 +01:00
case WID_BV_BUILD : {
2008-05-13 16:28:27 +02:00
EngineID sel_eng = this - > sel_engine ;
if ( sel_eng ! = INVALID_ENGINE ) {
2023-11-12 22:32:12 +01:00
CargoID cargo = this - > cargo_filter_criteria ;
2024-01-06 16:29:48 +01:00
if ( cargo = = CargoFilterCriteria : : CF_ANY | | cargo = = CargoFilterCriteria : : CF_ENGINES | | cargo = = CargoFilterCriteria : : CF_NONE ) cargo = INVALID_CARGO ;
2021-11-30 23:21:16 +01:00
if ( this - > vehicle_type = = VEH_TRAIN & & RailVehInfo ( sel_eng ) - > railveh_type = = RAILVEH_WAGON ) {
Command < CMD_BUILD_VEHICLE > : : Post ( GetCmdBuildVehMsg ( this - > vehicle_type ) , CcBuildWagon , this - > window_number , sel_eng , true , cargo , INVALID_CLIENT_ID ) ;
} else {
Command < CMD_BUILD_VEHICLE > : : Post ( GetCmdBuildVehMsg ( this - > vehicle_type ) , CcBuildPrimaryVehicle , this - > window_number , sel_eng , true , cargo , INVALID_CLIENT_ID ) ;
}
2022-12-05 20:54:41 +01:00
2023-10-03 13:14:32 +02:00
/* Update last used variant in hierarchy and refresh if necessary. */
2022-12-05 20:54:41 +01:00
bool refresh = false ;
2023-10-03 13:14:32 +02:00
EngineID parent = sel_eng ;
while ( parent ! = INVALID_ENGINE ) {
Engine * e = Engine : : Get ( parent ) ;
2022-12-05 20:54:41 +01:00
refresh | = ( e - > display_last_variant ! = sel_eng ) ;
e - > display_last_variant = sel_eng ;
2023-10-03 13:14:32 +02:00
parent = e - > info . variant_id ;
2022-12-05 20:54:41 +01:00
}
if ( refresh ) {
InvalidateWindowData ( WC_REPLACE_VEHICLE , this - > vehicle_type , 0 ) ; // Update the autoreplace window
InvalidateWindowClassesData ( WC_BUILD_VEHICLE ) ; // The build windows needs updating as well
return ;
}
2007-01-21 23:50:43 +01:00
}
2008-05-13 16:28:27 +02:00
break ;
2006-11-30 19:47:57 +01:00
}
2006-10-10 17:02:38 +02:00
2011-12-16 17:27:45 +01:00
case WID_BV_RENAME : {
2008-05-13 16:28:27 +02:00
EngineID sel_eng = this - > sel_engine ;
if ( sel_eng ! = INVALID_ENGINE ) {
this - > rename_engine = sel_eng ;
2023-01-22 22:06:48 +01:00
SetDParam ( 0 , PackEngineNameDParam ( sel_eng , EngineNameContext : : Generic ) ) ;
2011-04-17 20:42:17 +02:00
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 ) ;
2007-01-21 23:50:43 +01:00
}
2008-05-13 16:28:27 +02:00
break ;
2006-10-10 17:02:38 +02:00
}
2006-11-30 17:03:12 +01:00
}
2006-10-10 17:02:38 +02:00
}
2011-03-13 22:31:29 +01:00
/**
* 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 .
*/
2023-09-16 22:20:53 +02:00
void OnInvalidateData ( [[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true ) override
2008-05-13 16:28:27 +02:00
{
2011-03-13 22:31:29 +01:00
if ( ! gui_scope ) return ;
2010-03-06 14:03:17 +01:00
/* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
if ( this - > vehicle_type = = VEH_ROAD & &
_settings_game . vehicle . roadveh_acceleration_model = = AM_ORIGINAL & &
this - > sort_criteria > 7 ) {
this - > sort_criteria = 0 ;
2014-09-07 18:10:27 +02:00
_engine_sort_last_criteria [ VEH_ROAD ] = 0 ;
2010-03-06 14:03:17 +01:00
}
2009-04-12 16:12:17 +02:00
this - > eng_list . ForceRebuild ( ) ;
2008-05-13 16:28:27 +02:00
}
2006-11-30 17:03:12 +01:00
2023-12-29 20:11:59 +01:00
void SetStringParameters ( WidgetID widget ) const override
2008-05-13 16:28:27 +02:00
{
2009-10-25 02:26:40 +02:00
switch ( widget ) {
2011-12-16 17:27:45 +01:00
case WID_BV_CAPTION :
2009-10-25 02:26:40 +02:00
if ( this - > vehicle_type = = VEH_TRAIN & & ! this - > listview_mode ) {
2023-09-11 10:55:12 +02:00
const RailTypeInfo * rti = GetRailTypeInfo ( this - > filter . railtype ) ;
2009-10-25 02:26:40 +02:00
SetDParam ( 0 , rti - > strings . build_caption ) ;
2019-04-06 08:46:15 +02:00
} else if ( this - > vehicle_type = = VEH_ROAD & & ! this - > listview_mode ) {
const RoadTypeInfo * rti = GetRoadTypeInfo ( this - > filter . roadtype ) ;
SetDParam ( 0 , rti - > strings . build_caption ) ;
2009-10-25 02:26:40 +02:00
} else {
SetDParam ( 0 , ( this - > listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION ) + this - > vehicle_type ) ;
}
break ;
2007-07-30 00:58:59 +02:00
2011-12-16 17:27:45 +01:00
case WID_BV_SORT_DROPDOWN :
2014-09-07 18:10:27 +02:00
SetDParam ( 0 , _engine_sort_listing [ this - > vehicle_type ] [ this - > sort_criteria ] ) ;
2009-10-25 02:26:40 +02:00
break ;
2007-07-30 00:58:59 +02:00
2011-12-16 17:27:45 +01:00
case WID_BV_CARGO_FILTER_DROPDOWN :
2023-11-12 22:32:12 +01:00
SetDParam ( 0 , this - > GetCargoFilterLabel ( this - > cargo_filter_criteria ) ) ;
2014-09-07 18:09:48 +02:00
break ;
2014-09-07 18:14:06 +02:00
case WID_BV_SHOW_HIDE : {
2019-04-10 23:07:06 +02:00
const Engine * e = ( this - > sel_engine = = INVALID_ENGINE ) ? nullptr : Engine : : Get ( this - > sel_engine ) ;
if ( e ! = nullptr & & e - > IsHidden ( _local_company ) ) {
2014-09-07 18:14:06 +02:00
SetDParam ( 0 , STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this - > vehicle_type ) ;
} else {
SetDParam ( 0 , STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this - > vehicle_type ) ;
}
break ;
}
2008-08-24 23:31:24 +02:00
}
2009-10-25 02:26:40 +02:00
}
2024-04-09 09:34:45 +02:00
void UpdateWidgetSize ( WidgetID widget , Dimension & size , [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension & resize ) override
2009-10-25 02:26:40 +02:00
{
switch ( widget ) {
2011-12-16 17:27:45 +01:00
case WID_BV_LIST :
2024-04-09 09:34:45 +02:00
resize . height = GetEngineListHeight ( this - > vehicle_type ) ;
size . height = 3 * resize . height ;
size . width = std : : max ( size . width , GetVehicleImageCellSize ( this - > vehicle_type , EIT_PURCHASE ) . extend_left + GetVehicleImageCellSize ( this - > vehicle_type , EIT_PURCHASE ) . extend_right + 165 ) + padding . width ;
2009-10-25 02:26:40 +02:00
break ;
2006-10-10 17:02:38 +02:00
2011-12-16 17:27:45 +01:00
case WID_BV_PANEL :
2024-04-09 09:34:45 +02:00
size . height = GetCharacterHeight ( FS_NORMAL ) * this - > details_height + padding . height ;
2009-10-25 02:26:40 +02:00
break ;
2010-11-12 17:29:09 +01:00
2014-09-11 19:10:38 +02:00
case WID_BV_SORT_ASCENDING_DESCENDING : {
2010-11-12 17:29:09 +01:00
Dimension d = GetStringBoundingBox ( this - > GetWidget < NWidgetCore > ( widget ) - > widget_data ) ;
2014-10-05 13:20:02 +02:00
d . width + = padding . width + Window : : SortButtonWidth ( ) * 2 ; // Doubled since the string is centred and it also looks better.
2010-11-12 17:29:09 +01:00
d . height + = padding . height ;
2024-04-09 09:34:45 +02:00
size = maxdim ( size , d ) ;
2010-11-12 17:29:09 +01:00
break ;
}
2014-09-07 18:14:06 +02:00
2023-11-12 22:32:12 +01:00
case WID_BV_CARGO_FILTER_DROPDOWN :
2024-04-09 09:34:45 +02:00
size . width = std : : max ( size . width , GetDropDownListDimension ( this - > BuildCargoDropDownList ( ) ) . width + padding . width ) ;
2023-11-12 22:32:12 +01:00
break ;
2019-02-28 22:32:08 +01:00
case WID_BV_BUILD :
2024-04-09 09:34:45 +02:00
size = GetStringBoundingBox ( STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this - > vehicle_type ) ;
size = maxdim ( size , GetStringBoundingBox ( STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this - > vehicle_type ) ) ;
size . width + = padding . width ;
size . height + = padding . height ;
2019-02-28 22:32:08 +01:00
break ;
2014-09-07 18:14:06 +02:00
case WID_BV_SHOW_HIDE :
2024-04-09 09:34:45 +02:00
size = GetStringBoundingBox ( STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this - > vehicle_type ) ;
size = maxdim ( size , GetStringBoundingBox ( STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this - > vehicle_type ) ) ;
size . width + = padding . width ;
size . height + = padding . height ;
2014-09-07 18:14:06 +02:00
break ;
2009-10-25 02:26:40 +02:00
}
}
2006-10-10 17:02:38 +02:00
2023-12-29 20:11:59 +01:00
void DrawWidget ( const Rect & r , WidgetID widget ) const override
2009-10-25 02:26:40 +02:00
{
switch ( widget ) {
2011-12-16 17:27:45 +01:00
case WID_BV_LIST :
2021-01-08 11:16:18 +01:00
DrawEngineList (
this - > vehicle_type ,
2022-10-21 20:58:43 +02:00
r ,
2019-02-27 08:04:17 +01:00
this - > eng_list ,
2024-02-25 22:33:11 +01:00
* this - > vscroll ,
2021-01-08 11:16:18 +01:00
this - > sel_engine ,
false ,
DEFAULT_GROUP
) ;
2009-10-25 02:26:40 +02:00
break ;
2009-04-12 19:38:01 +02:00
2014-09-11 19:10:38 +02:00
case WID_BV_SORT_ASCENDING_DESCENDING :
this - > DrawSortButtonState ( WID_BV_SORT_ASCENDING_DESCENDING , this - > descending_sort_order ? SBS_DOWN : SBS_UP ) ;
2009-10-25 02:26:40 +02:00
break ;
}
}
2006-10-10 17:02:38 +02:00
2019-03-04 08:49:37 +01:00
void OnPaint ( ) override
2009-10-25 02:26:40 +02:00
{
this - > GenerateBuildList ( ) ;
2023-05-07 17:10:56 +02:00
this - > vscroll - > SetCount ( this - > eng_list . size ( ) ) ;
2006-10-10 17:02:38 +02:00
2023-09-16 21:56:09 +02:00
this - > SetWidgetsDisabledState ( this - > sel_engine = = INVALID_ENGINE , WID_BV_SHOW_HIDE , WID_BV_BUILD ) ;
2021-07-19 22:38:36 +02:00
/* Disable renaming engines in network games if you are not the server. */
this - > SetWidgetDisabledState ( WID_BV_RENAME , this - > sel_engine = = INVALID_ENGINE | | ( _networking & & ! _network_server ) ) ;
2014-09-07 18:14:06 +02:00
2009-10-25 02:26:40 +02:00
this - > DrawWidgets ( ) ;
2007-06-22 12:57:53 +02:00
2009-12-23 11:12:43 +01:00
if ( ! this - > IsShaded ( ) ) {
int needed_height = this - > details_height ;
/* Draw details panels. */
2010-03-19 22:00:15 +01:00
if ( this - > sel_engine ! = INVALID_ENGINE ) {
2024-02-22 23:23:29 +01:00
const Rect r = this - > GetWidget < NWidgetBase > ( WID_BV_PANEL ) - > GetCurrentRect ( ) . Shrink ( WidgetDimensions : : scaled . framerect ) ;
2022-10-15 17:55:47 +02:00
int text_end = DrawVehiclePurchaseInfo ( r . left , r . right , r . top , this - > sel_engine , this - > te ) ;
2023-11-21 20:04:24 +01:00
needed_height = std : : max ( needed_height , ( text_end - r . top ) / GetCharacterHeight ( FS_NORMAL ) ) ;
2009-12-23 11:12:43 +01:00
}
if ( needed_height ! = this - > details_height ) { // Details window are not high enough, enlarge them.
2010-03-20 13:21:01 +01:00
int resize = needed_height - this - > details_height ;
2009-12-23 11:12:43 +01:00
this - > details_height = needed_height ;
2023-11-21 20:04:24 +01:00
this - > ReInit ( 0 , resize * GetCharacterHeight ( FS_NORMAL ) ) ;
2009-12-23 11:12:43 +01:00
return ;
2006-10-10 17:02:38 +02:00
}
2009-10-25 02:26:40 +02:00
}
2008-05-13 16:28:27 +02:00
}
2019-03-04 08:49:37 +01:00
void OnQueryTextFinished ( char * str ) override
2008-05-13 16:28:27 +02:00
{
2019-04-10 23:07:06 +02:00
if ( str = = nullptr ) return ;
2008-09-15 21:02:50 +02:00
2021-11-05 23:55:23 +01:00
Command < CMD_RENAME_ENGINE > : : Post ( STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this - > vehicle_type , this - > rename_engine , str ) ;
2008-05-13 16:28:27 +02:00
}
2006-10-10 17:02:38 +02:00
2023-12-29 20:11:59 +01:00
void OnDropdownSelect ( WidgetID widget , int index ) override
2008-05-13 16:28:27 +02:00
{
2009-04-12 19:38:01 +02:00
switch ( widget ) {
2011-12-16 17:27:45 +01:00
case WID_BV_SORT_DROPDOWN :
2009-04-12 19:38:01 +02:00
if ( this - > sort_criteria ! = index ) {
this - > sort_criteria = index ;
2014-09-07 18:10:27 +02:00
_engine_sort_last_criteria [ this - > vehicle_type ] = this - > sort_criteria ;
2009-04-12 19:38:01 +02:00
this - > eng_list . ForceRebuild ( ) ;
}
break ;
2011-12-16 17:27:45 +01:00
case WID_BV_CARGO_FILTER_DROPDOWN : // Select a cargo filter criteria
2009-04-12 19:38:01 +02:00
if ( this - > cargo_filter_criteria ! = index ) {
this - > cargo_filter_criteria = index ;
2023-11-12 22:32:12 +01:00
_engine_sort_last_cargo_criteria [ this - > vehicle_type ] = this - > cargo_filter_criteria ;
2009-04-12 19:38:01 +02:00
/* deactivate filter if criteria is 'Show All', activate it otherwise */
2024-01-06 16:29:48 +01:00
this - > eng_list . SetFilterState ( this - > cargo_filter_criteria ! = CargoFilterCriteria : : CF_ANY ) ;
2009-04-12 19:38:01 +02:00
this - > eng_list . ForceRebuild ( ) ;
2019-03-23 22:06:46 +01:00
this - > SelectEngine ( this - > sel_engine ) ;
2009-04-12 19:38:01 +02:00
}
break ;
2008-05-13 16:28:27 +02:00
}
this - > SetDirty ( ) ;
}
2007-01-21 23:50:43 +01:00
2019-03-04 08:49:37 +01:00
void OnResize ( ) override
2008-05-13 16:28:27 +02:00
{
2011-12-16 17:27:45 +01:00
this - > vscroll - > SetCapacityFromWidget ( this , WID_BV_LIST ) ;
2006-10-10 17:02:38 +02:00
}
2023-05-01 19:02:16 +02:00
2023-12-29 20:11:59 +01:00
void OnEditboxChanged ( WidgetID wid ) override
2023-05-01 19:02:16 +02:00
{
if ( wid = = WID_BV_FILTER ) {
this - > string_filter . SetFilterTerm ( this - > vehicle_editbox . text . buf ) ;
this - > InvalidateData ( ) ;
}
}
EventState OnHotkey ( int hotkey ) override
{
switch ( hotkey ) {
case BVHK_FOCUS_FILTER_BOX :
this - > SetFocusedWidget ( WID_BV_FILTER ) ;
SetFocusedWindow ( this ) ; // The user has asked to give focus to the text box, so make sure this window is focused.
return ES_HANDLED ;
default :
return ES_NOT_HANDLED ;
}
return ES_HANDLED ;
}
2023-06-05 19:12:30 +02:00
static inline HotkeyList hotkeys { " buildvehicle " , {
Hotkey ( ' F ' , " focus_filter_box " , BVHK_FOCUS_FILTER_BOX ) ,
} } ;
2023-05-01 19:02:16 +02:00
} ;
2024-01-17 04:17:02 +01:00
static WindowDesc _build_vehicle_desc (
2013-05-26 21:25:01 +02:00
WDP_AUTO , " build_vehicle " , 240 , 268 ,
2007-02-01 16:49:12 +01:00
WC_BUILD_VEHICLE , WC_NONE ,
2012-11-11 17:10:43 +01:00
WDF_CONSTRUCTION ,
2023-09-03 22:54:13 +02:00
std : : begin ( _nested_build_vehicle_widgets ) , std : : end ( _nested_build_vehicle_widgets ) ,
2023-05-01 19:02:16 +02:00
& BuildVehicleWindow : : hotkeys
2009-03-15 16:12:06 +01:00
) ;
2006-10-10 17:02:38 +02:00
2007-05-18 19:31:41 +02:00
void ShowBuildVehicleWindow ( TileIndex tile , VehicleType type )
2006-10-10 17:02:38 +02:00
{
2007-07-13 16:51:55 +02:00
/* We want to be able to open both Available Train as Available Ships,
2009-01-03 17:06:58 +01:00
* so if tile = = INVALID_TILE ( Available XXX Window ) , use ' type ' as unique number .
2007-07-13 16:51:55 +02:00
* As it always is a low value , it won ' t collide with any real tile
* number . */
2023-11-06 21:29:35 +01:00
uint num = ( tile = = INVALID_TILE ) ? ( int ) type : tile . base ( ) ;
2006-10-10 17:02:38 +02:00
2008-09-30 22:39:50 +02:00
assert ( IsCompanyBuildableVehicleType ( type ) ) ;
2007-01-21 23:50:43 +01:00
2021-05-17 15:46:38 +02:00
CloseWindowById ( WC_BUILD_VEHICLE , num ) ;
2007-01-21 23:50:43 +01:00
2008-05-13 16:28:27 +02:00
new BuildVehicleWindow ( & _build_vehicle_desc , tile , type ) ;
2006-10-10 17:02:38 +02:00
}