OpenTTD Source  1.10.3
build_vehicle_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "engine_base.h"
12 #include "engine_func.h"
13 #include "station_base.h"
14 #include "network/network.h"
15 #include "articulated_vehicles.h"
16 #include "textbuf_gui.h"
17 #include "command_func.h"
18 #include "company_func.h"
19 #include "vehicle_gui.h"
20 #include "newgrf_engine.h"
21 #include "newgrf_text.h"
22 #include "group.h"
23 #include "string_func.h"
24 #include "strings_func.h"
25 #include "window_func.h"
26 #include "date_func.h"
27 #include "vehicle_func.h"
28 #include "widgets/dropdown_func.h"
29 #include "engine_gui.h"
30 #include "cargotype.h"
31 #include "core/geometry_func.hpp"
32 #include "autoreplace_func.h"
33 
35 
36 #include "table/strings.h"
37 
38 #include "safeguards.h"
39 
46 {
48 }
49 
50 static const NWidgetPart _nested_build_vehicle_widgets[] = {
52  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
53  NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
54  NWidget(WWT_SHADEBOX, COLOUR_GREY),
55  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
56  NWidget(WWT_STICKYBOX, COLOUR_GREY),
57  EndContainer(),
58  NWidget(WWT_PANEL, COLOUR_GREY),
61  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
62  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
63  EndContainer(),
66  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
67  EndContainer(),
68  EndContainer(),
69  EndContainer(),
70  /* Vehicle list. */
72  NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR),
74  EndContainer(),
75  /* Panel with details. */
76  NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
77  /* Build/rename buttons, resize button. */
79  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL),
80  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0),
81  EndContainer(),
82  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL),
83  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0),
84  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
85  EndContainer(),
86 };
87 
89 static const CargoID CF_ANY = CT_NO_REFIT;
90 static const CargoID CF_NONE = CT_INVALID;
91 
93 byte _engine_sort_last_criteria[] = {0, 0, 0, 0};
94 bool _engine_sort_last_order[] = {false, false, false, false};
95 bool _engine_sort_show_hidden_engines[] = {false, false, false, false};
97 
104 static bool EngineNumberSorter(const EngineID &a, const EngineID &b)
105 {
106  int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position;
107 
108  return _engine_sort_direction ? r > 0 : r < 0;
109 }
110 
117 static bool EngineIntroDateSorter(const EngineID &a, const EngineID &b)
118 {
119  const int va = Engine::Get(a)->intro_date;
120  const int vb = Engine::Get(b)->intro_date;
121  const int r = va - vb;
122 
123  /* Use EngineID to sort instead since we want consistent sorting */
124  if (r == 0) return EngineNumberSorter(a, b);
125  return _engine_sort_direction ? r > 0 : r < 0;
126 }
127 
128 /* cached values for EngineNameSorter to spare many GetString() calls */
129 static EngineID _last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
130 
137 static bool EngineNameSorter(const EngineID &a, const EngineID &b)
138 {
139  static char last_name[2][64] = { "", "" };
140 
141  if (a != _last_engine[0]) {
142  _last_engine[0] = a;
143  SetDParam(0, a);
144  GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0]));
145  }
146 
147  if (b != _last_engine[1]) {
148  _last_engine[1] = b;
149  SetDParam(0, b);
150  GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1]));
151  }
152 
153  int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting).
154 
155  /* Use EngineID to sort instead since we want consistent sorting */
156  if (r == 0) return EngineNumberSorter(a, b);
157  return _engine_sort_direction ? r > 0 : r < 0;
158 }
159 
166 static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b)
167 {
168  const int va = Engine::Get(a)->reliability;
169  const int vb = Engine::Get(b)->reliability;
170  const int r = va - vb;
171 
172  /* Use EngineID to sort instead since we want consistent sorting */
173  if (r == 0) return EngineNumberSorter(a, b);
174  return _engine_sort_direction ? r > 0 : r < 0;
175 }
176 
183 static bool EngineCostSorter(const EngineID &a, const EngineID &b)
184 {
185  Money va = Engine::Get(a)->GetCost();
186  Money vb = Engine::Get(b)->GetCost();
187  int r = ClampToI32(va - vb);
188 
189  /* Use EngineID to sort instead since we want consistent sorting */
190  if (r == 0) return EngineNumberSorter(a, b);
191  return _engine_sort_direction ? r > 0 : r < 0;
192 }
193 
200 static bool EngineSpeedSorter(const EngineID &a, const EngineID &b)
201 {
202  int va = Engine::Get(a)->GetDisplayMaxSpeed();
203  int vb = Engine::Get(b)->GetDisplayMaxSpeed();
204  int r = va - vb;
205 
206  /* Use EngineID to sort instead since we want consistent sorting */
207  if (r == 0) return EngineNumberSorter(a, b);
208  return _engine_sort_direction ? r > 0 : r < 0;
209 }
210 
217 static bool EnginePowerSorter(const EngineID &a, const EngineID &b)
218 {
219  int va = Engine::Get(a)->GetPower();
220  int vb = Engine::Get(b)->GetPower();
221  int r = va - vb;
222 
223  /* Use EngineID to sort instead since we want consistent sorting */
224  if (r == 0) return EngineNumberSorter(a, b);
225  return _engine_sort_direction ? r > 0 : r < 0;
226 }
227 
234 static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b)
235 {
236  int va = Engine::Get(a)->GetDisplayMaxTractiveEffort();
237  int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort();
238  int r = va - vb;
239 
240  /* Use EngineID to sort instead since we want consistent sorting */
241  if (r == 0) return EngineNumberSorter(a, b);
242  return _engine_sort_direction ? r > 0 : r < 0;
243 }
244 
251 static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b)
252 {
253  Money va = Engine::Get(a)->GetRunningCost();
254  Money vb = Engine::Get(b)->GetRunningCost();
255  int r = ClampToI32(va - vb);
256 
257  /* Use EngineID to sort instead since we want consistent sorting */
258  if (r == 0) return EngineNumberSorter(a, b);
259  return _engine_sort_direction ? r > 0 : r < 0;
260 }
261 
268 static bool EnginePowerVsRunningCostSorter(const EngineID &a, const EngineID &b)
269 {
270  const Engine *e_a = Engine::Get(a);
271  const Engine *e_b = Engine::Get(b);
272  uint p_a = e_a->GetPower();
273  uint p_b = e_b->GetPower();
274  Money r_a = e_a->GetRunningCost();
275  Money r_b = e_b->GetRunningCost();
276  /* Check if running cost is zero in one or both engines.
277  * If only one of them is zero then that one has higher value,
278  * else if both have zero cost then compare powers. */
279  if (r_a == 0) {
280  if (r_b == 0) {
281  /* If it is ambiguous which to return go with their ID */
282  if (p_a == p_b) return EngineNumberSorter(a, b);
283  return _engine_sort_direction != (p_a < p_b);
284  }
285  return !_engine_sort_direction;
286  }
287  if (r_b == 0) return _engine_sort_direction;
288  /* Using double for more precision when comparing close values.
289  * This shouldn't have any major effects in performance nor in keeping
290  * the game in sync between players since it's used in GUI only in client side */
291  double v_a = (double)p_a / (double)r_a;
292  double v_b = (double)p_b / (double)r_b;
293  /* Use EngineID to sort if both have same power/running cost,
294  * since we want consistent sorting.
295  * Also if both have no power then sort with reverse of running cost to simulate
296  * previous sorting behaviour for wagons. */
297  if (v_a == 0 && v_b == 0) return !EngineRunningCostSorter(a, b);
298  if (v_a == v_b) return EngineNumberSorter(a, b);
299  return _engine_sort_direction != (v_a < v_b);
300 }
301 
302 /* Train sorting functions */
303 
310 static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b)
311 {
312  const RailVehicleInfo *rvi_a = RailVehInfo(a);
313  const RailVehicleInfo *rvi_b = RailVehInfo(b);
314 
315  int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
316  int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
317  int r = va - vb;
318 
319  /* Use EngineID to sort instead since we want consistent sorting */
320  if (r == 0) return EngineNumberSorter(a, b);
321  return _engine_sort_direction ? r > 0 : r < 0;
322 }
323 
330 static bool TrainEnginesThenWagonsSorter(const EngineID &a, const EngineID &b)
331 {
332  int val_a = (RailVehInfo(a)->railveh_type == RAILVEH_WAGON ? 1 : 0);
333  int val_b = (RailVehInfo(b)->railveh_type == RAILVEH_WAGON ? 1 : 0);
334  int r = val_a - val_b;
335 
336  /* Use EngineID to sort instead since we want consistent sorting */
337  if (r == 0) return EngineNumberSorter(a, b);
338  return _engine_sort_direction ? r > 0 : r < 0;
339 }
340 
341 /* Road vehicle sorting functions */
342 
349 static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b)
350 {
353  int r = va - vb;
354 
355  /* Use EngineID to sort instead since we want consistent sorting */
356  if (r == 0) return EngineNumberSorter(a, b);
357  return _engine_sort_direction ? r > 0 : r < 0;
358 }
359 
360 /* Ship vehicle sorting functions */
361 
368 static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b)
369 {
370  const Engine *e_a = Engine::Get(a);
371  const Engine *e_b = Engine::Get(b);
372 
373  int va = e_a->GetDisplayDefaultCapacity();
374  int vb = e_b->GetDisplayDefaultCapacity();
375  int r = va - vb;
376 
377  /* Use EngineID to sort instead since we want consistent sorting */
378  if (r == 0) return EngineNumberSorter(a, b);
379  return _engine_sort_direction ? r > 0 : r < 0;
380 }
381 
382 /* Aircraft sorting functions */
383 
390 static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b)
391 {
392  const Engine *e_a = Engine::Get(a);
393  const Engine *e_b = Engine::Get(b);
394 
395  uint16 mail_a, mail_b;
396  int va = e_a->GetDisplayDefaultCapacity(&mail_a);
397  int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
398  int r = va - vb;
399 
400  if (r == 0) {
401  /* The planes have the same passenger capacity. Check mail capacity instead */
402  r = mail_a - mail_b;
403 
404  if (r == 0) {
405  /* Use EngineID to sort instead since we want consistent sorting */
406  return EngineNumberSorter(a, b);
407  }
408  }
409  return _engine_sort_direction ? r > 0 : r < 0;
410 }
411 
418 static bool AircraftRangeSorter(const EngineID &a, const EngineID &b)
419 {
420  uint16 r_a = Engine::Get(a)->GetRange();
421  uint16 r_b = Engine::Get(b)->GetRange();
422 
423  int r = r_a - r_b;
424 
425  /* Use EngineID to sort instead since we want consistent sorting */
426  if (r == 0) return EngineNumberSorter(a, b);
427  return _engine_sort_direction ? r > 0 : r < 0;
428 }
429 
432  /* Trains */
444 }, {
445  /* Road vehicles */
457 }, {
458  /* Ships */
467 }, {
468  /* Aircraft */
478 }};
479 
482  /* Trains */
483  STR_SORT_BY_ENGINE_ID,
484  STR_SORT_BY_COST,
485  STR_SORT_BY_MAX_SPEED,
486  STR_SORT_BY_POWER,
487  STR_SORT_BY_TRACTIVE_EFFORT,
488  STR_SORT_BY_INTRO_DATE,
489  STR_SORT_BY_NAME,
490  STR_SORT_BY_RUNNING_COST,
491  STR_SORT_BY_POWER_VS_RUNNING_COST,
492  STR_SORT_BY_RELIABILITY,
493  STR_SORT_BY_CARGO_CAPACITY,
495 }, {
496  /* Road vehicles */
497  STR_SORT_BY_ENGINE_ID,
498  STR_SORT_BY_COST,
499  STR_SORT_BY_MAX_SPEED,
500  STR_SORT_BY_POWER,
501  STR_SORT_BY_TRACTIVE_EFFORT,
502  STR_SORT_BY_INTRO_DATE,
503  STR_SORT_BY_NAME,
504  STR_SORT_BY_RUNNING_COST,
505  STR_SORT_BY_POWER_VS_RUNNING_COST,
506  STR_SORT_BY_RELIABILITY,
507  STR_SORT_BY_CARGO_CAPACITY,
508  INVALID_STRING_ID
509 }, {
510  /* Ships */
511  STR_SORT_BY_ENGINE_ID,
512  STR_SORT_BY_COST,
513  STR_SORT_BY_MAX_SPEED,
514  STR_SORT_BY_INTRO_DATE,
515  STR_SORT_BY_NAME,
516  STR_SORT_BY_RUNNING_COST,
517  STR_SORT_BY_RELIABILITY,
518  STR_SORT_BY_CARGO_CAPACITY,
519  INVALID_STRING_ID
520 }, {
521  /* Aircraft */
522  STR_SORT_BY_ENGINE_ID,
523  STR_SORT_BY_COST,
524  STR_SORT_BY_MAX_SPEED,
525  STR_SORT_BY_INTRO_DATE,
526  STR_SORT_BY_NAME,
527  STR_SORT_BY_RUNNING_COST,
528  STR_SORT_BY_RELIABILITY,
529  STR_SORT_BY_CARGO_CAPACITY,
530  STR_SORT_BY_RANGE,
531  INVALID_STRING_ID
532 }};
533 
535 static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid)
536 {
537  if (cid == CF_ANY) return true;
538  CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask;
539  return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid));
540 }
541 
542 static GUIEngineList::FilterFunction * const _filter_funcs[] = {
543  &CargoFilter,
544 };
545 
546 static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, TestedEngineDetails &te)
547 {
548  CargoArray cap;
549  CargoTypes refits;
550  GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits, te.cargo, te.capacity);
551 
552  for (CargoID c = 0; c < NUM_CARGO; c++) {
553  if (cap[c] == 0) continue;
554 
555  SetDParam(0, c);
556  SetDParam(1, cap[c]);
557  SetDParam(2, HasBit(refits, c) ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
558  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
559  y += FONT_HEIGHT_NORMAL;
560  }
561 
562  return y;
563 }
564 
565 /* Draw rail wagon specific details */
566 static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
567 {
568  const Engine *e = Engine::Get(engine_number);
569 
570  /* Purchase cost */
571  if (te.cost != 0) {
572  SetDParam(0, e->GetCost() + te.cost);
573  SetDParam(1, te.cost);
574  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
575  } else {
576  SetDParam(0, e->GetCost());
577  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
578  }
579  y += FONT_HEIGHT_NORMAL;
580 
581  /* Wagon weight - (including cargo) */
582  uint weight = e->GetDisplayWeight();
583  SetDParam(0, weight);
584  uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
585  SetDParam(1, cargo_weight + weight);
586  DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
587  y += FONT_HEIGHT_NORMAL;
588 
589  /* Wagon speed limit, displayed if above zero */
591  uint max_speed = e->GetDisplayMaxSpeed();
592  if (max_speed > 0) {
593  SetDParam(0, max_speed);
594  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
595  y += FONT_HEIGHT_NORMAL;
596  }
597  }
598 
599  /* Running cost */
600  if (rvi->running_cost_class != INVALID_PRICE) {
601  SetDParam(0, e->GetRunningCost());
602  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
603  y += FONT_HEIGHT_NORMAL;
604  }
605 
606  return y;
607 }
608 
609 /* Draw locomotive specific details */
610 static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
611 {
612  const Engine *e = Engine::Get(engine_number);
613 
614  /* Purchase Cost - Engine weight */
615  if (te.cost != 0) {
616  SetDParam(0, e->GetCost() + te.cost);
617  SetDParam(1, te.cost);
618  SetDParam(2, e->GetDisplayWeight());
619  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_WEIGHT);
620  } else {
621  SetDParam(0, e->GetCost());
622  SetDParam(1, e->GetDisplayWeight());
623  DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
624  }
625  y += FONT_HEIGHT_NORMAL;
626 
627  /* Max speed - Engine power */
628  SetDParam(0, e->GetDisplayMaxSpeed());
629  SetDParam(1, e->GetPower());
630  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
631  y += FONT_HEIGHT_NORMAL;
632 
633  /* Max tractive effort - not applicable if old acceleration or maglev */
634  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
636  DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
637  y += FONT_HEIGHT_NORMAL;
638  }
639 
640  /* Running cost */
641  if (rvi->running_cost_class != INVALID_PRICE) {
642  SetDParam(0, e->GetRunningCost());
643  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
644  y += FONT_HEIGHT_NORMAL;
645  }
646 
647  /* Powered wagons power - Powered wagons extra weight */
648  if (rvi->pow_wag_power != 0) {
649  SetDParam(0, rvi->pow_wag_power);
650  SetDParam(1, rvi->pow_wag_weight);
651  DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT);
652  y += FONT_HEIGHT_NORMAL;
653  }
654 
655  return y;
656 }
657 
658 /* Draw road vehicle specific details */
659 static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
660 {
661  const Engine *e = Engine::Get(engine_number);
662 
664  /* Purchase Cost */
665  if (te.cost != 0) {
666  SetDParam(0, e->GetCost() + te.cost);
667  SetDParam(1, te.cost);
668  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
669  } else {
670  SetDParam(0, e->GetCost());
671  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
672  }
673  y += FONT_HEIGHT_NORMAL;
674 
675  /* Road vehicle weight - (including cargo) */
676  int16 weight = e->GetDisplayWeight();
677  SetDParam(0, weight);
678  uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
679  SetDParam(1, cargo_weight + weight);
680  DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
681  y += FONT_HEIGHT_NORMAL;
682 
683  /* Max speed - Engine power */
684  SetDParam(0, e->GetDisplayMaxSpeed());
685  SetDParam(1, e->GetPower());
686  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
687  y += FONT_HEIGHT_NORMAL;
688 
689  /* Max tractive effort */
691  DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
692  y += FONT_HEIGHT_NORMAL;
693  } else {
694  /* Purchase cost - Max speed */
695  if (te.cost != 0) {
696  SetDParam(0, e->GetCost() + te.cost);
697  SetDParam(1, te.cost);
698  SetDParam(2, e->GetDisplayMaxSpeed());
699  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
700  } else {
701  SetDParam(0, e->GetCost());
702  SetDParam(1, e->GetDisplayMaxSpeed());
703  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
704  }
705  y += FONT_HEIGHT_NORMAL;
706  }
707 
708  /* Running cost */
709  SetDParam(0, e->GetRunningCost());
710  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
711  y += FONT_HEIGHT_NORMAL;
712 
713  return y;
714 }
715 
716 /* Draw ship specific details */
717 static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
718 {
719  const Engine *e = Engine::Get(engine_number);
720 
721  /* Purchase cost - Max speed */
722  uint raw_speed = e->GetDisplayMaxSpeed();
723  uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
724  uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
725 
726  if (ocean_speed == canal_speed) {
727  if (te.cost != 0) {
728  SetDParam(0, e->GetCost() + te.cost);
729  SetDParam(1, te.cost);
730  SetDParam(2, ocean_speed);
731  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
732  } else {
733  SetDParam(0, e->GetCost());
734  SetDParam(1, ocean_speed);
735  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
736  }
737  y += FONT_HEIGHT_NORMAL;
738  } else {
739  if (te.cost != 0) {
740  SetDParam(0, e->GetCost() + te.cost);
741  SetDParam(1, te.cost);
742  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
743  } else {
744  SetDParam(0, e->GetCost());
745  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
746  }
747  y += FONT_HEIGHT_NORMAL;
748 
749  SetDParam(0, ocean_speed);
750  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN);
751  y += FONT_HEIGHT_NORMAL;
752 
753  SetDParam(0, canal_speed);
754  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL);
755  y += FONT_HEIGHT_NORMAL;
756  }
757 
758  /* Cargo type + capacity */
759  SetDParam(0, te.cargo);
760  SetDParam(1, te.capacity);
761  SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
762  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
763  y += FONT_HEIGHT_NORMAL;
764 
765  /* Running cost */
766  SetDParam(0, e->GetRunningCost());
767  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
768  y += FONT_HEIGHT_NORMAL;
769 
770  return y;
771 }
772 
782 static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
783 {
784  const Engine *e = Engine::Get(engine_number);
785 
786  /* Purchase cost - Max speed */
787  if (te.cost != 0) {
788  SetDParam(0, e->GetCost() + te.cost);
789  SetDParam(1, te.cost);
790  SetDParam(2, e->GetDisplayMaxSpeed());
791  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
792  } else {
793  SetDParam(0, e->GetCost());
794  SetDParam(1, e->GetDisplayMaxSpeed());
795  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
796  }
797  y += FONT_HEIGHT_NORMAL;
798 
799  /* Cargo capacity */
800  if (te.mail_capacity > 0) {
801  SetDParam(0, te.cargo);
802  SetDParam(1, te.capacity);
803  SetDParam(2, CT_MAIL);
804  SetDParam(3, te.mail_capacity);
805  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
806  } else {
807  /* Note, if the default capacity is selected by the refit capacity
808  * callback, then the capacity shown is likely to be incorrect. */
809  SetDParam(0, te.cargo);
810  SetDParam(1, te.capacity);
811  SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
812  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
813  }
814  y += FONT_HEIGHT_NORMAL;
815 
816  /* Running cost */
817  SetDParam(0, e->GetRunningCost());
818  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
819  y += FONT_HEIGHT_NORMAL;
820 
821  /* Aircraft type */
823  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_TYPE);
824  y += FONT_HEIGHT_NORMAL;
825 
826  /* Aircraft range, if available. */
827  uint16 range = e->GetRange();
828  if (range != 0) {
829  SetDParam(0, range);
830  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE);
831  y += FONT_HEIGHT_NORMAL;
832  }
833 
834  return y;
835 }
836 
845 static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
846 {
847  uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
848  if (callback == CALLBACK_FAILED || callback == 0x400) return y;
849  const GRFFile *grffile = Engine::Get(engine)->GetGRF();
850  if (callback > 0x400) {
851  ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
852  return y;
853  }
854 
855  StartTextRefStackUsage(grffile, 6);
856  uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK);
858  return result;
859 }
860 
867 int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
868 {
869  const Engine *e = Engine::Get(engine_number);
870  YearMonthDay ymd;
871  ConvertDateToYMD(e->intro_date, &ymd);
872  bool refittable = IsArticulatedVehicleRefittable(engine_number);
873  bool articulated_cargo = false;
874 
875  switch (e->type) {
876  default: NOT_REACHED();
877  case VEH_TRAIN:
878  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
879  y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
880  } else {
881  y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
882  }
883  articulated_cargo = true;
884  break;
885 
886  case VEH_ROAD:
887  y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
888  articulated_cargo = true;
889  break;
890 
891  case VEH_SHIP:
892  y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
893  break;
894 
895  case VEH_AIRCRAFT:
896  y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
897  break;
898  }
899 
900  if (articulated_cargo) {
901  /* Cargo type + capacity, or N/A */
902  int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, te);
903 
904  if (new_y == y) {
905  SetDParam(0, CT_INVALID);
906  SetDParam(2, STR_EMPTY);
907  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
908  y += FONT_HEIGHT_NORMAL;
909  } else {
910  y = new_y;
911  }
912  }
913 
914  /* Draw details that apply to all types except rail wagons. */
915  if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
916  /* Design date - Life length */
917  SetDParam(0, ymd.year);
919  DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
920  y += FONT_HEIGHT_NORMAL;
921 
922  /* Reliability */
924  DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
925  y += FONT_HEIGHT_NORMAL;
926  }
927 
928  if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
929 
930  /* Additional text from NewGRF */
931  y = ShowAdditionalText(left, right, y, engine_number);
932 
933  /* The NewGRF's name which the vehicle comes from */
934  const GRFConfig *config = GetGRFConfig(e->GetGRFID());
935  if (_settings_client.gui.show_newgrf_name && config != nullptr)
936  {
937  DrawString(left, right, y, config->GetName(), TC_BLACK);
938  y += FONT_HEIGHT_NORMAL;
939  }
940 
941  return y;
942 }
943 
957 void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group)
958 {
959  static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
960 
961  /* Obligatory sanity checks! */
962  assert(max <= eng_list->size());
963 
964  bool rtl = _current_text_dir == TD_RTL;
965  int step_size = GetEngineListHeight(type);
966  int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
967  int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
968  int sprite_width = sprite_left + sprite_right;
969 
970  int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1;
971  int sprite_y_offset = sprite_y_offsets[type] + step_size / 2;
972 
973  Dimension replace_icon = {0, 0};
974  int count_width = 0;
975  if (show_count) {
976  replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
978  count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width;
979  }
980 
981  int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT);
982  int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width);
983  int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width;
984  int count_left = l;
985  int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8;
986 
987  int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2;
988  int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1;
989  int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1;
990 
991  for (; min < max; min++, y += step_size) {
992  const EngineID engine = (*eng_list)[min];
993  /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
994  const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
995 
996  const Engine *e = Engine::Get(engine);
997  bool hidden = HasBit(e->company_hidden, _local_company);
998  StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
999  TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK));
1000 
1001  SetDParam(0, engine);
1002  DrawString(text_left, text_right, y + normal_text_y_offset, str, tc);
1003  DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE);
1004  if (show_count) {
1005  SetDParam(0, num_engines);
1006  DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
1007  if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset);
1008  }
1009  }
1010 }
1011 
1019 void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button)
1020 {
1021  uint32 hidden_mask = 0;
1022  /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1023  if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1024  SetBit(hidden_mask, 3); // power
1025  SetBit(hidden_mask, 4); // tractive effort
1026  SetBit(hidden_mask, 8); // power by running costs
1027  }
1028  /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1029  if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1030  SetBit(hidden_mask, 4); // tractive effort
1031  }
1032  ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1033 }
1034 
1038  union {
1041  } filter;
1048  GUIEngineList eng_list;
1053  Scrollbar *vscroll;
1055 
1056  void SetBuyVehicleText()
1057  {
1058  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
1059 
1060  bool refit = this->sel_engine != INVALID_ENGINE && this->cargo_filter[this->cargo_filter_criteria] != CF_ANY && this->cargo_filter[this->cargo_filter_criteria] != CF_NONE;
1061  if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria];
1062 
1063  if (refit) {
1064  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type;
1065  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type;
1066  } else {
1067  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type;
1068  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type;
1069  }
1070  }
1071 
1072  BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
1073  {
1074  this->vehicle_type = type;
1075  this->listview_mode = tile == INVALID_TILE;
1076  this->window_number = this->listview_mode ? (int)type : tile;
1077 
1078  this->sel_engine = INVALID_ENGINE;
1079 
1080  this->sort_criteria = _engine_sort_last_criteria[type];
1081  this->descending_sort_order = _engine_sort_last_order[type];
1082  this->show_hidden_engines = _engine_sort_show_hidden_engines[type];
1083 
1084  this->UpdateFilterByTile();
1085 
1086  this->CreateNestedTree();
1087 
1088  this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1089 
1090  /* If we are just viewing the list of vehicles, we do not need the Build button.
1091  * So we just hide it, and enlarge the Rename button by the now vacant place. */
1092  if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1093 
1094  /* disable renaming engines in network games if you are not the server */
1096 
1097  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
1098  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
1099 
1100  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDE);
1101  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type;
1102 
1103  widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1104  widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
1105  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
1106 
1107  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDDEN_ENGINES);
1108  widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type;
1109  widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type;
1110  widget->SetLowered(this->show_hidden_engines);
1111 
1112  this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
1113 
1114  this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile);
1115 
1116  this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1117 
1118  this->eng_list.ForceRebuild();
1119  this->GenerateBuildList(); // generate the list, since we need it in the next line
1120  /* Select the first engine in the list as default when opening the window */
1121  if (this->eng_list.size() > 0) {
1122  this->SelectEngine(this->eng_list[0]);
1123  } else {
1124  this->SelectEngine(INVALID_ENGINE);
1125  }
1126  }
1127 
1130  {
1131  switch (this->vehicle_type) {
1132  default: NOT_REACHED();
1133  case VEH_TRAIN:
1134  if (this->listview_mode) {
1135  this->filter.railtype = INVALID_RAILTYPE;
1136  } else {
1137  this->filter.railtype = GetRailType(this->window_number);
1138  }
1139  break;
1140 
1141  case VEH_ROAD:
1142  if (this->listview_mode) {
1143  this->filter.roadtype = INVALID_ROADTYPE;
1144  } else {
1145  this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1146  if (this->filter.roadtype == INVALID_ROADTYPE) {
1147  this->filter.roadtype = GetRoadTypeTram(this->window_number);
1148  }
1149  }
1150  break;
1151 
1152  case VEH_SHIP:
1153  case VEH_AIRCRAFT:
1154  break;
1155  }
1156  }
1157 
1160  {
1161  uint filter_items = 0;
1162 
1163  /* Add item for disabling filtering. */
1164  this->cargo_filter[filter_items] = CF_ANY;
1165  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES;
1166  filter_items++;
1167 
1168  /* Add item for vehicles not carrying anything, e.g. train engines.
1169  * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1170  if (this->vehicle_type == VEH_TRAIN) {
1171  this->cargo_filter[filter_items] = CF_NONE;
1172  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_NONE;
1173  filter_items++;
1174  }
1175 
1176  /* Collect available cargo types for filtering. */
1177  const CargoSpec *cs;
1179  this->cargo_filter[filter_items] = cs->Index();
1180  this->cargo_filter_texts[filter_items] = cs->name;
1181  filter_items++;
1182  }
1183 
1184  /* Terminate the filter list. */
1185  this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
1186 
1187  /* If not found, the cargo criteria will be set to all cargoes. */
1188  this->cargo_filter_criteria = 0;
1189 
1190  /* Find the last cargo filter criteria. */
1191  for (uint i = 0; i < filter_items; i++) {
1192  if (this->cargo_filter[i] == _engine_sort_last_cargo_criteria[this->vehicle_type]) {
1193  this->cargo_filter_criteria = i;
1194  break;
1195  }
1196  }
1197 
1198  this->eng_list.SetFilterFuncs(_filter_funcs);
1199  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1200  }
1201 
1202  void SelectEngine(EngineID engine)
1203  {
1204  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1205  if (cargo == CF_ANY) cargo = CF_NONE;
1206 
1207  this->sel_engine = engine;
1208  this->SetBuyVehicleText();
1209 
1210  if (this->sel_engine == INVALID_ENGINE) return;
1211 
1212  const Engine *e = Engine::Get(this->sel_engine);
1213  if (!e->CanCarryCargo()) {
1214  this->te.cost = 0;
1215  this->te.cargo = CT_INVALID;
1216  return;
1217  }
1218 
1219  if (!this->listview_mode) {
1220  /* Query for cost and refitted capacity */
1221  CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
1222  if (ret.Succeeded()) {
1223  this->te.cost = ret.GetCost() - e->GetCost();
1226  this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo;
1227  return;
1228  }
1229  }
1230 
1231  /* Purchase test was not possible or failed, fill in the defaults instead. */
1232  this->te.cost = 0;
1233  this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity);
1234  this->te.cargo = e->GetDefaultCargoType();
1235  }
1236 
1237  void OnInit() override
1238  {
1239  this->SetCargoFilterArray();
1240  }
1241 
1244  {
1245  this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
1246  if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1247  this->SelectEngine(INVALID_ENGINE);
1248  } 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
1249  this->SelectEngine(this->eng_list[0]);
1250  }
1251  }
1252 
1255  {
1256  CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria];
1257  return (filter_type == CF_ANY || CargoFilter(&eid, filter_type));
1258  }
1259 
1260  /* Figure out what train EngineIDs to put in the list */
1261  void GenerateBuildTrainList()
1262  {
1263  EngineID sel_id = INVALID_ENGINE;
1264  int num_engines = 0;
1265  int num_wagons = 0;
1266 
1267  this->eng_list.clear();
1268 
1269  /* Make list of all available train engines and wagons.
1270  * Also check to see if the previously selected engine is still available,
1271  * and if not, reset selection to INVALID_ENGINE. This could be the case
1272  * when engines become obsolete and are removed */
1273  for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1274  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1275  EngineID eid = e->index;
1276  const RailVehicleInfo *rvi = &e->u.rail;
1277 
1278  if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
1279  if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
1280 
1281  /* Filter now! So num_engines and num_wagons is valid */
1282  if (!FilterSingleEngine(eid)) continue;
1283 
1284  this->eng_list.push_back(eid);
1285 
1286  if (rvi->railveh_type != RAILVEH_WAGON) {
1287  num_engines++;
1288  } else {
1289  num_wagons++;
1290  }
1291 
1292  if (eid == this->sel_engine) sel_id = eid;
1293  }
1294 
1295  this->SelectEngine(sel_id);
1296 
1297  /* invalidate cached values for name sorter - engine names could change */
1298  _last_engine[0] = _last_engine[1] = INVALID_ENGINE;
1299 
1300  /* make engines first, and then wagons, sorted by selected sort_criteria */
1301  _engine_sort_direction = false;
1302  EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
1303 
1304  /* and then sort engines */
1306  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1307 
1308  /* and finally sort wagons */
1309  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons);
1310  }
1311 
1312  /* Figure out what road vehicle EngineIDs to put in the list */
1313  void GenerateBuildRoadVehList()
1314  {
1315  EngineID sel_id = INVALID_ENGINE;
1316 
1317  this->eng_list.clear();
1318 
1319  for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1320  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1321  EngineID eid = e->index;
1322  if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1323  if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
1324 
1325  this->eng_list.push_back(eid);
1326 
1327  if (eid == this->sel_engine) sel_id = eid;
1328  }
1329  this->SelectEngine(sel_id);
1330  }
1331 
1332  /* Figure out what ship EngineIDs to put in the list */
1333  void GenerateBuildShipList()
1334  {
1335  EngineID sel_id = INVALID_ENGINE;
1336  this->eng_list.clear();
1337 
1338  for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1339  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1340  EngineID eid = e->index;
1341  if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1342  this->eng_list.push_back(eid);
1343 
1344  if (eid == this->sel_engine) sel_id = eid;
1345  }
1346  this->SelectEngine(sel_id);
1347  }
1348 
1349  /* Figure out what aircraft EngineIDs to put in the list */
1350  void GenerateBuildAircraftList()
1351  {
1352  EngineID sel_id = INVALID_ENGINE;
1353 
1354  this->eng_list.clear();
1355 
1356  const Station *st = this->listview_mode ? nullptr : Station::GetByTile(this->window_number);
1357 
1358  /* Make list of all available planes.
1359  * Also check to see if the previously selected plane is still available,
1360  * and if not, reset selection to INVALID_ENGINE. This could be the case
1361  * when planes become obsolete and are removed */
1362  for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1363  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1364  EngineID eid = e->index;
1365  if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
1366  /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1367  if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1368 
1369  this->eng_list.push_back(eid);
1370  if (eid == this->sel_engine) sel_id = eid;
1371  }
1372 
1373  this->SelectEngine(sel_id);
1374  }
1375 
1376  /* Generate the list of vehicles */
1377  void GenerateBuildList()
1378  {
1379  if (!this->eng_list.NeedRebuild()) return;
1380 
1381  /* Update filter type in case the road/railtype of the depot got converted */
1382  this->UpdateFilterByTile();
1383 
1384  switch (this->vehicle_type) {
1385  default: NOT_REACHED();
1386  case VEH_TRAIN:
1387  this->GenerateBuildTrainList();
1388  this->eng_list.shrink_to_fit();
1389  this->eng_list.RebuildDone();
1390  return; // trains should not reach the last sorting
1391  case VEH_ROAD:
1392  this->GenerateBuildRoadVehList();
1393  break;
1394  case VEH_SHIP:
1395  this->GenerateBuildShipList();
1396  break;
1397  case VEH_AIRCRAFT:
1398  this->GenerateBuildAircraftList();
1399  break;
1400  }
1401 
1402  this->FilterEngineList();
1403 
1405  EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1406 
1407  this->eng_list.shrink_to_fit();
1408  this->eng_list.RebuildDone();
1409  }
1410 
1411  void OnClick(Point pt, int widget, int click_count) override
1412  {
1413  switch (widget) {
1415  this->descending_sort_order ^= true;
1417  this->eng_list.ForceRebuild();
1418  this->SetDirty();
1419  break;
1420 
1422  this->show_hidden_engines ^= true;
1424  this->eng_list.ForceRebuild();
1425  this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1426  this->SetDirty();
1427  break;
1428 
1429  case WID_BV_LIST: {
1430  uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
1431  size_t num_items = this->eng_list.size();
1432  this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE);
1433  this->SetDirty();
1434  if (_ctrl_pressed) {
1435  this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1436  } else if (click_count > 1 && !this->listview_mode) {
1437  this->OnClick(pt, WID_BV_BUILD, 1);
1438  }
1439  break;
1440  }
1441 
1442  case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1443  DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1444  break;
1445 
1446  case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1447  ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0);
1448  break;
1449 
1450  case WID_BV_SHOW_HIDE: {
1451  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1452  if (e != nullptr) {
1453  DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY);
1454  }
1455  break;
1456  }
1457 
1458  case WID_BV_BUILD: {
1459  EngineID sel_eng = this->sel_engine;
1460  if (sel_eng != INVALID_ENGINE) {
1461  CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
1462  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1463  if (cargo == CF_ANY) cargo = CF_NONE;
1464  DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback);
1465  }
1466  break;
1467  }
1468 
1469  case WID_BV_RENAME: {
1470  EngineID sel_eng = this->sel_engine;
1471  if (sel_eng != INVALID_ENGINE) {
1472  this->rename_engine = sel_eng;
1473  SetDParam(0, sel_eng);
1474  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);
1475  }
1476  break;
1477  }
1478  }
1479  }
1480 
1486  void OnInvalidateData(int data = 0, bool gui_scope = true) override
1487  {
1488  if (!gui_scope) return;
1489  /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1490  if (this->vehicle_type == VEH_ROAD &&
1492  this->sort_criteria > 7) {
1493  this->sort_criteria = 0;
1495  }
1496  this->eng_list.ForceRebuild();
1497  }
1498 
1499  void SetStringParameters(int widget) const override
1500  {
1501  switch (widget) {
1502  case WID_BV_CAPTION:
1503  if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1504  const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1505  SetDParam(0, rti->strings.build_caption);
1506  } else if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1507  const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1508  SetDParam(0, rti->strings.build_caption);
1509  } else {
1510  SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1511  }
1512  break;
1513 
1514  case WID_BV_SORT_DROPDOWN:
1515  SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]);
1516  break;
1517 
1519  SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
1520  break;
1521 
1522  case WID_BV_SHOW_HIDE: {
1523  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1524  if (e != nullptr && e->IsHidden(_local_company)) {
1525  SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1526  } else {
1527  SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1528  }
1529  break;
1530  }
1531  }
1532  }
1533 
1534  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1535  {
1536  switch (widget) {
1537  case WID_BV_LIST:
1538  resize->height = GetEngineListHeight(this->vehicle_type);
1539  size->height = 3 * resize->height;
1540  size->width = max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165);
1541  break;
1542 
1543  case WID_BV_PANEL:
1544  size->height = this->details_height;
1545  break;
1546 
1548  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
1549  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1550  d.height += padding.height;
1551  *size = maxdim(*size, d);
1552  break;
1553  }
1554 
1555  case WID_BV_BUILD:
1556  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
1557  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
1558  size->width += padding.width;
1559  size->height += padding.height;
1560  break;
1561 
1562  case WID_BV_SHOW_HIDE:
1563  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1564  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1565  size->width += padding.width;
1566  size->height += padding.height;
1567  break;
1568  }
1569  }
1570 
1571  void DrawWidget(const Rect &r, int widget) const override
1572  {
1573  switch (widget) {
1574  case WID_BV_LIST:
1575  DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->eng_list.size()), this->sel_engine, false, DEFAULT_GROUP);
1576  break;
1577 
1579  this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1580  break;
1581  }
1582  }
1583 
1584  void OnPaint() override
1585  {
1586  this->GenerateBuildList();
1587  this->vscroll->SetCount((uint)this->eng_list.size());
1588 
1590 
1591  this->DrawWidgets();
1592 
1593  if (!this->IsShaded()) {
1594  int needed_height = this->details_height;
1595  /* Draw details panels. */
1596  if (this->sel_engine != INVALID_ENGINE) {
1597  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_BV_PANEL);
1599  nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te);
1600  needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
1601  }
1602  if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1603  int resize = needed_height - this->details_height;
1604  this->details_height = needed_height;
1605  this->ReInit(0, resize);
1606  return;
1607  }
1608  }
1609  }
1610 
1611  void OnQueryTextFinished(char *str) override
1612  {
1613  if (str == nullptr) return;
1614 
1615  DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str);
1616  }
1617 
1618  void OnDropdownSelect(int widget, int index) override
1619  {
1620  switch (widget) {
1621  case WID_BV_SORT_DROPDOWN:
1622  if (this->sort_criteria != index) {
1623  this->sort_criteria = index;
1625  this->eng_list.ForceRebuild();
1626  }
1627  break;
1628 
1629  case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1630  if (this->cargo_filter_criteria != index) {
1631  this->cargo_filter_criteria = index;
1632  _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria];
1633  /* deactivate filter if criteria is 'Show All', activate it otherwise */
1634  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1635  this->eng_list.ForceRebuild();
1636  this->SelectEngine(this->sel_engine);
1637  }
1638  break;
1639  }
1640  this->SetDirty();
1641  }
1642 
1643  void OnResize() override
1644  {
1645  this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1646  }
1647 };
1648 
1649 static WindowDesc _build_vehicle_desc(
1650  WDP_AUTO, "build_vehicle", 240, 268,
1653  _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
1654 );
1655 
1656 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
1657 {
1658  /* We want to be able to open both Available Train as Available Ships,
1659  * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
1660  * As it always is a low value, it won't collide with any real tile
1661  * number. */
1662  uint num = (tile == INVALID_TILE) ? (int)type : tile;
1663 
1664  assert(IsCompanyBuildableVehicleType(type));
1665 
1667 
1668  new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
1669 }
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition: engine.cpp:1123
void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw an engine.
Definition: engine_gui.cpp:296
Functions related to OTTD&#39;s strings.
VehicleSettings vehicle
options for vehicles
static bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition: rail.h:332
uint16 reliability
Current reliability of the engine.
Definition: engine_base.h:25
void RebuildDone()
Notify the sortlist that the rebuild is done.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:80
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
Definition: engine_base.h:157
bool _networking
are we in networking mode?
Definition: network.cpp:52
Functions for NewGRF engines.
uint32 widget_data
Data of the widget.
Definition: widget_type.h:303
static const RailtypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:304
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
ResizeInfo resize
Resize information.
Definition: window_gui.h:322
uint8 weight
Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
Definition: cargotype.h:60
void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group)
Engine drawing loop.
static bool EnginePowerSorter(const EngineID &a, const EngineID &b)
Determines order of engines by power.
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:928
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1870
void SetWidgetDisabledState(byte widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:392
CargoID cargo_filter[NUM_CARGO+2]
Available cargo filters; CargoID or CF_ANY or CF_NONE.
void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:453
GUI for building vehicles.
High level window description.
Definition: window_gui.h:166
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint cargo_capacity)
Get the default cargoes and refits of an articulated vehicle.
StringID tool_tip
Tooltip of the widget.
Definition: widget_type.h:304
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition: engine.cpp:468
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
Train vehicle type.
Definition: vehicle_type.h:24
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups...
Definition: group_cmd.cpp:783
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:602
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:329
union BuildVehicleWindow::@0 filter
Filter to apply.
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition: engine.cpp:171
Functions related to dates.
static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b)
Determines order of train engines by capacity.
Scrollbar data structure.
Definition: widget_type.h:587
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:62
uint16 GetRange() const
Get the range of an aircraft type.
Definition: engine.cpp:454
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button)
Display the dropdown for the vehicle sort criteria.
Horizontal container.
Definition: widget_type.h:73
byte sort_criteria
Current sort criterium.
query cost only, don&#39;t build.
Definition: command_type.h:348
byte _engine_sort_last_criteria[]
Last set sort criteria, for each vehicle type.
void CDECL SetWidgetsDisabledState(bool disab_stat, int widgets,...)
Sets the enabled/disabled status of a list of widgets.
Definition: window.cpp:536
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1121
Ship vehicle type.
Definition: vehicle_type.h:26
Base class for groups and group functions.
Maximal number of cargo types in a game.
Definition: cargo_type.h:64
Date intro_date
Date of introduction of the engine.
Definition: engine_base.h:23
Rename button.
Flag for invalid railtype.
Definition: rail_type.h:34
uint ApplyWaterClassSpeedFrac(uint raw_speed, bool is_ocean) const
Apply ocean/canal speed fraction to a velocity.
Definition: engine_type.h:78
Specification of a cargo type.
Definition: cargotype.h:55
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
uint extend_right
Extend of the cell to the right.
Definition: vehicle_gui.h:80
Functions related to vehicles.
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:66
Build panel.
static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid)
Cargo filter functions.
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company...
Definition: engine_base.h:38
EngineID sel_engine
Currently selected engine, or INVALID_ENGINE.
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
Build vehicle; Window numbers:
Definition: window_type.h:376
VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type)
Get the GUI cell size for a vehicle image.
Definition: depot_gui.cpp:158
uint height
Vehicle cell height.
Definition: vehicle_gui.h:78
flag for invalid roadtype
Definition: road_type.h:27
static bool EngineIntroDateSorter(const EngineID &a, const EngineID &b)
Determines order of engines by introduction date.
Close box (at top-left of a window)
Definition: widget_type.h:67
Offset at top of a matrix cell.
Definition: window_gui.h:78
void SetCargoFilterArray()
Populate the filter list and set the cargo filter criteria.
uint GetEngineListHeight(VehicleType type)
Get the height of a single &#39;entry&#39; in the engine lists.
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition: road.h:103
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:48
void ReInit(int rx=0, int ry=0)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:995
StringID GetGRFStringID(uint32 grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Money GetCost() const
The costs as made up to this moment.
Definition: command_type.h:82
Stuff related to the text buffer GUI.
void SetFilterFuncs(FilterFunction *const *n_funcs)
Hand the array of filter function pointers to the sort list.
EngList_SortTypeFunction *const _engine_sort_functions[][11]
Sort functions for the vehicle sort criteria, for each vehicle type.
Common return value for all commands.
Definition: command_type.h:23
Vehicle drawn in purchase list, autoreplace gui, ...
Definition: vehicle_type.h:90
byte pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition: engine_type.h:56
void CcBuildPrimaryVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
This is the Callback method after the construction attempt of a primary vehicle.
RoadType
The different roadtypes we support.
Definition: road_type.h:22
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
struct RailtypeInfo::@39 strings
Strings associated with the rail type.
void CreateNestedTree(bool fill_nested=true)
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1831
Functions related to the vehicle&#39;s GUIs.
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition: engine_base.h:79
uint16 mail_capacity
Mail capacity if available.
Definition: vehicle_gui.h:43
StringID name
Name of this type of cargo.
Definition: cargotype.h:70
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-new).
Definition: cargo_type.h:67
bool NeedRebuild() const
Check if a rebuild is needed.
static bool AircraftRangeSorter(const EngineID &a, const EngineID &b)
Determines order of aircraft by range.
uint32 GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition: engine.cpp:160
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition: rail.h:176
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:124
bool _engine_sort_last_order[]
Last set direction of the sort order, for each vehicle type.
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:668
Force the alignment, i.e. don&#39;t swap for RTL languages.
Definition: gfx_func.h:106
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:908
void ForceRebuild()
Force that a rebuild is needed.
static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b)
Determines order of aircraft by cargo.
Data structure for an opened window.
Definition: window_gui.h:276
Invalid cargo type.
Definition: cargo_type.h:68
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1847
Scrollbar of list.
static NWidgetPart SetMatrixDataTip(uint8 cols, uint8 rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1030
hide or unhide a vehicle in the build vehicle and autoreplace GUIs
Definition: command_type.h:218
static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b)
Determines order of engines by running costs.
Header of Action 04 "universal holder" structure and functions.
bool show_hidden_engines
State of the &#39;show hidden engines&#39; button.
enable the &#39;Default&#39; button ("\0" is returned)
Definition: textbuf_gui.h:21
static const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition: road.h:224
Functions related to low-level strings.
This callback is called from vehicle purchase lists.
void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
Define a callback function for the client, after the command is finished.
Definition: command_type.h:472
Money GetCost() const
Return how much a new engine costs.
Definition: engine.cpp:319
RoadType roadtype
Road type to show, or INVALID_ROADTYPE.
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
Draw the purchase info details of a vehicle at a given location.
Offset at bottom of a matrix cell.
Definition: window_gui.h:79
static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b)
Determines order of road vehicles by capacity.
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:174
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:445
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:63
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1957
TestedEngineDetails te
Tested cost and capacity after refit.
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:208
Information about GRF, used in the game and (part of it) in savegames.
static bool TrainEnginesThenWagonsSorter(const EngineID &a, const EngineID &b)
Determines order of train engines by engine / wagon.
void SetLowered(bool lowered)
Lower or raise the widget.
Definition: widget_type.h:335
Functions related to engines.
Extra information about refitted cargo and capacity.
Definition: vehicle_gui.h:39
Sort descending.
Definition: window_gui.h:225
uint16 pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition: engine_type.h:55
static Owner GetTileOwner(TileIndex tile)
Returns the owner of a tile.
Definition: tile_map.h:178
RailType railtype
Rail type to show, or INVALID_RAILTYPE.
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:177
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1012
simple wagon, not motorized
Definition: engine_type.h:29
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:79
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:945
bool descending_sort_order
Sort direction,.
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:150
void UpdateFilterByTile()
Set the filter type according to the depot type.
Definition of base types and functions in a cross-platform compatible way.
PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition: vehicle.cpp:1972
Data structure to convert between Date and triplet (year, month, and day).
Definition: date_type.h:103
the length of the string is counted in characters
Definition: textbuf_gui.h:22
static CargoID _engine_sort_last_cargo_criteria[]
Last set filter criteria, for each vehicle type.
void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items)
Sort selected range of items (on indices @ <begin, begin+num_items-1>)
Definition: engine_gui.cpp:339
A number of safeguards to prevent using unsafe methods.
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:245
uint8 acceleration_type
Acceleration type of this rail type.
Definition: rail.h:223
bool listview_mode
If set, only display the available vehicles and do not show a &#39;build&#39; button.
bool EngList_SortTypeFunction(const EngineID &, const EngineID &)
argument type for EngList_Sort.
Definition: engine_gui.h:20
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:102
Geometry functions.
static bool EngineCostSorter(const EngineID &a, const EngineID &b)
Determines order of engines by purchase cost.
Simple depressed panel.
Definition: widget_type.h:48
Toggle whether to display the hidden vehicles.
uint16 GroupID
Type for all group identifiers.
Definition: group_type.h:13
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui
static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b)
Determines order of engines by tractive effort.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition: engine_base.h:40
void DrawSortButtonState(int widget, SortButtonState state) const
Draw a sort button&#39;s up or down arrow symbol.
Definition: widget.cpp:636
VehicleType vehicle_type
Type of vehicles shown in the window.
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:309
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:175
Button to hide or show the selected engine.
static bool EngineSpeedSorter(const EngineID &a, const EngineID &b)
Determines order of engines by speed.
void SetDParamMaxDigits(uint n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:120
const StringID _engine_sort_listing[][12]
Dropdown menu strings for the vehicle sort criteria.
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1112
Year year
Year (0...)
Definition: date_type.h:104
bool show_newgrf_name
Show the name of the NewGRF in the build vehicle window.
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:63
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition: vehicle.cpp:2779
Baseclass for nested widgets.
Definition: widget_type.h:124
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:636
Basic functions/variables used all over the place.
struct RoadTypeInfo::@42 strings
Strings associated with the rail type.
Right offset of the text of the frame.
Definition: window_gui.h:71
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:536
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
Grid of rows and columns.
Definition: widget_type.h:57
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:40
Display plane with zero size in both directions (none filling and resizing).
Definition: widget_type.h:388
#define FOR_ALL_SORTED_STANDARD_CARGOSPECS(var)
Loop header for iterating over &#39;real&#39; cargoes, sorted by name.
Definition: cargotype.h:171
Left offset of the text of the frame.
Definition: window_gui.h:70
void FilterEngineList()
Filter the engine list against the currently selected cargo filter.
void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values)
Start using the TTDP compatible string code parsing.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:656
StringID cargo_filter_texts[NUM_CARGO+3]
Texts for filter_cargo, terminated by INVALID_STRING_ID.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
int details_height
Minimal needed height of the details panels (found so far).
void CcBuildWagon(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
Callback for building wagons.
Definition: train_gui.cpp:30
static const int WIDGET_LIST_END
indicate the end of widgets&#39; list for vararg functions
Definition: widget_type.h:20
Information about a rail vehicle.
Definition: engine_type.h:42
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition: engine.cpp:359
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:984
static const CargoID CF_ANY
Special cargo filter criteria.
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:838
bool IsHidden(CompanyID c) const
Check whether the engine is hidden in the GUI for the given company.
Definition: engine_base.h:119
bool _engine_sort_direction
false = descending, true = ascending.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:38
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1165
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition: engine.cpp:391
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
Definition: engine_type.h:174
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
static int32 ClampToI32(const int64 a)
Reduce a signed 64-bit int to a signed 32-bit one.
Definition: math_func.hpp:201
Functions related to companies.
static bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype)
Checks if an engine of the given RoadType got power on a tile with a given RoadType.
Definition: road.h:239
uint GetTotalCapacityOfArticulatedParts(EngineID engine)
Get the capacity of an engine with articulated parts.
Definition: engine_gui.cpp:163
GRFConfig * GetGRFConfig(uint32 grfid, uint32 mask)
Retrieve a NewGRF from the current config by its grfid.
Functions related to articulated vehicles.
void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
Class for storing amounts of cargo.
Definition: cargo_type.h:81
Base class for engines.
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:27
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:27
GUISettings gui
settings related to the GUI
uint _returned_refit_capacity
Stores the capacity after a refit operation.
Definition: vehicle.cpp:85
void OnPaint() override
The window must be repainted.
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:59
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:578
EngineID rename_engine
Engine being renamed.
bool FilterSingleEngine(EngineID eid)
Filter a single engine.
uint16 EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
void SetFilterState(bool state)
Enable or disable the filter.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:117
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1587
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:48
bool CDECL FilterFunction(const EngineID *, CargoID)
Signature of filter function.
Definition: sortlist_type.h:50
Sort ascending.
Definition: window_gui.h:224
bool wagon_speed_limits
enable wagon speed limits
Vertical container.
Definition: widget_type.h:75
indicates a combination of two locomotives
Definition: engine_type.h:28
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:997
Do not add shading to this text colour.
Definition: gfx_type.h:269
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:172
static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
Draw aircraft specific details in the buy window.
byte cargo_filter_criteria
Selected cargo filter.
static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
Display additional text from NewGRF in the purchase information window.
static Station * GetByTile(TileIndex tile)
Get the station belonging to a specific tile.
uint16 _returned_mail_refit_capacity
Stores the mail capacity after a refit operation (Aircraft only).
Definition: vehicle.cpp:86
uint GetDisplayDefaultCapacity(uint16 *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
Definition: engine_base.h:99
static uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
Definition: math_func.hpp:298
void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
Sort all items using quick sort and given &#39;CompareItems&#39; function.
Definition: engine_gui.cpp:326
Functions related to commands.
Types/functions related to cargoes.
bool _network_server
network-server is active
Definition: network.cpp:53
Coordinates of a point in 2D.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:908
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:45
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:88
rename a engine (in the engine list)
Definition: command_type.h:244
uint8 train_acceleration_model
realistic acceleration for trains
Drop down list.
Definition: widget_type.h:68
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:620
Index of the small font in the font tables.
Definition: gfx_type.h:203
Button panel.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable...
Definition: window_gui.h:324
uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
const char * GetName() const
Get the name of this grf.
Aircraft vehicle type.
Definition: vehicle_type.h:27
uint8 roadveh_acceleration_model
realistic acceleration for road vehicles
static bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
Check if a company has a replacement set up for the given engine.
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:61
uint capacity
Cargo capacity.
Definition: vehicle_gui.h:42
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition: engine.cpp:282
void OnInit() override
Notification that the nested widget tree gets initialized.
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:64
static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b)
Determines order of engines by reliability.
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:981
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b)
Determines order of ships by capacity.
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
#define CMD_MSG(x)
Used to combine a StringID with the command.
Definition: command_type.h:370
static bool EnginePowerVsRunningCostSorter(const EngineID &a, const EngineID &b)
Determines order of engines by running costs.
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
Definition: cargotype.cpp:34
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget. ...
Definition: widget.cpp:1971
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:82
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
bool IsShaded() const
Is window shaded currently?
Definition: window_gui.h:524
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Text is written right-to-left by default.
Definition: strings_type.h:24
Right align the text (must be a single bit).
Definition: gfx_func.h:96
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:312
uint extend_left
Extend of the cell to the left.
Definition: vehicle_gui.h:79
static bool EngineNameSorter(const EngineID &a, const EngineID &b)
Determines order of engines by name.
static const uint MAX_LENGTH_ENGINE_NAME_CHARS
The maximum length of an engine name in characters including &#39;\0&#39;.
Definition: engine_type.h:172
bool _engine_sort_show_hidden_engines[]
Last set &#39;show hidden engines&#39; setting for each vehicle type.
static bool EngineNumberSorter(const EngineID &a, const EngineID &b)
Determines order of engines by engineID.
Window functions not directly related to making/drawing windows.
List of vehicles.
uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
Display list of cargo types of the engine, for the purchase information window.
Caption of window.
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
Find a place automatically.
Definition: window_gui.h:154
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:78
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition: engine.cpp:409
Criteria of sorting dropdown.
Money cost
Refit cost.
Definition: vehicle_gui.h:40
Base classes/functions for stations.
Types related to the build_vehicle widgets.
Functions related to autoreplacing.
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
Converts a Date to a Year, Month & Day.
Definition: date.cpp:95
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition: engine.cpp:427
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1093
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
static bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
Definition: vehicle_func.h:89
Dimensions (a width and height) of a rectangle in 2D.
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:60
Station data structure.
Definition: station_base.h:450
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:62
CargoID cargo
Cargo type.
Definition: vehicle_gui.h:41
Road vehicle type.
Definition: vehicle_type.h:25
Date GetLifeLengthInDays() const
Returns the vehicle&#39;s (not model&#39;s!) life length in days.
Definition: engine.cpp:444
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:973
static RailType GetRailType(TileIndex t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
int pos_y
Vertical position of top-left corner of the widget in the window.
Definition: widget_type.h:176
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
void OnResize() override
Called after the window got resized.
static const int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
Definition: date_type.h:30
void StopTextRefStackUsage()
Stop using the TTDP compatible string code parsing.
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:759
(Toggle) Button with text
Definition: widget_type.h:53
bool IsArticulatedVehicleRefittable(EngineID engine)
Checks whether any of the articulated parts is refittable.
Dynamic data of a loaded NewGRF.
Definition: newgrf.h:105
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:629
static const CargoID CF_NONE
Show only vehicles which do not carry cargo (e.g. train engines)
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
Base class for a &#39;real&#39; widget.
Definition: widget_type.h:282