OpenTTD
vehicle.cpp
Go to the documentation of this file.
1 /* $Id: vehicle.cpp 27986 2018-03-11 13:23:26Z frosch $ */
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 "error.h"
14 #include "roadveh.h"
15 #include "ship.h"
16 #include "spritecache.h"
17 #include "timetable.h"
18 #include "viewport_func.h"
19 #include "news_func.h"
20 #include "command_func.h"
21 #include "company_func.h"
22 #include "train.h"
23 #include "aircraft.h"
24 #include "newgrf_debug.h"
25 #include "newgrf_sound.h"
26 #include "newgrf_station.h"
27 #include "group_gui.h"
28 #include "strings_func.h"
29 #include "zoom_func.h"
30 #include "date_func.h"
31 #include "vehicle_func.h"
32 #include "autoreplace_func.h"
33 #include "autoreplace_gui.h"
34 #include "station_base.h"
35 #include "ai/ai.hpp"
36 #include "depot_func.h"
37 #include "network/network.h"
38 #include "core/pool_func.hpp"
39 #include "economy_base.h"
40 #include "articulated_vehicles.h"
41 #include "roadstop_base.h"
42 #include "core/random_func.hpp"
43 #include "core/backup_type.hpp"
44 #include "order_backup.h"
45 #include "sound_func.h"
46 #include "effectvehicle_func.h"
47 #include "effectvehicle_base.h"
48 #include "vehiclelist.h"
49 #include "bridge_map.h"
50 #include "tunnel_map.h"
51 #include "depot_map.h"
52 #include "gamelog.h"
53 #include "linkgraph/linkgraph.h"
54 #include "linkgraph/refresh.h"
55 
56 #include "table/strings.h"
57 
58 #include "safeguards.h"
59 
60 /* Number of bits in the hash to use from each vehicle coord */
61 static const uint GEN_HASHX_BITS = 6;
62 static const uint GEN_HASHY_BITS = 6;
63 
64 /* Size of each hash bucket */
65 static const uint GEN_HASHX_BUCKET_BITS = 7;
66 static const uint GEN_HASHY_BUCKET_BITS = 6;
67 
68 /* Compute hash for vehicle coord */
69 #define GEN_HASHX(x) GB((x), GEN_HASHX_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHX_BITS)
70 #define GEN_HASHY(y) (GB((y), GEN_HASHY_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS)
71 #define GEN_HASH(x, y) (GEN_HASHY(y) + GEN_HASHX(x))
72 
73 /* Maximum size until hash repeats */
74 static const int GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_LVL_SHIFT);
75 static const int GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_LVL_SHIFT);
76 
77 /* Increments to reach next bucket in hash table */
78 static const int GEN_HASHX_INC = 1;
79 static const int GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
80 
81 /* Mask to wrap-around buckets */
82 static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
83 static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
84 
85 VehicleID _new_vehicle_id;
88 
89 
91 VehiclePool _vehicle_pool("Vehicle");
93 
94 
95 
99 void VehicleSpriteSeq::GetBounds(Rect *bounds) const
100 {
101  bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
102  for (uint i = 0; i < this->count; ++i) {
103  const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL);
104  if (i == 0) {
105  bounds->left = spr->x_offs;
106  bounds->top = spr->y_offs;
107  bounds->right = spr->width + spr->x_offs - 1;
108  bounds->bottom = spr->height + spr->y_offs - 1;
109  } else {
110  if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
111  if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
112  int right = spr->width + spr->x_offs - 1;
113  int bottom = spr->height + spr->y_offs - 1;
114  if (right > bounds->right) bounds->right = right;
115  if (bottom > bounds->bottom) bounds->bottom = bottom;
116  }
117  }
118 }
119 
127 void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
128 {
129  for (uint i = 0; i < this->count; ++i) {
130  PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
131  DrawSprite(this->seq[i].sprite, pal, x, y);
132  }
133 }
134 
141 bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
142 {
143  /* We can always generate the Company pointer when we have the vehicle.
144  * However this takes time and since the Company pointer is often present
145  * when this function is called then it's faster to pass the pointer as an
146  * argument rather than finding it again. */
147  assert(c == Company::Get(this->owner));
148 
149  if (use_renew_setting && !c->settings.engine_renew) return false;
150  if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
151 
152  /* Only engines need renewing */
153  if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
154 
155  return true;
156 }
157 
164 {
165  assert(v != NULL);
166  SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
167 
168  do {
171  v->reliability = v->GetEngine()->reliability;
172  /* Prevent vehicles from breaking down directly after exiting the depot. */
173  v->breakdown_chance /= 4;
174  v = v->Next();
175  } while (v != NULL && v->HasEngineType());
176 }
177 
185 {
186  /* Stopped or crashed vehicles will not move, as such making unmovable
187  * vehicles to go for service is lame. */
188  if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
189 
190  /* Are we ready for the next service cycle? */
191  const Company *c = Company::Get(this->owner);
192  if (this->ServiceIntervalIsPercent() ?
193  (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
194  (this->date_of_last_service + this->GetServiceInterval() >= _date)) {
195  return false;
196  }
197 
198  /* If we're servicing anyway, because we have not disabled servicing when
199  * there are no breakdowns or we are playing with breakdowns, bail out. */
202  return true;
203  }
204 
205  /* Test whether there is some pending autoreplace.
206  * Note: We do this after the service-interval test.
207  * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
208  bool pending_replace = false;
209  Money needed_money = c->settings.engine_renew_money;
210  if (needed_money > c->money) return false;
211 
212  for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
213  bool replace_when_old = false;
214  EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
215 
216  /* Check engine availability */
217  if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
218  /* Is the vehicle old if we are not always replacing? */
219  if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
220 
221  /* Check refittability */
222  uint32 available_cargo_types, union_mask;
223  GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
224  /* Is there anything to refit? */
225  if (union_mask != 0) {
227  /* We cannot refit to mixed cargoes in an automated way */
228  if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
229 
230  /* Did the old vehicle carry anything? */
231  if (cargo_type != CT_INVALID) {
232  /* We can't refit the vehicle to carry the cargo we want */
233  if (!HasBit(available_cargo_types, cargo_type)) continue;
234  }
235  }
236 
237  /* Check money.
238  * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
239  pending_replace = true;
240  needed_money += 2 * Engine::Get(new_engine)->GetCost();
241  if (needed_money > c->money) return false;
242  }
243 
244  return pending_replace;
245 }
246 
253 {
254  if (this->HasDepotOrder()) return false;
255  if (this->current_order.IsType(OT_LOADING)) return false;
256  if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
257  return NeedsServicing();
258 }
259 
260 uint Vehicle::Crash(bool flooded)
261 {
262  assert((this->vehstatus & VS_CRASHED) == 0);
263  assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
264 
265  uint pass = 0;
266  /* Stop the vehicle. */
267  if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
268  /* crash all wagons, and count passengers */
269  for (Vehicle *v = this; v != NULL; v = v->Next()) {
270  /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
271  if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
272  v->vehstatus |= VS_CRASHED;
273  v->MarkAllViewportsDirty();
274  }
275 
276  /* Dirty some windows */
281 
282  delete this->cargo_payment;
283  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
284 
285  return RandomRange(pass + 1); // Randomise deceased passengers.
286 }
287 
288 
297 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
298 {
299  const Engine *e = Engine::Get(engine);
300  GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
301 
302  /* Missing GRF. Nothing useful can be done in this situation. */
303  if (grfconfig == NULL) return;
304 
305  if (!HasBit(grfconfig->grf_bugs, bug_type)) {
306  SetBit(grfconfig->grf_bugs, bug_type);
307  SetDParamStr(0, grfconfig->GetName());
308  SetDParam(1, engine);
309  ShowErrorMessage(part1, part2, WL_CRITICAL);
311  }
312 
313  /* debug output */
314  char buffer[512];
315 
316  SetDParamStr(0, grfconfig->GetName());
317  GetString(buffer, part1, lastof(buffer));
318  DEBUG(grf, 0, "%s", buffer + 3);
319 
320  SetDParam(1, engine);
321  GetString(buffer, part2, lastof(buffer));
322  DEBUG(grf, 0, "%s", buffer + 3);
323 }
324 
331 {
332  /* show a warning once for each engine in whole game and once for each GRF after each game load */
333  const Engine *engine = u->GetEngine();
334  uint32 grfid = engine->grf_prop.grffile->grfid;
335  GRFConfig *grfconfig = GetGRFConfig(grfid);
336  if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
337  ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
338  }
339 }
340 
346 {
347  this->type = type;
348  this->coord.left = INVALID_COORD;
349  this->group_id = DEFAULT_GROUP;
350  this->fill_percent_te_id = INVALID_TE_ID;
351  this->first = this;
352  this->colourmap = PAL_NONE;
353  this->cargo_age_counter = 1;
354  this->last_station_visited = INVALID_STATION;
355  this->last_loading_station = INVALID_STATION;
356 }
357 
363 {
364  return GB(Random(), 0, 8);
365 }
366 
367 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
368  * lookup times at the expense of memory usage. */
369 const int HASH_BITS = 7;
370 const int HASH_SIZE = 1 << HASH_BITS;
371 const int HASH_MASK = HASH_SIZE - 1;
372 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
373 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
374 
375 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
376  * Profiling results show that 0 is fastest. */
377 const int HASH_RES = 0;
378 
379 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
380 
381 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
382 {
383  for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
384  for (int x = xl; ; x = (x + 1) & HASH_MASK) {
385  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
386  for (; v != NULL; v = v->hash_tile_next) {
387  Vehicle *a = proc(v, data);
388  if (find_first && a != NULL) return a;
389  }
390  if (x == xu) break;
391  }
392  if (y == yu) break;
393  }
394 
395  return NULL;
396 }
397 
398 
410 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
411 {
412  const int COLL_DIST = 6;
413 
414  /* Hash area to scan is from xl,yl to xu,yu */
415  int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
416  int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
417  int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
418  int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
419 
420  return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
421 }
422 
437 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
438 {
439  VehicleFromPosXY(x, y, data, proc, false);
440 }
441 
453 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
454 {
455  return VehicleFromPosXY(x, y, data, proc, true) != NULL;
456 }
457 
468 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
469 {
470  int x = GB(TileX(tile), HASH_RES, HASH_BITS);
471  int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
472 
473  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
474  for (; v != NULL; v = v->hash_tile_next) {
475  if (v->tile != tile) continue;
476 
477  Vehicle *a = proc(v, data);
478  if (find_first && a != NULL) return a;
479  }
480 
481  return NULL;
482 }
483 
497 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
498 {
499  VehicleFromPos(tile, data, proc, false);
500 }
501 
512 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
513 {
514  return VehicleFromPos(tile, data, proc, true) != NULL;
515 }
516 
523 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
524 {
525  int z = *(int*)data;
526 
527  if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
528  if (v->z_pos > z) return NULL;
529 
530  return v;
531 }
532 
539 {
540  int z = GetTileMaxPixelZ(tile);
541 
542  /* Value v is not safe in MP games, however, it is used to generate a local
543  * error message only (which may be different for different machines).
544  * Such a message does not affect MP synchronisation.
545  */
546  Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
547  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
548  return CommandCost();
549 }
550 
553 {
554  if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
555  if (v == (const Vehicle *)data) return NULL;
556 
557  return v;
558 }
559 
568 {
569  /* Value v is not safe in MP games, however, it is used to generate a local
570  * error message only (which may be different for different machines).
571  * Such a message does not affect MP synchronisation.
572  */
573  Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
574  if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
575 
576  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
577  return CommandCost();
578 }
579 
580 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
581 {
582  TrackBits rail_bits = *(TrackBits *)data;
583 
584  if (v->type != VEH_TRAIN) return NULL;
585 
586  Train *t = Train::From(v);
587  if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
588 
589  return v;
590 }
591 
601 {
602  /* Value v is not safe in MP games, however, it is used to generate a local
603  * error message only (which may be different for different machines).
604  * Such a message does not affect MP synchronisation.
605  */
606  Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
607  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
608  return CommandCost();
609 }
610 
611 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
612 {
613  Vehicle **old_hash = v->hash_tile_current;
614  Vehicle **new_hash;
615 
616  if (remove) {
617  new_hash = NULL;
618  } else {
619  int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
620  int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
621  new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
622  }
623 
624  if (old_hash == new_hash) return;
625 
626  /* Remove from the old position in the hash table */
627  if (old_hash != NULL) {
630  }
631 
632  /* Insert vehicle at beginning of the new position in the hash table */
633  if (new_hash != NULL) {
634  v->hash_tile_next = *new_hash;
636  v->hash_tile_prev = new_hash;
637  *new_hash = v;
638  }
639 
640  /* Remember current hash position */
641  v->hash_tile_current = new_hash;
642 }
643 
644 static Vehicle *_vehicle_viewport_hash[1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)];
645 
646 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
647 {
648  Vehicle **old_hash, **new_hash;
649  int old_x = v->coord.left;
650  int old_y = v->coord.top;
651 
652  new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
653  old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
654 
655  if (old_hash == new_hash) return;
656 
657  /* remove from hash table? */
658  if (old_hash != NULL) {
661  }
662 
663  /* insert into hash table? */
664  if (new_hash != NULL) {
665  v->hash_viewport_next = *new_hash;
667  v->hash_viewport_prev = new_hash;
668  *new_hash = v;
669  }
670 }
671 
672 void ResetVehicleHash()
673 {
674  Vehicle *v;
675  FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; }
676  memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
677  memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
678 }
679 
680 void ResetVehicleColourMap()
681 {
682  Vehicle *v;
683  FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
684 }
685 
691 static AutoreplaceMap _vehicles_to_autoreplace;
692 
693 void InitializeVehicles()
694 {
695  _vehicles_to_autoreplace.Reset();
696  ResetVehicleHash();
697 }
698 
699 uint CountVehiclesInChain(const Vehicle *v)
700 {
701  uint count = 0;
702  do count++; while ((v = v->Next()) != NULL);
703  return count;
704 }
705 
711 {
712  switch (this->type) {
713  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
714  case VEH_TRAIN:
715  return !this->IsArticulatedPart() && // tenders and other articulated parts
716  !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
717  case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
718  case VEH_SHIP: return true;
719  default: return false; // Only count company buildable vehicles
720  }
721 }
722 
728 {
729  switch (this->type) {
730  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
731  case VEH_TRAIN:
732  case VEH_ROAD:
733  case VEH_SHIP: return true;
734  default: return false;
735  }
736 }
737 
744 {
745  return Engine::Get(this->engine_type);
746 }
747 
753 const GRFFile *Vehicle::GetGRF() const
754 {
755  return this->GetEngine()->GetGRF();
756 }
757 
763 uint32 Vehicle::GetGRFID() const
764 {
765  return this->GetEngine()->GetGRFID();
766 }
767 
775 void Vehicle::HandlePathfindingResult(bool path_found)
776 {
777  if (path_found) {
778  /* Route found, is the vehicle marked with "lost" flag? */
779  if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
780 
781  /* Clear the flag as the PF's problem was solved. */
783  /* Delete the news item. */
784  DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
785  return;
786  }
787 
788  /* Were we already lost? */
789  if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
790 
791  /* It is first time the problem occurred, set the "lost" flag. */
793  /* Notify user about the event. */
794  AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
795  if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
796  SetDParam(0, this->index);
797  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index);
798  }
799 }
800 
803 {
804  if (CleaningPool()) return;
805 
808  st->loading_vehicles.remove(this);
809 
811  this->CancelReservation(INVALID_STATION, st);
812  delete this->cargo_payment;
813  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
814  }
815 
816  if (this->IsEngineCountable()) {
818  if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
820 
823  }
824 
825  if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
826  Aircraft *a = Aircraft::From(this);
828  if (st != NULL) {
829  const AirportFTA *layout = st->airport.GetFTA()->layout;
830  CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
831  }
832  }
833 
834 
835  if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
836  RoadVehicle *v = RoadVehicle::From(this);
837  if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
838  /* Leave the drive through roadstop, when you have not already left it. */
840  }
841  }
842 
843  if (this->Previous() == NULL) {
845  }
846 
847  if (this->IsPrimaryVehicle()) {
855  }
857 
858  this->cargo.Truncate();
859  DeleteVehicleOrders(this);
861 
862  extern void StopGlobalFollowVehicle(const Vehicle *v);
863  StopGlobalFollowVehicle(this);
864 
866 }
867 
869 {
870  if (CleaningPool()) {
871  this->cargo.OnCleanPool();
872  return;
873  }
874 
875  /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
876  * it may happen that vehicle chain is deleted when visible */
877  if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
878 
879  Vehicle *v = this->Next();
880  this->SetNext(NULL);
881 
882  delete v;
883 
884  UpdateVehicleTileHash(this, true);
885  UpdateVehicleViewportHash(this, INVALID_COORD, 0);
888 }
889 
895 {
896  /* Vehicle should stop in the depot if it was in 'stopping' state */
897  _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
898 
899  /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
900  * stopping in the depot, so we stop it to ensure that it will not reserve
901  * the path out of the depot before we might autoreplace it to a different
902  * engine. The new engine would not own the reserved path we store that we
903  * stopped the vehicle, so autoreplace can start it again */
904  v->vehstatus |= VS_STOPPED;
905 }
906 
912 static void RunVehicleDayProc()
913 {
914  if (_game_mode != GM_NORMAL) return;
915 
916  /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
917  for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
918  Vehicle *v = Vehicle::Get(i);
919  if (v == NULL) continue;
920 
921  /* Call the 32-day callback if needed */
922  if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
923  uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
924  if (callback != CALLBACK_FAILED) {
925  if (HasBit(callback, 0)) {
926  TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
927  }
928 
929  /* After a vehicle trigger, the graphics and properties of the vehicle could change.
930  * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
931  if (callback != 0) v->First()->MarkDirty();
932 
933  if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
934  }
935  }
936 
937  /* This is called once per day for each vehicle, but not in the first tick of the day */
938  v->OnNewDay();
939  }
940 }
941 
942 void CallVehicleTicks()
943 {
944  _vehicles_to_autoreplace.Clear();
945 
947 
948  Station *st;
949  FOR_ALL_STATIONS(st) LoadUnloadStation(st);
950 
951  Vehicle *v;
952  FOR_ALL_VEHICLES(v) {
953  /* Vehicle could be deleted in this tick */
954  if (!v->Tick()) {
955  assert(Vehicle::Get(vehicle_index) == NULL);
956  continue;
957  }
958 
959  assert(Vehicle::Get(vehicle_index) == v);
960 
961  switch (v->type) {
962  default: break;
963 
964  case VEH_TRAIN:
965  case VEH_ROAD:
966  case VEH_AIRCRAFT:
967  case VEH_SHIP: {
968  Vehicle *front = v->First();
969 
970  if (v->vcache.cached_cargo_age_period != 0) {
971  v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
972  if (--v->cargo_age_counter == 0) {
973  v->cargo.AgeCargo();
974  v->cargo_age_counter = v->vcache.cached_cargo_age_period;
975  }
976  }
977 
978  /* Do not play any sound when crashed */
979  if (front->vehstatus & VS_CRASHED) continue;
980 
981  /* Do not play any sound when in depot or tunnel */
982  if (v->vehstatus & VS_HIDDEN) continue;
983 
984  /* Do not play any sound when stopped */
985  if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
986 
987  /* Check vehicle type specifics */
988  switch (v->type) {
989  case VEH_TRAIN:
990  if (Train::From(v)->IsWagon()) continue;
991  break;
992 
993  case VEH_ROAD:
994  if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
995  break;
996 
997  case VEH_AIRCRAFT:
998  if (!Aircraft::From(v)->IsNormalAircraft()) continue;
999  break;
1000 
1001  default:
1002  break;
1003  }
1004 
1005  v->motion_counter += front->cur_speed;
1006  /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1007  if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1008 
1009  /* Play an alternating running sound every 16 ticks */
1010  if (GB(v->tick_counter, 0, 4) == 0) {
1011  /* Play running sound when speed > 0 and not braking */
1012  bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
1014  }
1015 
1016  break;
1017  }
1018  }
1019  }
1020 
1021  Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
1022  for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
1023  v = it->first;
1024  /* Autoreplace needs the current company set as the vehicle owner */
1025  cur_company.Change(v->owner);
1026 
1027  /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1028  * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1029  * they are already leaving the depot again before being replaced. */
1030  if (it->second) v->vehstatus &= ~VS_STOPPED;
1031 
1032  /* Store the position of the effect as the vehicle pointer will become invalid later */
1033  int x = v->x_pos;
1034  int y = v->y_pos;
1035  int z = v->z_pos;
1036 
1039  CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
1041 
1042  if (!IsLocalCompany()) continue;
1043 
1044  if (res.Succeeded()) {
1045  ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1046  continue;
1047  }
1048 
1049  StringID error_message = res.GetErrorMessage();
1050  if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1051 
1052  if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1053 
1054  StringID message;
1055  if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1056  message = error_message;
1057  } else {
1058  message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1059  }
1060 
1061  SetDParam(0, v->index);
1062  SetDParam(1, error_message);
1063  AddVehicleAdviceNewsItem(message, v->index);
1064  }
1065 
1066  cur_company.Restore();
1067 }
1068 
1073 static void DoDrawVehicle(const Vehicle *v)
1074 {
1075  PaletteID pal = PAL_NONE;
1076 
1078 
1079  /* Check whether the vehicle shall be transparent due to the game state */
1080  bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
1081 
1082  if (v->type == VEH_EFFECT) {
1083  /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1084  * However, transparent smoke and bubbles look weird, so always hide them. */
1086  if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1087  }
1088 
1090  for (uint i = 0; i < v->sprite_seq.count; ++i) {
1091  PaletteID pal2 = v->sprite_seq.seq[i].pal;
1092  if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal;
1093  AddSortableSpriteToDraw(v->sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
1094  v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
1095  }
1096  EndSpriteCombine();
1097 }
1098 
1104 {
1105  /* The bounding rectangle */
1106  const int l = dpi->left;
1107  const int r = dpi->left + dpi->width;
1108  const int t = dpi->top;
1109  const int b = dpi->top + dpi->height;
1110 
1111  /* The hash area to scan */
1112  int xl, xu, yl, yu;
1113 
1114  if (dpi->width + (MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE) < GEN_HASHX_SIZE) {
1115  xl = GEN_HASHX(l - MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE);
1116  xu = GEN_HASHX(r);
1117  } else {
1118  /* scan whole hash row */
1119  xl = 0;
1120  xu = GEN_HASHX_MASK;
1121  }
1122 
1123  if (dpi->height + (MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE) < GEN_HASHY_SIZE) {
1124  yl = GEN_HASHY(t - MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE);
1125  yu = GEN_HASHY(b);
1126  } else {
1127  /* scan whole column */
1128  yl = 0;
1129  yu = GEN_HASHY_MASK;
1130  }
1131 
1132  for (int y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1133  for (int x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1134  const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1135 
1136  while (v != NULL) {
1137  if (!(v->vehstatus & VS_HIDDEN) &&
1138  l <= v->coord.right &&
1139  t <= v->coord.bottom &&
1140  r >= v->coord.left &&
1141  b >= v->coord.top) {
1142  DoDrawVehicle(v);
1143  }
1144  v = v->hash_viewport_next;
1145  }
1146 
1147  if (x == xu) break;
1148  }
1149 
1150  if (y == yu) break;
1151  }
1152 }
1153 
1161 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
1162 {
1163  Vehicle *found = NULL, *v;
1164  uint dist, best_dist = UINT_MAX;
1165 
1166  if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
1167 
1168  x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
1169  y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
1170 
1171  FOR_ALL_VEHICLES(v) {
1172  if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
1173  x >= v->coord.left && x <= v->coord.right &&
1174  y >= v->coord.top && y <= v->coord.bottom) {
1175 
1176  dist = max(
1177  abs(((v->coord.left + v->coord.right) >> 1) - x),
1178  abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1179  );
1180 
1181  if (dist < best_dist) {
1182  found = v;
1183  best_dist = dist;
1184  }
1185  }
1186  }
1187 
1188  return found;
1189 }
1190 
1196 {
1197  v->value -= v->value >> 8;
1199 }
1200 
1201 static const byte _breakdown_chance[64] = {
1202  3, 3, 3, 3, 3, 3, 3, 3,
1203  4, 4, 5, 5, 6, 6, 7, 7,
1204  8, 8, 9, 9, 10, 10, 11, 11,
1205  12, 13, 13, 13, 13, 14, 15, 16,
1206  17, 19, 21, 25, 28, 31, 34, 37,
1207  40, 44, 48, 52, 56, 60, 64, 68,
1208  72, 80, 90, 100, 110, 120, 130, 140,
1209  150, 170, 190, 210, 230, 250, 250, 250,
1210 };
1211 
1212 void CheckVehicleBreakdown(Vehicle *v)
1213 {
1214  int rel, rel_old;
1215 
1216  /* decrease reliability */
1217  v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1218  if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1219 
1220  if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
1222  v->cur_speed < 5 || _game_mode == GM_MENU) {
1223  return;
1224  }
1225 
1226  uint32 r = Random();
1227 
1228  /* increase chance of failure */
1229  int chance = v->breakdown_chance + 1;
1230  if (Chance16I(1, 25, r)) chance += 25;
1231  v->breakdown_chance = min(255, chance);
1232 
1233  /* calculate reliability value to use in comparison */
1234  rel = v->reliability;
1235  if (v->type == VEH_SHIP) rel += 0x6666;
1236 
1237  /* reduced breakdowns? */
1238  if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1239 
1240  /* check if to break down */
1241  if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
1242  v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1243  v->breakdown_delay = GB(r, 24, 7) + 0x80;
1244  v->breakdown_chance = 0;
1245  }
1246 }
1247 
1255 {
1256  /* Possible states for Vehicle::breakdown_ctr
1257  * 0 - vehicle is running normally
1258  * 1 - vehicle is currently broken down
1259  * 2 - vehicle is going to break down now
1260  * >2 - vehicle is counting down to the actual breakdown event */
1261  switch (this->breakdown_ctr) {
1262  case 0:
1263  return false;
1264 
1265  case 2:
1266  this->breakdown_ctr = 1;
1267 
1268  if (this->breakdowns_since_last_service != 255) {
1270  }
1271 
1272  if (this->type == VEH_AIRCRAFT) {
1273  /* Aircraft just need this flag, the rest is handled elsewhere */
1274  this->vehstatus |= VS_AIRCRAFT_BROKEN;
1275  } else {
1276  this->cur_speed = 0;
1277 
1278  if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1279  bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1280  SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
1281  (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1282  (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
1283  }
1284 
1285  if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
1287  if (u != NULL) u->animation_state = this->breakdown_delay * 2;
1288  }
1289  }
1290 
1291  this->MarkDirty(); // Update graphics after speed is zeroed
1294 
1295  FALLTHROUGH;
1296  case 1:
1297  /* Aircraft breakdowns end only when arriving at the airport */
1298  if (this->type == VEH_AIRCRAFT) return false;
1299 
1300  /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1301  if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1302  if (--this->breakdown_delay == 0) {
1303  this->breakdown_ctr = 0;
1304  this->MarkDirty();
1306  }
1307  }
1308  return true;
1309 
1310  default:
1311  if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1312  return false;
1313  }
1314 }
1315 
1321 {
1322  if (v->age < MAX_DAY) {
1323  v->age++;
1325  }
1326 
1327  if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1328 
1329  int age = v->age - v->max_age;
1330  if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
1331  age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
1332  v->reliability_spd_dec <<= 1;
1333  }
1334 
1336 
1337  /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
1338  if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
1339 
1340  /* Don't warn if a renew is active */
1341  if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
1342 
1343  StringID str;
1344  if (age == -DAYS_IN_LEAP_YEAR) {
1345  str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1346  } else if (age == 0) {
1347  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1348  } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
1349  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1350  } else {
1351  return;
1352  }
1353 
1354  SetDParam(0, v->index);
1356 }
1357 
1367 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1368 {
1369  int count = 0;
1370  int max = 0;
1371  int cars = 0;
1372  int unloading = 0;
1373  bool loading = false;
1374 
1375  bool is_loading = front->current_order.IsType(OT_LOADING);
1376 
1377  /* The station may be NULL when the (colour) string does not need to be set. */
1378  const Station *st = Station::GetIfValid(front->last_station_visited);
1379  assert(colour == NULL || (st != NULL && is_loading));
1380 
1381  bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1382  bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1383 
1384  /* Count up max and used */
1385  for (const Vehicle *v = front; v != NULL; v = v->Next()) {
1386  count += v->cargo.StoredCount();
1387  max += v->cargo_cap;
1388  if (v->cargo_cap != 0 && colour != NULL) {
1389  unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1390  loading |= !order_no_load &&
1391  (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1393  cars++;
1394  }
1395  }
1396 
1397  if (colour != NULL) {
1398  if (unloading == 0 && loading) {
1399  *colour = STR_PERCENT_UP;
1400  } else if (unloading == 0 && !loading) {
1401  *colour = STR_PERCENT_NONE;
1402  } else if (cars == unloading || !loading) {
1403  *colour = STR_PERCENT_DOWN;
1404  } else {
1405  *colour = STR_PERCENT_UP_DOWN;
1406  }
1407  }
1408 
1409  /* Train without capacity */
1410  if (max == 0) return 100;
1411 
1412  /* Return the percentage */
1413  if (count * 2 < max) {
1414  /* Less than 50%; round up, so that 0% means really empty. */
1415  return CeilDiv(count * 100, max);
1416  } else {
1417  /* More than 50%; round down, so that 100% means really full. */
1418  return (count * 100) / max;
1419  }
1420 }
1421 
1427 {
1428  /* Always work with the front of the vehicle */
1429  assert(v == v->First());
1430 
1431  switch (v->type) {
1432  case VEH_TRAIN: {
1433  Train *t = Train::From(v);
1435  /* Clear path reservation */
1436  SetDepotReservation(t->tile, false);
1438 
1440  t->wait_counter = 0;
1441  t->force_proceed = TFP_NONE;
1442  ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1444  break;
1445  }
1446 
1447  case VEH_ROAD:
1449  break;
1450 
1451  case VEH_SHIP: {
1453  Ship *ship = Ship::From(v);
1454  ship->state = TRACK_BIT_DEPOT;
1455  ship->UpdateCache();
1456  ship->UpdateViewport(true, true);
1458  break;
1459  }
1460 
1461  case VEH_AIRCRAFT:
1464  break;
1465  default: NOT_REACHED();
1466  }
1468 
1469  if (v->type != VEH_TRAIN) {
1470  /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1471  * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
1473  }
1475 
1476  v->vehstatus |= VS_HIDDEN;
1477  v->cur_speed = 0;
1478 
1480 
1481  /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1482  TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1483  v->MarkDirty();
1484 
1485  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1487 
1488  const Order *real_order = v->GetOrder(v->cur_real_order_index);
1489 
1490  /* Test whether we are heading for this depot. If not, do nothing.
1491  * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1493  real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1494  (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
1495  /* We are heading for another depot, keep driving. */
1496  return;
1497  }
1498 
1499  if (v->current_order.IsRefit()) {
1500  Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
1501  CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
1502  cur_company.Restore();
1503 
1504  if (cost.Failed()) {
1505  _vehicles_to_autoreplace[v] = false;
1506  if (v->owner == _local_company) {
1507  /* Notify the user that we stopped the vehicle */
1508  SetDParam(0, v->index);
1509  AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
1510  }
1511  } else if (cost.GetCost() != 0) {
1512  v->profit_this_year -= cost.GetCost() << 8;
1513  if (v->owner == _local_company) {
1514  ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
1515  }
1516  }
1517  }
1518 
1520  /* Part of orders */
1522  UpdateVehicleTimetable(v, true);
1524  }
1526  /* Vehicles are always stopped on entering depots. Do not restart this one. */
1527  _vehicles_to_autoreplace[v] = false;
1528  /* Invalidate last_loading_station. As the link from the station
1529  * before the stop to the station after the stop can't be predicted
1530  * we shouldn't construct it when the vehicle visits the next stop. */
1531  v->last_loading_station = INVALID_STATION;
1532  if (v->owner == _local_company) {
1533  SetDParam(0, v->index);
1534  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1535  }
1536  AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1537  }
1538  v->current_order.MakeDummy();
1539  }
1540 }
1541 
1542 
1548 {
1549  UpdateVehicleTileHash(this, false);
1550 }
1551 
1557 void Vehicle::UpdateViewport(bool dirty)
1558 {
1559  Rect new_coord;
1560  this->sprite_seq.GetBounds(&new_coord);
1561 
1562  Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1563  new_coord.left += pt.x;
1564  new_coord.top += pt.y;
1565  new_coord.right += pt.x + 2 * ZOOM_LVL_BASE;
1566  new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
1567 
1568  UpdateVehicleViewportHash(this, new_coord.left, new_coord.top);
1569 
1570  Rect old_coord = this->coord;
1571  this->coord = new_coord;
1572 
1573  if (dirty) {
1574  if (old_coord.left == INVALID_COORD) {
1575  this->MarkAllViewportsDirty();
1576  } else {
1578  min(old_coord.left, this->coord.left),
1579  min(old_coord.top, this->coord.top),
1580  max(old_coord.right, this->coord.right),
1581  max(old_coord.bottom, this->coord.bottom));
1582  }
1583  }
1584 }
1585 
1590 {
1591  this->UpdatePosition();
1592  this->UpdateViewport(true);
1593 }
1594 
1599 {
1600  ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1601 }
1602 
1609 {
1610  static const int8 _delta_coord[16] = {
1611  -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1612  -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1613  };
1614 
1615  int x = v->x_pos + _delta_coord[v->direction];
1616  int y = v->y_pos + _delta_coord[v->direction + 8];
1617 
1619  gp.x = x;
1620  gp.y = y;
1621  gp.old_tile = v->tile;
1622  gp.new_tile = TileVirtXY(x, y);
1623  return gp;
1624 }
1625 
1626 static const Direction _new_direction_table[] = {
1627  DIR_N, DIR_NW, DIR_W,
1628  DIR_NE, DIR_SE, DIR_SW,
1629  DIR_E, DIR_SE, DIR_S
1630 };
1631 
1632 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1633 {
1634  int i = 0;
1635 
1636  if (y >= v->y_pos) {
1637  if (y != v->y_pos) i += 3;
1638  i += 3;
1639  }
1640 
1641  if (x >= v->x_pos) {
1642  if (x != v->x_pos) i++;
1643  i++;
1644  }
1645 
1646  Direction dir = v->direction;
1647 
1648  DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1649  if (dirdiff == DIRDIFF_SAME) return dir;
1650  return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1651 }
1652 
1663 {
1664  return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1665 }
1666 
1674 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
1675 {
1676  /* Find maximum */
1677  const Vehicle *v;
1678  FOR_ALL_VEHICLES(v) {
1679  if (v->type == type && v->owner == owner) {
1680  this->maxid = max<UnitID>(this->maxid, v->unitnumber);
1681  }
1682  }
1683 
1684  if (this->maxid == 0) return;
1685 
1686  /* Reserving 'maxid + 2' because we need:
1687  * - space for the last item (with v->unitnumber == maxid)
1688  * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
1689  this->cache = CallocT<bool>(this->maxid + 2);
1690 
1691  /* Fill the cache */
1692  FOR_ALL_VEHICLES(v) {
1693  if (v->type == type && v->owner == owner) {
1694  this->cache[v->unitnumber] = true;
1695  }
1696  }
1697 }
1698 
1701 {
1702  if (this->maxid <= this->curid) return ++this->curid;
1703 
1704  while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
1705 
1706  return this->curid;
1707 }
1708 
1715 {
1716  /* Check whether it is allowed to build another vehicle. */
1717  uint max_veh;
1718  switch (type) {
1719  case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1720  case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1721  case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1722  case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1723  default: NOT_REACHED();
1724  }
1725 
1727  if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1728 
1730 
1731  return gen.NextID();
1732 }
1733 
1734 
1744 {
1745  assert(IsCompanyBuildableVehicleType(type));
1746 
1747  if (!Company::IsValidID(_local_company)) return false;
1749 
1750  UnitID max;
1751  switch (type) {
1752  case VEH_TRAIN: max = _settings_game.vehicle.max_trains; break;
1753  case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break;
1754  case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1755  case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1756  default: NOT_REACHED();
1757  }
1758 
1759  /* We can build vehicle infrastructure when we may build the vehicle type */
1760  if (max > 0) {
1761  /* Can we actually build the vehicle type? */
1762  const Engine *e;
1763  FOR_ALL_ENGINES_OF_TYPE(e, type) {
1764  if (HasBit(e->company_avail, _local_company)) return true;
1765  }
1766  return false;
1767  }
1768 
1769  /* We should be able to build infrastructure when we have the actual vehicle type */
1770  const Vehicle *v;
1771  FOR_ALL_VEHICLES(v) {
1772  if (v->owner == _local_company && v->type == type) return true;
1773  }
1774 
1775  return false;
1776 }
1777 
1778 
1786 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1787 {
1788  CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
1789  const Engine *e = Engine::Get(engine_type);
1790  switch (e->type) {
1791  default: NOT_REACHED();
1792  case VEH_TRAIN:
1793  if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1794  /* Wagonoverrides use the colour scheme of the front engine.
1795  * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1796  engine_type = parent_engine_type;
1797  e = Engine::Get(engine_type);
1798  /* Note: Luckily cargo_type is not needed for engines */
1799  }
1800 
1801  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1802  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1803  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1804  if (!CargoSpec::Get(cargo_type)->is_freight) {
1805  if (parent_engine_type == INVALID_ENGINE) {
1806  return LS_PASSENGER_WAGON_STEAM;
1807  } else {
1808  switch (RailVehInfo(parent_engine_type)->engclass) {
1809  default: NOT_REACHED();
1810  case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1811  case EC_DIESEL: return LS_PASSENGER_WAGON_DIESEL;
1812  case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
1813  case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1814  case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1815  }
1816  }
1817  } else {
1818  return LS_FREIGHT_WAGON;
1819  }
1820  } else {
1821  bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
1822 
1823  switch (e->u.rail.engclass) {
1824  default: NOT_REACHED();
1825  case EC_STEAM: return LS_STEAM;
1826  case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
1827  case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1828  case EC_MONORAIL: return LS_MONORAIL;
1829  case EC_MAGLEV: return LS_MAGLEV;
1830  }
1831  }
1832 
1833  case VEH_ROAD:
1834  /* Always use the livery of the front */
1835  if (v != NULL && parent_engine_type != INVALID_ENGINE) {
1836  engine_type = parent_engine_type;
1837  e = Engine::Get(engine_type);
1838  cargo_type = v->First()->cargo_type;
1839  }
1840  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1841  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1842 
1843  /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
1844  if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
1845  /* Tram */
1846  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
1847  } else {
1848  /* Bus or truck */
1849  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
1850  }
1851 
1852  case VEH_SHIP:
1853  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1854  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1855  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
1856 
1857  case VEH_AIRCRAFT:
1858  switch (e->u.air.subtype) {
1859  case AIR_HELI: return LS_HELICOPTER;
1860  case AIR_CTOL: return LS_SMALL_PLANE;
1861  case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
1862  default: NOT_REACHED();
1863  }
1864  }
1865 }
1866 
1876 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
1877 {
1878  const Company *c = Company::Get(company);
1879  LiveryScheme scheme = LS_DEFAULT;
1880 
1881  /* The default livery is always available for use, but its in_use flag determines
1882  * whether any _other_ liveries are in use. */
1883  if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
1884  /* Determine the livery scheme to use */
1885  scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
1886 
1887  /* Switch back to the default scheme if the resolved scheme is not in use */
1888  if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
1889  }
1890 
1891  return &c->livery[scheme];
1892 }
1893 
1894 
1895 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
1896 {
1897  PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
1898 
1899  /* Return cached value if any */
1900  if (map != PAL_NONE) return map;
1901 
1902  const Engine *e = Engine::Get(engine_type);
1903 
1904  /* Check if we should use the colour map callback */
1906  uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
1907  /* Failure means "use the default two-colour" */
1908  if (callback != CALLBACK_FAILED) {
1909  assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
1910  map = GB(callback, 0, 14);
1911  /* If bit 14 is set, then the company colours are applied to the
1912  * map else it's returned as-is. */
1913  if (!HasBit(callback, 14)) {
1914  /* Update cache */
1915  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1916  return map;
1917  }
1918  }
1919  }
1920 
1921  bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
1922 
1923  if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
1924 
1925  /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
1926  if (!Company::IsValidID(company)) return map;
1927 
1928  const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
1929 
1930  map += livery->colour1;
1931  if (twocc) map += livery->colour2 * 16;
1932 
1933  /* Update cache */
1934  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1935  return map;
1936 }
1937 
1945 {
1946  return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
1947 }
1948 
1955 {
1956  if (v->IsGroundVehicle()) {
1957  return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
1958  }
1959 
1960  return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
1961 }
1962 
1967 {
1968  if (this->IsGroundVehicle()) {
1969  uint16 &gv_flags = this->GetGroundVehicleFlags();
1970  if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
1971  /* Do not delete orders, only skip them */
1974  InvalidateVehicleOrder(this, 0);
1975  return;
1976  }
1977  }
1978 
1979  const Order *order = this->GetOrder(this->cur_implicit_order_index);
1980  while (order != NULL) {
1981  if (this->cur_implicit_order_index == this->cur_real_order_index) break;
1982 
1983  if (order->IsType(OT_IMPLICIT)) {
1985  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
1986  order = this->GetOrder(this->cur_implicit_order_index);
1987  } else {
1988  /* Skip non-implicit orders, e.g. service-orders */
1989  order = order->next;
1990  this->cur_implicit_order_index++;
1991  }
1992 
1993  /* Wrap around */
1994  if (order == NULL) {
1995  order = this->GetOrder(0);
1996  this->cur_implicit_order_index = 0;
1997  }
1998  }
1999 }
2000 
2006 {
2007  assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
2008 
2009  if (this->current_order.IsType(OT_GOTO_STATION) &&
2012 
2013  /* Now both order indices point to the destination station, and we can start loading */
2014  this->current_order.MakeLoading(true);
2015  UpdateVehicleTimetable(this, true);
2016 
2017  /* Furthermore add the Non Stop flag to mark that this station
2018  * is the actual destination of the vehicle, which is (for example)
2019  * necessary to be known for HandleTrainLoading to determine
2020  * whether the train is lost or not; not marking a train lost
2021  * that arrives at random stations is bad. */
2023 
2024  } else {
2025  /* We weren't scheduled to stop here. Insert an implicit order
2026  * to show that we are stopping here.
2027  * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2028  * the 'wrong' terminal when skipping orders etc. */
2029  Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2030  if (this->IsGroundVehicle() &&
2031  (in_list == NULL || !in_list->IsType(OT_IMPLICIT) ||
2032  in_list->GetDestination() != this->last_station_visited)) {
2033  bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2034  /* Do not create consecutive duplicates of implicit orders */
2035  Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
2036  if (prev_order == NULL ||
2037  (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2038  prev_order->GetDestination() != this->last_station_visited) {
2039 
2040  /* Prefer deleting implicit orders instead of inserting new ones,
2041  * so test whether the right order follows later. In case of only
2042  * implicit orders treat the last order in the list like an
2043  * explicit one, except if the overall number of orders surpasses
2044  * IMPLICIT_ORDER_ONLY_CAP. */
2045  int target_index = this->cur_implicit_order_index;
2046  bool found = false;
2047  while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2048  const Order *order = this->GetOrder(target_index);
2049  if (order == NULL) break; // No orders.
2050  if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2051  found = true;
2052  break;
2053  }
2054  target_index++;
2055  if (target_index >= this->orders.list->GetNumOrders()) {
2056  if (this->GetNumManualOrders() == 0 &&
2058  break;
2059  }
2060  target_index = 0;
2061  }
2062  if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2063  }
2064 
2065  if (found) {
2066  if (suppress_implicit_orders) {
2067  /* Skip to the found order */
2068  this->cur_implicit_order_index = target_index;
2069  InvalidateVehicleOrder(this, 0);
2070  } else {
2071  /* Delete all implicit orders up to the station we just reached */
2072  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2073  while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2074  if (order->IsType(OT_IMPLICIT)) {
2076  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2077  order = this->GetOrder(this->cur_implicit_order_index);
2078  } else {
2079  /* Skip non-implicit orders, e.g. service-orders */
2080  order = order->next;
2081  this->cur_implicit_order_index++;
2082  }
2083 
2084  /* Wrap around */
2085  if (order == NULL) {
2086  order = this->GetOrder(0);
2087  this->cur_implicit_order_index = 0;
2088  }
2089  assert(order != NULL);
2090  }
2091  }
2092  } else if (!suppress_implicit_orders &&
2093  ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2095  /* Insert new implicit order */
2096  Order *implicit_order = new Order();
2097  implicit_order->MakeImplicit(this->last_station_visited);
2098  InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2099  if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2100 
2101  /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2102  * Reenable it for this vehicle */
2103  uint16 &gv_flags = this->GetGroundVehicleFlags();
2105  }
2106  }
2107  }
2108  this->current_order.MakeLoading(false);
2109  }
2110 
2111  if (this->last_loading_station != INVALID_STATION &&
2112  this->last_loading_station != this->last_station_visited &&
2113  ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2114  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2116  }
2117 
2118  PrepareUnload(this);
2119 
2124 
2125  Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2126  this->cur_speed = 0;
2127  this->MarkDirty();
2128 }
2129 
2135 void Vehicle::CancelReservation(StationID next, Station *st)
2136 {
2137  for (Vehicle *v = this; v != NULL; v = v->next) {
2139  if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2140  DEBUG(misc, 1, "cancelling cargo reservation");
2141  cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
2142  cargo.SetTransferLoadPlace(st->xy);
2143  }
2144  cargo.KeepAll();
2145  }
2146 }
2147 
2153 {
2154  assert(this->current_order.IsType(OT_LOADING));
2155 
2156  delete this->cargo_payment;
2157  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
2158 
2159  /* Only update the timetable if the vehicle was supposed to stop here. */
2161 
2162  if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2163  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2164  if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
2165  /* Refresh next hop stats to make sure we've done that at least once
2166  * during the stop and that refit_cap == cargo_cap for each vehicle in
2167  * the consist. */
2168  this->ResetRefitCaps();
2169  LinkRefresher::Run(this);
2170 
2171  /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2173  } else {
2174  /* if the vehicle couldn't load and had to unload or transfer everything
2175  * set the last loading station to invalid as it will leave empty. */
2176  this->last_loading_station = INVALID_STATION;
2177  }
2178  }
2179 
2182  this->CancelReservation(INVALID_STATION, st);
2183  st->loading_vehicles.remove(this);
2184 
2187 
2188  if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2189  /* Trigger station animation (trains only) */
2190  if (IsTileType(this->tile, MP_STATION)) {
2192  TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2193  }
2194 
2195  SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2196  }
2197 
2198  this->MarkDirty();
2199 }
2200 
2205 {
2206  for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
2207 }
2208 
2214 void Vehicle::HandleLoading(bool mode)
2215 {
2216  switch (this->current_order.GetType()) {
2217  case OT_LOADING: {
2218  uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2219 
2220  /* Not the first call for this tick, or still loading */
2221  if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2222 
2223  this->PlayLeaveStationSound();
2224 
2225  this->LeaveStation();
2226 
2227  /* Only advance to next order if we just loaded at the current one */
2228  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2229  if (order == NULL ||
2230  (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2231  order->GetDestination() != this->last_station_visited) {
2232  return;
2233  }
2234  break;
2235  }
2236 
2237  case OT_DUMMY: break;
2238 
2239  default: return;
2240  }
2241 
2243 }
2244 
2250 {
2251  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2252  if (v->cargo_cap == 0) continue;
2253  SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2254  if (pair == capacities.End()) {
2255  pair = capacities.Append();
2256  pair->first = v->cargo_type;
2257  pair->second = v->cargo_cap - v->cargo.StoredCount();
2258  } else {
2259  pair->second += v->cargo_cap - v->cargo.StoredCount();
2260  }
2261  }
2262 }
2263 
2264 uint Vehicle::GetConsistTotalCapacity() const
2265 {
2266  uint result = 0;
2267  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2268  result += v->cargo_cap;
2269  }
2270  return result;
2271 }
2272 
2280 {
2281  CommandCost ret = CheckOwnership(this->owner);
2282  if (ret.Failed()) return ret;
2283 
2284  if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2285  if (this->IsStoppedInDepot()) return CMD_ERROR;
2286 
2287  if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2288  bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2289  if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2290  /* We called with a different DEPOT_SERVICE setting.
2291  * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2292  * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2293  if (flags & DC_EXEC) {
2297  }
2298  return CommandCost();
2299  }
2300 
2301  if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
2302  if (flags & DC_EXEC) {
2303  /* If the orders to 'goto depot' are in the orders list (forced servicing),
2304  * then skip to the next order; effectively cancelling this forced service */
2306 
2307  if (this->IsGroundVehicle()) {
2308  uint16 &gv_flags = this->GetGroundVehicleFlags();
2310  }
2311 
2312  this->current_order.MakeDummy();
2314  }
2315  return CommandCost();
2316  }
2317 
2318  TileIndex location;
2319  DestinationID destination;
2320  bool reverse;
2321  static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR};
2322  if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2323 
2324  if (flags & DC_EXEC) {
2325  if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2326 
2327  if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2328  uint16 &gv_flags = this->GetGroundVehicleFlags();
2330  }
2331 
2332  this->dest_tile = location;
2333  this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2334  if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2336 
2337  /* If there is no depot in front, reverse automatically (trains only) */
2338  if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2339 
2340  if (this->type == VEH_AIRCRAFT) {
2341  Aircraft *a = Aircraft::From(this);
2342  if (a->state == FLYING && a->targetairport != destination) {
2343  /* The aircraft is now heading for a different hangar than the next in the orders */
2346  }
2347  }
2348  }
2349 
2350  return CommandCost();
2351 
2352 }
2353 
2358 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2359 {
2360  bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2361  const Engine *e = this->GetEngine();
2362 
2363  /* Evaluate properties */
2364  byte visual_effect;
2365  switch (e->type) {
2366  case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2367  case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2368  case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2369  default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2370  }
2371 
2372  /* Check powered wagon / visual effect callback */
2374  uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2375 
2376  if (callback != CALLBACK_FAILED) {
2377  if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2378 
2379  callback = GB(callback, 0, 8);
2380  /* Avoid accidentally setting 'visual_effect' to the default value
2381  * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2382  if (callback == VE_DEFAULT) {
2383  assert(HasBit(callback, VE_DISABLE_EFFECT));
2384  SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2385  }
2386  visual_effect = callback;
2387  }
2388  }
2389 
2390  /* Apply default values */
2391  if (visual_effect == VE_DEFAULT ||
2392  (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2393  /* Only train engines have default effects.
2394  * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2395  if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2396  if (visual_effect == VE_DEFAULT) {
2397  visual_effect = 1 << VE_DISABLE_EFFECT;
2398  } else {
2399  SetBit(visual_effect, VE_DISABLE_EFFECT);
2400  }
2401  } else {
2402  if (visual_effect == VE_DEFAULT) {
2403  /* Also set the offset */
2404  visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2405  }
2406  SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2407  }
2408  }
2409 
2410  this->vcache.cached_vis_effect = visual_effect;
2411 
2412  if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2414  ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2415  }
2416 }
2417 
2418 static const int8 _vehicle_smoke_pos[8] = {
2419  1, 1, 1, 0, -1, -1, -1, 0
2420 };
2421 
2426 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2427 {
2428  uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2429  if (callback == CALLBACK_FAILED) return;
2430 
2431  uint count = GB(callback, 0, 2);
2432  bool auto_center = HasBit(callback, 13);
2433  bool auto_rotate = !HasBit(callback, 14);
2434 
2435  int8 l_center = 0;
2436  if (auto_center) {
2437  /* For road vehicles: Compute offset from vehicle position to vehicle center */
2438  if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2439  } else {
2440  /* For trains: Compute offset from vehicle position to sprite position */
2441  if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2442  }
2443 
2444  Direction l_dir = v->direction;
2445  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2446  Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2447 
2448  int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2449  int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2450 
2451  for (uint i = 0; i < count; i++) {
2452  uint32 reg = GetRegister(0x100 + i);
2453  uint type = GB(reg, 0, 8);
2454  int8 x = GB(reg, 8, 8);
2455  int8 y = GB(reg, 16, 8);
2456  int8 z = GB(reg, 24, 8);
2457 
2458  if (auto_rotate) {
2459  int8 l = x;
2460  int8 t = y;
2461  x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2462  y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2463  }
2464 
2465  if (type >= 0xF0) {
2466  switch (type) {
2467  case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2468  case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2469  case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2470  case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2471  default: break;
2472  }
2473  }
2474  }
2475 }
2476 
2482 {
2483  assert(this->IsPrimaryVehicle());
2484  bool sound = false;
2485 
2486  /* Do not show any smoke when:
2487  * - vehicle smoke is disabled by the player
2488  * - the vehicle is slowing down or stopped (by the player)
2489  * - the vehicle is moving very slowly
2490  */
2491  if (_settings_game.vehicle.smoke_amount == 0 ||
2492  this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2493  this->cur_speed < 2) {
2494  return;
2495  }
2496 
2497  /* Use the speed as limited by underground and orders. */
2498  uint max_speed = this->GetCurrentMaxSpeed();
2499 
2500  if (this->type == VEH_TRAIN) {
2501  const Train *t = Train::From(this);
2502  /* For trains, do not show any smoke when:
2503  * - the train is reversing
2504  * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2505  */
2506  if (HasBit(t->flags, VRF_REVERSING) ||
2508  t->cur_speed >= max_speed)) {
2509  return;
2510  }
2511  }
2512 
2513  const Vehicle *v = this;
2514 
2515  do {
2516  bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2518  VisualEffectSpawnModel effect_model = VESM_NONE;
2519  if (advanced) {
2520  effect_offset = VE_OFFSET_CENTRE;
2522  if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2523  } else {
2525  assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2526  assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2527  assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2528  assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2529  }
2530 
2531  /* Show no smoke when:
2532  * - Smoke has been disabled for this vehicle
2533  * - The vehicle is not visible
2534  * - The vehicle is under a bridge
2535  * - The vehicle is on a depot tile
2536  * - The vehicle is on a tunnel tile
2537  * - The vehicle is a train engine that is currently unpowered */
2538  if (effect_model == VESM_NONE ||
2539  v->vehstatus & VS_HIDDEN ||
2540  IsBridgeAbove(v->tile) ||
2541  IsDepotTile(v->tile) ||
2542  IsTunnelTile(v->tile) ||
2543  (v->type == VEH_TRAIN &&
2544  !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2545  continue;
2546  }
2547 
2548  EffectVehicleType evt = EV_END;
2549  switch (effect_model) {
2550  case VESM_STEAM:
2551  /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2552  * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2553  * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2554  * REGULATION:
2555  * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2556  if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2557  evt = EV_STEAM_SMOKE;
2558  }
2559  break;
2560 
2561  case VESM_DIESEL: {
2562  /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2563  * when smoke emission stops.
2564  * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2565  * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2566  * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2567  * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2568  * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2569  * maximum speed no diesel_smoke is emitted.
2570  * REGULATION:
2571  * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2572  * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2573  int power_weight_effect = 0;
2574  if (v->type == VEH_TRAIN) {
2575  power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2576  }
2577  if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2578  Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2579  evt = EV_DIESEL_SMOKE;
2580  }
2581  break;
2582  }
2583 
2584  case VESM_ELECTRIC:
2585  /* Electric train's spark - more often occurs when train is departing (more load)
2586  * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2587  * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2588  * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2589  * REGULATION:
2590  * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2591  if (GB(v->tick_counter, 0, 2) == 0 &&
2592  Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2593  evt = EV_ELECTRIC_SPARK;
2594  }
2595  break;
2596 
2597  default:
2598  NOT_REACHED();
2599  }
2600 
2601  if (evt != EV_END && advanced) {
2602  sound = true;
2604  } else if (evt != EV_END) {
2605  sound = true;
2606 
2607  /* The effect offset is relative to a point 4 units behind the vehicle's
2608  * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2609  * correction factor. */
2610  if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2611 
2612  int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2613  int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2614 
2615  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2616  x = -x;
2617  y = -y;
2618  }
2619 
2620  CreateEffectVehicleRel(v, x, y, 10, evt);
2621  }
2622  } while ((v = v->Next()) != NULL);
2623 
2624  if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2625 }
2626 
2632 {
2633  assert(this != next);
2634 
2635  if (this->next != NULL) {
2636  /* We had an old next vehicle. Update the first and previous pointers */
2637  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2638  v->first = this->next;
2639  }
2640  this->next->previous = NULL;
2641  }
2642 
2643  this->next = next;
2644 
2645  if (this->next != NULL) {
2646  /* A new next vehicle. Update the first and previous pointers */
2647  if (this->next->previous != NULL) this->next->previous->next = NULL;
2648  this->next->previous = this;
2649  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2650  v->first = this->first;
2651  }
2652  }
2653 }
2654 
2660 void Vehicle::AddToShared(Vehicle *shared_chain)
2661 {
2662  assert(this->previous_shared == NULL && this->next_shared == NULL);
2663 
2664  if (shared_chain->orders.list == NULL) {
2665  assert(shared_chain->previous_shared == NULL);
2666  assert(shared_chain->next_shared == NULL);
2667  this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
2668  }
2669 
2670  this->next_shared = shared_chain->next_shared;
2671  this->previous_shared = shared_chain;
2672 
2673  shared_chain->next_shared = this;
2674 
2675  if (this->next_shared != NULL) this->next_shared->previous_shared = this;
2676 
2677  shared_chain->orders.list->AddVehicle(this);
2678 }
2679 
2684 {
2685  /* Remember if we were first and the old window number before RemoveVehicle()
2686  * as this changes first if needed. */
2687  bool were_first = (this->FirstShared() == this);
2688  VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2689 
2690  this->orders.list->RemoveVehicle(this);
2691 
2692  if (!were_first) {
2693  /* We are not the first shared one, so only relink our previous one. */
2694  this->previous_shared->next_shared = this->NextShared();
2695  }
2696 
2697  if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
2698 
2699 
2700  if (this->orders.list->GetNumVehicles() == 1) {
2701  /* When there is only one vehicle, remove the shared order list window. */
2704  } else if (were_first) {
2705  /* If we were the first one, update to the new first one.
2706  * Note: FirstShared() is already the new first */
2707  InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2708  }
2709 
2710  this->next_shared = NULL;
2711  this->previous_shared = NULL;
2712 }
2713 
2714 void VehiclesYearlyLoop()
2715 {
2716  Vehicle *v;
2717  FOR_ALL_VEHICLES(v) {
2718  if (v->IsPrimaryVehicle()) {
2719  /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2720  Money profit = v->GetDisplayProfitThisYear();
2721  if (v->age >= 730 && profit < 0) {
2723  SetDParam(0, v->index);
2724  SetDParam(1, profit);
2725  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2726  }
2727  AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2728  }
2729 
2731  v->profit_this_year = 0;
2733  }
2734  }
2740 }
2741 
2742 
2752 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2753 {
2754  const Engine *e = Engine::GetIfValid(engine_type);
2755  assert(e != NULL);
2756 
2757  switch (e->type) {
2758  case VEH_TRAIN:
2759  return (st->facilities & FACIL_TRAIN) != 0;
2760 
2761  case VEH_ROAD:
2762  /* For road vehicles we need the vehicle to know whether it can actually
2763  * use the station, but if it doesn't have facilities for RVs it is
2764  * certainly not possible that the station can be used. */
2765  return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2766 
2767  case VEH_SHIP:
2768  return (st->facilities & FACIL_DOCK) != 0;
2769 
2770  case VEH_AIRCRAFT:
2771  return (st->facilities & FACIL_AIRPORT) != 0 &&
2773 
2774  default:
2775  return false;
2776  }
2777 }
2778 
2785 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2786 {
2787  if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
2788 
2789  return CanVehicleUseStation(v->engine_type, st);
2790 }
2791 
2798 {
2799  assert(this->IsGroundVehicle());
2800  if (this->type == VEH_TRAIN) {
2801  return &Train::From(this)->gcache;
2802  } else {
2803  return &RoadVehicle::From(this)->gcache;
2804  }
2805 }
2806 
2813 {
2814  assert(this->IsGroundVehicle());
2815  if (this->type == VEH_TRAIN) {
2816  return &Train::From(this)->gcache;
2817  } else {
2818  return &RoadVehicle::From(this)->gcache;
2819  }
2820 }
2821 
2828 {
2829  assert(this->IsGroundVehicle());
2830  if (this->type == VEH_TRAIN) {
2831  return Train::From(this)->gv_flags;
2832  } else {
2833  return RoadVehicle::From(this)->gv_flags;
2834  }
2835 }
2836 
2842 const uint16 &Vehicle::GetGroundVehicleFlags() const
2843 {
2844  assert(this->IsGroundVehicle());
2845  if (this->type == VEH_TRAIN) {
2846  return Train::From(this)->gv_flags;
2847  } else {
2848  return RoadVehicle::From(this)->gv_flags;
2849  }
2850 }
2851 
2860 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2861 {
2862  if (v->type == VEH_TRAIN) {
2863  Train *u = Train::From(v);
2864  /* Only include whole vehicles, so start with the first articulated part */
2865  u = u->GetFirstEnginePart();
2866 
2867  /* Include num_vehicles vehicles, not counting articulated parts */
2868  for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2869  do {
2870  /* Include current vehicle in the selection. */
2871  set.Include(u->index);
2872 
2873  /* If the vehicle is multiheaded, add the other part too. */
2874  if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
2875 
2876  u = u->Next();
2877  } while (u != NULL && u->IsArticulatedPart());
2878  }
2879  }
2880 }