OpenTTD
vehicle.cpp
Go to the documentation of this file.
1 /* $Id: vehicle.cpp 27668 2016-10-16 14:59:44Z 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 #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  /* FALL THROUGH */
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 
2163 
2164  if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2165  /* Trigger station animation (trains only) */
2166  if (IsTileType(this->tile, MP_STATION)) {
2168  TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2169  }
2170 
2171  SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2172  }
2173 
2174  this->MarkDirty();
2175 }
2176 
2181 {
2182  for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
2183 }
2184 
2190 void Vehicle::HandleLoading(bool mode)
2191 {
2192  switch (this->current_order.GetType()) {
2193  case OT_LOADING: {
2194  uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2195 
2196  /* Not the first call for this tick, or still loading */
2197  if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2198 
2199  this->PlayLeaveStationSound();
2200 
2201  this->LeaveStation();
2202 
2203  /* Only advance to next order if we just loaded at the current one */
2204  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2205  if (order == NULL ||
2206  (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2207  order->GetDestination() != this->last_station_visited) {
2208  return;
2209  }
2210  break;
2211  }
2212 
2213  case OT_DUMMY: break;
2214 
2215  default: return;
2216  }
2217 
2219 }
2220 
2226 {
2227  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2228  if (v->cargo_cap == 0) continue;
2229  SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2230  if (pair == capacities.End()) {
2231  pair = capacities.Append();
2232  pair->first = v->cargo_type;
2233  pair->second = v->cargo_cap - v->cargo.StoredCount();
2234  } else {
2235  pair->second += v->cargo_cap - v->cargo.StoredCount();
2236  }
2237  }
2238 }
2239 
2240 uint Vehicle::GetConsistTotalCapacity() const
2241 {
2242  uint result = 0;
2243  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2244  result += v->cargo_cap;
2245  }
2246  return result;
2247 }
2248 
2256 {
2257  CommandCost ret = CheckOwnership(this->owner);
2258  if (ret.Failed()) return ret;
2259 
2260  if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2261  if (this->IsStoppedInDepot()) return CMD_ERROR;
2262 
2263  if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2264  bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2265  if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2266  /* We called with a different DEPOT_SERVICE setting.
2267  * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2268  * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2269  if (flags & DC_EXEC) {
2273  }
2274  return CommandCost();
2275  }
2276 
2277  if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
2278  if (flags & DC_EXEC) {
2279  /* If the orders to 'goto depot' are in the orders list (forced servicing),
2280  * then skip to the next order; effectively cancelling this forced service */
2282 
2283  if (this->IsGroundVehicle()) {
2284  uint16 &gv_flags = this->GetGroundVehicleFlags();
2286  }
2287 
2288  this->current_order.MakeDummy();
2290  }
2291  return CommandCost();
2292  }
2293 
2294  TileIndex location;
2295  DestinationID destination;
2296  bool reverse;
2297  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};
2298  if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2299 
2300  if (flags & DC_EXEC) {
2301  if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2302 
2303  if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2304  uint16 &gv_flags = this->GetGroundVehicleFlags();
2306  }
2307 
2308  this->dest_tile = location;
2309  this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2310  if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2312 
2313  /* If there is no depot in front, reverse automatically (trains only) */
2314  if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2315 
2316  if (this->type == VEH_AIRCRAFT) {
2317  Aircraft *a = Aircraft::From(this);
2318  if (a->state == FLYING && a->targetairport != destination) {
2319  /* The aircraft is now heading for a different hangar than the next in the orders */
2322  }
2323  }
2324  }
2325 
2326  return CommandCost();
2327 
2328 }
2329 
2334 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2335 {
2336  bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2337  const Engine *e = this->GetEngine();
2338 
2339  /* Evaluate properties */
2340  byte visual_effect;
2341  switch (e->type) {
2342  case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2343  case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2344  case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2345  default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2346  }
2347 
2348  /* Check powered wagon / visual effect callback */
2350  uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2351 
2352  if (callback != CALLBACK_FAILED) {
2353  if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2354 
2355  callback = GB(callback, 0, 8);
2356  /* Avoid accidentally setting 'visual_effect' to the default value
2357  * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2358  if (callback == VE_DEFAULT) {
2359  assert(HasBit(callback, VE_DISABLE_EFFECT));
2360  SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2361  }
2362  visual_effect = callback;
2363  }
2364  }
2365 
2366  /* Apply default values */
2367  if (visual_effect == VE_DEFAULT ||
2368  (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2369  /* Only train engines have default effects.
2370  * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2371  if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2372  if (visual_effect == VE_DEFAULT) {
2373  visual_effect = 1 << VE_DISABLE_EFFECT;
2374  } else {
2375  SetBit(visual_effect, VE_DISABLE_EFFECT);
2376  }
2377  } else {
2378  if (visual_effect == VE_DEFAULT) {
2379  /* Also set the offset */
2380  visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2381  }
2382  SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2383  }
2384  }
2385 
2386  this->vcache.cached_vis_effect = visual_effect;
2387 
2388  if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2390  ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2391  }
2392 }
2393 
2394 static const int8 _vehicle_smoke_pos[8] = {
2395  1, 1, 1, 0, -1, -1, -1, 0
2396 };
2397 
2402 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2403 {
2404  uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2405  if (callback == CALLBACK_FAILED) return;
2406 
2407  uint count = GB(callback, 0, 2);
2408  bool auto_center = HasBit(callback, 13);
2409  bool auto_rotate = !HasBit(callback, 14);
2410 
2411  int8 l_center = 0;
2412  if (auto_center) {
2413  /* For road vehicles: Compute offset from vehicle position to vehicle center */
2414  if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2415  } else {
2416  /* For trains: Compute offset from vehicle position to sprite position */
2417  if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2418  }
2419 
2420  Direction l_dir = v->direction;
2421  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2422  Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2423 
2424  int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2425  int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2426 
2427  for (uint i = 0; i < count; i++) {
2428  uint32 reg = GetRegister(0x100 + i);
2429  uint type = GB(reg, 0, 8);
2430  int8 x = GB(reg, 8, 8);
2431  int8 y = GB(reg, 16, 8);
2432  int8 z = GB(reg, 24, 8);
2433 
2434  if (auto_rotate) {
2435  int8 l = x;
2436  int8 t = y;
2437  x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2438  y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2439  }
2440 
2441  if (type >= 0xF0) {
2442  switch (type) {
2443  case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2444  case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2445  case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2446  case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2447  default: break;
2448  }
2449  }
2450  }
2451 }
2452 
2458 {
2459  assert(this->IsPrimaryVehicle());
2460  bool sound = false;
2461 
2462  /* Do not show any smoke when:
2463  * - vehicle smoke is disabled by the player
2464  * - the vehicle is slowing down or stopped (by the player)
2465  * - the vehicle is moving very slowly
2466  */
2467  if (_settings_game.vehicle.smoke_amount == 0 ||
2468  this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2469  this->cur_speed < 2) {
2470  return;
2471  }
2472 
2473  /* Use the speed as limited by underground and orders. */
2474  uint max_speed = this->GetCurrentMaxSpeed();
2475 
2476  if (this->type == VEH_TRAIN) {
2477  const Train *t = Train::From(this);
2478  /* For trains, do not show any smoke when:
2479  * - the train is reversing
2480  * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2481  */
2482  if (HasBit(t->flags, VRF_REVERSING) ||
2484  t->cur_speed >= max_speed)) {
2485  return;
2486  }
2487  }
2488 
2489  const Vehicle *v = this;
2490 
2491  do {
2492  bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2494  VisualEffectSpawnModel effect_model = VESM_NONE;
2495  if (advanced) {
2496  effect_offset = VE_OFFSET_CENTRE;
2498  if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2499  } else {
2501  assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2502  assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2503  assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2504  assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2505  }
2506 
2507  /* Show no smoke when:
2508  * - Smoke has been disabled for this vehicle
2509  * - The vehicle is not visible
2510  * - The vehicle is under a bridge
2511  * - The vehicle is on a depot tile
2512  * - The vehicle is on a tunnel tile
2513  * - The vehicle is a train engine that is currently unpowered */
2514  if (effect_model == VESM_NONE ||
2515  v->vehstatus & VS_HIDDEN ||
2516  IsBridgeAbove(v->tile) ||
2517  IsDepotTile(v->tile) ||
2518  IsTunnelTile(v->tile) ||
2519  (v->type == VEH_TRAIN &&
2520  !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2521  continue;
2522  }
2523 
2524  EffectVehicleType evt = EV_END;
2525  switch (effect_model) {
2526  case VESM_STEAM:
2527  /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2528  * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2529  * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2530  * REGULATION:
2531  * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2532  if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2533  evt = EV_STEAM_SMOKE;
2534  }
2535  break;
2536 
2537  case VESM_DIESEL: {
2538  /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2539  * when smoke emission stops.
2540  * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2541  * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2542  * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2543  * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2544  * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2545  * maximum speed no diesel_smoke is emitted.
2546  * REGULATION:
2547  * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2548  * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2549  int power_weight_effect = 0;
2550  if (v->type == VEH_TRAIN) {
2551  power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2552  }
2553  if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2554  Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2555  evt = EV_DIESEL_SMOKE;
2556  }
2557  break;
2558  }
2559 
2560  case VESM_ELECTRIC:
2561  /* Electric train's spark - more often occurs when train is departing (more load)
2562  * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2563  * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2564  * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2565  * REGULATION:
2566  * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2567  if (GB(v->tick_counter, 0, 2) == 0 &&
2568  Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2569  evt = EV_ELECTRIC_SPARK;
2570  }
2571  break;
2572 
2573  default:
2574  NOT_REACHED();
2575  }
2576 
2577  if (evt != EV_END && advanced) {
2578  sound = true;
2580  } else if (evt != EV_END) {
2581  sound = true;
2582 
2583  /* The effect offset is relative to a point 4 units behind the vehicle's
2584  * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2585  * correction factor. */
2586  if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2587 
2588  int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2589  int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2590 
2591  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2592  x = -x;
2593  y = -y;
2594  }
2595 
2596  CreateEffectVehicleRel(v, x, y, 10, evt);
2597  }
2598  } while ((v = v->Next()) != NULL);
2599 
2600  if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2601 }
2602 
2608 {
2609  assert(this != next);
2610 
2611  if (this->next != NULL) {
2612  /* We had an old next vehicle. Update the first and previous pointers */
2613  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2614  v->first = this->next;
2615  }
2616  this->next->previous = NULL;
2617  }
2618 
2619  this->next = next;
2620 
2621  if (this->next != NULL) {
2622  /* A new next vehicle. Update the first and previous pointers */
2623  if (this->next->previous != NULL) this->next->previous->next = NULL;
2624  this->next->previous = this;
2625  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2626  v->first = this->first;
2627  }
2628  }
2629 }
2630 
2636 void Vehicle::AddToShared(Vehicle *shared_chain)
2637 {
2638  assert(this->previous_shared == NULL && this->next_shared == NULL);
2639 
2640  if (shared_chain->orders.list == NULL) {
2641  assert(shared_chain->previous_shared == NULL);
2642  assert(shared_chain->next_shared == NULL);
2643  this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
2644  }
2645 
2646  this->next_shared = shared_chain->next_shared;
2647  this->previous_shared = shared_chain;
2648 
2649  shared_chain->next_shared = this;
2650 
2651  if (this->next_shared != NULL) this->next_shared->previous_shared = this;
2652 
2653  shared_chain->orders.list->AddVehicle(this);
2654 }
2655 
2660 {
2661  /* Remember if we were first and the old window number before RemoveVehicle()
2662  * as this changes first if needed. */
2663  bool were_first = (this->FirstShared() == this);
2664  VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2665 
2666  this->orders.list->RemoveVehicle(this);
2667 
2668  if (!were_first) {
2669  /* We are not the first shared one, so only relink our previous one. */
2670  this->previous_shared->next_shared = this->NextShared();
2671  }
2672 
2673  if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
2674 
2675 
2676  if (this->orders.list->GetNumVehicles() == 1) {
2677  /* When there is only one vehicle, remove the shared order list window. */
2679  InvalidateVehicleOrder(this->FirstShared(), 0);
2680  } else if (were_first) {
2681  /* If we were the first one, update to the new first one.
2682  * Note: FirstShared() is already the new first */
2683  InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2684  }
2685 
2686  this->next_shared = NULL;
2687  this->previous_shared = NULL;
2688 }
2689 
2690 void VehiclesYearlyLoop()
2691 {
2692  Vehicle *v;
2693  FOR_ALL_VEHICLES(v) {
2694  if (v->IsPrimaryVehicle()) {
2695  /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2696  Money profit = v->GetDisplayProfitThisYear();
2697  if (v->age >= 730 && profit < 0) {
2699  SetDParam(0, v->index);
2700  SetDParam(1, profit);
2701  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2702  }
2703  AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2704  }
2705 
2707  v->profit_this_year = 0;
2709  }
2710  }
2716 }
2717 
2718 
2728 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2729 {
2730  const Engine *e = Engine::GetIfValid(engine_type);
2731  assert(e != NULL);
2732 
2733  switch (e->type) {
2734  case VEH_TRAIN:
2735  return (st->facilities & FACIL_TRAIN) != 0;
2736 
2737  case VEH_ROAD:
2738  /* For road vehicles we need the vehicle to know whether it can actually
2739  * use the station, but if it doesn't have facilities for RVs it is
2740  * certainly not possible that the station can be used. */
2741  return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2742 
2743  case VEH_SHIP:
2744  return (st->facilities & FACIL_DOCK) != 0;
2745 
2746  case VEH_AIRCRAFT:
2747  return (st->facilities & FACIL_AIRPORT) != 0 &&
2749 
2750  default:
2751  return false;
2752  }
2753 }
2754 
2761 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2762 {
2763  if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
2764 
2765  return CanVehicleUseStation(v->engine_type, st);
2766 }
2767 
2774 {
2775  assert(this->IsGroundVehicle());
2776  if (this->type == VEH_TRAIN) {
2777  return &Train::From(this)->gcache;
2778  } else {
2779  return &RoadVehicle::From(this)->gcache;
2780  }
2781 }
2782 
2789 {
2790  assert(this->IsGroundVehicle());
2791  if (this->type == VEH_TRAIN) {
2792  return &Train::From(this)->gcache;
2793  } else {
2794  return &RoadVehicle::From(this)->gcache;
2795  }
2796 }
2797 
2804 {
2805  assert(this->IsGroundVehicle());
2806  if (this->type == VEH_TRAIN) {
2807  return Train::From(this)->gv_flags;
2808  } else {
2809  return RoadVehicle::From(this)->gv_flags;
2810  }
2811 }
2812 
2818 const uint16 &Vehicle::GetGroundVehicleFlags() const
2819 {
2820  assert(this->IsGroundVehicle());
2821  if (this->type == VEH_TRAIN) {
2822  return Train::From(this)->gv_flags;
2823  } else {
2824  return RoadVehicle::From(this)->gv_flags;
2825  }
2826 }
2827 
2836 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2837 {
2838  if (v->type == VEH_TRAIN) {
2839  Train *u = Train::From(v);
2840  /* Only include whole vehicles, so start with the first articulated part */
2841  u = u->GetFirstEnginePart();
2842 
2843  /* Include num_vehicles vehicles, not counting articulated parts */
2844  for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2845  do {
2846  /* Include current vehicle in the selection. */
2847  set.Include(u->index);
2848 
2849  /* If the vehicle is multiheaded, add the other part too. */
2850  if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
2851 
2852  u = u->Next();
2853  } while (u != NULL && u->IsArticulatedPart());
2854  }
2855  }
2856 }