OpenTTD Source  1.10.0-RC1
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 
134 static bool EngineNameSorter(const EngineID &a, const EngineID &b)
135 {
136  static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
137  static char last_name[2][64] = { "\0", "\0" };
138 
139  if (a != last_engine[0]) {
140  last_engine[0] = a;
141  SetDParam(0, a);
142  GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0]));
143  }
144 
145  if (b != last_engine[1]) {
146  last_engine[1] = b;
147  SetDParam(0, b);
148  GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1]));
149  }
150 
151  int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting).
152 
153  /* Use EngineID to sort instead since we want consistent sorting */
154  if (r == 0) return EngineNumberSorter(a, b);
155  return _engine_sort_direction ? r > 0 : r < 0;
156 }
157 
164 static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b)
165 {
166  const int va = Engine::Get(a)->reliability;
167  const int vb = Engine::Get(b)->reliability;
168  const int r = va - vb;
169 
170  /* Use EngineID to sort instead since we want consistent sorting */
171  if (r == 0) return EngineNumberSorter(a, b);
172  return _engine_sort_direction ? r > 0 : r < 0;
173 }
174 
181 static bool EngineCostSorter(const EngineID &a, const EngineID &b)
182 {
183  Money va = Engine::Get(a)->GetCost();
184  Money vb = Engine::Get(b)->GetCost();
185  int r = ClampToI32(va - vb);
186 
187  /* Use EngineID to sort instead since we want consistent sorting */
188  if (r == 0) return EngineNumberSorter(a, b);
189  return _engine_sort_direction ? r > 0 : r < 0;
190 }
191 
198 static bool EngineSpeedSorter(const EngineID &a, const EngineID &b)
199 {
200  int va = Engine::Get(a)->GetDisplayMaxSpeed();
201  int vb = Engine::Get(b)->GetDisplayMaxSpeed();
202  int r = va - vb;
203 
204  /* Use EngineID to sort instead since we want consistent sorting */
205  if (r == 0) return EngineNumberSorter(a, b);
206  return _engine_sort_direction ? r > 0 : r < 0;
207 }
208 
215 static bool EnginePowerSorter(const EngineID &a, const EngineID &b)
216 {
217  int va = Engine::Get(a)->GetPower();
218  int vb = Engine::Get(b)->GetPower();
219  int r = va - vb;
220 
221  /* Use EngineID to sort instead since we want consistent sorting */
222  if (r == 0) return EngineNumberSorter(a, b);
223  return _engine_sort_direction ? r > 0 : r < 0;
224 }
225 
232 static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b)
233 {
234  int va = Engine::Get(a)->GetDisplayMaxTractiveEffort();
235  int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort();
236  int r = va - vb;
237 
238  /* Use EngineID to sort instead since we want consistent sorting */
239  if (r == 0) return EngineNumberSorter(a, b);
240  return _engine_sort_direction ? r > 0 : r < 0;
241 }
242 
249 static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b)
250 {
251  Money va = Engine::Get(a)->GetRunningCost();
252  Money vb = Engine::Get(b)->GetRunningCost();
253  int r = ClampToI32(va - vb);
254 
255  /* Use EngineID to sort instead since we want consistent sorting */
256  if (r == 0) return EngineNumberSorter(a, b);
257  return _engine_sort_direction ? r > 0 : r < 0;
258 }
259 
266 static bool EnginePowerVsRunningCostSorter(const EngineID &a, const EngineID &b)
267 {
268  const Engine *e_a = Engine::Get(a);
269  const Engine *e_b = Engine::Get(b);
270  uint p_a = e_a->GetPower();
271  uint p_b = e_b->GetPower();
272  Money r_a = e_a->GetRunningCost();
273  Money r_b = e_b->GetRunningCost();
274  /* Check if running cost is zero in one or both engines.
275  * If only one of them is zero then that one has higher value,
276  * else if both have zero cost then compare powers. */
277  if (r_a == 0) {
278  if (r_b == 0) {
279  /* If it is ambiguous which to return go with their ID */
280  if (p_a == p_b) return EngineNumberSorter(a, b);
281  return _engine_sort_direction != (p_a < p_b);
282  }
283  return !_engine_sort_direction;
284  }
285  if (r_b == 0) return _engine_sort_direction;
286  /* Using double for more precision when comparing close values.
287  * This shouldn't have any major effects in performance nor in keeping
288  * the game in sync between players since it's used in GUI only in client side */
289  double v_a = (double)p_a / (double)r_a;
290  double v_b = (double)p_b / (double)r_b;
291  /* Use EngineID to sort if both have same power/running cost,
292  * since we want consistent sorting.
293  * Also if both have no power then sort with reverse of running cost to simulate
294  * previous sorting behaviour for wagons. */
295  if (v_a == 0 && v_b == 0) return !EngineRunningCostSorter(a, b);
296  if (v_a == v_b) return EngineNumberSorter(a, b);
297  return _engine_sort_direction != (v_a < v_b);
298 }
299 
300 /* Train sorting functions */
301 
308 static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b)
309 {
310  const RailVehicleInfo *rvi_a = RailVehInfo(a);
311  const RailVehicleInfo *rvi_b = RailVehInfo(b);
312 
313  int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
314  int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
315  int r = va - vb;
316 
317  /* Use EngineID to sort instead since we want consistent sorting */
318  if (r == 0) return EngineNumberSorter(a, b);
319  return _engine_sort_direction ? r > 0 : r < 0;
320 }
321 
328 static bool TrainEnginesThenWagonsSorter(const EngineID &a, const EngineID &b)
329 {
330  int val_a = (RailVehInfo(a)->railveh_type == RAILVEH_WAGON ? 1 : 0);
331  int val_b = (RailVehInfo(b)->railveh_type == RAILVEH_WAGON ? 1 : 0);
332  int r = val_a - val_b;
333 
334  /* Use EngineID to sort instead since we want consistent sorting */
335  if (r == 0) return EngineNumberSorter(a, b);
336  return _engine_sort_direction ? r > 0 : r < 0;
337 }
338 
339 /* Road vehicle sorting functions */
340 
347 static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b)
348 {
351  int r = va - vb;
352 
353  /* Use EngineID to sort instead since we want consistent sorting */
354  if (r == 0) return EngineNumberSorter(a, b);
355  return _engine_sort_direction ? r > 0 : r < 0;
356 }
357 
358 /* Ship vehicle sorting functions */
359 
366 static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b)
367 {
368  const Engine *e_a = Engine::Get(a);
369  const Engine *e_b = Engine::Get(b);
370 
371  int va = e_a->GetDisplayDefaultCapacity();
372  int vb = e_b->GetDisplayDefaultCapacity();
373  int r = va - vb;
374 
375  /* Use EngineID to sort instead since we want consistent sorting */
376  if (r == 0) return EngineNumberSorter(a, b);
377  return _engine_sort_direction ? r > 0 : r < 0;
378 }
379 
380 /* Aircraft sorting functions */
381 
388 static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b)
389 {
390  const Engine *e_a = Engine::Get(a);
391  const Engine *e_b = Engine::Get(b);
392 
393  uint16 mail_a, mail_b;
394  int va = e_a->GetDisplayDefaultCapacity(&mail_a);
395  int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
396  int r = va - vb;
397 
398  if (r == 0) {
399  /* The planes have the same passenger capacity. Check mail capacity instead */
400  r = mail_a - mail_b;
401 
402  if (r == 0) {
403  /* Use EngineID to sort instead since we want consistent sorting */
404  return EngineNumberSorter(a, b);
405  }
406  }
407  return _engine_sort_direction ? r > 0 : r < 0;
408 }
409 
416 static bool AircraftRangeSorter(const EngineID &a, const EngineID &b)
417 {
418  uint16 r_a = Engine::Get(a)->GetRange();
419  uint16 r_b = Engine::Get(b)->GetRange();
420 
421  int r = r_a - r_b;
422 
423  /* Use EngineID to sort instead since we want consistent sorting */
424  if (r == 0) return EngineNumberSorter(a, b);
425  return _engine_sort_direction ? r > 0 : r < 0;
426 }
427 
430  /* Trains */
442 }, {
443  /* Road vehicles */
455 }, {
456  /* Ships */
465 }, {
466  /* Aircraft */
476 }};
477 
480  /* Trains */
481  STR_SORT_BY_ENGINE_ID,
482  STR_SORT_BY_COST,
483  STR_SORT_BY_MAX_SPEED,
484  STR_SORT_BY_POWER,
485  STR_SORT_BY_TRACTIVE_EFFORT,
486  STR_SORT_BY_INTRO_DATE,
487  STR_SORT_BY_NAME,
488  STR_SORT_BY_RUNNING_COST,
489  STR_SORT_BY_POWER_VS_RUNNING_COST,
490  STR_SORT_BY_RELIABILITY,
491  STR_SORT_BY_CARGO_CAPACITY,
493 }, {
494  /* Road vehicles */
495  STR_SORT_BY_ENGINE_ID,
496  STR_SORT_BY_COST,
497  STR_SORT_BY_MAX_SPEED,
498  STR_SORT_BY_POWER,
499  STR_SORT_BY_TRACTIVE_EFFORT,
500  STR_SORT_BY_INTRO_DATE,
501  STR_SORT_BY_NAME,
502  STR_SORT_BY_RUNNING_COST,
503  STR_SORT_BY_POWER_VS_RUNNING_COST,
504  STR_SORT_BY_RELIABILITY,
505  STR_SORT_BY_CARGO_CAPACITY,
506  INVALID_STRING_ID
507 }, {
508  /* Ships */
509  STR_SORT_BY_ENGINE_ID,
510  STR_SORT_BY_COST,
511  STR_SORT_BY_MAX_SPEED,
512  STR_SORT_BY_INTRO_DATE,
513  STR_SORT_BY_NAME,
514  STR_SORT_BY_RUNNING_COST,
515  STR_SORT_BY_RELIABILITY,
516  STR_SORT_BY_CARGO_CAPACITY,
517  INVALID_STRING_ID
518 }, {
519  /* Aircraft */
520  STR_SORT_BY_ENGINE_ID,
521  STR_SORT_BY_COST,
522  STR_SORT_BY_MAX_SPEED,
523  STR_SORT_BY_INTRO_DATE,
524  STR_SORT_BY_NAME,
525  STR_SORT_BY_RUNNING_COST,
526  STR_SORT_BY_RELIABILITY,
527  STR_SORT_BY_CARGO_CAPACITY,
528  STR_SORT_BY_RANGE,
529  INVALID_STRING_ID
530 }};
531 
533 static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid)
534 {
535  if (cid == CF_ANY) return true;
536  CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask;
537  return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid));
538 }
539 
540 static GUIEngineList::FilterFunction * const _filter_funcs[] = {
541  &CargoFilter,
542 };
543 
544 static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, TestedEngineDetails &te)
545 {
546  CargoArray cap;
547  CargoTypes refits;
548  GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits, te.cargo, te.capacity);
549 
550  for (CargoID c = 0; c < NUM_CARGO; c++) {
551  if (cap[c] == 0) continue;
552 
553  SetDParam(0, c);
554  SetDParam(1, cap[c]);
555  SetDParam(2, HasBit(refits, c) ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
556  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
557  y += FONT_HEIGHT_NORMAL;
558  }
559 
560  return y;
561 }
562 
563 /* Draw rail wagon specific details */
564 static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
565 {
566  const Engine *e = Engine::Get(engine_number);
567 
568  /* Purchase cost */
569  if (te.cost != 0) {
570  SetDParam(0, e->GetCost() + te.cost);
571  SetDParam(1, te.cost);
572  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
573  } else {
574  SetDParam(0, e->GetCost());
575  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
576  }
577  y += FONT_HEIGHT_NORMAL;
578 
579  /* Wagon weight - (including cargo) */
580  uint weight = e->GetDisplayWeight();
581  SetDParam(0, weight);
582  uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
583  SetDParam(1, cargo_weight + weight);
584  DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
585  y += FONT_HEIGHT_NORMAL;
586 
587  /* Wagon speed limit, displayed if above zero */
589  uint max_speed = e->GetDisplayMaxSpeed();
590  if (max_speed > 0) {
591  SetDParam(0, max_speed);
592  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
593  y += FONT_HEIGHT_NORMAL;
594  }
595  }
596 
597  /* Running cost */
598  if (rvi->running_cost_class != INVALID_PRICE) {
599  SetDParam(0, e->GetRunningCost());
600  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
601  y += FONT_HEIGHT_NORMAL;
602  }
603 
604  return y;
605 }
606 
607 /* Draw locomotive specific details */
608 static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
609 {
610  const Engine *e = Engine::Get(engine_number);
611 
612  /* Purchase Cost - Engine weight */
613  if (te.cost != 0) {
614  SetDParam(0, e->GetCost() + te.cost);
615  SetDParam(1, te.cost);
616  SetDParam(2, e->GetDisplayWeight());
617  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_WEIGHT);
618  } else {
619  SetDParam(0, e->GetCost());
620  SetDParam(1, e->GetDisplayWeight());
621  DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
622  }
623  y += FONT_HEIGHT_NORMAL;
624 
625  /* Max speed - Engine power */
626  SetDParam(0, e->GetDisplayMaxSpeed());
627  SetDParam(1, e->GetPower());
628  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
629  y += FONT_HEIGHT_NORMAL;
630 
631  /* Max tractive effort - not applicable if old acceleration or maglev */
632  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
634  DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
635  y += FONT_HEIGHT_NORMAL;
636  }
637 
638  /* Running cost */
639  if (rvi->running_cost_class != INVALID_PRICE) {
640  SetDParam(0, e->GetRunningCost());
641  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
642  y += FONT_HEIGHT_NORMAL;
643  }
644 
645  /* Powered wagons power - Powered wagons extra weight */
646  if (rvi->pow_wag_power != 0) {
647  SetDParam(0, rvi->pow_wag_power);
648  SetDParam(1, rvi->pow_wag_weight);
649  DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT);
650  y += FONT_HEIGHT_NORMAL;
651  }
652 
653  return y;
654 }
655 
656 /* Draw road vehicle specific details */
657 static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
658 {
659  const Engine *e = Engine::Get(engine_number);
660 
662  /* Purchase Cost */
663  if (te.cost != 0) {
664  SetDParam(0, e->GetCost() + te.cost);
665  SetDParam(1, te.cost);
666  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
667  } else {
668  SetDParam(0, e->GetCost());
669  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
670  }
671  y += FONT_HEIGHT_NORMAL;
672 
673  /* Road vehicle weight - (including cargo) */
674  int16 weight = e->GetDisplayWeight();
675  SetDParam(0, weight);
676  uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
677  SetDParam(1, cargo_weight + weight);
678  DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
679  y += FONT_HEIGHT_NORMAL;
680 
681  /* Max speed - Engine power */
682  SetDParam(0, e->GetDisplayMaxSpeed());
683  SetDParam(1, e->GetPower());
684  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
685  y += FONT_HEIGHT_NORMAL;
686 
687  /* Max tractive effort */
689  DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
690  y += FONT_HEIGHT_NORMAL;
691  } else {
692  /* Purchase cost - Max speed */
693  if (te.cost != 0) {
694  SetDParam(0, e->GetCost() + te.cost);
695  SetDParam(1, te.cost);
696  SetDParam(2, e->GetDisplayMaxSpeed());
697  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
698  } else {
699  SetDParam(0, e->GetCost());
700  SetDParam(1, e->GetDisplayMaxSpeed());
701  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
702  }
703  y += FONT_HEIGHT_NORMAL;
704  }
705 
706  /* Running cost */
707  SetDParam(0, e->GetRunningCost());
708  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
709  y += FONT_HEIGHT_NORMAL;
710 
711  return y;
712 }
713 
714 /* Draw ship specific details */
715 static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
716 {
717  const Engine *e = Engine::Get(engine_number);
718 
719  /* Purchase cost - Max speed */
720  uint raw_speed = e->GetDisplayMaxSpeed();
721  uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
722  uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
723 
724  if (ocean_speed == canal_speed) {
725  if (te.cost != 0) {
726  SetDParam(0, e->GetCost() + te.cost);
727  SetDParam(1, te.cost);
728  SetDParam(2, ocean_speed);
729  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
730  } else {
731  SetDParam(0, e->GetCost());
732  SetDParam(1, ocean_speed);
733  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
734  }
735  y += FONT_HEIGHT_NORMAL;
736  } else {
737  if (te.cost != 0) {
738  SetDParam(0, e->GetCost() + te.cost);
739  SetDParam(1, te.cost);
740  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
741  } else {
742  SetDParam(0, e->GetCost());
743  DrawString(left, right, y, STR_PURCHASE_INFO_COST);
744  }
745  y += FONT_HEIGHT_NORMAL;
746 
747  SetDParam(0, ocean_speed);
748  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN);
749  y += FONT_HEIGHT_NORMAL;
750 
751  SetDParam(0, canal_speed);
752  DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL);
753  y += FONT_HEIGHT_NORMAL;
754  }
755 
756  /* Cargo type + capacity */
757  SetDParam(0, te.cargo);
758  SetDParam(1, te.capacity);
759  SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
760  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
761  y += FONT_HEIGHT_NORMAL;
762 
763  /* Running cost */
764  SetDParam(0, e->GetRunningCost());
765  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
766  y += FONT_HEIGHT_NORMAL;
767 
768  return y;
769 }
770 
780 static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
781 {
782  const Engine *e = Engine::Get(engine_number);
783 
784  /* Purchase cost - Max speed */
785  if (te.cost != 0) {
786  SetDParam(0, e->GetCost() + te.cost);
787  SetDParam(1, te.cost);
788  SetDParam(2, e->GetDisplayMaxSpeed());
789  DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
790  } else {
791  SetDParam(0, e->GetCost());
792  SetDParam(1, e->GetDisplayMaxSpeed());
793  DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
794  }
795  y += FONT_HEIGHT_NORMAL;
796 
797  /* Cargo capacity */
798  if (te.mail_capacity > 0) {
799  SetDParam(0, te.cargo);
800  SetDParam(1, te.capacity);
801  SetDParam(2, CT_MAIL);
802  SetDParam(3, te.mail_capacity);
803  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
804  } else {
805  /* Note, if the default capacity is selected by the refit capacity
806  * callback, then the capacity shown is likely to be incorrect. */
807  SetDParam(0, te.cargo);
808  SetDParam(1, te.capacity);
809  SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
810  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
811  }
812  y += FONT_HEIGHT_NORMAL;
813 
814  /* Running cost */
815  SetDParam(0, e->GetRunningCost());
816  DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
817  y += FONT_HEIGHT_NORMAL;
818 
819  /* Aircraft type */
821  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_TYPE);
822  y += FONT_HEIGHT_NORMAL;
823 
824  /* Aircraft range, if available. */
825  uint16 range = e->GetRange();
826  if (range != 0) {
827  SetDParam(0, range);
828  DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE);
829  y += FONT_HEIGHT_NORMAL;
830  }
831 
832  return y;
833 }
834 
843 static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
844 {
845  uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
846  if (callback == CALLBACK_FAILED || callback == 0x400) return y;
847  const GRFFile *grffile = Engine::Get(engine)->GetGRF();
848  if (callback > 0x400) {
849  ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
850  return y;
851  }
852 
853  StartTextRefStackUsage(grffile, 6);
854  uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK);
856  return result;
857 }
858 
865 int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
866 {
867  const Engine *e = Engine::Get(engine_number);
868  YearMonthDay ymd;
869  ConvertDateToYMD(e->intro_date, &ymd);
870  bool refittable = IsArticulatedVehicleRefittable(engine_number);
871  bool articulated_cargo = false;
872 
873  switch (e->type) {
874  default: NOT_REACHED();
875  case VEH_TRAIN:
876  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
877  y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
878  } else {
879  y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
880  }
881  articulated_cargo = true;
882  break;
883 
884  case VEH_ROAD:
885  y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
886  articulated_cargo = true;
887  break;
888 
889  case VEH_SHIP:
890  y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
891  break;
892 
893  case VEH_AIRCRAFT:
894  y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
895  break;
896  }
897 
898  if (articulated_cargo) {
899  /* Cargo type + capacity, or N/A */
900  int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, te);
901 
902  if (new_y == y) {
903  SetDParam(0, CT_INVALID);
904  SetDParam(2, STR_EMPTY);
905  DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
906  y += FONT_HEIGHT_NORMAL;
907  } else {
908  y = new_y;
909  }
910  }
911 
912  /* Draw details that apply to all types except rail wagons. */
913  if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
914  /* Design date - Life length */
915  SetDParam(0, ymd.year);
917  DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
918  y += FONT_HEIGHT_NORMAL;
919 
920  /* Reliability */
922  DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
923  y += FONT_HEIGHT_NORMAL;
924  }
925 
926  if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
927 
928  /* Additional text from NewGRF */
929  y = ShowAdditionalText(left, right, y, engine_number);
930 
931  /* The NewGRF's name which the vehicle comes from */
932  const GRFConfig *config = GetGRFConfig(e->GetGRFID());
933  if (_settings_client.gui.show_newgrf_name && config != nullptr)
934  {
935  DrawString(left, right, y, config->GetName(), TC_BLACK);
936  y += FONT_HEIGHT_NORMAL;
937  }
938 
939  return y;
940 }
941 
955 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)
956 {
957  static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
958 
959  /* Obligatory sanity checks! */
960  assert(max <= eng_list->size());
961 
962  bool rtl = _current_text_dir == TD_RTL;
963  int step_size = GetEngineListHeight(type);
964  int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
965  int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
966  int sprite_width = sprite_left + sprite_right;
967 
968  int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1;
969  int sprite_y_offset = sprite_y_offsets[type] + step_size / 2;
970 
971  Dimension replace_icon = {0, 0};
972  int count_width = 0;
973  if (show_count) {
974  replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
976  count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width;
977  }
978 
979  int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT);
980  int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width);
981  int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width;
982  int count_left = l;
983  int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8;
984 
985  int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2;
986  int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1;
987  int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1;
988 
989  for (; min < max; min++, y += step_size) {
990  const EngineID engine = (*eng_list)[min];
991  /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
992  const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
993 
994  const Engine *e = Engine::Get(engine);
995  bool hidden = HasBit(e->company_hidden, _local_company);
996  StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
997  TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK));
998 
999  SetDParam(0, engine);
1000  DrawString(text_left, text_right, y + normal_text_y_offset, str, tc);
1001  DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE);
1002  if (show_count) {
1003  SetDParam(0, num_engines);
1004  DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
1005  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);
1006  }
1007  }
1008 }
1009 
1017 void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button)
1018 {
1019  uint32 hidden_mask = 0;
1020  /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1021  if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1022  SetBit(hidden_mask, 3); // power
1023  SetBit(hidden_mask, 4); // tractive effort
1024  SetBit(hidden_mask, 8); // power by running costs
1025  }
1026  /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1027  if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1028  SetBit(hidden_mask, 4); // tractive effort
1029  }
1030  ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1031 }
1032 
1036  union {
1039  } filter;
1046  GUIEngineList eng_list;
1051  Scrollbar *vscroll;
1053 
1054  void SetBuyVehicleText()
1055  {
1056  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
1057 
1058  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;
1059  if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria];
1060 
1061  if (refit) {
1062  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type;
1063  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type;
1064  } else {
1065  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type;
1066  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type;
1067  }
1068  }
1069 
1070  BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
1071  {
1072  this->vehicle_type = type;
1073  this->listview_mode = tile == INVALID_TILE;
1074  this->window_number = this->listview_mode ? (int)type : tile;
1075 
1076  this->sel_engine = INVALID_ENGINE;
1077 
1078  this->sort_criteria = _engine_sort_last_criteria[type];
1079  this->descending_sort_order = _engine_sort_last_order[type];
1080  this->show_hidden_engines = _engine_sort_show_hidden_engines[type];
1081 
1082  this->UpdateFilterByTile();
1083 
1084  this->CreateNestedTree();
1085 
1086  this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1087 
1088  /* If we are just viewing the list of vehicles, we do not need the Build button.
1089  * So we just hide it, and enlarge the Rename button by the now vacant place. */
1090  if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1091 
1092  /* disable renaming engines in network games if you are not the server */
1094 
1095  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
1096  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
1097 
1098  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDE);
1099  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type;
1100 
1101  widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1102  widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
1103  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
1104 
1105  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDDEN_ENGINES);
1106  widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type;
1107  widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type;
1108  widget->SetLowered(this->show_hidden_engines);
1109 
1110  this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
1111 
1112  this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile);
1113 
1114  this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1115 
1116  this->eng_list.ForceRebuild();
1117  this->GenerateBuildList(); // generate the list, since we need it in the next line
1118  /* Select the first engine in the list as default when opening the window */
1119  if (this->eng_list.size() > 0) {
1120  this->SelectEngine(this->eng_list[0]);
1121  } else {
1122  this->SelectEngine(INVALID_ENGINE);
1123  }
1124  }
1125 
1128  {
1129  switch (this->vehicle_type) {
1130  default: NOT_REACHED();
1131  case VEH_TRAIN:
1132  if (this->listview_mode) {
1133  this->filter.railtype = INVALID_RAILTYPE;
1134  } else {
1135  this->filter.railtype = GetRailType(this->window_number);
1136  }
1137  break;
1138 
1139  case VEH_ROAD:
1140  if (this->listview_mode) {
1141  this->filter.roadtype = INVALID_ROADTYPE;
1142  } else {
1143  this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1144  if (this->filter.roadtype == INVALID_ROADTYPE) {
1145  this->filter.roadtype = GetRoadTypeTram(this->window_number);
1146  }
1147  }
1148  break;
1149 
1150  case VEH_SHIP:
1151  case VEH_AIRCRAFT:
1152  break;
1153  }
1154  }
1155 
1158  {
1159  uint filter_items = 0;
1160 
1161  /* Add item for disabling filtering. */
1162  this->cargo_filter[filter_items] = CF_ANY;
1163  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES;
1164  filter_items++;
1165 
1166  /* Add item for vehicles not carrying anything, e.g. train engines.
1167  * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1168  if (this->vehicle_type == VEH_TRAIN) {
1169  this->cargo_filter[filter_items] = CF_NONE;
1170  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_NONE;
1171  filter_items++;
1172  }
1173 
1174  /* Collect available cargo types for filtering. */
1175  const CargoSpec *cs;
1177  this->cargo_filter[filter_items] = cs->Index();
1178  this->cargo_filter_texts[filter_items] = cs->name;
1179  filter_items++;
1180  }
1181 
1182  /* Terminate the filter list. */
1183  this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
1184 
1185  /* If not found, the cargo criteria will be set to all cargoes. */
1186  this->cargo_filter_criteria = 0;
1187 
1188  /* Find the last cargo filter criteria. */
1189  for (uint i = 0; i < filter_items; i++) {
1190  if (this->cargo_filter[i] == _engine_sort_last_cargo_criteria[this->vehicle_type]) {
1191  this->cargo_filter_criteria = i;
1192  break;
1193  }
1194  }
1195 
1196  this->eng_list.SetFilterFuncs(_filter_funcs);
1197  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1198  }
1199 
1200  void SelectEngine(EngineID engine)
1201  {
1202  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1203  if (cargo == CF_ANY) cargo = CF_NONE;
1204 
1205  this->sel_engine = engine;
1206  this->SetBuyVehicleText();
1207 
1208  if (this->sel_engine == INVALID_ENGINE) return;
1209 
1210  const Engine *e = Engine::Get(this->sel_engine);
1211  if (!e->CanCarryCargo()) {
1212  this->te.cost = 0;
1213  this->te.cargo = CT_INVALID;
1214  return;
1215  }
1216 
1217  if (!this->listview_mode) {
1218  /* Query for cost and refitted capacity */
1219  CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
1220  if (ret.Succeeded()) {
1221  this->te.cost = ret.GetCost() - e->GetCost();
1224  this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo;
1225  return;
1226  }
1227  }
1228 
1229  /* Purchase test was not possible or failed, fill in the defaults instead. */
1230  this->te.cost = 0;
1231  this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity);
1232  this->te.cargo = e->GetDefaultCargoType();
1233  }
1234 
1235  void OnInit() override
1236  {
1237  this->SetCargoFilterArray();
1238  }
1239 
1242  {
1243  this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
1244  if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1245  this->SelectEngine(INVALID_ENGINE);
1246  } 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
1247  this->SelectEngine(this->eng_list[0]);
1248  }
1249  }
1250 
1253  {
1254  CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria];
1255  return (filter_type == CF_ANY || CargoFilter(&eid, filter_type));
1256  }
1257 
1258  /* Figure out what train EngineIDs to put in the list */
1259  void GenerateBuildTrainList()
1260  {
1261  EngineID sel_id = INVALID_ENGINE;
1262  int num_engines = 0;
1263  int num_wagons = 0;
1264 
1265  this->eng_list.clear();
1266 
1267  /* Make list of all available train engines and wagons.
1268  * Also check to see if the previously selected engine is still available,
1269  * and if not, reset selection to INVALID_ENGINE. This could be the case
1270  * when engines become obsolete and are removed */
1271  for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1272  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1273  EngineID eid = e->index;
1274  const RailVehicleInfo *rvi = &e->u.rail;
1275 
1276  if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
1277  if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
1278 
1279  /* Filter now! So num_engines and num_wagons is valid */
1280  if (!FilterSingleEngine(eid)) continue;
1281 
1282  this->eng_list.push_back(eid);
1283 
1284  if (rvi->railveh_type != RAILVEH_WAGON) {
1285  num_engines++;
1286  } else {
1287  num_wagons++;
1288  }
1289 
1290  if (eid == this->sel_engine) sel_id = eid;
1291  }
1292 
1293  this->SelectEngine(sel_id);
1294 
1295  /* make engines first, and then wagons, sorted by selected sort_criteria */
1296  _engine_sort_direction = false;
1297  EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
1298 
1299  /* and then sort engines */
1301  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1302 
1303  /* and finally sort wagons */
1304  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons);
1305  }
1306 
1307  /* Figure out what road vehicle EngineIDs to put in the list */
1308  void GenerateBuildRoadVehList()
1309  {
1310  EngineID sel_id = INVALID_ENGINE;
1311 
1312  this->eng_list.clear();
1313 
1314  for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1315  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1316  EngineID eid = e->index;
1317  if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1318  if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
1319 
1320  this->eng_list.push_back(eid);
1321 
1322  if (eid == this->sel_engine) sel_id = eid;
1323  }
1324  this->SelectEngine(sel_id);
1325  }
1326 
1327  /* Figure out what ship EngineIDs to put in the list */
1328  void GenerateBuildShipList()
1329  {
1330  EngineID sel_id = INVALID_ENGINE;
1331  this->eng_list.clear();
1332 
1333  for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1334  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1335  EngineID eid = e->index;
1336  if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1337  this->eng_list.push_back(eid);
1338 
1339  if (eid == this->sel_engine) sel_id = eid;
1340  }
1341  this->SelectEngine(sel_id);
1342  }
1343 
1344  /* Figure out what aircraft EngineIDs to put in the list */
1345  void GenerateBuildAircraftList()
1346  {
1347  EngineID sel_id = INVALID_ENGINE;
1348 
1349  this->eng_list.clear();
1350 
1351  const Station *st = this->listview_mode ? nullptr : Station::GetByTile(this->window_number);
1352 
1353  /* Make list of all available planes.
1354  * Also check to see if the previously selected plane is still available,
1355  * and if not, reset selection to INVALID_ENGINE. This could be the case
1356  * when planes become obsolete and are removed */
1357  for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1358  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1359  EngineID eid = e->index;
1360  if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
1361  /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1362  if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1363 
1364  this->eng_list.push_back(eid);
1365  if (eid == this->sel_engine) sel_id = eid;
1366  }
1367 
1368  this->SelectEngine(sel_id);
1369  }
1370 
1371  /* Generate the list of vehicles */
1372  void GenerateBuildList()
1373  {
1374  if (!this->eng_list.NeedRebuild()) return;
1375 
1376  /* Update filter type in case the road/railtype of the depot got converted */
1377  this->UpdateFilterByTile();
1378 
1379  switch (this->vehicle_type) {
1380  default: NOT_REACHED();
1381  case VEH_TRAIN:
1382  this->GenerateBuildTrainList();
1383  this->eng_list.shrink_to_fit();
1384  this->eng_list.RebuildDone();
1385  return; // trains should not reach the last sorting
1386  case VEH_ROAD:
1387  this->GenerateBuildRoadVehList();
1388  break;
1389  case VEH_SHIP:
1390  this->GenerateBuildShipList();
1391  break;
1392  case VEH_AIRCRAFT:
1393  this->GenerateBuildAircraftList();
1394  break;
1395  }
1396 
1397  this->FilterEngineList();
1398 
1400  EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1401 
1402  this->eng_list.shrink_to_fit();
1403  this->eng_list.RebuildDone();
1404  }
1405 
1406  void OnClick(Point pt, int widget, int click_count) override
1407  {
1408  switch (widget) {
1410  this->descending_sort_order ^= true;
1412  this->eng_list.ForceRebuild();
1413  this->SetDirty();
1414  break;
1415 
1417  this->show_hidden_engines ^= true;
1419  this->eng_list.ForceRebuild();
1420  this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1421  this->SetDirty();
1422  break;
1423 
1424  case WID_BV_LIST: {
1425  uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
1426  size_t num_items = this->eng_list.size();
1427  this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE);
1428  this->SetDirty();
1429  if (_ctrl_pressed) {
1430  this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1431  } else if (click_count > 1 && !this->listview_mode) {
1432  this->OnClick(pt, WID_BV_BUILD, 1);
1433  }
1434  break;
1435  }
1436 
1437  case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1438  DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1439  break;
1440 
1441  case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1442  ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0);
1443  break;
1444 
1445  case WID_BV_SHOW_HIDE: {
1446  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1447  if (e != nullptr) {
1448  DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY);
1449  }
1450  break;
1451  }
1452 
1453  case WID_BV_BUILD: {
1454  EngineID sel_eng = this->sel_engine;
1455  if (sel_eng != INVALID_ENGINE) {
1456  CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
1457  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1458  if (cargo == CF_ANY) cargo = CF_NONE;
1459  DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback);
1460  }
1461  break;
1462  }
1463 
1464  case WID_BV_RENAME: {
1465  EngineID sel_eng = this->sel_engine;
1466  if (sel_eng != INVALID_ENGINE) {
1467  this->rename_engine = sel_eng;
1468  SetDParam(0, sel_eng);
1469  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);
1470  }
1471  break;
1472  }
1473  }
1474  }
1475 
1481  void OnInvalidateData(int data = 0, bool gui_scope = true) override
1482  {
1483  if (!gui_scope) return;
1484  /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1485  if (this->vehicle_type == VEH_ROAD &&
1487  this->sort_criteria > 7) {
1488  this->sort_criteria = 0;
1490  }
1491  this->eng_list.ForceRebuild();
1492  }
1493 
1494  void SetStringParameters(int widget) const override
1495  {
1496  switch (widget) {
1497  case WID_BV_CAPTION:
1498  if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1499  const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1500  SetDParam(0, rti->strings.build_caption);
1501  } else if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1502  const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1503  SetDParam(0, rti->strings.build_caption);
1504  } else {
1505  SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1506  }
1507  break;
1508 
1509  case WID_BV_SORT_DROPDOWN:
1510  SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]);
1511  break;
1512 
1514  SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
1515  break;
1516 
1517  case WID_BV_SHOW_HIDE: {
1518  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1519  if (e != nullptr && e->IsHidden(_local_company)) {
1520  SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1521  } else {
1522  SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1523  }
1524  break;
1525  }
1526  }
1527  }
1528 
1529  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1530  {
1531  switch (widget) {
1532  case WID_BV_LIST:
1533  resize->height = GetEngineListHeight(this->vehicle_type);
1534  size->height = 3 * resize->height;
1535  size->width = max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165);
1536  break;
1537 
1538  case WID_BV_PANEL:
1539  size->height = this->details_height;
1540  break;
1541 
1543  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
1544  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1545  d.height += padding.height;
1546  *size = maxdim(*size, d);
1547  break;
1548  }
1549 
1550  case WID_BV_BUILD:
1551  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
1552  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
1553  size->width += padding.width;
1554  size->height += padding.height;
1555  break;
1556 
1557  case WID_BV_SHOW_HIDE:
1558  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1559  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1560  size->width += padding.width;
1561  size->height += padding.height;
1562  break;
1563  }
1564  }
1565 
1566  void DrawWidget(const Rect &r, int widget) const override
1567  {
1568  switch (widget) {
1569  case WID_BV_LIST:
1570  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);
1571  break;
1572 
1574  this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1575  break;
1576  }
1577  }
1578 
1579  void OnPaint() override
1580  {
1581  this->GenerateBuildList();
1582  this->vscroll->SetCount((uint)this->eng_list.size());
1583 
1585 
1586  this->DrawWidgets();
1587 
1588  if (!this->IsShaded()) {
1589  int needed_height = this->details_height;
1590  /* Draw details panels. */
1591  if (this->sel_engine != INVALID_ENGINE) {
1592  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_BV_PANEL);
1594  nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te);
1595  needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
1596  }
1597  if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1598  int resize = needed_height - this->details_height;
1599  this->details_height = needed_height;
1600  this->ReInit(0, resize);
1601  return;
1602  }
1603  }
1604  }
1605 
1606  void OnQueryTextFinished(char *str) override
1607  {
1608  if (str == nullptr) return;
1609 
1610  DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str);
1611  }
1612 
1613  void OnDropdownSelect(int widget, int index) override
1614  {
1615  switch (widget) {
1616  case WID_BV_SORT_DROPDOWN:
1617  if (this->sort_criteria != index) {
1618  this->sort_criteria = index;
1620  this->eng_list.ForceRebuild();
1621  }
1622  break;
1623 
1624  case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1625  if (this->cargo_filter_criteria != index) {
1626  this->cargo_filter_criteria = index;
1627  _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria];
1628  /* deactivate filter if criteria is 'Show All', activate it otherwise */
1629  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1630  this->eng_list.ForceRebuild();
1631  this->SelectEngine(this->sel_engine);
1632  }
1633  break;
1634  }
1635  this->SetDirty();
1636  }
1637 
1638  void OnResize() override
1639  {
1640  this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1641  }
1642 };
1643 
1644 static WindowDesc _build_vehicle_desc(
1645  WDP_AUTO, "build_vehicle", 240, 268,
1648  _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
1649 );
1650 
1651 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
1652 {
1653  /* We want to be able to open both Available Train as Available Ships,
1654  * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
1655  * As it always is a low value, it won't collide with any real tile
1656  * number. */
1657  uint num = (tile == INVALID_TILE) ? (int)type : tile;
1658 
1659  assert(IsCompanyBuildableVehicleType(type));
1660 
1662 
1663  new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
1664 }
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
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 capacity
Cargo capacity.
Definition: vehicle_gui.h:42
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:1119
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
uint16 _returned_refit_capacity
Stores the capacity after a refit operation.
Definition: vehicle.cpp:85
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
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint16 cargo_capacity)
Get the default cargoes and refits of an articulated vehicle.
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
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
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