OpenTTD
vehicle.cpp
Go to the documentation of this file.
1 /* $Id: vehicle.cpp 27904 2017-08-31 06:47:17Z adf88 $ */
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 #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
61 
62 VehicleID _new_vehicle_id;
65 
66 
68 VehiclePool _vehicle_pool("Vehicle");
70 
71 
72 
76 void VehicleSpriteSeq::GetBounds(Rect *bounds) const
77 {
78  bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
79  for (uint i = 0; i < this->count; ++i) {
80  const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL);
81  if (i == 0) {
82  bounds->left = spr->x_offs;
83  bounds->top = spr->y_offs;
84  bounds->right = spr->width + spr->x_offs - 1;
85  bounds->bottom = spr->height + spr->y_offs - 1;
86  } else {
87  if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
88  if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
89  int right = spr->width + spr->x_offs - 1;
90  int bottom = spr->height + spr->y_offs - 1;
91  if (right > bounds->right) bounds->right = right;
92  if (bottom > bounds->bottom) bounds->bottom = bottom;
93  }
94  }
95 }
96 
104 void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
105 {
106  for (uint i = 0; i < this->count; ++i) {
107  PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
108  DrawSprite(this->seq[i].sprite, pal, x, y);
109  }
110 }
111 
118 bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
119 {
120  /* We can always generate the Company pointer when we have the vehicle.
121  * However this takes time and since the Company pointer is often present
122  * when this function is called then it's faster to pass the pointer as an
123  * argument rather than finding it again. */
124  assert(c == Company::Get(this->owner));
125 
126  if (use_renew_setting && !c->settings.engine_renew) return false;
127  if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
128 
129  /* Only engines need renewing */
130  if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
131 
132  return true;
133 }
134 
141 {
142  assert(v != NULL);
143  SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
144 
145  do {
148  v->reliability = v->GetEngine()->reliability;
149  /* Prevent vehicles from breaking down directly after exiting the depot. */
150  v->breakdown_chance /= 4;
151  v = v->Next();
152  } while (v != NULL && v->HasEngineType());
153 }
154 
162 {
163  /* Stopped or crashed vehicles will not move, as such making unmovable
164  * vehicles to go for service is lame. */
165  if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
166 
167  /* Are we ready for the next service cycle? */
168  const Company *c = Company::Get(this->owner);
169  if (this->ServiceIntervalIsPercent() ?
170  (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
171  (this->date_of_last_service + this->GetServiceInterval() >= _date)) {
172  return false;
173  }
174 
175  /* If we're servicing anyway, because we have not disabled servicing when
176  * there are no breakdowns or we are playing with breakdowns, bail out. */
179  return true;
180  }
181 
182  /* Test whether there is some pending autoreplace.
183  * Note: We do this after the service-interval test.
184  * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
185  bool pending_replace = false;
186  Money needed_money = c->settings.engine_renew_money;
187  if (needed_money > c->money) return false;
188 
189  for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
190  bool replace_when_old = false;
191  EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
192 
193  /* Check engine availability */
194  if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
195  /* Is the vehicle old if we are not always replacing? */
196  if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
197 
198  /* Check refittability */
199  uint32 available_cargo_types, union_mask;
200  GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
201  /* Is there anything to refit? */
202  if (union_mask != 0) {
204  /* We cannot refit to mixed cargoes in an automated way */
205  if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
206 
207  /* Did the old vehicle carry anything? */
208  if (cargo_type != CT_INVALID) {
209  /* We can't refit the vehicle to carry the cargo we want */
210  if (!HasBit(available_cargo_types, cargo_type)) continue;
211  }
212  }
213 
214  /* Check money.
215  * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
216  pending_replace = true;
217  needed_money += 2 * Engine::Get(new_engine)->GetCost();
218  if (needed_money > c->money) return false;
219  }
220 
221  return pending_replace;
222 }
223 
230 {
231  if (this->HasDepotOrder()) return false;
232  if (this->current_order.IsType(OT_LOADING)) return false;
233  if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
234  return NeedsServicing();
235 }
236 
237 uint Vehicle::Crash(bool flooded)
238 {
239  assert((this->vehstatus & VS_CRASHED) == 0);
240  assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
241 
242  uint pass = 0;
243  /* Stop the vehicle. */
244  if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
245  /* crash all wagons, and count passengers */
246  for (Vehicle *v = this; v != NULL; v = v->Next()) {
247  /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
248  if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
249  v->vehstatus |= VS_CRASHED;
250  v->MarkAllViewportsDirty();
251  }
252 
253  /* Dirty some windows */
258 
259  delete this->cargo_payment;
260  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
261 
262  return RandomRange(pass + 1); // Randomise deceased passengers.
263 }
264 
265 
274 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
275 {
276  const Engine *e = Engine::Get(engine);
277  GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
278 
279  /* Missing GRF. Nothing useful can be done in this situation. */
280  if (grfconfig == NULL) return;
281 
282  if (!HasBit(grfconfig->grf_bugs, bug_type)) {
283  SetBit(grfconfig->grf_bugs, bug_type);
284  SetDParamStr(0, grfconfig->GetName());
285  SetDParam(1, engine);
286  ShowErrorMessage(part1, part2, WL_CRITICAL);
288  }
289 
290  /* debug output */
291  char buffer[512];
292 
293  SetDParamStr(0, grfconfig->GetName());
294  GetString(buffer, part1, lastof(buffer));
295  DEBUG(grf, 0, "%s", buffer + 3);
296 
297  SetDParam(1, engine);
298  GetString(buffer, part2, lastof(buffer));
299  DEBUG(grf, 0, "%s", buffer + 3);
300 }
301 
308 {
309  /* show a warning once for each engine in whole game and once for each GRF after each game load */
310  const Engine *engine = u->GetEngine();
311  uint32 grfid = engine->grf_prop.grffile->grfid;
312  GRFConfig *grfconfig = GetGRFConfig(grfid);
313  if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
314  ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
315  }
316 }
317 
323 {
324  this->type = type;
325  this->coord.left = INVALID_COORD;
326  this->group_id = DEFAULT_GROUP;
327  this->fill_percent_te_id = INVALID_TE_ID;
328  this->first = this;
329  this->colourmap = PAL_NONE;
330  this->cargo_age_counter = 1;
331  this->last_station_visited = INVALID_STATION;
332  this->last_loading_station = INVALID_STATION;
333 }
334 
340 {
341  return GB(Random(), 0, 8);
342 }
343 
344 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
345  * lookup times at the expense of memory usage. */
346 const int HASH_BITS = 7;
347 const int HASH_SIZE = 1 << HASH_BITS;
348 const int HASH_MASK = HASH_SIZE - 1;
349 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
350 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
351 
352 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
353  * Profiling results show that 0 is fastest. */
354 const int HASH_RES = 0;
355 
356 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
357 
358 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
359 {
360  for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
361  for (int x = xl; ; x = (x + 1) & HASH_MASK) {
362  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
363  for (; v != NULL; v = v->hash_tile_next) {
364  Vehicle *a = proc(v, data);
365  if (find_first && a != NULL) return a;
366  }
367  if (x == xu) break;
368  }
369  if (y == yu) break;
370  }
371 
372  return NULL;
373 }
374 
375 
387 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
388 {
389  const int COLL_DIST = 6;
390 
391  /* Hash area to scan is from xl,yl to xu,yu */
392  int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
393  int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
394  int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
395  int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
396 
397  return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
398 }
399 
414 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
415 {
416  VehicleFromPosXY(x, y, data, proc, false);
417 }
418 
430 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
431 {
432  return VehicleFromPosXY(x, y, data, proc, true) != NULL;
433 }
434 
445 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
446 {
447  int x = GB(TileX(tile), HASH_RES, HASH_BITS);
448  int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
449 
450  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
451  for (; v != NULL; v = v->hash_tile_next) {
452  if (v->tile != tile) continue;
453 
454  Vehicle *a = proc(v, data);
455  if (find_first && a != NULL) return a;
456  }
457 
458  return NULL;
459 }
460 
474 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
475 {
476  VehicleFromPos(tile, data, proc, false);
477 }
478 
489 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
490 {
491  return VehicleFromPos(tile, data, proc, true) != NULL;
492 }
493 
500 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
501 {
502  int z = *(int*)data;
503 
504  if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
505  if (v->z_pos > z) return NULL;
506 
507  return v;
508 }
509 
516 {
517  int z = GetTileMaxPixelZ(tile);
518 
519  /* Value v is not safe in MP games, however, it is used to generate a local
520  * error message only (which may be different for different machines).
521  * Such a message does not affect MP synchronisation.
522  */
523  Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
524  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
525  return CommandCost();
526 }
527 
530 {
531  if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
532  if (v == (const Vehicle *)data) return NULL;
533 
534  return v;
535 }
536 
545 {
546  /* Value v is not safe in MP games, however, it is used to generate a local
547  * error message only (which may be different for different machines).
548  * Such a message does not affect MP synchronisation.
549  */
550  Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
551  if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
552 
553  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
554  return CommandCost();
555 }
556 
557 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
558 {
559  TrackBits rail_bits = *(TrackBits *)data;
560 
561  if (v->type != VEH_TRAIN) return NULL;
562 
563  Train *t = Train::From(v);
564  if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
565 
566  return v;
567 }
568 
578 {
579  /* Value v is not safe in MP games, however, it is used to generate a local
580  * error message only (which may be different for different machines).
581  * Such a message does not affect MP synchronisation.
582  */
583  Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
584  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
585  return CommandCost();
586 }
587 
588 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
589 {
590  Vehicle **old_hash = v->hash_tile_current;
591  Vehicle **new_hash;
592 
593  if (remove) {
594  new_hash = NULL;
595  } else {
596  int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
597  int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
598  new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
599  }
600 
601  if (old_hash == new_hash) return;
602 
603  /* Remove from the old position in the hash table */
604  if (old_hash != NULL) {
607  }
608 
609  /* Insert vehicle at beginning of the new position in the hash table */
610  if (new_hash != NULL) {
611  v->hash_tile_next = *new_hash;
613  v->hash_tile_prev = new_hash;
614  *new_hash = v;
615  }
616 
617  /* Remember current hash position */
618  v->hash_tile_current = new_hash;
619 }
620 
621 static Vehicle *_vehicle_viewport_hash[0x1000];
622 
623 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
624 {
625  Vehicle **old_hash, **new_hash;
626  int old_x = v->coord.left;
627  int old_y = v->coord.top;
628 
629  new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
630  old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
631 
632  if (old_hash == new_hash) return;
633 
634  /* remove from hash table? */
635  if (old_hash != NULL) {
638  }
639 
640  /* insert into hash table? */
641  if (new_hash != NULL) {
642  v->hash_viewport_next = *new_hash;
644  v->hash_viewport_prev = new_hash;
645  *new_hash = v;
646  }
647 }
648 
649 void ResetVehicleHash()
650 {
651  Vehicle *v;
652  FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; }
653  memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
654  memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
655 }
656 
657 void ResetVehicleColourMap()
658 {
659  Vehicle *v;
660  FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
661 }
662 
668 static AutoreplaceMap _vehicles_to_autoreplace;
669 
670 void InitializeVehicles()
671 {
672  _vehicles_to_autoreplace.Reset();
673  ResetVehicleHash();
674 }
675 
676 uint CountVehiclesInChain(const Vehicle *v)
677 {
678  uint count = 0;
679  do count++; while ((v = v->Next()) != NULL);
680  return count;
681 }
682 
688 {
689  switch (this->type) {
690  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
691  case VEH_TRAIN:
692  return !this->IsArticulatedPart() && // tenders and other articulated parts
693  !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
694  case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
695  case VEH_SHIP: return true;
696  default: return false; // Only count company buildable vehicles
697  }
698 }
699 
705 {
706  switch (this->type) {
707  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
708  case VEH_TRAIN:
709  case VEH_ROAD:
710  case VEH_SHIP: return true;
711  default: return false;
712  }
713 }
714 
721 {
722  return Engine::Get(this->engine_type);
723 }
724 
730 const GRFFile *Vehicle::GetGRF() const
731 {
732  return this->GetEngine()->GetGRF();
733 }
734 
740 uint32 Vehicle::GetGRFID() const
741 {
742  return this->GetEngine()->GetGRFID();
743 }
744 
752 void Vehicle::HandlePathfindingResult(bool path_found)
753 {
754  if (path_found) {
755  /* Route found, is the vehicle marked with "lost" flag? */
756  if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
757 
758  /* Clear the flag as the PF's problem was solved. */
760  /* Delete the news item. */
761  DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
762  return;
763  }
764 
765  /* Were we already lost? */
766  if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
767 
768  /* It is first time the problem occurred, set the "lost" flag. */
770  /* Notify user about the event. */
771  AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
772  if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
773  SetDParam(0, this->index);
774  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index);
775  }
776 }
777 
780 {
781  if (CleaningPool()) return;
782 
785  st->loading_vehicles.remove(this);
786 
788  this->CancelReservation(INVALID_STATION, st);
789  delete this->cargo_payment;
790  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
791  }
792 
793  if (this->IsEngineCountable()) {
795  if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
797 
800  }
801 
802  if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
803  Aircraft *a = Aircraft::From(this);
805  if (st != NULL) {
806  const AirportFTA *layout = st->airport.GetFTA()->layout;
807  CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
808  }
809  }
810 
811 
812  if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
813  RoadVehicle *v = RoadVehicle::From(this);
814  if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
815  /* Leave the drive through roadstop, when you have not already left it. */
817  }
818  }
819 
820  if (this->Previous() == NULL) {
822  }
823 
824  if (this->IsPrimaryVehicle()) {
832  }
834 
835  this->cargo.Truncate();
836  DeleteVehicleOrders(this);
838 
839  extern void StopGlobalFollowVehicle(const Vehicle *v);
840  StopGlobalFollowVehicle(this);
841 
843 }
844 
846 {
847  if (CleaningPool()) {
848  this->cargo.OnCleanPool();
849  return;
850  }
851 
852  /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
853  * it may happen that vehicle chain is deleted when visible */
854  if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
855 
856  Vehicle *v = this->Next();
857  this->SetNext(NULL);
858 
859  delete v;
860 
861  UpdateVehicleTileHash(this, true);
862  UpdateVehicleViewportHash(this, INVALID_COORD, 0);
865 }
866 
872 {
873  /* Vehicle should stop in the depot if it was in 'stopping' state */
874  _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
875 
876  /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
877  * stopping in the depot, so we stop it to ensure that it will not reserve
878  * the path out of the depot before we might autoreplace it to a different
879  * engine. The new engine would not own the reserved path we store that we
880  * stopped the vehicle, so autoreplace can start it again */
881  v->vehstatus |= VS_STOPPED;
882 }
883 
889 static void RunVehicleDayProc()
890 {
891  if (_game_mode != GM_NORMAL) return;
892 
893  /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
894  for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
895  Vehicle *v = Vehicle::Get(i);
896  if (v == NULL) continue;
897 
898  /* Call the 32-day callback if needed */
899  if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
900  uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
901  if (callback != CALLBACK_FAILED) {
902  if (HasBit(callback, 0)) {
903  TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
904  }
905 
906  /* After a vehicle trigger, the graphics and properties of the vehicle could change.
907  * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
908  if (callback != 0) v->First()->MarkDirty();
909 
910  if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
911  }
912  }
913 
914  /* This is called once per day for each vehicle, but not in the first tick of the day */
915  v->OnNewDay();
916  }
917 }
918 
919 void CallVehicleTicks()
920 {
921  _vehicles_to_autoreplace.Clear();
922 
924 
925  Station *st;
926  FOR_ALL_STATIONS(st) LoadUnloadStation(st);
927 
928  Vehicle *v;
929  FOR_ALL_VEHICLES(v) {
930  /* Vehicle could be deleted in this tick */
931  if (!v->Tick()) {
932  assert(Vehicle::Get(vehicle_index) == NULL);
933  continue;
934  }
935 
936  assert(Vehicle::Get(vehicle_index) == v);
937 
938  switch (v->type) {
939  default: break;
940 
941  case VEH_TRAIN:
942  case VEH_ROAD:
943  case VEH_AIRCRAFT:
944  case VEH_SHIP: {
945  Vehicle *front = v->First();
946 
947  if (v->vcache.cached_cargo_age_period != 0) {
948  v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
949  if (--v->cargo_age_counter == 0) {
950  v->cargo.AgeCargo();
951  v->cargo_age_counter = v->vcache.cached_cargo_age_period;
952  }
953  }
954 
955  /* Do not play any sound when crashed */
956  if (front->vehstatus & VS_CRASHED) continue;
957 
958  /* Do not play any sound when in depot or tunnel */
959  if (v->vehstatus & VS_HIDDEN) continue;
960 
961  /* Do not play any sound when stopped */
962  if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
963 
964  /* Check vehicle type specifics */
965  switch (v->type) {
966  case VEH_TRAIN:
967  if (Train::From(v)->IsWagon()) continue;
968  break;
969 
970  case VEH_ROAD:
971  if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
972  break;
973 
974  case VEH_AIRCRAFT:
975  if (!Aircraft::From(v)->IsNormalAircraft()) continue;
976  break;
977 
978  default:
979  break;
980  }
981 
982  v->motion_counter += front->cur_speed;
983  /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
984  if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
985 
986  /* Play an alternating running sound every 16 ticks */
987  if (GB(v->tick_counter, 0, 4) == 0) {
988  /* Play running sound when speed > 0 and not braking */
989  bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
991  }
992 
993  break;
994  }
995  }
996  }
997 
998  Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
999  for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
1000  v = it->first;
1001  /* Autoreplace needs the current company set as the vehicle owner */
1002  cur_company.Change(v->owner);
1003 
1004  /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1005  * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1006  * they are already leaving the depot again before being replaced. */
1007  if (it->second) v->vehstatus &= ~VS_STOPPED;
1008 
1009  /* Store the position of the effect as the vehicle pointer will become invalid later */
1010  int x = v->x_pos;
1011  int y = v->y_pos;
1012  int z = v->z_pos;
1013 
1016  CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
1018 
1019  if (!IsLocalCompany()) continue;
1020 
1021  if (res.Succeeded()) {
1022  ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1023  continue;
1024  }
1025 
1026  StringID error_message = res.GetErrorMessage();
1027  if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1028 
1029  if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1030 
1031  StringID message;
1032  if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1033  message = error_message;
1034  } else {
1035  message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1036  }
1037 
1038  SetDParam(0, v->index);
1039  SetDParam(1, error_message);
1040  AddVehicleAdviceNewsItem(message, v->index);
1041  }
1042 
1043  cur_company.Restore();
1044 }
1045 
1050 static void DoDrawVehicle(const Vehicle *v)
1051 {
1052  PaletteID pal = PAL_NONE;
1053 
1055 
1056  /* Check whether the vehicle shall be transparent due to the game state */
1057  bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
1058 
1059  if (v->type == VEH_EFFECT) {
1060  /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1061  * However, transparent smoke and bubbles look weird, so always hide them. */
1063  if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1064  }
1065 
1067  for (uint i = 0; i < v->sprite_seq.count; ++i) {
1068  PaletteID pal2 = v->sprite_seq.seq[i].pal;
1069  if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal;
1070  AddSortableSpriteToDraw(v->sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
1071  v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
1072  }
1073  EndSpriteCombine();
1074 }
1075 
1081 {
1082  /* The bounding rectangle */
1083  const int l = dpi->left;
1084  const int r = dpi->left + dpi->width;
1085  const int t = dpi->top;
1086  const int b = dpi->top + dpi->height;
1087 
1088  /* The hash area to scan */
1089  int xl, xu, yl, yu;
1090 
1091  if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
1092  xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
1093  xu = GB(r, 7 + ZOOM_LVL_SHIFT, 6);
1094  } else {
1095  /* scan whole hash row */
1096  xl = 0;
1097  xu = 0x3F;
1098  }
1099 
1100  if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
1101  yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
1102  yu = GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
1103  } else {
1104  /* scan whole column */
1105  yl = 0;
1106  yu = 0x3F << 6;
1107  }
1108 
1109  for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
1110  for (int x = xl;; x = (x + 1) & 0x3F) {
1111  const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1112 
1113  while (v != NULL) {
1114  if (!(v->vehstatus & VS_HIDDEN) &&
1115  l <= v->coord.right &&
1116  t <= v->coord.bottom &&
1117  r >= v->coord.left &&
1118  b >= v->coord.top) {
1119  DoDrawVehicle(v);
1120  }
1121  v = v->hash_viewport_next;
1122  }
1123 
1124  if (x == xu) break;
1125  }
1126 
1127  if (y == yu) break;
1128  }
1129 }
1130 
1138 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
1139 {
1140  Vehicle *found = NULL, *v;
1141  uint dist, best_dist = UINT_MAX;
1142 
1143  if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
1144 
1145  x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
1146  y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
1147 
1148  FOR_ALL_VEHICLES(v) {
1149  if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
1150  x >= v->coord.left && x <= v->coord.right &&
1151  y >= v->coord.top && y <= v->coord.bottom) {
1152 
1153  dist = max(
1154  abs(((v->coord.left + v->coord.right) >> 1) - x),
1155  abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1156  );
1157 
1158  if (dist < best_dist) {
1159  found = v;
1160  best_dist = dist;
1161  }
1162  }
1163  }
1164 
1165  return found;
1166 }
1167 
1173 {
1174  v->value -= v->value >> 8;
1176 }
1177 
1178 static const byte _breakdown_chance[64] = {
1179  3, 3, 3, 3, 3, 3, 3, 3,
1180  4, 4, 5, 5, 6, 6, 7, 7,
1181  8, 8, 9, 9, 10, 10, 11, 11,
1182  12, 13, 13, 13, 13, 14, 15, 16,
1183  17, 19, 21, 25, 28, 31, 34, 37,
1184  40, 44, 48, 52, 56, 60, 64, 68,
1185  72, 80, 90, 100, 110, 120, 130, 140,
1186  150, 170, 190, 210, 230, 250, 250, 250,
1187 };
1188 
1189 void CheckVehicleBreakdown(Vehicle *v)
1190 {
1191  int rel, rel_old;
1192 
1193  /* decrease reliability */
1194  v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1195  if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1196 
1197  if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
1199  v->cur_speed < 5 || _game_mode == GM_MENU) {
1200  return;
1201  }
1202 
1203  uint32 r = Random();
1204 
1205  /* increase chance of failure */
1206  int chance = v->breakdown_chance + 1;
1207  if (Chance16I(1, 25, r)) chance += 25;
1208  v->breakdown_chance = min(255, chance);
1209 
1210  /* calculate reliability value to use in comparison */
1211  rel = v->reliability;
1212  if (v->type == VEH_SHIP) rel += 0x6666;
1213 
1214  /* reduced breakdowns? */
1215  if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1216 
1217  /* check if to break down */
1218  if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
1219  v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1220  v->breakdown_delay = GB(r, 24, 7) + 0x80;
1221  v->breakdown_chance = 0;
1222  }
1223 }
1224 
1232 {
1233  /* Possible states for Vehicle::breakdown_ctr
1234  * 0 - vehicle is running normally
1235  * 1 - vehicle is currently broken down
1236  * 2 - vehicle is going to break down now
1237  * >2 - vehicle is counting down to the actual breakdown event */
1238  switch (this->breakdown_ctr) {
1239  case 0:
1240  return false;
1241 
1242  case 2:
1243  this->breakdown_ctr = 1;
1244 
1245  if (this->breakdowns_since_last_service != 255) {
1247  }
1248 
1249  if (this->type == VEH_AIRCRAFT) {
1250  /* Aircraft just need this flag, the rest is handled elsewhere */
1251  this->vehstatus |= VS_AIRCRAFT_BROKEN;
1252  } else {
1253  this->cur_speed = 0;
1254 
1255  if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1256  bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1257  SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
1258  (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1259  (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
1260  }
1261 
1262  if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
1264  if (u != NULL) u->animation_state = this->breakdown_delay * 2;
1265  }
1266  }
1267 
1268  this->MarkDirty(); // Update graphics after speed is zeroed
1271 
1272  FALLTHROUGH;
1273  case 1:
1274  /* Aircraft breakdowns end only when arriving at the airport */
1275  if (this->type == VEH_AIRCRAFT) return false;
1276 
1277  /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1278  if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1279  if (--this->breakdown_delay == 0) {
1280  this->breakdown_ctr = 0;
1281  this->MarkDirty();
1283  }
1284  }
1285  return true;
1286 
1287  default:
1288  if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1289  return false;
1290  }
1291 }
1292 
1298 {
1299  if (v->age < MAX_DAY) {
1300  v->age++;
1302  }
1303 
1304  if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1305 
1306  int age = v->age - v->max_age;
1307  if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
1308  age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
1309  v->reliability_spd_dec <<= 1;
1310  }
1311 
1313 
1314  /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
1315  if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
1316 
1317  /* Don't warn if a renew is active */
1318  if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
1319 
1320  StringID str;
1321  if (age == -DAYS_IN_LEAP_YEAR) {
1322  str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1323  } else if (age == 0) {
1324  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1325  } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
1326  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1327  } else {
1328  return;
1329  }
1330 
1331  SetDParam(0, v->index);
1333 }
1334 
1344 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1345 {
1346  int count = 0;
1347  int max = 0;
1348  int cars = 0;
1349  int unloading = 0;
1350  bool loading = false;
1351 
1352  bool is_loading = front->current_order.IsType(OT_LOADING);
1353 
1354  /* The station may be NULL when the (colour) string does not need to be set. */
1355  const Station *st = Station::GetIfValid(front->last_station_visited);
1356  assert(colour == NULL || (st != NULL && is_loading));
1357 
1358  bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1359  bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1360 
1361  /* Count up max and used */
1362  for (const Vehicle *v = front; v != NULL; v = v->Next()) {
1363  count += v->cargo.StoredCount();
1364  max += v->cargo_cap;
1365  if (v->cargo_cap != 0 && colour != NULL) {
1366  unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1367  loading |= !order_no_load &&
1368  (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1370  cars++;
1371  }
1372  }
1373 
1374  if (colour != NULL) {
1375  if (unloading == 0 && loading) {
1376  *colour = STR_PERCENT_UP;
1377  } else if (unloading == 0 && !loading) {
1378  *colour = STR_PERCENT_NONE;
1379  } else if (cars == unloading || !loading) {
1380  *colour = STR_PERCENT_DOWN;
1381  } else {
1382  *colour = STR_PERCENT_UP_DOWN;
1383  }
1384  }
1385 
1386  /* Train without capacity */
1387  if (max == 0) return 100;
1388 
1389  /* Return the percentage */
1390  if (count * 2 < max) {
1391  /* Less than 50%; round up, so that 0% means really empty. */
1392  return CeilDiv(count * 100, max);
1393  } else {
1394  /* More than 50%; round down, so that 100% means really full. */
1395  return (count * 100) / max;
1396  }
1397 }
1398 
1404 {
1405  /* Always work with the front of the vehicle */
1406  assert(v == v->First());
1407 
1408  switch (v->type) {
1409  case VEH_TRAIN: {
1410  Train *t = Train::From(v);
1412  /* Clear path reservation */
1413  SetDepotReservation(t->tile, false);
1415 
1417  t->wait_counter = 0;
1418  t->force_proceed = TFP_NONE;
1419  ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1421  break;
1422  }
1423 
1424  case VEH_ROAD:
1426  break;
1427 
1428  case VEH_SHIP: {
1430  Ship *ship = Ship::From(v);
1431  ship->state = TRACK_BIT_DEPOT;
1432  ship->UpdateCache();
1433  ship->UpdateViewport(true, true);
1435  break;
1436  }
1437 
1438  case VEH_AIRCRAFT:
1441  break;
1442  default: NOT_REACHED();
1443  }
1445 
1446  if (v->type != VEH_TRAIN) {
1447  /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1448  * 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 */
1450  }
1452 
1453  v->vehstatus |= VS_HIDDEN;
1454  v->cur_speed = 0;
1455 
1457 
1458  /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1459  TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1460  v->MarkDirty();
1461 
1462  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1464 
1465  const Order *real_order = v->GetOrder(v->cur_real_order_index);
1466 
1467  /* Test whether we are heading for this depot. If not, do nothing.
1468  * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1470  real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1471  (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
1472  /* We are heading for another depot, keep driving. */
1473  return;
1474  }
1475 
1476  if (v->current_order.IsRefit()) {
1477  Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
1478  CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
1479  cur_company.Restore();
1480 
1481  if (cost.Failed()) {
1482  _vehicles_to_autoreplace[v] = false;
1483  if (v->owner == _local_company) {
1484  /* Notify the user that we stopped the vehicle */
1485  SetDParam(0, v->index);
1486  AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
1487  }
1488  } else if (cost.GetCost() != 0) {
1489  v->profit_this_year -= cost.GetCost() << 8;
1490  if (v->owner == _local_company) {
1491  ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
1492  }
1493  }
1494  }
1495 
1497  /* Part of orders */
1499  UpdateVehicleTimetable(v, true);
1501  }
1503  /* Vehicles are always stopped on entering depots. Do not restart this one. */
1504  _vehicles_to_autoreplace[v] = false;
1505  /* Invalidate last_loading_station. As the link from the station
1506  * before the stop to the station after the stop can't be predicted
1507  * we shouldn't construct it when the vehicle visits the next stop. */
1508  v->last_loading_station = INVALID_STATION;
1509  if (v->owner == _local_company) {
1510  SetDParam(0, v->index);
1511  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1512  }
1513  AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1514  }
1515  v->current_order.MakeDummy();
1516  }
1517 }
1518 
1519 
1525 {
1526  UpdateVehicleTileHash(this, false);
1527 }
1528 
1534 void Vehicle::UpdateViewport(bool dirty)
1535 {
1536  Rect new_coord;
1537  this->sprite_seq.GetBounds(&new_coord);
1538 
1539  Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1540  new_coord.left += pt.x;
1541  new_coord.top += pt.y;
1542  new_coord.right += pt.x + 2 * ZOOM_LVL_BASE;
1543  new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
1544 
1545  UpdateVehicleViewportHash(this, new_coord.left, new_coord.top);
1546 
1547  Rect old_coord = this->coord;
1548  this->coord = new_coord;
1549 
1550  if (dirty) {
1551  if (old_coord.left == INVALID_COORD) {
1552  this->MarkAllViewportsDirty();
1553  } else {
1555  min(old_coord.left, this->coord.left),
1556  min(old_coord.top, this->coord.top),
1557  max(old_coord.right, this->coord.right),
1558  max(old_coord.bottom, this->coord.bottom));
1559  }
1560  }
1561 }
1562 
1567 {
1568  this->UpdatePosition();
1569  this->UpdateViewport(true);
1570 }
1571 
1576 {
1577  ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1578 }
1579 
1586 {
1587  static const int8 _delta_coord[16] = {
1588  -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1589  -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1590  };
1591 
1592  int x = v->x_pos + _delta_coord[v->direction];
1593  int y = v->y_pos + _delta_coord[v->direction + 8];
1594 
1596  gp.x = x;
1597  gp.y = y;
1598  gp.old_tile = v->tile;
1599  gp.new_tile = TileVirtXY(x, y);
1600  return gp;
1601 }
1602 
1603 static const Direction _new_direction_table[] = {
1604  DIR_N, DIR_NW, DIR_W,
1605  DIR_NE, DIR_SE, DIR_SW,
1606  DIR_E, DIR_SE, DIR_S
1607 };
1608 
1609 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1610 {
1611  int i = 0;
1612 
1613  if (y >= v->y_pos) {
1614  if (y != v->y_pos) i += 3;
1615  i += 3;
1616  }
1617 
1618  if (x >= v->x_pos) {
1619  if (x != v->x_pos) i++;
1620  i++;
1621  }
1622 
1623  Direction dir = v->direction;
1624 
1625  DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1626  if (dirdiff == DIRDIFF_SAME) return dir;
1627  return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1628 }
1629 
1640 {
1641  return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1642 }
1643 
1651 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
1652 {
1653  /* Find maximum */
1654  const Vehicle *v;
1655  FOR_ALL_VEHICLES(v) {
1656  if (v->type == type && v->owner == owner) {
1657  this->maxid = max<UnitID>(this->maxid, v->unitnumber);
1658  }
1659  }
1660 
1661  if (this->maxid == 0) return;
1662 
1663  /* Reserving 'maxid + 2' because we need:
1664  * - space for the last item (with v->unitnumber == maxid)
1665  * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
1666  this->cache = CallocT<bool>(this->maxid + 2);
1667 
1668  /* Fill the cache */
1669  FOR_ALL_VEHICLES(v) {
1670  if (v->type == type && v->owner == owner) {
1671  this->cache[v->unitnumber] = true;
1672  }
1673  }
1674 }
1675 
1678 {
1679  if (this->maxid <= this->curid) return ++this->curid;
1680 
1681  while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
1682 
1683  return this->curid;
1684 }
1685 
1692 {
1693  /* Check whether it is allowed to build another vehicle. */
1694  uint max_veh;
1695  switch (type) {
1696  case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1697  case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1698  case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1699  case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1700  default: NOT_REACHED();
1701  }
1702 
1704  if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1705 
1707 
1708  return gen.NextID();
1709 }
1710 
1711 
1721 {
1722  assert(IsCompanyBuildableVehicleType(type));
1723 
1724  if (!Company::IsValidID(_local_company)) return false;
1726 
1727  UnitID max;
1728  switch (type) {
1729  case VEH_TRAIN: max = _settings_game.vehicle.max_trains; break;
1730  case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break;
1731  case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1732  case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1733  default: NOT_REACHED();
1734  }
1735 
1736  /* We can build vehicle infrastructure when we may build the vehicle type */
1737  if (max > 0) {
1738  /* Can we actually build the vehicle type? */
1739  const Engine *e;
1740  FOR_ALL_ENGINES_OF_TYPE(e, type) {
1741  if (HasBit(e->company_avail, _local_company)) return true;
1742  }
1743  return false;
1744  }
1745 
1746  /* We should be able to build infrastructure when we have the actual vehicle type */
1747  const Vehicle *v;
1748  FOR_ALL_VEHICLES(v) {
1749  if (v->owner == _local_company && v->type == type) return true;
1750  }
1751 
1752  return false;
1753 }
1754 
1755 
1763 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1764 {
1765  CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
1766  const Engine *e = Engine::Get(engine_type);
1767  switch (e->type) {
1768  default: NOT_REACHED();
1769  case VEH_TRAIN:
1770  if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1771  /* Wagonoverrides use the colour scheme of the front engine.
1772  * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1773  engine_type = parent_engine_type;
1774  e = Engine::Get(engine_type);
1775  /* Note: Luckily cargo_type is not needed for engines */
1776  }
1777 
1778  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1779  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1780  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1781  if (!CargoSpec::Get(cargo_type)->is_freight) {
1782  if (parent_engine_type == INVALID_ENGINE) {
1783  return LS_PASSENGER_WAGON_STEAM;
1784  } else {
1785  switch (RailVehInfo(parent_engine_type)->engclass) {
1786  default: NOT_REACHED();
1787  case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1788  case EC_DIESEL: return LS_PASSENGER_WAGON_DIESEL;
1789  case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
1790  case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1791  case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1792  }
1793  }
1794  } else {
1795  return LS_FREIGHT_WAGON;
1796  }
1797  } else {
1798  bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
1799 
1800  switch (e->u.rail.engclass) {
1801  default: NOT_REACHED();
1802  case EC_STEAM: return LS_STEAM;
1803  case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
1804  case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1805  case EC_MONORAIL: return LS_MONORAIL;
1806  case EC_MAGLEV: return LS_MAGLEV;
1807  }
1808  }
1809 
1810  case VEH_ROAD:
1811  /* Always use the livery of the front */
1812  if (v != NULL && parent_engine_type != INVALID_ENGINE) {
1813  engine_type = parent_engine_type;
1814  e = Engine::Get(engine_type);
1815  cargo_type = v->First()->cargo_type;
1816  }
1817  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1818  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1819 
1820  /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
1821  if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
1822  /* Tram */
1823  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
1824  } else {
1825  /* Bus or truck */
1826  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
1827  }
1828 
1829  case VEH_SHIP:
1830  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1831  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1832  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
1833 
1834  case VEH_AIRCRAFT:
1835  switch (e->u.air.subtype) {
1836  case AIR_HELI: return LS_HELICOPTER;
1837  case AIR_CTOL: return LS_SMALL_PLANE;
1838  case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
1839  default: NOT_REACHED();
1840  }
1841  }
1842 }
1843 
1853 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
1854 {
1855  const Company *c = Company::Get(company);
1856  LiveryScheme scheme = LS_DEFAULT;
1857 
1858  /* The default livery is always available for use, but its in_use flag determines
1859  * whether any _other_ liveries are in use. */
1860  if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
1861  /* Determine the livery scheme to use */
1862  scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
1863 
1864  /* Switch back to the default scheme if the resolved scheme is not in use */
1865  if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
1866  }
1867 
1868  return &c->livery[scheme];
1869 }
1870 
1871 
1872 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
1873 {
1874  PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
1875 
1876  /* Return cached value if any */
1877  if (map != PAL_NONE) return map;
1878 
1879  const Engine *e = Engine::Get(engine_type);
1880 
1881  /* Check if we should use the colour map callback */
1883  uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
1884  /* Failure means "use the default two-colour" */
1885  if (callback != CALLBACK_FAILED) {
1886  assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
1887  map = GB(callback, 0, 14);
1888  /* If bit 14 is set, then the company colours are applied to the
1889  * map else it's returned as-is. */
1890  if (!HasBit(callback, 14)) {
1891  /* Update cache */
1892  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1893  return map;
1894  }
1895  }
1896  }
1897 
1898  bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
1899 
1900  if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
1901 
1902  /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
1903  if (!Company::IsValidID(company)) return map;
1904 
1905  const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
1906 
1907  map += livery->colour1;
1908  if (twocc) map += livery->colour2 * 16;
1909 
1910  /* Update cache */
1911  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1912  return map;
1913 }
1914 
1922 {
1923  return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
1924 }
1925 
1932 {
1933  if (v->IsGroundVehicle()) {
1934  return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
1935  }
1936 
1937  return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
1938 }
1939 
1944 {
1945  if (this->IsGroundVehicle()) {
1946  uint16 &gv_flags = this->GetGroundVehicleFlags();
1947  if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
1948  /* Do not delete orders, only skip them */
1951  InvalidateVehicleOrder(this, 0);
1952  return;
1953  }
1954  }
1955 
1956  const Order *order = this->GetOrder(this->cur_implicit_order_index);
1957  while (order != NULL) {
1958  if (this->cur_implicit_order_index == this->cur_real_order_index) break;
1959 
1960  if (order->IsType(OT_IMPLICIT)) {
1962  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
1963  order = this->GetOrder(this->cur_implicit_order_index);
1964  } else {
1965  /* Skip non-implicit orders, e.g. service-orders */
1966  order = order->next;
1967  this->cur_implicit_order_index++;
1968  }
1969 
1970  /* Wrap around */
1971  if (order == NULL) {
1972  order = this->GetOrder(0);
1973  this->cur_implicit_order_index = 0;
1974  }
1975  }
1976 }
1977 
1983 {
1984  assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
1985 
1986  if (this->current_order.IsType(OT_GOTO_STATION) &&
1989 
1990  /* Now both order indices point to the destination station, and we can start loading */
1991  this->current_order.MakeLoading(true);
1992  UpdateVehicleTimetable(this, true);
1993 
1994  /* Furthermore add the Non Stop flag to mark that this station
1995  * is the actual destination of the vehicle, which is (for example)
1996  * necessary to be known for HandleTrainLoading to determine
1997  * whether the train is lost or not; not marking a train lost
1998  * that arrives at random stations is bad. */
2000 
2001  } else {
2002  /* We weren't scheduled to stop here. Insert an implicit order
2003  * to show that we are stopping here.
2004  * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2005  * the 'wrong' terminal when skipping orders etc. */
2006  Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2007  if (this->IsGroundVehicle() &&
2008  (in_list == NULL || !in_list->IsType(OT_IMPLICIT) ||
2009  in_list->GetDestination() != this->last_station_visited)) {
2010  bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2011  /* Do not create consecutive duplicates of implicit orders */
2012  Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
2013  if (prev_order == NULL ||
2014  (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2015  prev_order->GetDestination() != this->last_station_visited) {
2016 
2017  /* Prefer deleting implicit orders instead of inserting new ones,
2018  * so test whether the right order follows later. In case of only
2019  * implicit orders treat the last order in the list like an
2020  * explicit one, except if the overall number of orders surpasses
2021  * IMPLICIT_ORDER_ONLY_CAP. */
2022  int target_index = this->cur_implicit_order_index;
2023  bool found = false;
2024  while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2025  const Order *order = this->GetOrder(target_index);
2026  if (order == NULL) break; // No orders.
2027  if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2028  found = true;
2029  break;
2030  }
2031  target_index++;
2032  if (target_index >= this->orders.list->GetNumOrders()) {
2033  if (this->GetNumManualOrders() == 0 &&
2035  break;
2036  }
2037  target_index = 0;
2038  }
2039  if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2040  }
2041 
2042  if (found) {
2043  if (suppress_implicit_orders) {
2044  /* Skip to the found order */
2045  this->cur_implicit_order_index = target_index;
2046  InvalidateVehicleOrder(this, 0);
2047  } else {
2048  /* Delete all implicit orders up to the station we just reached */
2049  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2050  while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2051  if (order->IsType(OT_IMPLICIT)) {
2053  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2054  order = this->GetOrder(this->cur_implicit_order_index);
2055  } else {
2056  /* Skip non-implicit orders, e.g. service-orders */
2057  order = order->next;
2058  this->cur_implicit_order_index++;
2059  }
2060 
2061  /* Wrap around */
2062  if (order == NULL) {
2063  order = this->GetOrder(0);
2064  this->cur_implicit_order_index = 0;
2065  }
2066  assert(order != NULL);
2067  }
2068  }
2069  } else if (!suppress_implicit_orders &&
2070  ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2072  /* Insert new implicit order */
2073  Order *implicit_order = new Order();
2074  implicit_order->MakeImplicit(this->last_station_visited);
2075  InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2076  if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2077 
2078  /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2079  * Reenable it for this vehicle */
2080  uint16 &gv_flags = this->GetGroundVehicleFlags();
2082  }
2083  }
2084  }
2085  this->current_order.MakeLoading(false);
2086  }
2087 
2088  if (this->last_loading_station != INVALID_STATION &&
2089  this->last_loading_station != this->last_station_visited &&
2090  ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2091  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2093  }
2094 
2095  PrepareUnload(this);
2096 
2101 
2102  Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2103  this->cur_speed = 0;
2104  this->MarkDirty();
2105 }
2106 
2112 void Vehicle::CancelReservation(StationID next, Station *st)
2113 {
2114  for (Vehicle *v = this; v != NULL; v = v->next) {
2116  if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2117  DEBUG(misc, 1, "cancelling cargo reservation");
2118  cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
2119  cargo.SetTransferLoadPlace(st->xy);
2120  }
2121  cargo.KeepAll();
2122  }
2123 }
2124 
2130 {
2131  assert(this->current_order.IsType(OT_LOADING));
2132 
2133  delete this->cargo_payment;
2134  assert(this->cargo_payment == NULL); // cleared by ~CargoPayment
2135 
2136  /* Only update the timetable if the vehicle was supposed to stop here. */
2138 
2139  if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2140  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2141  if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
2142  /* Refresh next hop stats to make sure we've done that at least once
2143  * during the stop and that refit_cap == cargo_cap for each vehicle in
2144  * the consist. */
2145  this->ResetRefitCaps();
2146  LinkRefresher::Run(this);
2147 
2148  /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2150  } else {
2151  /* if the vehicle couldn't load and had to unload or transfer everything
2152  * set the last loading station to invalid as it will leave empty. */
2153  this->last_loading_station = INVALID_STATION;
2154  }
2155  }
2156 
2159  this->CancelReservation(INVALID_STATION, st);
2160  st->loading_vehicles.remove(this);
2161 
2164 
2165  if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2166  /* Trigger station animation (trains only) */
2167  if (IsTileType(this->tile, MP_STATION)) {
2169  TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2170  }
2171 
2172  SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2173  }
2174 
2175  this->MarkDirty();
2176 }
2177 
2182 {
2183  for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
2184 }
2185 
2191 void Vehicle::HandleLoading(bool mode)
2192 {
2193  switch (this->current_order.GetType()) {
2194  case OT_LOADING: {
2195  uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2196 
2197  /* Not the first call for this tick, or still loading */
2198  if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2199 
2200  this->PlayLeaveStationSound();
2201 
2202  this->LeaveStation();
2203 
2204  /* Only advance to next order if we just loaded at the current one */
2205  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2206  if (order == NULL ||
2207  (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2208  order->GetDestination() != this->last_station_visited) {
2209  return;
2210  }
2211  break;
2212  }
2213 
2214  case OT_DUMMY: break;
2215 
2216  default: return;
2217  }
2218 
2220 }
2221 
2227 {
2228  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2229  if (v->cargo_cap == 0) continue;
2230  SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2231  if (pair == capacities.End()) {
2232  pair = capacities.Append();
2233  pair->first = v->cargo_type;
2234  pair->second = v->cargo_cap - v->cargo.StoredCount();
2235  } else {
2236  pair->second += v->cargo_cap - v->cargo.StoredCount();
2237  }
2238  }
2239 }
2240 
2241 uint Vehicle::GetConsistTotalCapacity() const
2242 {
2243  uint result = 0;
2244  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2245  result += v->cargo_cap;
2246  }
2247  return result;
2248 }
2249 
2257 {
2258  CommandCost ret = CheckOwnership(this->owner);
2259  if (ret.Failed()) return ret;
2260 
2261  if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2262  if (this->IsStoppedInDepot()) return CMD_ERROR;
2263 
2264  if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2265  bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2266  if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2267  /* We called with a different DEPOT_SERVICE setting.
2268  * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2269  * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2270  if (flags & DC_EXEC) {
2274  }
2275  return CommandCost();
2276  }
2277 
2278  if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
2279  if (flags & DC_EXEC) {
2280  /* If the orders to 'goto depot' are in the orders list (forced servicing),
2281  * then skip to the next order; effectively cancelling this forced service */
2283 
2284  if (this->IsGroundVehicle()) {
2285  uint16 &gv_flags = this->GetGroundVehicleFlags();
2287  }
2288 
2289  this->current_order.MakeDummy();
2291  }
2292  return CommandCost();
2293  }
2294 
2295  TileIndex location;
2296  DestinationID destination;
2297  bool reverse;
2298  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};
2299  if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2300 
2301  if (flags & DC_EXEC) {
2302  if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2303 
2304  if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2305  uint16 &gv_flags = this->GetGroundVehicleFlags();
2307  }
2308 
2309  this->dest_tile = location;
2310  this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2311  if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2313 
2314  /* If there is no depot in front, reverse automatically (trains only) */
2315  if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2316 
2317  if (this->type == VEH_AIRCRAFT) {
2318  Aircraft *a = Aircraft::From(this);
2319  if (a->state == FLYING && a->targetairport != destination) {
2320  /* The aircraft is now heading for a different hangar than the next in the orders */
2323  }
2324  }
2325  }
2326 
2327  return CommandCost();
2328 
2329 }
2330 
2335 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2336 {
2337  bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2338  const Engine *e = this->GetEngine();
2339 
2340  /* Evaluate properties */
2341  byte visual_effect;
2342  switch (e->type) {
2343  case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2344  case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2345  case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2346  default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2347  }
2348 
2349  /* Check powered wagon / visual effect callback */
2351  uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2352 
2353  if (callback != CALLBACK_FAILED) {
2354  if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2355 
2356  callback = GB(callback, 0, 8);
2357  /* Avoid accidentally setting 'visual_effect' to the default value
2358  * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2359  if (callback == VE_DEFAULT) {
2360  assert(HasBit(callback, VE_DISABLE_EFFECT));
2361  SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2362  }
2363  visual_effect = callback;
2364  }
2365  }
2366 
2367  /* Apply default values */
2368  if (visual_effect == VE_DEFAULT ||
2369  (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2370  /* Only train engines have default effects.
2371  * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2372  if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2373  if (visual_effect == VE_DEFAULT) {
2374  visual_effect = 1 << VE_DISABLE_EFFECT;
2375  } else {
2376  SetBit(visual_effect, VE_DISABLE_EFFECT);
2377  }
2378  } else {
2379  if (visual_effect == VE_DEFAULT) {
2380  /* Also set the offset */
2381  visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2382  }
2383  SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2384  }
2385  }
2386 
2387  this->vcache.cached_vis_effect = visual_effect;
2388 
2389  if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2391  ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2392  }
2393 }
2394 
2395 static const int8 _vehicle_smoke_pos[8] = {
2396  1, 1, 1, 0, -1, -1, -1, 0
2397 };
2398 
2403 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2404 {
2405  uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2406  if (callback == CALLBACK_FAILED) return;
2407 
2408  uint count = GB(callback, 0, 2);
2409  bool auto_center = HasBit(callback, 13);
2410  bool auto_rotate = !HasBit(callback, 14);
2411 
2412  int8 l_center = 0;
2413  if (auto_center) {
2414  /* For road vehicles: Compute offset from vehicle position to vehicle center */
2415  if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2416  } else {
2417  /* For trains: Compute offset from vehicle position to sprite position */
2418  if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2419  }
2420 
2421  Direction l_dir = v->direction;
2422  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2423  Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2424 
2425  int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2426  int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2427 
2428  for (uint i = 0; i < count; i++) {
2429  uint32 reg = GetRegister(0x100 + i);
2430  uint type = GB(reg, 0, 8);
2431  int8 x = GB(reg, 8, 8);
2432  int8 y = GB(reg, 16, 8);
2433  int8 z = GB(reg, 24, 8);
2434 
2435  if (auto_rotate) {
2436  int8 l = x;
2437  int8 t = y;
2438  x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2439  y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2440  }
2441 
2442  if (type >= 0xF0) {
2443  switch (type) {
2444  case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2445  case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2446  case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2447  case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2448  default: break;
2449  }
2450  }
2451  }
2452 }
2453 
2459 {
2460  assert(this->IsPrimaryVehicle());
2461  bool sound = false;
2462 
2463  /* Do not show any smoke when:
2464  * - vehicle smoke is disabled by the player
2465  * - the vehicle is slowing down or stopped (by the player)
2466  * - the vehicle is moving very slowly
2467  */
2468  if (_settings_game.vehicle.smoke_amount == 0 ||
2469  this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2470  this->cur_speed < 2) {
2471  return;
2472  }
2473 
2474  /* Use the speed as limited by underground and orders. */
2475  uint max_speed = this->GetCurrentMaxSpeed();
2476 
2477  if (this->type == VEH_TRAIN) {
2478  const Train *t = Train::From(this);
2479  /* For trains, do not show any smoke when:
2480  * - the train is reversing
2481  * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2482  */
2483  if (HasBit(t->flags, VRF_REVERSING) ||
2485  t->cur_speed >= max_speed)) {
2486  return;
2487  }
2488  }
2489 
2490  const Vehicle *v = this;
2491 
2492  do {
2493  bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2495  VisualEffectSpawnModel effect_model = VESM_NONE;
2496  if (advanced) {
2497  effect_offset = VE_OFFSET_CENTRE;
2499  if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2500  } else {
2502  assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2503  assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2504  assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2505  assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2506  }
2507 
2508  /* Show no smoke when:
2509  * - Smoke has been disabled for this vehicle
2510  * - The vehicle is not visible
2511  * - The vehicle is under a bridge
2512  * - The vehicle is on a depot tile
2513  * - The vehicle is on a tunnel tile
2514  * - The vehicle is a train engine that is currently unpowered */
2515  if (effect_model == VESM_NONE ||
2516  v->vehstatus & VS_HIDDEN ||
2517  IsBridgeAbove(v->tile) ||
2518  IsDepotTile(v->tile) ||
2519  IsTunnelTile(v->tile) ||
2520  (v->type == VEH_TRAIN &&
2521  !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2522  continue;
2523  }
2524 
2525  EffectVehicleType evt = EV_END;
2526  switch (effect_model) {
2527  case VESM_STEAM:
2528  /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2529  * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2530  * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2531  * REGULATION:
2532  * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2533  if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2534  evt = EV_STEAM_SMOKE;
2535  }
2536  break;
2537 
2538  case VESM_DIESEL: {
2539  /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2540  * when smoke emission stops.
2541  * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2542  * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2543  * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2544  * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2545  * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2546  * maximum speed no diesel_smoke is emitted.
2547  * REGULATION:
2548  * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2549  * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2550  int power_weight_effect = 0;
2551  if (v->type == VEH_TRAIN) {
2552  power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2553  }
2554  if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2555  Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2556  evt = EV_DIESEL_SMOKE;
2557  }
2558  break;
2559  }
2560 
2561  case VESM_ELECTRIC:
2562  /* Electric train's spark - more often occurs when train is departing (more load)
2563  * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2564  * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2565  * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2566  * REGULATION:
2567  * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2568  if (GB(v->tick_counter, 0, 2) == 0 &&
2569  Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2570  evt = EV_ELECTRIC_SPARK;
2571  }
2572  break;
2573 
2574  default:
2575  NOT_REACHED();
2576  }
2577 
2578  if (evt != EV_END && advanced) {
2579  sound = true;
2581  } else if (evt != EV_END) {
2582  sound = true;
2583 
2584  /* The effect offset is relative to a point 4 units behind the vehicle's
2585  * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2586  * correction factor. */
2587  if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2588 
2589  int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2590  int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2591 
2592  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2593  x = -x;
2594  y = -y;
2595  }
2596 
2597  CreateEffectVehicleRel(v, x, y, 10, evt);
2598  }
2599  } while ((v = v->Next()) != NULL);
2600 
2601  if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2602 }
2603 
2609 {
2610  assert(this != next);
2611 
2612  if (this->next != NULL) {
2613  /* We had an old next vehicle. Update the first and previous pointers */
2614  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2615  v->first = this->next;
2616  }
2617  this->next->previous = NULL;
2618  }
2619 
2620  this->next = next;
2621 
2622  if (this->next != NULL) {
2623  /* A new next vehicle. Update the first and previous pointers */
2624  if (this->next->previous != NULL) this->next->previous->next = NULL;
2625  this->next->previous = this;
2626  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2627  v->first = this->first;
2628  }
2629  }
2630 }
2631 
2637 void Vehicle::AddToShared(Vehicle *shared_chain)
2638 {
2639  assert(this->previous_shared == NULL && this->next_shared == NULL);
2640 
2641  if (shared_chain->orders.list == NULL) {
2642  assert(shared_chain->previous_shared == NULL);
2643  assert(shared_chain->next_shared == NULL);
2644  this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
2645  }
2646 
2647  this->next_shared = shared_chain->next_shared;
2648  this->previous_shared = shared_chain;
2649 
2650  shared_chain->next_shared = this;
2651 
2652  if (this->next_shared != NULL) this->next_shared->previous_shared = this;
2653 
2654  shared_chain->orders.list->AddVehicle(this);
2655 }
2656 
2661 {
2662  /* Remember if we were first and the old window number before RemoveVehicle()
2663  * as this changes first if needed. */
2664  bool were_first = (this->FirstShared() == this);
2665  VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2666 
2667  this->orders.list->RemoveVehicle(this);
2668 
2669  if (!were_first) {
2670  /* We are not the first shared one, so only relink our previous one. */
2671  this->previous_shared->next_shared = this->NextShared();
2672  }
2673 
2674  if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
2675 
2676 
2677  if (this->orders.list->GetNumVehicles() == 1) {
2678  /* When there is only one vehicle, remove the shared order list window. */
2681  } else if (were_first) {
2682  /* If we were the first one, update to the new first one.
2683  * Note: FirstShared() is already the new first */
2684  InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2685  }
2686 
2687  this->next_shared = NULL;
2688  this->previous_shared = NULL;
2689 }
2690 
2691 void VehiclesYearlyLoop()
2692 {
2693  Vehicle *v;
2694  FOR_ALL_VEHICLES(v) {
2695  if (v->IsPrimaryVehicle()) {
2696  /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2697  Money profit = v->GetDisplayProfitThisYear();
2698  if (v->age >= 730 && profit < 0) {
2700  SetDParam(0, v->index);
2701  SetDParam(1, profit);
2702  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2703  }
2704  AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2705  }
2706 
2708  v->profit_this_year = 0;
2710  }
2711  }
2717 }
2718 
2719 
2729 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2730 {
2731  const Engine *e = Engine::GetIfValid(engine_type);
2732  assert(e != NULL);
2733 
2734  switch (e->type) {
2735  case VEH_TRAIN:
2736  return (st->facilities & FACIL_TRAIN) != 0;
2737 
2738  case VEH_ROAD:
2739  /* For road vehicles we need the vehicle to know whether it can actually
2740  * use the station, but if it doesn't have facilities for RVs it is
2741  * certainly not possible that the station can be used. */
2742  return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2743 
2744  case VEH_SHIP:
2745  return (st->facilities & FACIL_DOCK) != 0;
2746 
2747  case VEH_AIRCRAFT:
2748  return (st->facilities & FACIL_AIRPORT) != 0 &&
2750 
2751  default:
2752  return false;
2753  }
2754 }
2755 
2762 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2763 {
2764  if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
2765 
2766  return CanVehicleUseStation(v->engine_type, st);
2767 }
2768 
2775 {
2776  assert(this->IsGroundVehicle());
2777  if (this->type == VEH_TRAIN) {
2778  return &Train::From(this)->gcache;
2779  } else {
2780  return &RoadVehicle::From(this)->gcache;
2781  }
2782 }
2783 
2790 {
2791  assert(this->IsGroundVehicle());
2792  if (this->type == VEH_TRAIN) {
2793  return &Train::From(this)->gcache;
2794  } else {
2795  return &RoadVehicle::From(this)->gcache;
2796  }
2797 }
2798 
2805 {
2806  assert(this->IsGroundVehicle());
2807  if (this->type == VEH_TRAIN) {
2808  return Train::From(this)->gv_flags;
2809  } else {
2810  return RoadVehicle::From(this)->gv_flags;
2811  }
2812 }
2813 
2819 const uint16 &Vehicle::GetGroundVehicleFlags() const
2820 {
2821  assert(this->IsGroundVehicle());
2822  if (this->type == VEH_TRAIN) {
2823  return Train::From(this)->gv_flags;
2824  } else {
2825  return RoadVehicle::From(this)->gv_flags;
2826  }
2827 }
2828 
2837 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2838 {
2839  if (v->type == VEH_TRAIN) {
2840  Train *u = Train::From(v);
2841  /* Only include whole vehicles, so start with the first articulated part */
2842  u = u->GetFirstEnginePart();
2843 
2844  /* Include num_vehicles vehicles, not counting articulated parts */
2845  for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2846  do {
2847  /* Include current vehicle in the selection. */
2848  set.Include(u->index);
2849 
2850  /* If the vehicle is multiheaded, add the other part too. */
2851  if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
2852 
2853  u = u->Next();
2854  } while (u != NULL && u->IsArticulatedPart());
2855  }
2856  }
2857 }