OpenTTD
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  return y;
932 }
933 
947 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)
948 {
949  static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
950 
951  /* Obligatory sanity checks! */
952  assert(max <= eng_list->size());
953 
954  bool rtl = _current_text_dir == TD_RTL;
955  int step_size = GetEngineListHeight(type);
956  int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
957  int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
958  int sprite_width = sprite_left + sprite_right;
959 
960  int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1;
961  int sprite_y_offset = sprite_y_offsets[type] + step_size / 2;
962 
963  Dimension replace_icon = {0, 0};
964  int count_width = 0;
965  if (show_count) {
966  replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
968  count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width;
969  }
970 
971  int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT);
972  int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width);
973  int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width;
974  int count_left = l;
975  int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8;
976 
977  int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2;
978  int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1;
979  int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1;
980 
981  for (; min < max; min++, y += step_size) {
982  const EngineID engine = (*eng_list)[min];
983  /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
984  const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
985 
986  const Engine *e = Engine::Get(engine);
987  bool hidden = HasBit(e->company_hidden, _local_company);
988  StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
989  TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK));
990 
991  SetDParam(0, engine);
992  DrawString(text_left, text_right, y + normal_text_y_offset, str, tc);
993  DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE);
994  if (show_count) {
995  SetDParam(0, num_engines);
996  DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
997  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);
998  }
999  }
1000 }
1001 
1009 void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button)
1010 {
1011  uint32 hidden_mask = 0;
1012  /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */
1013  if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
1014  SetBit(hidden_mask, 3); // power
1015  SetBit(hidden_mask, 4); // tractive effort
1016  SetBit(hidden_mask, 8); // power by running costs
1017  }
1018  /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */
1019  if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
1020  SetBit(hidden_mask, 4); // tractive effort
1021  }
1022  ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
1023 }
1024 
1028  union {
1031  } filter;
1038  GUIEngineList eng_list;
1043  Scrollbar *vscroll;
1045 
1046  void SetBuyVehicleText()
1047  {
1048  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
1049 
1050  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;
1051  if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria];
1052 
1053  if (refit) {
1054  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type;
1055  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type;
1056  } else {
1057  widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type;
1058  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type;
1059  }
1060  }
1061 
1062  BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
1063  {
1064  this->vehicle_type = type;
1065  this->listview_mode = tile == INVALID_TILE;
1066  this->window_number = this->listview_mode ? (int)type : tile;
1067 
1068  this->sel_engine = INVALID_ENGINE;
1069 
1070  this->sort_criteria = _engine_sort_last_criteria[type];
1071  this->descending_sort_order = _engine_sort_last_order[type];
1072  this->show_hidden_engines = _engine_sort_show_hidden_engines[type];
1073 
1074  this->UpdateFilterByTile();
1075 
1076  this->CreateNestedTree();
1077 
1078  this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR);
1079 
1080  /* If we are just viewing the list of vehicles, we do not need the Build button.
1081  * So we just hide it, and enlarge the Rename button by the now vacant place. */
1082  if (this->listview_mode) this->GetWidget<NWidgetStacked>(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
1083 
1084  /* disable renaming engines in network games if you are not the server */
1086 
1087  NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_LIST);
1088  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
1089 
1090  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDE);
1091  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type;
1092 
1093  widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
1094  widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
1095  widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
1096 
1097  widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDDEN_ENGINES);
1098  widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type;
1099  widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type;
1100  widget->SetLowered(this->show_hidden_engines);
1101 
1102  this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
1103 
1104  this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile);
1105 
1106  this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
1107 
1108  this->eng_list.ForceRebuild();
1109  this->GenerateBuildList(); // generate the list, since we need it in the next line
1110  /* Select the first engine in the list as default when opening the window */
1111  if (this->eng_list.size() > 0) {
1112  this->SelectEngine(this->eng_list[0]);
1113  } else {
1114  this->SelectEngine(INVALID_ENGINE);
1115  }
1116  }
1117 
1120  {
1121  switch (this->vehicle_type) {
1122  default: NOT_REACHED();
1123  case VEH_TRAIN:
1124  if (this->listview_mode) {
1125  this->filter.railtype = INVALID_RAILTYPE;
1126  } else {
1127  this->filter.railtype = GetRailType(this->window_number);
1128  }
1129  break;
1130 
1131  case VEH_ROAD:
1132  if (this->listview_mode) {
1133  this->filter.roadtype = INVALID_ROADTYPE;
1134  } else {
1135  this->filter.roadtype = GetRoadTypeRoad(this->window_number);
1136  if (this->filter.roadtype == INVALID_ROADTYPE) {
1137  this->filter.roadtype = GetRoadTypeTram(this->window_number);
1138  }
1139  }
1140  break;
1141 
1142  case VEH_SHIP:
1143  case VEH_AIRCRAFT:
1144  break;
1145  }
1146  }
1147 
1150  {
1151  uint filter_items = 0;
1152 
1153  /* Add item for disabling filtering. */
1154  this->cargo_filter[filter_items] = CF_ANY;
1155  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES;
1156  filter_items++;
1157 
1158  /* Add item for vehicles not carrying anything, e.g. train engines.
1159  * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
1160  if (this->vehicle_type == VEH_TRAIN) {
1161  this->cargo_filter[filter_items] = CF_NONE;
1162  this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_NONE;
1163  filter_items++;
1164  }
1165 
1166  /* Collect available cargo types for filtering. */
1167  const CargoSpec *cs;
1169  this->cargo_filter[filter_items] = cs->Index();
1170  this->cargo_filter_texts[filter_items] = cs->name;
1171  filter_items++;
1172  }
1173 
1174  /* Terminate the filter list. */
1175  this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
1176 
1177  /* If not found, the cargo criteria will be set to all cargoes. */
1178  this->cargo_filter_criteria = 0;
1179 
1180  /* Find the last cargo filter criteria. */
1181  for (uint i = 0; i < filter_items; i++) {
1182  if (this->cargo_filter[i] == _engine_sort_last_cargo_criteria[this->vehicle_type]) {
1183  this->cargo_filter_criteria = i;
1184  break;
1185  }
1186  }
1187 
1188  this->eng_list.SetFilterFuncs(_filter_funcs);
1189  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1190  }
1191 
1192  void SelectEngine(EngineID engine)
1193  {
1194  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1195  if (cargo == CF_ANY) cargo = CF_NONE;
1196 
1197  this->sel_engine = engine;
1198  this->SetBuyVehicleText();
1199 
1200  if (this->sel_engine == INVALID_ENGINE) return;
1201 
1202  const Engine *e = Engine::Get(this->sel_engine);
1203  if (!e->CanCarryCargo()) {
1204  this->te.cost = 0;
1205  this->te.cargo = CT_INVALID;
1206  return;
1207  }
1208 
1209  if (!this->listview_mode) {
1210  /* Query for cost and refitted capacity */
1211  CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
1212  if (ret.Succeeded()) {
1213  this->te.cost = ret.GetCost() - e->GetCost();
1216  this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo;
1217  return;
1218  }
1219  }
1220 
1221  /* Purchase test was not possible or failed, fill in the defaults instead. */
1222  this->te.cost = 0;
1223  this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity);
1224  this->te.cargo = e->GetDefaultCargoType();
1225  }
1226 
1227  void OnInit() override
1228  {
1229  this->SetCargoFilterArray();
1230  }
1231 
1234  {
1235  this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
1236  if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
1237  this->SelectEngine(INVALID_ENGINE);
1238  } 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
1239  this->SelectEngine(this->eng_list[0]);
1240  }
1241  }
1242 
1245  {
1246  CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria];
1247  return (filter_type == CF_ANY || CargoFilter(&eid, filter_type));
1248  }
1249 
1250  /* Figure out what train EngineIDs to put in the list */
1251  void GenerateBuildTrainList()
1252  {
1253  EngineID sel_id = INVALID_ENGINE;
1254  int num_engines = 0;
1255  int num_wagons = 0;
1256 
1257  this->eng_list.clear();
1258 
1259  /* Make list of all available train engines and wagons.
1260  * Also check to see if the previously selected engine is still available,
1261  * and if not, reset selection to INVALID_ENGINE. This could be the case
1262  * when engines become obsolete and are removed */
1263  for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1264  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1265  EngineID eid = e->index;
1266  const RailVehicleInfo *rvi = &e->u.rail;
1267 
1268  if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
1269  if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
1270 
1271  /* Filter now! So num_engines and num_wagons is valid */
1272  if (!FilterSingleEngine(eid)) continue;
1273 
1274  this->eng_list.push_back(eid);
1275 
1276  if (rvi->railveh_type != RAILVEH_WAGON) {
1277  num_engines++;
1278  } else {
1279  num_wagons++;
1280  }
1281 
1282  if (eid == this->sel_engine) sel_id = eid;
1283  }
1284 
1285  this->SelectEngine(sel_id);
1286 
1287  /* make engines first, and then wagons, sorted by selected sort_criteria */
1288  _engine_sort_direction = false;
1289  EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
1290 
1291  /* and then sort engines */
1293  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines);
1294 
1295  /* and finally sort wagons */
1296  EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons);
1297  }
1298 
1299  /* Figure out what road vehicle EngineIDs to put in the list */
1300  void GenerateBuildRoadVehList()
1301  {
1302  EngineID sel_id = INVALID_ENGINE;
1303 
1304  this->eng_list.clear();
1305 
1306  for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1307  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1308  EngineID eid = e->index;
1309  if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
1310  if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
1311 
1312  this->eng_list.push_back(eid);
1313 
1314  if (eid == this->sel_engine) sel_id = eid;
1315  }
1316  this->SelectEngine(sel_id);
1317  }
1318 
1319  /* Figure out what ship EngineIDs to put in the list */
1320  void GenerateBuildShipList()
1321  {
1322  EngineID sel_id = INVALID_ENGINE;
1323  this->eng_list.clear();
1324 
1325  for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
1326  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1327  EngineID eid = e->index;
1328  if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
1329  this->eng_list.push_back(eid);
1330 
1331  if (eid == this->sel_engine) sel_id = eid;
1332  }
1333  this->SelectEngine(sel_id);
1334  }
1335 
1336  /* Figure out what aircraft EngineIDs to put in the list */
1337  void GenerateBuildAircraftList()
1338  {
1339  EngineID sel_id = INVALID_ENGINE;
1340 
1341  this->eng_list.clear();
1342 
1343  const Station *st = this->listview_mode ? nullptr : Station::GetByTile(this->window_number);
1344 
1345  /* Make list of all available planes.
1346  * Also check to see if the previously selected plane is still available,
1347  * and if not, reset selection to INVALID_ENGINE. This could be the case
1348  * when planes become obsolete and are removed */
1349  for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) {
1350  if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
1351  EngineID eid = e->index;
1352  if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
1353  /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
1354  if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
1355 
1356  this->eng_list.push_back(eid);
1357  if (eid == this->sel_engine) sel_id = eid;
1358  }
1359 
1360  this->SelectEngine(sel_id);
1361  }
1362 
1363  /* Generate the list of vehicles */
1364  void GenerateBuildList()
1365  {
1366  if (!this->eng_list.NeedRebuild()) return;
1367 
1368  /* Update filter type in case the road/railtype of the depot got converted */
1369  this->UpdateFilterByTile();
1370 
1371  switch (this->vehicle_type) {
1372  default: NOT_REACHED();
1373  case VEH_TRAIN:
1374  this->GenerateBuildTrainList();
1375  this->eng_list.shrink_to_fit();
1376  this->eng_list.RebuildDone();
1377  return; // trains should not reach the last sorting
1378  case VEH_ROAD:
1379  this->GenerateBuildRoadVehList();
1380  break;
1381  case VEH_SHIP:
1382  this->GenerateBuildShipList();
1383  break;
1384  case VEH_AIRCRAFT:
1385  this->GenerateBuildAircraftList();
1386  break;
1387  }
1388 
1389  this->FilterEngineList();
1390 
1392  EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
1393 
1394  this->eng_list.shrink_to_fit();
1395  this->eng_list.RebuildDone();
1396  }
1397 
1398  void OnClick(Point pt, int widget, int click_count) override
1399  {
1400  switch (widget) {
1402  this->descending_sort_order ^= true;
1404  this->eng_list.ForceRebuild();
1405  this->SetDirty();
1406  break;
1407 
1409  this->show_hidden_engines ^= true;
1411  this->eng_list.ForceRebuild();
1412  this->SetWidgetLoweredState(widget, this->show_hidden_engines);
1413  this->SetDirty();
1414  break;
1415 
1416  case WID_BV_LIST: {
1417  uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
1418  size_t num_items = this->eng_list.size();
1419  this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE);
1420  this->SetDirty();
1421  if (_ctrl_pressed) {
1422  this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
1423  } else if (click_count > 1 && !this->listview_mode) {
1424  this->OnClick(pt, WID_BV_BUILD, 1);
1425  }
1426  break;
1427  }
1428 
1429  case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu
1430  DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN);
1431  break;
1432 
1433  case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu
1434  ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0);
1435  break;
1436 
1437  case WID_BV_SHOW_HIDE: {
1438  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1439  if (e != nullptr) {
1440  DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY);
1441  }
1442  break;
1443  }
1444 
1445  case WID_BV_BUILD: {
1446  EngineID sel_eng = this->sel_engine;
1447  if (sel_eng != INVALID_ENGINE) {
1448  CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
1449  CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
1450  if (cargo == CF_ANY) cargo = CF_NONE;
1451  DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback);
1452  }
1453  break;
1454  }
1455 
1456  case WID_BV_RENAME: {
1457  EngineID sel_eng = this->sel_engine;
1458  if (sel_eng != INVALID_ENGINE) {
1459  this->rename_engine = sel_eng;
1460  SetDParam(0, sel_eng);
1461  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);
1462  }
1463  break;
1464  }
1465  }
1466  }
1467 
1473  void OnInvalidateData(int data = 0, bool gui_scope = true) override
1474  {
1475  if (!gui_scope) return;
1476  /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
1477  if (this->vehicle_type == VEH_ROAD &&
1479  this->sort_criteria > 7) {
1480  this->sort_criteria = 0;
1482  }
1483  this->eng_list.ForceRebuild();
1484  }
1485 
1486  void SetStringParameters(int widget) const override
1487  {
1488  switch (widget) {
1489  case WID_BV_CAPTION:
1490  if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
1491  const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
1492  SetDParam(0, rti->strings.build_caption);
1493  } else if (this->vehicle_type == VEH_ROAD && !this->listview_mode) {
1494  const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype);
1495  SetDParam(0, rti->strings.build_caption);
1496  } else {
1497  SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
1498  }
1499  break;
1500 
1501  case WID_BV_SORT_DROPDOWN:
1502  SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]);
1503  break;
1504 
1506  SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
1507  break;
1508 
1509  case WID_BV_SHOW_HIDE: {
1510  const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine);
1511  if (e != nullptr && e->IsHidden(_local_company)) {
1512  SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type);
1513  } else {
1514  SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1515  }
1516  break;
1517  }
1518  }
1519  }
1520 
1521  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
1522  {
1523  switch (widget) {
1524  case WID_BV_LIST:
1525  resize->height = GetEngineListHeight(this->vehicle_type);
1526  size->height = 3 * resize->height;
1527  size->width = max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165);
1528  break;
1529 
1530  case WID_BV_PANEL:
1531  size->height = this->details_height;
1532  break;
1533 
1535  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
1536  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
1537  d.height += padding.height;
1538  *size = maxdim(*size, d);
1539  break;
1540  }
1541 
1542  case WID_BV_BUILD:
1543  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
1544  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
1545  size->width += padding.width;
1546  size->height += padding.height;
1547  break;
1548 
1549  case WID_BV_SHOW_HIDE:
1550  *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
1551  *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
1552  size->width += padding.width;
1553  size->height += padding.height;
1554  break;
1555  }
1556  }
1557 
1558  void DrawWidget(const Rect &r, int widget) const override
1559  {
1560  switch (widget) {
1561  case WID_BV_LIST:
1562  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);
1563  break;
1564 
1566  this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
1567  break;
1568  }
1569  }
1570 
1571  void OnPaint() override
1572  {
1573  this->GenerateBuildList();
1574  this->vscroll->SetCount((uint)this->eng_list.size());
1575 
1577 
1578  this->DrawWidgets();
1579 
1580  if (!this->IsShaded()) {
1581  int needed_height = this->details_height;
1582  /* Draw details panels. */
1583  if (this->sel_engine != INVALID_ENGINE) {
1584  NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_BV_PANEL);
1586  nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te);
1587  needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
1588  }
1589  if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
1590  int resize = needed_height - this->details_height;
1591  this->details_height = needed_height;
1592  this->ReInit(0, resize);
1593  return;
1594  }
1595  }
1596  }
1597 
1598  void OnQueryTextFinished(char *str) override
1599  {
1600  if (str == nullptr) return;
1601 
1602  DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str);
1603  }
1604 
1605  void OnDropdownSelect(int widget, int index) override
1606  {
1607  switch (widget) {
1608  case WID_BV_SORT_DROPDOWN:
1609  if (this->sort_criteria != index) {
1610  this->sort_criteria = index;
1612  this->eng_list.ForceRebuild();
1613  }
1614  break;
1615 
1616  case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria
1617  if (this->cargo_filter_criteria != index) {
1618  this->cargo_filter_criteria = index;
1619  _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria];
1620  /* deactivate filter if criteria is 'Show All', activate it otherwise */
1621  this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
1622  this->eng_list.ForceRebuild();
1623  this->SelectEngine(this->sel_engine);
1624  }
1625  break;
1626  }
1627  this->SetDirty();
1628  }
1629 
1630  void OnResize() override
1631  {
1632  this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
1633  }
1634 };
1635 
1636 static WindowDesc _build_vehicle_desc(
1637  WDP_AUTO, "build_vehicle", 240, 268,
1640  _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
1641 );
1642 
1643 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
1644 {
1645  /* We want to be able to open both Available Train as Available Ships,
1646  * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number.
1647  * As it always is a low value, it won't collide with any real tile
1648  * number. */
1649  uint num = (tile == INVALID_TILE) ? (int)type : tile;
1650 
1651  assert(IsCompanyBuildableVehicleType(type));
1652 
1654 
1655  new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
1656 }
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition: engine.cpp:1062
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:79
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:1867
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:291
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:346
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:1828
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.
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:1844
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:470
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:173
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:441
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
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:176
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
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:101
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:102
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:498
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:532
#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:700
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:1162
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
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
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:770
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:243
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.
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:368
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:92
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:835
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:621
(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
static Pool::IterateWrapper< Engine > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
Definition: engine_base.h:151