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