OpenTTD
vehicle.cpp
Go to the documentation of this file.
1 /* $Id: vehicle.cpp 27426 2015-10-30 17:24:05Z 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 
77 bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
78 {
79  /* We can always generate the Company pointer when we have the vehicle.
80  * However this takes time and since the Company pointer is often present
81  * when this function is called then it's faster to pass the pointer as an
82  * argument rather than finding it again. */
83  assert(c == Company::Get(this->owner));
84 
85  if (use_renew_setting && !c->settings.engine_renew) return false;
86  if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
87 
88  /* Only engines need renewing */
89  if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
90 
91  return true;
92 }
93 
100 {
101  assert(v != NULL);
102  SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
103 
104  do {
107  v->reliability = v->GetEngine()->reliability;
108  /* Prevent vehicles from breaking down directly after exiting the depot. */
109  v->breakdown_chance /= 4;
110  v = v->Next();
111  } while (v != NULL && v->HasEngineType());
112 }
113 
121 {
122  /* Stopped or crashed vehicles will not move, as such making unmovable
123  * vehicles to go for service is lame. */
124  if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
125 
126  /* Are we ready for the next service cycle? */
127  const Company *c = Company::Get(this->owner);
128  if (this->ServiceIntervalIsPercent() ?
129  (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
130  (this->date_of_last_service + this->GetServiceInterval() >= _date)) {
131  return false;
132  }
133 
134  /* If we're servicing anyway, because we have not disabled servicing when
135  * there are no breakdowns or we are playing with breakdowns, bail out. */
138  return true;
139  }
140 
141  /* Test whether there is some pending autoreplace.
142  * Note: We do this after the service-interval test.
143  * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
144  bool pending_replace = false;
145  Money needed_money = c->settings.engine_renew_money;
146  if (needed_money > c->money) return false;
147 
148  for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
149  bool replace_when_old = false;
150  EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
151 
152  /* Check engine availability */
153  if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
154  /* Is the vehicle old if we are not always replacing? */
155  if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
156 
157  /* Check refittability */
158  uint32 available_cargo_types, union_mask;
159  GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
160  /* Is there anything to refit? */
161  if (union_mask != 0) {
163  /* We cannot refit to mixed cargoes in an automated way */
164  if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
165 
166  /* Did the old vehicle carry anything? */
167  if (cargo_type != CT_INVALID) {
168  /* We can't refit the vehicle to carry the cargo we want */
169  if (!HasBit(available_cargo_types, cargo_type)) continue;
170  }
171  }
172 
173  /* Check money.
174  * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
175  pending_replace = true;
176  needed_money += 2 * Engine::Get(new_engine)->GetCost();
177  if (needed_money > c->money) return false;
178  }
179 
180  return pending_replace;
181 }
182 
189 {
190  if (this->HasDepotOrder()) return false;
191  if (this->current_order.IsType(OT_LOADING)) return false;
192  if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
193  return NeedsServicing();
194 }
195 
196 uint Vehicle::Crash(bool flooded)
197 {
198  assert((this->vehstatus & VS_CRASHED) == 0);
199  assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
200 
201  uint pass = 0;
202  /* Stop the vehicle. */
203  if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
204  /* crash all wagons, and count passengers */
205  for (Vehicle *v = this; v != NULL; v = v->Next()) {
206  /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
207  if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
208  v->vehstatus |= VS_CRASHED;
209  v->MarkAllViewportsDirty();
210  }
211 
212  /* Dirty some windows */
217 
218  delete this->cargo_payment;
219  this->cargo_payment = NULL;
220 
221  return RandomRange(pass + 1); // Randomise deceased passengers.
222 }
223 
224 
233 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
234 {
235  const Engine *e = Engine::Get(engine);
236  GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
237 
238  /* Missing GRF. Nothing useful can be done in this situation. */
239  if (grfconfig == NULL) return;
240 
241  if (!HasBit(grfconfig->grf_bugs, bug_type)) {
242  SetBit(grfconfig->grf_bugs, bug_type);
243  SetDParamStr(0, grfconfig->GetName());
244  SetDParam(1, engine);
245  ShowErrorMessage(part1, part2, WL_CRITICAL);
247  }
248 
249  /* debug output */
250  char buffer[512];
251 
252  SetDParamStr(0, grfconfig->GetName());
253  GetString(buffer, part1, lastof(buffer));
254  DEBUG(grf, 0, "%s", buffer + 3);
255 
256  SetDParam(1, engine);
257  GetString(buffer, part2, lastof(buffer));
258  DEBUG(grf, 0, "%s", buffer + 3);
259 }
260 
267 {
268  /* show a warning once for each engine in whole game and once for each GRF after each game load */
269  const Engine *engine = u->GetEngine();
270  uint32 grfid = engine->grf_prop.grffile->grfid;
271  GRFConfig *grfconfig = GetGRFConfig(grfid);
272  if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
273  ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
274  }
275 }
276 
282 {
283  this->type = type;
284  this->coord.left = INVALID_COORD;
285  this->group_id = DEFAULT_GROUP;
286  this->fill_percent_te_id = INVALID_TE_ID;
287  this->first = this;
288  this->colourmap = PAL_NONE;
289  this->cargo_age_counter = 1;
290  this->last_station_visited = INVALID_STATION;
291  this->last_loading_station = INVALID_STATION;
292 }
293 
299 {
300  return GB(Random(), 0, 8);
301 }
302 
303 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
304  * lookup times at the expense of memory usage. */
305 const int HASH_BITS = 7;
306 const int HASH_SIZE = 1 << HASH_BITS;
307 const int HASH_MASK = HASH_SIZE - 1;
308 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
309 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
310 
311 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
312  * Profiling results show that 0 is fastest. */
313 const int HASH_RES = 0;
314 
315 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
316 
317 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
318 {
319  for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
320  for (int x = xl; ; x = (x + 1) & HASH_MASK) {
321  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
322  for (; v != NULL; v = v->hash_tile_next) {
323  Vehicle *a = proc(v, data);
324  if (find_first && a != NULL) return a;
325  }
326  if (x == xu) break;
327  }
328  if (y == yu) break;
329  }
330 
331  return NULL;
332 }
333 
334 
346 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
347 {
348  const int COLL_DIST = 6;
349 
350  /* Hash area to scan is from xl,yl to xu,yu */
351  int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
352  int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
353  int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
354  int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
355 
356  return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
357 }
358 
373 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
374 {
375  VehicleFromPosXY(x, y, data, proc, false);
376 }
377 
389 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
390 {
391  return VehicleFromPosXY(x, y, data, proc, true) != NULL;
392 }
393 
404 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
405 {
406  int x = GB(TileX(tile), HASH_RES, HASH_BITS);
407  int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
408 
409  Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
410  for (; v != NULL; v = v->hash_tile_next) {
411  if (v->tile != tile) continue;
412 
413  Vehicle *a = proc(v, data);
414  if (find_first && a != NULL) return a;
415  }
416 
417  return NULL;
418 }
419 
433 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
434 {
435  VehicleFromPos(tile, data, proc, false);
436 }
437 
448 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
449 {
450  return VehicleFromPos(tile, data, proc, true) != NULL;
451 }
452 
459 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
460 {
461  int z = *(int*)data;
462 
463  if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
464  if (v->z_pos > z) return NULL;
465 
466  return v;
467 }
468 
475 {
476  int z = GetTileMaxPixelZ(tile);
477 
478  /* Value v is not safe in MP games, however, it is used to generate a local
479  * error message only (which may be different for different machines).
480  * Such a message does not affect MP synchronisation.
481  */
482  Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
483  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
484  return CommandCost();
485 }
486 
489 {
490  if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
491  if (v == (const Vehicle *)data) return NULL;
492 
493  return v;
494 }
495 
504 {
505  /* Value v is not safe in MP games, however, it is used to generate a local
506  * error message only (which may be different for different machines).
507  * Such a message does not affect MP synchronisation.
508  */
509  Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
510  if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
511 
512  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
513  return CommandCost();
514 }
515 
516 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
517 {
518  TrackBits rail_bits = *(TrackBits *)data;
519 
520  if (v->type != VEH_TRAIN) return NULL;
521 
522  Train *t = Train::From(v);
523  if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
524 
525  return v;
526 }
527 
537 {
538  /* Value v is not safe in MP games, however, it is used to generate a local
539  * error message only (which may be different for different machines).
540  * Such a message does not affect MP synchronisation.
541  */
542  Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
543  if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
544  return CommandCost();
545 }
546 
547 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
548 {
549  Vehicle **old_hash = v->hash_tile_current;
550  Vehicle **new_hash;
551 
552  if (remove) {
553  new_hash = NULL;
554  } else {
555  int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
556  int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
557  new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
558  }
559 
560  if (old_hash == new_hash) return;
561 
562  /* Remove from the old position in the hash table */
563  if (old_hash != NULL) {
566  }
567 
568  /* Insert vehicle at beginning of the new position in the hash table */
569  if (new_hash != NULL) {
570  v->hash_tile_next = *new_hash;
572  v->hash_tile_prev = new_hash;
573  *new_hash = v;
574  }
575 
576  /* Remember current hash position */
577  v->hash_tile_current = new_hash;
578 }
579 
580 static Vehicle *_vehicle_viewport_hash[0x1000];
581 
582 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
583 {
584  Vehicle **old_hash, **new_hash;
585  int old_x = v->coord.left;
586  int old_y = v->coord.top;
587 
588  new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
589  old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
590 
591  if (old_hash == new_hash) return;
592 
593  /* remove from hash table? */
594  if (old_hash != NULL) {
597  }
598 
599  /* insert into hash table? */
600  if (new_hash != NULL) {
601  v->hash_viewport_next = *new_hash;
603  v->hash_viewport_prev = new_hash;
604  *new_hash = v;
605  }
606 }
607 
608 void ResetVehicleHash()
609 {
610  Vehicle *v;
611  FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; }
612  memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
613  memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
614 }
615 
616 void ResetVehicleColourMap()
617 {
618  Vehicle *v;
619  FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
620 }
621 
627 static AutoreplaceMap _vehicles_to_autoreplace;
628 
629 void InitializeVehicles()
630 {
631  _vehicles_to_autoreplace.Reset();
632  ResetVehicleHash();
633 }
634 
635 uint CountVehiclesInChain(const Vehicle *v)
636 {
637  uint count = 0;
638  do count++; while ((v = v->Next()) != NULL);
639  return count;
640 }
641 
647 {
648  switch (this->type) {
649  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
650  case VEH_TRAIN:
651  return !this->IsArticulatedPart() && // tenders and other articulated parts
652  !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
653  case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
654  case VEH_SHIP: return true;
655  default: return false; // Only count company buildable vehicles
656  }
657 }
658 
664 {
665  switch (this->type) {
666  case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
667  case VEH_TRAIN:
668  case VEH_ROAD:
669  case VEH_SHIP: return true;
670  default: return false;
671  }
672 }
673 
680 {
681  return Engine::Get(this->engine_type);
682 }
683 
689 const GRFFile *Vehicle::GetGRF() const
690 {
691  return this->GetEngine()->GetGRF();
692 }
693 
699 uint32 Vehicle::GetGRFID() const
700 {
701  return this->GetEngine()->GetGRFID();
702 }
703 
711 void Vehicle::HandlePathfindingResult(bool path_found)
712 {
713  if (path_found) {
714  /* Route found, is the vehicle marked with "lost" flag? */
715  if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
716 
717  /* Clear the flag as the PF's problem was solved. */
719  /* Delete the news item. */
720  DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
721  return;
722  }
723 
724  /* Were we already lost? */
725  if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
726 
727  /* It is first time the problem occurred, set the "lost" flag. */
729  /* Notify user about the event. */
730  AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
731  if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
732  SetDParam(0, this->index);
733  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index);
734  }
735 }
736 
739 {
740  if (CleaningPool()) return;
741 
744  st->loading_vehicles.remove(this);
745 
747  this->CancelReservation(INVALID_STATION, st);
748  delete this->cargo_payment;
749  }
750 
751  if (this->IsEngineCountable()) {
753  if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
755 
758  }
759 
760  if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
761  Aircraft *a = Aircraft::From(this);
763  if (st != NULL) {
764  const AirportFTA *layout = st->airport.GetFTA()->layout;
765  CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
766  }
767  }
768 
769 
770  if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
771  RoadVehicle *v = RoadVehicle::From(this);
772  if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
773  /* Leave the drive through roadstop, when you have not already left it. */
775  }
776  }
777 
778  if (this->Previous() == NULL) {
780  }
781 
782  if (this->IsPrimaryVehicle()) {
790  }
792 
793  this->cargo.Truncate();
794  DeleteVehicleOrders(this);
796 
797  extern void StopGlobalFollowVehicle(const Vehicle *v);
798  StopGlobalFollowVehicle(this);
799 
801 }
802 
804 {
805  if (CleaningPool()) {
806  this->cargo.OnCleanPool();
807  return;
808  }
809 
810  /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
811  * it may happen that vehicle chain is deleted when visible */
812  if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
813 
814  Vehicle *v = this->Next();
815  this->SetNext(NULL);
816 
817  delete v;
818 
819  UpdateVehicleTileHash(this, true);
820  UpdateVehicleViewportHash(this, INVALID_COORD, 0);
823 }
824 
830 {
831  /* Vehicle should stop in the depot if it was in 'stopping' state */
832  _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
833 
834  /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
835  * stopping in the depot, so we stop it to ensure that it will not reserve
836  * the path out of the depot before we might autoreplace it to a different
837  * engine. The new engine would not own the reserved path we store that we
838  * stopped the vehicle, so autoreplace can start it again */
839  v->vehstatus |= VS_STOPPED;
840 }
841 
847 static void RunVehicleDayProc()
848 {
849  if (_game_mode != GM_NORMAL) return;
850 
851  /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
852  for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
853  Vehicle *v = Vehicle::Get(i);
854  if (v == NULL) continue;
855 
856  /* Call the 32-day callback if needed */
857  if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
858  uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
859  if (callback != CALLBACK_FAILED) {
860  if (HasBit(callback, 0)) {
861  TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
862  }
863 
864  /* After a vehicle trigger, the graphics and properties of the vehicle could change.
865  * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
866  if (callback != 0) v->First()->MarkDirty();
867 
868  if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
869  }
870  }
871 
872  /* This is called once per day for each vehicle, but not in the first tick of the day */
873  v->OnNewDay();
874  }
875 }
876 
877 void CallVehicleTicks()
878 {
879  _vehicles_to_autoreplace.Clear();
880 
882 
883  Station *st;
884  FOR_ALL_STATIONS(st) LoadUnloadStation(st);
885 
886  Vehicle *v;
887  FOR_ALL_VEHICLES(v) {
888  /* Vehicle could be deleted in this tick */
889  if (!v->Tick()) {
890  assert(Vehicle::Get(vehicle_index) == NULL);
891  continue;
892  }
893 
894  assert(Vehicle::Get(vehicle_index) == v);
895 
896  switch (v->type) {
897  default: break;
898 
899  case VEH_TRAIN:
900  case VEH_ROAD:
901  case VEH_AIRCRAFT:
902  case VEH_SHIP: {
903  Vehicle *front = v->First();
904 
905  if (v->vcache.cached_cargo_age_period != 0) {
906  v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
907  if (--v->cargo_age_counter == 0) {
908  v->cargo.AgeCargo();
909  v->cargo_age_counter = v->vcache.cached_cargo_age_period;
910  }
911  }
912 
913  /* Do not play any sound when crashed */
914  if (front->vehstatus & VS_CRASHED) continue;
915 
916  /* Do not play any sound when in depot or tunnel */
917  if (v->vehstatus & VS_HIDDEN) continue;
918 
919  /* Do not play any sound when stopped */
920  if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
921 
922  /* Check vehicle type specifics */
923  switch (v->type) {
924  case VEH_TRAIN:
925  if (Train::From(v)->IsWagon()) continue;
926  break;
927 
928  case VEH_ROAD:
929  if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
930  break;
931 
932  case VEH_AIRCRAFT:
933  if (!Aircraft::From(v)->IsNormalAircraft()) continue;
934  break;
935 
936  default:
937  break;
938  }
939 
940  v->motion_counter += front->cur_speed;
941  /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
942  if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
943 
944  /* Play an alternating running sound every 16 ticks */
945  if (GB(v->tick_counter, 0, 4) == 0) {
946  /* Play running sound when speed > 0 and not braking */
947  bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
949  }
950 
951  break;
952  }
953  }
954  }
955 
956  Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
957  for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
958  v = it->first;
959  /* Autoreplace needs the current company set as the vehicle owner */
960  cur_company.Change(v->owner);
961 
962  /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
963  * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
964  * they are already leaving the depot again before being replaced. */
965  if (it->second) v->vehstatus &= ~VS_STOPPED;
966 
967  /* Store the position of the effect as the vehicle pointer will become invalid later */
968  int x = v->x_pos;
969  int y = v->y_pos;
970  int z = v->z_pos;
971 
974  CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
976 
977  if (!IsLocalCompany()) continue;
978 
979  if (res.Succeeded()) {
980  ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
981  continue;
982  }
983 
984  StringID error_message = res.GetErrorMessage();
985  if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
986 
987  if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
988 
989  StringID message;
990  if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
991  message = error_message;
992  } else {
993  message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
994  }
995 
996  SetDParam(0, v->index);
997  SetDParam(1, error_message);
998  AddVehicleAdviceNewsItem(message, v->index);
999  }
1000 
1001  cur_company.Restore();
1002 }
1003 
1008 static void DoDrawVehicle(const Vehicle *v)
1009 {
1010  SpriteID image = v->cur_image;
1011  PaletteID pal = PAL_NONE;
1012 
1014 
1015  /* Check whether the vehicle shall be transparent due to the game state */
1016  bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
1017 
1018  if (v->type == VEH_EFFECT) {
1019  /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1020  * However, transparent smoke and bubbles look weird, so always hide them. */
1022  if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1023  }
1024 
1025  AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
1026  v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
1027 }
1028 
1034 {
1035  /* The bounding rectangle */
1036  const int l = dpi->left;
1037  const int r = dpi->left + dpi->width;
1038  const int t = dpi->top;
1039  const int b = dpi->top + dpi->height;
1040 
1041  /* The hash area to scan */
1042  int xl, xu, yl, yu;
1043 
1044  if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
1045  xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
1046  xu = GB(r, 7 + ZOOM_LVL_SHIFT, 6);
1047  } else {
1048  /* scan whole hash row */
1049  xl = 0;
1050  xu = 0x3F;
1051  }
1052 
1053  if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
1054  yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
1055  yu = GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
1056  } else {
1057  /* scan whole column */
1058  yl = 0;
1059  yu = 0x3F << 6;
1060  }
1061 
1062  for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
1063  for (int x = xl;; x = (x + 1) & 0x3F) {
1064  const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1065 
1066  while (v != NULL) {
1067  if (!(v->vehstatus & VS_HIDDEN) &&
1068  l <= v->coord.right &&
1069  t <= v->coord.bottom &&
1070  r >= v->coord.left &&
1071  b >= v->coord.top) {
1072  DoDrawVehicle(v);
1073  }
1074  v = v->hash_viewport_next;
1075  }
1076 
1077  if (x == xu) break;
1078  }
1079 
1080  if (y == yu) break;
1081  }
1082 }
1083 
1091 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
1092 {
1093  Vehicle *found = NULL, *v;
1094  uint dist, best_dist = UINT_MAX;
1095 
1096  if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
1097 
1098  x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
1099  y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
1100 
1101  FOR_ALL_VEHICLES(v) {
1102  if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
1103  x >= v->coord.left && x <= v->coord.right &&
1104  y >= v->coord.top && y <= v->coord.bottom) {
1105 
1106  dist = max(
1107  abs(((v->coord.left + v->coord.right) >> 1) - x),
1108  abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1109  );
1110 
1111  if (dist < best_dist) {
1112  found = v;
1113  best_dist = dist;
1114  }
1115  }
1116  }
1117 
1118  return found;
1119 }
1120 
1126 {
1127  v->value -= v->value >> 8;
1129 }
1130 
1131 static const byte _breakdown_chance[64] = {
1132  3, 3, 3, 3, 3, 3, 3, 3,
1133  4, 4, 5, 5, 6, 6, 7, 7,
1134  8, 8, 9, 9, 10, 10, 11, 11,
1135  12, 13, 13, 13, 13, 14, 15, 16,
1136  17, 19, 21, 25, 28, 31, 34, 37,
1137  40, 44, 48, 52, 56, 60, 64, 68,
1138  72, 80, 90, 100, 110, 120, 130, 140,
1139  150, 170, 190, 210, 230, 250, 250, 250,
1140 };
1141 
1142 void CheckVehicleBreakdown(Vehicle *v)
1143 {
1144  int rel, rel_old;
1145 
1146  /* decrease reliability */
1147  v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1148  if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1149 
1150  if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
1152  v->cur_speed < 5 || _game_mode == GM_MENU) {
1153  return;
1154  }
1155 
1156  uint32 r = Random();
1157 
1158  /* increase chance of failure */
1159  int chance = v->breakdown_chance + 1;
1160  if (Chance16I(1, 25, r)) chance += 25;
1161  v->breakdown_chance = min(255, chance);
1162 
1163  /* calculate reliability value to use in comparison */
1164  rel = v->reliability;
1165  if (v->type == VEH_SHIP) rel += 0x6666;
1166 
1167  /* reduced breakdowns? */
1168  if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1169 
1170  /* check if to break down */
1171  if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
1172  v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1173  v->breakdown_delay = GB(r, 24, 7) + 0x80;
1174  v->breakdown_chance = 0;
1175  }
1176 }
1177 
1185 {
1186  /* Possible states for Vehicle::breakdown_ctr
1187  * 0 - vehicle is running normally
1188  * 1 - vehicle is currently broken down
1189  * 2 - vehicle is going to break down now
1190  * >2 - vehicle is counting down to the actual breakdown event */
1191  switch (this->breakdown_ctr) {
1192  case 0:
1193  return false;
1194 
1195  case 2:
1196  this->breakdown_ctr = 1;
1197 
1198  if (this->breakdowns_since_last_service != 255) {
1200  }
1201 
1202  if (this->type == VEH_AIRCRAFT) {
1203  /* Aircraft just need this flag, the rest is handled elsewhere */
1204  this->vehstatus |= VS_AIRCRAFT_BROKEN;
1205  } else {
1206  this->cur_speed = 0;
1207 
1208  if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1209  bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1210  SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
1211  (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1212  (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
1213  }
1214 
1215  if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
1217  if (u != NULL) u->animation_state = this->breakdown_delay * 2;
1218  }
1219  }
1220 
1221  this->MarkDirty(); // Update graphics after speed is zeroed
1224 
1225  /* FALL THROUGH */
1226  case 1:
1227  /* Aircraft breakdowns end only when arriving at the airport */
1228  if (this->type == VEH_AIRCRAFT) return false;
1229 
1230  /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1231  if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1232  if (--this->breakdown_delay == 0) {
1233  this->breakdown_ctr = 0;
1234  this->MarkDirty();
1236  }
1237  }
1238  return true;
1239 
1240  default:
1241  if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1242  return false;
1243  }
1244 }
1245 
1251 {
1252  if (v->age < MAX_DAY) {
1253  v->age++;
1255  }
1256 
1257  if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1258 
1259  int age = v->age - v->max_age;
1260  if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
1261  age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
1262  v->reliability_spd_dec <<= 1;
1263  }
1264 
1266 
1267  /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
1268  if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
1269 
1270  /* Don't warn if a renew is active */
1271  if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
1272 
1273  StringID str;
1274  if (age == -DAYS_IN_LEAP_YEAR) {
1275  str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1276  } else if (age == 0) {
1277  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1278  } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
1279  str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1280  } else {
1281  return;
1282  }
1283 
1284  SetDParam(0, v->index);
1286 }
1287 
1297 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1298 {
1299  int count = 0;
1300  int max = 0;
1301  int cars = 0;
1302  int unloading = 0;
1303  bool loading = false;
1304 
1305  bool is_loading = front->current_order.IsType(OT_LOADING);
1306 
1307  /* The station may be NULL when the (colour) string does not need to be set. */
1308  const Station *st = Station::GetIfValid(front->last_station_visited);
1309  assert(colour == NULL || (st != NULL && is_loading));
1310 
1311  bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1312  bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1313 
1314  /* Count up max and used */
1315  for (const Vehicle *v = front; v != NULL; v = v->Next()) {
1316  count += v->cargo.StoredCount();
1317  max += v->cargo_cap;
1318  if (v->cargo_cap != 0 && colour != NULL) {
1319  unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1320  loading |= !order_no_load &&
1321  (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1323  cars++;
1324  }
1325  }
1326 
1327  if (colour != NULL) {
1328  if (unloading == 0 && loading) {
1329  *colour = STR_PERCENT_UP;
1330  } else if (unloading == 0 && !loading) {
1331  *colour = STR_PERCENT_NONE;
1332  } else if (cars == unloading || !loading) {
1333  *colour = STR_PERCENT_DOWN;
1334  } else {
1335  *colour = STR_PERCENT_UP_DOWN;
1336  }
1337  }
1338 
1339  /* Train without capacity */
1340  if (max == 0) return 100;
1341 
1342  /* Return the percentage */
1343  if (count * 2 < max) {
1344  /* Less than 50%; round up, so that 0% means really empty. */
1345  return CeilDiv(count * 100, max);
1346  } else {
1347  /* More than 50%; round down, so that 100% means really full. */
1348  return (count * 100) / max;
1349  }
1350 }
1351 
1357 {
1358  /* Always work with the front of the vehicle */
1359  assert(v == v->First());
1360 
1361  switch (v->type) {
1362  case VEH_TRAIN: {
1363  Train *t = Train::From(v);
1365  /* Clear path reservation */
1366  SetDepotReservation(t->tile, false);
1368 
1370  t->wait_counter = 0;
1371  t->force_proceed = TFP_NONE;
1372  ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1374  break;
1375  }
1376 
1377  case VEH_ROAD:
1379  break;
1380 
1381  case VEH_SHIP: {
1383  Ship *ship = Ship::From(v);
1384  ship->state = TRACK_BIT_DEPOT;
1385  ship->UpdateCache();
1386  ship->UpdateViewport(true, true);
1388  break;
1389  }
1390 
1391  case VEH_AIRCRAFT:
1394  break;
1395  default: NOT_REACHED();
1396  }
1398 
1399  if (v->type != VEH_TRAIN) {
1400  /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1401  * 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 */
1403  }
1405 
1406  v->vehstatus |= VS_HIDDEN;
1407  v->cur_speed = 0;
1408 
1410 
1411  /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1412  TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1413  v->MarkDirty();
1414 
1415  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1417 
1418  const Order *real_order = v->GetOrder(v->cur_real_order_index);
1419 
1420  /* Test whether we are heading for this depot. If not, do nothing.
1421  * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1423  real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1424  (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
1425  /* We are heading for another depot, keep driving. */
1426  return;
1427  }
1428 
1429  if (v->current_order.IsRefit()) {
1430  Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
1431  CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
1432  cur_company.Restore();
1433 
1434  if (cost.Failed()) {
1435  _vehicles_to_autoreplace[v] = false;
1436  if (v->owner == _local_company) {
1437  /* Notify the user that we stopped the vehicle */
1438  SetDParam(0, v->index);
1439  AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
1440  }
1441  } else if (cost.GetCost() != 0) {
1442  v->profit_this_year -= cost.GetCost() << 8;
1443  if (v->owner == _local_company) {
1444  ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
1445  }
1446  }
1447  }
1448 
1450  /* Part of orders */
1452  UpdateVehicleTimetable(v, true);
1454  }
1456  /* Vehicles are always stopped on entering depots. Do not restart this one. */
1457  _vehicles_to_autoreplace[v] = false;
1458  /* Invalidate last_loading_station. As the link from the station
1459  * before the stop to the station after the stop can't be predicted
1460  * we shouldn't construct it when the vehicle visits the next stop. */
1461  v->last_loading_station = INVALID_STATION;
1462  if (v->owner == _local_company) {
1463  SetDParam(0, v->index);
1464  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1465  }
1466  AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1467  }
1468  v->current_order.MakeDummy();
1469  }
1470 }
1471 
1472 
1478 {
1479  UpdateVehicleTileHash(this, false);
1480 }
1481 
1487 void Vehicle::UpdateViewport(bool dirty)
1488 {
1489  int img = this->cur_image;
1490  Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1491  const Sprite *spr = GetSprite(img, ST_NORMAL);
1492 
1493  pt.x += spr->x_offs;
1494  pt.y += spr->y_offs;
1495 
1496  UpdateVehicleViewportHash(this, pt.x, pt.y);
1497 
1498  Rect old_coord = this->coord;
1499  this->coord.left = pt.x;
1500  this->coord.top = pt.y;
1501  this->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
1502  this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
1503 
1504  if (dirty) {
1505  if (old_coord.left == INVALID_COORD) {
1506  this->MarkAllViewportsDirty();
1507  } else {
1509  min(old_coord.left, this->coord.left),
1510  min(old_coord.top, this->coord.top),
1511  max(old_coord.right, this->coord.right),
1512  max(old_coord.bottom, this->coord.bottom));
1513  }
1514  }
1515 }
1516 
1521 {
1522  this->UpdatePosition();
1523  this->UpdateViewport(true);
1524 }
1525 
1530 {
1531  ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1532 }
1533 
1540 {
1541  static const int8 _delta_coord[16] = {
1542  -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1543  -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1544  };
1545 
1546  int x = v->x_pos + _delta_coord[v->direction];
1547  int y = v->y_pos + _delta_coord[v->direction + 8];
1548 
1550  gp.x = x;
1551  gp.y = y;
1552  gp.old_tile = v->tile;
1553  gp.new_tile = TileVirtXY(x, y);
1554  return gp;
1555 }
1556 
1557 static const Direction _new_direction_table[] = {
1558  DIR_N, DIR_NW, DIR_W,
1559  DIR_NE, DIR_SE, DIR_SW,
1560  DIR_E, DIR_SE, DIR_S
1561 };
1562 
1563 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1564 {
1565  int i = 0;
1566 
1567  if (y >= v->y_pos) {
1568  if (y != v->y_pos) i += 3;
1569  i += 3;
1570  }
1571 
1572  if (x >= v->x_pos) {
1573  if (x != v->x_pos) i++;
1574  i++;
1575  }
1576 
1577  Direction dir = v->direction;
1578 
1579  DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1580  if (dirdiff == DIRDIFF_SAME) return dir;
1581  return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1582 }
1583 
1594 {
1595  return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1596 }
1597 
1605 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
1606 {
1607  /* Find maximum */
1608  const Vehicle *v;
1609  FOR_ALL_VEHICLES(v) {
1610  if (v->type == type && v->owner == owner) {
1611  this->maxid = max<UnitID>(this->maxid, v->unitnumber);
1612  }
1613  }
1614 
1615  if (this->maxid == 0) return;
1616 
1617  /* Reserving 'maxid + 2' because we need:
1618  * - space for the last item (with v->unitnumber == maxid)
1619  * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
1620  this->cache = CallocT<bool>(this->maxid + 2);
1621 
1622  /* Fill the cache */
1623  FOR_ALL_VEHICLES(v) {
1624  if (v->type == type && v->owner == owner) {
1625  this->cache[v->unitnumber] = true;
1626  }
1627  }
1628 }
1629 
1632 {
1633  if (this->maxid <= this->curid) return ++this->curid;
1634 
1635  while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
1636 
1637  return this->curid;
1638 }
1639 
1646 {
1647  /* Check whether it is allowed to build another vehicle. */
1648  uint max_veh;
1649  switch (type) {
1650  case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1651  case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1652  case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1653  case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1654  default: NOT_REACHED();
1655  }
1656 
1658  if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1659 
1661 
1662  return gen.NextID();
1663 }
1664 
1665 
1675 {
1676  assert(IsCompanyBuildableVehicleType(type));
1677 
1678  if (!Company::IsValidID(_local_company)) return false;
1680 
1681  UnitID max;
1682  switch (type) {
1683  case VEH_TRAIN: max = _settings_game.vehicle.max_trains; break;
1684  case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break;
1685  case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1686  case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1687  default: NOT_REACHED();
1688  }
1689 
1690  /* We can build vehicle infrastructure when we may build the vehicle type */
1691  if (max > 0) {
1692  /* Can we actually build the vehicle type? */
1693  const Engine *e;
1694  FOR_ALL_ENGINES_OF_TYPE(e, type) {
1695  if (HasBit(e->company_avail, _local_company)) return true;
1696  }
1697  return false;
1698  }
1699 
1700  /* We should be able to build infrastructure when we have the actual vehicle type */
1701  const Vehicle *v;
1702  FOR_ALL_VEHICLES(v) {
1703  if (v->owner == _local_company && v->type == type) return true;
1704  }
1705 
1706  return false;
1707 }
1708 
1709 
1717 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1718 {
1719  CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
1720  const Engine *e = Engine::Get(engine_type);
1721  switch (e->type) {
1722  default: NOT_REACHED();
1723  case VEH_TRAIN:
1724  if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1725  /* Wagonoverrides use the colour scheme of the front engine.
1726  * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1727  engine_type = parent_engine_type;
1728  e = Engine::Get(engine_type);
1729  /* Note: Luckily cargo_type is not needed for engines */
1730  }
1731 
1732  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1733  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1734  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1735  if (!CargoSpec::Get(cargo_type)->is_freight) {
1736  if (parent_engine_type == INVALID_ENGINE) {
1737  return LS_PASSENGER_WAGON_STEAM;
1738  } else {
1739  switch (RailVehInfo(parent_engine_type)->engclass) {
1740  default: NOT_REACHED();
1741  case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1742  case EC_DIESEL: return LS_PASSENGER_WAGON_DIESEL;
1743  case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
1744  case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1745  case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1746  }
1747  }
1748  } else {
1749  return LS_FREIGHT_WAGON;
1750  }
1751  } else {
1752  bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
1753 
1754  switch (e->u.rail.engclass) {
1755  default: NOT_REACHED();
1756  case EC_STEAM: return LS_STEAM;
1757  case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
1758  case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1759  case EC_MONORAIL: return LS_MONORAIL;
1760  case EC_MAGLEV: return LS_MAGLEV;
1761  }
1762  }
1763 
1764  case VEH_ROAD:
1765  /* Always use the livery of the front */
1766  if (v != NULL && parent_engine_type != INVALID_ENGINE) {
1767  engine_type = parent_engine_type;
1768  e = Engine::Get(engine_type);
1769  cargo_type = v->First()->cargo_type;
1770  }
1771  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1772  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1773 
1774  /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
1775  if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
1776  /* Tram */
1777  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
1778  } else {
1779  /* Bus or truck */
1780  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
1781  }
1782 
1783  case VEH_SHIP:
1784  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1785  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1786  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
1787 
1788  case VEH_AIRCRAFT:
1789  switch (e->u.air.subtype) {
1790  case AIR_HELI: return LS_HELICOPTER;
1791  case AIR_CTOL: return LS_SMALL_PLANE;
1792  case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
1793  default: NOT_REACHED();
1794  }
1795  }
1796 }
1797 
1807 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
1808 {
1809  const Company *c = Company::Get(company);
1810  LiveryScheme scheme = LS_DEFAULT;
1811 
1812  /* The default livery is always available for use, but its in_use flag determines
1813  * whether any _other_ liveries are in use. */
1814  if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
1815  /* Determine the livery scheme to use */
1816  scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
1817 
1818  /* Switch back to the default scheme if the resolved scheme is not in use */
1819  if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
1820  }
1821 
1822  return &c->livery[scheme];
1823 }
1824 
1825 
1826 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
1827 {
1828  PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
1829 
1830  /* Return cached value if any */
1831  if (map != PAL_NONE) return map;
1832 
1833  const Engine *e = Engine::Get(engine_type);
1834 
1835  /* Check if we should use the colour map callback */
1837  uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
1838  /* Failure means "use the default two-colour" */
1839  if (callback != CALLBACK_FAILED) {
1840  assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
1841  map = GB(callback, 0, 14);
1842  /* If bit 14 is set, then the company colours are applied to the
1843  * map else it's returned as-is. */
1844  if (!HasBit(callback, 14)) {
1845  /* Update cache */
1846  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1847  return map;
1848  }
1849  }
1850  }
1851 
1852  bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
1853 
1854  if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
1855 
1856  /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
1857  if (!Company::IsValidID(company)) return map;
1858 
1859  const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
1860 
1861  map += livery->colour1;
1862  if (twocc) map += livery->colour2 * 16;
1863 
1864  /* Update cache */
1865  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1866  return map;
1867 }
1868 
1876 {
1877  return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
1878 }
1879 
1886 {
1887  if (v->IsGroundVehicle()) {
1888  return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
1889  }
1890 
1891  return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
1892 }
1893 
1898 {
1899  if (this->IsGroundVehicle()) {
1900  uint16 &gv_flags = this->GetGroundVehicleFlags();
1901  if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
1902  /* Do not delete orders, only skip them */
1905  InvalidateVehicleOrder(this, 0);
1906  return;
1907  }
1908  }
1909 
1910  const Order *order = this->GetOrder(this->cur_implicit_order_index);
1911  while (order != NULL) {
1912  if (this->cur_implicit_order_index == this->cur_real_order_index) break;
1913 
1914  if (order->IsType(OT_IMPLICIT)) {
1916  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
1917  order = this->GetOrder(this->cur_implicit_order_index);
1918  } else {
1919  /* Skip non-implicit orders, e.g. service-orders */
1920  order = order->next;
1921  this->cur_implicit_order_index++;
1922  }
1923 
1924  /* Wrap around */
1925  if (order == NULL) {
1926  order = this->GetOrder(0);
1927  this->cur_implicit_order_index = 0;
1928  }
1929  }
1930 }
1931 
1937 {
1938  assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
1939 
1940  if (this->current_order.IsType(OT_GOTO_STATION) &&
1943 
1944  /* Now both order indices point to the destination station, and we can start loading */
1945  this->current_order.MakeLoading(true);
1946  UpdateVehicleTimetable(this, true);
1947 
1948  /* Furthermore add the Non Stop flag to mark that this station
1949  * is the actual destination of the vehicle, which is (for example)
1950  * necessary to be known for HandleTrainLoading to determine
1951  * whether the train is lost or not; not marking a train lost
1952  * that arrives at random stations is bad. */
1954 
1955  } else {
1956  /* We weren't scheduled to stop here. Insert an implicit order
1957  * to show that we are stopping here.
1958  * While only groundvehicles have implicit orders, e.g. aircraft might still enter
1959  * the 'wrong' terminal when skipping orders etc. */
1960  Order *in_list = this->GetOrder(this->cur_implicit_order_index);
1961  if (this->IsGroundVehicle() &&
1962  (in_list == NULL || !in_list->IsType(OT_IMPLICIT) ||
1963  in_list->GetDestination() != this->last_station_visited)) {
1964  bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
1965  /* Do not create consecutive duplicates of implicit orders */
1966  Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
1967  if (prev_order == NULL ||
1968  (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
1969  prev_order->GetDestination() != this->last_station_visited) {
1970 
1971  /* Prefer deleting implicit orders instead of inserting new ones,
1972  * so test whether the right order follows later. In case of only
1973  * implicit orders treat the last order in the list like an
1974  * explicit one, except if the overall number of orders surpasses
1975  * IMPLICIT_ORDER_ONLY_CAP. */
1976  int target_index = this->cur_implicit_order_index;
1977  bool found = false;
1978  while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
1979  const Order *order = this->GetOrder(target_index);
1980  if (order == NULL) break; // No orders.
1981  if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
1982  found = true;
1983  break;
1984  }
1985  target_index++;
1986  if (target_index >= this->orders.list->GetNumOrders()) {
1987  if (this->GetNumManualOrders() == 0 &&
1989  break;
1990  }
1991  target_index = 0;
1992  }
1993  if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
1994  }
1995 
1996  if (found) {
1997  if (suppress_implicit_orders) {
1998  /* Skip to the found order */
1999  this->cur_implicit_order_index = target_index;
2000  InvalidateVehicleOrder(this, 0);
2001  } else {
2002  /* Delete all implicit orders up to the station we just reached */
2003  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2004  while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2005  if (order->IsType(OT_IMPLICIT)) {
2007  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2008  order = this->GetOrder(this->cur_implicit_order_index);
2009  } else {
2010  /* Skip non-implicit orders, e.g. service-orders */
2011  order = order->next;
2012  this->cur_implicit_order_index++;
2013  }
2014 
2015  /* Wrap around */
2016  if (order == NULL) {
2017  order = this->GetOrder(0);
2018  this->cur_implicit_order_index = 0;
2019  }
2020  assert(order != NULL);
2021  }
2022  }
2023  } else if (!suppress_implicit_orders &&
2024  ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2026  /* Insert new implicit order */
2027  Order *implicit_order = new Order();
2028  implicit_order->MakeImplicit(this->last_station_visited);
2029  InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2030  if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2031 
2032  /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2033  * Reenable it for this vehicle */
2034  uint16 &gv_flags = this->GetGroundVehicleFlags();
2036  }
2037  }
2038  }
2039  this->current_order.MakeLoading(false);
2040  }
2041 
2042  if (this->last_loading_station != INVALID_STATION &&
2043  this->last_loading_station != this->last_station_visited &&
2044  ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2045  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2047  }
2048 
2049  PrepareUnload(this);
2050 
2055 
2056  Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2057  this->cur_speed = 0;
2058  this->MarkDirty();
2059 }
2060 
2066 void Vehicle::CancelReservation(StationID next, Station *st)
2067 {
2068  for (Vehicle *v = this; v != NULL; v = v->next) {
2070  if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2071  DEBUG(misc, 1, "cancelling cargo reservation");
2072  cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
2073  cargo.SetTransferLoadPlace(st->xy);
2074  }
2075  cargo.KeepAll();
2076  }
2077 }
2078 
2084 {
2085  assert(this->current_order.IsType(OT_LOADING));
2086 
2087  delete this->cargo_payment;
2088 
2089  /* Only update the timetable if the vehicle was supposed to stop here. */
2091 
2092  if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2093  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2094  if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
2095  /* Refresh next hop stats to make sure we've done that at least once
2096  * during the stop and that refit_cap == cargo_cap for each vehicle in
2097  * the consist. */
2098  this->ResetRefitCaps();
2099  LinkRefresher::Run(this);
2100 
2101  /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2103  } else {
2104  /* if the vehicle couldn't load and had to unload or transfer everything
2105  * set the last loading station to invalid as it will leave empty. */
2106  this->last_loading_station = INVALID_STATION;
2107  }
2108  }
2109 
2112  this->CancelReservation(INVALID_STATION, st);
2113  st->loading_vehicles.remove(this);
2114 
2116 
2117  if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2118  /* Trigger station animation (trains only) */
2119  if (IsTileType(this->tile, MP_STATION)) {
2121  TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2122  }
2123 
2124  SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2125  }
2126 
2127  this->MarkDirty();
2128 }
2129 
2134 {
2135  for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
2136 }
2137 
2143 void Vehicle::HandleLoading(bool mode)
2144 {
2145  switch (this->current_order.GetType()) {
2146  case OT_LOADING: {
2147  uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2148 
2149  /* Not the first call for this tick, or still loading */
2150  if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2151 
2152  this->PlayLeaveStationSound();
2153 
2154  this->LeaveStation();
2155 
2156  /* Only advance to next order if we just loaded at the current one */
2157  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2158  if (order == NULL ||
2159  (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2160  order->GetDestination() != this->last_station_visited) {
2161  return;
2162  }
2163  break;
2164  }
2165 
2166  case OT_DUMMY: break;
2167 
2168  default: return;
2169  }
2170 
2172 }
2173 
2179 {
2180  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2181  if (v->cargo_cap == 0) continue;
2182  SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2183  if (pair == capacities.End()) {
2184  pair = capacities.Append();
2185  pair->first = v->cargo_type;
2186  pair->second = v->cargo_cap - v->cargo.StoredCount();
2187  } else {
2188  pair->second += v->cargo_cap - v->cargo.StoredCount();
2189  }
2190  }
2191 }
2192 
2193 uint Vehicle::GetConsistTotalCapacity() const
2194 {
2195  uint result = 0;
2196  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2197  result += v->cargo_cap;
2198  }
2199  return result;
2200 }
2201 
2209 {
2210  CommandCost ret = CheckOwnership(this->owner);
2211  if (ret.Failed()) return ret;
2212 
2213  if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2214  if (this->IsStoppedInDepot()) return CMD_ERROR;
2215 
2216  if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2217  bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2218  if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2219  /* We called with a different DEPOT_SERVICE setting.
2220  * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2221  * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2222  if (flags & DC_EXEC) {
2226  }
2227  return CommandCost();
2228  }
2229 
2230  if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
2231  if (flags & DC_EXEC) {
2232  /* If the orders to 'goto depot' are in the orders list (forced servicing),
2233  * then skip to the next order; effectively cancelling this forced service */
2235 
2236  if (this->IsGroundVehicle()) {
2237  uint16 &gv_flags = this->GetGroundVehicleFlags();
2239  }
2240 
2241  this->current_order.MakeDummy();
2243  }
2244  return CommandCost();
2245  }
2246 
2247  TileIndex location;
2248  DestinationID destination;
2249  bool reverse;
2250  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};
2251  if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2252 
2253  if (flags & DC_EXEC) {
2254  if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2255 
2256  if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2257  uint16 &gv_flags = this->GetGroundVehicleFlags();
2259  }
2260 
2261  this->dest_tile = location;
2262  this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2263  if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2265 
2266  /* If there is no depot in front, reverse automatically (trains only) */
2267  if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2268 
2269  if (this->type == VEH_AIRCRAFT) {
2270  Aircraft *a = Aircraft::From(this);
2271  if (a->state == FLYING && a->targetairport != destination) {
2272  /* The aircraft is now heading for a different hangar than the next in the orders */
2275  }
2276  }
2277  }
2278 
2279  return CommandCost();
2280 
2281 }
2282 
2287 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2288 {
2289  bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2290  const Engine *e = this->GetEngine();
2291 
2292  /* Evaluate properties */
2293  byte visual_effect;
2294  switch (e->type) {
2295  case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2296  case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2297  case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2298  default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2299  }
2300 
2301  /* Check powered wagon / visual effect callback */
2303  uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2304 
2305  if (callback != CALLBACK_FAILED) {
2306  if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2307 
2308  callback = GB(callback, 0, 8);
2309  /* Avoid accidentally setting 'visual_effect' to the default value
2310  * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2311  if (callback == VE_DEFAULT) {
2312  assert(HasBit(callback, VE_DISABLE_EFFECT));
2313  SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2314  }
2315  visual_effect = callback;
2316  }
2317  }
2318 
2319  /* Apply default values */
2320  if (visual_effect == VE_DEFAULT ||
2321  (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2322  /* Only train engines have default effects.
2323  * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2324  if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2325  if (visual_effect == VE_DEFAULT) {
2326  visual_effect = 1 << VE_DISABLE_EFFECT;
2327  } else {
2328  SetBit(visual_effect, VE_DISABLE_EFFECT);
2329  }
2330  } else {
2331  if (visual_effect == VE_DEFAULT) {
2332  /* Also set the offset */
2333  visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2334  }
2335  SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2336  }
2337  }
2338 
2339  this->vcache.cached_vis_effect = visual_effect;
2340 
2341  if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2343  ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2344  }
2345 }
2346 
2347 static const int8 _vehicle_smoke_pos[8] = {
2348  1, 1, 1, 0, -1, -1, -1, 0
2349 };
2350 
2355 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2356 {
2357  uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2358  if (callback == CALLBACK_FAILED) return;
2359 
2360  uint count = GB(callback, 0, 2);
2361  bool auto_center = HasBit(callback, 13);
2362  bool auto_rotate = !HasBit(callback, 14);
2363 
2364  int8 l_center = 0;
2365  if (auto_center) {
2366  /* For road vehicles: Compute offset from vehicle position to vehicle center */
2367  if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2368  } else {
2369  /* For trains: Compute offset from vehicle position to sprite position */
2370  if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2371  }
2372 
2373  Direction l_dir = v->direction;
2374  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2375  Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2376 
2377  int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2378  int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2379 
2380  for (uint i = 0; i < count; i++) {
2381  uint32 reg = GetRegister(0x100 + i);
2382  uint type = GB(reg, 0, 8);
2383  int8 x = GB(reg, 8, 8);
2384  int8 y = GB(reg, 16, 8);
2385  int8 z = GB(reg, 24, 8);
2386 
2387  if (auto_rotate) {
2388  int8 l = x;
2389  int8 t = y;
2390  x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2391  y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2392  }
2393 
2394  if (type >= 0xF0) {
2395  switch (type) {
2396  case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2397  case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2398  case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2399  case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2400  default: break;
2401  }
2402  }
2403  }
2404 }
2405 
2411 {
2412  assert(this->IsPrimaryVehicle());
2413  bool sound = false;
2414 
2415  /* Do not show any smoke when:
2416  * - vehicle smoke is disabled by the player
2417  * - the vehicle is slowing down or stopped (by the player)
2418  * - the vehicle is moving very slowly
2419  */
2420  if (_settings_game.vehicle.smoke_amount == 0 ||
2421  this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2422  this->cur_speed < 2) {
2423  return;
2424  }
2425 
2426  /* Use the speed as limited by underground and orders. */
2427  uint max_speed = this->GetCurrentMaxSpeed();
2428 
2429  if (this->type == VEH_TRAIN) {
2430  const Train *t = Train::From(this);
2431  /* For trains, do not show any smoke when:
2432  * - the train is reversing
2433  * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2434  */
2435  if (HasBit(t->flags, VRF_REVERSING) ||
2437  t->cur_speed >= max_speed)) {
2438  return;
2439  }
2440  }
2441 
2442  const Vehicle *v = this;
2443 
2444  do {
2445  bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2447  VisualEffectSpawnModel effect_model = VESM_NONE;
2448  if (advanced) {
2449  effect_offset = VE_OFFSET_CENTRE;
2451  if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2452  } else {
2454  assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2455  assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2456  assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2457  assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2458  }
2459 
2460  /* Show no smoke when:
2461  * - Smoke has been disabled for this vehicle
2462  * - The vehicle is not visible
2463  * - The vehicle is under a bridge
2464  * - The vehicle is on a depot tile
2465  * - The vehicle is on a tunnel tile
2466  * - The vehicle is a train engine that is currently unpowered */
2467  if (effect_model == VESM_NONE ||
2468  v->vehstatus & VS_HIDDEN ||
2469  IsBridgeAbove(v->tile) ||
2470  IsDepotTile(v->tile) ||
2471  IsTunnelTile(v->tile) ||
2472  (v->type == VEH_TRAIN &&
2473  !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2474  continue;
2475  }
2476 
2477  EffectVehicleType evt = EV_END;
2478  switch (effect_model) {
2479  case VESM_STEAM:
2480  /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2481  * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2482  * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2483  * REGULATION:
2484  * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2485  if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2486  evt = EV_STEAM_SMOKE;
2487  }
2488  break;
2489 
2490  case VESM_DIESEL: {
2491  /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2492  * when smoke emission stops.
2493  * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2494  * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2495  * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2496  * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2497  * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2498  * maximum speed no diesel_smoke is emitted.
2499  * REGULATION:
2500  * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2501  * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2502  int power_weight_effect = 0;
2503  if (v->type == VEH_TRAIN) {
2504  power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2505  }
2506  if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2507  Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2508  evt = EV_DIESEL_SMOKE;
2509  }
2510  break;
2511  }
2512 
2513  case VESM_ELECTRIC:
2514  /* Electric train's spark - more often occurs when train is departing (more load)
2515  * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2516  * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2517  * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2518  * REGULATION:
2519  * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2520  if (GB(v->tick_counter, 0, 2) == 0 &&
2521  Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2522  evt = EV_ELECTRIC_SPARK;
2523  }
2524  break;
2525 
2526  default:
2527  NOT_REACHED();
2528  }
2529 
2530  if (evt != EV_END && advanced) {
2531  sound = true;
2533  } else if (evt != EV_END) {
2534  sound = true;
2535 
2536  /* The effect offset is relative to a point 4 units behind the vehicle's
2537  * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2538  * correction factor. */
2539  if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2540 
2541  int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2542  int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2543 
2544  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2545  x = -x;
2546  y = -y;
2547  }
2548 
2549  CreateEffectVehicleRel(v, x, y, 10, evt);
2550  }
2551  } while ((v = v->Next()) != NULL);
2552 
2553  if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2554 }
2555 
2561 {
2562  assert(this != next);
2563 
2564  if (this->next != NULL) {
2565  /* We had an old next vehicle. Update the first and previous pointers */
2566  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2567  v->first = this->next;
2568  }
2569  this->next->previous = NULL;
2570  }
2571 
2572  this->next = next;
2573 
2574  if (this->next != NULL) {
2575  /* A new next vehicle. Update the first and previous pointers */
2576  if (this->next->previous != NULL) this->next->previous->next = NULL;
2577  this->next->previous = this;
2578  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2579  v->first = this->first;
2580  }
2581  }
2582 }
2583 
2589 void Vehicle::AddToShared(Vehicle *shared_chain)
2590 {
2591  assert(this->previous_shared == NULL && this->next_shared == NULL);
2592 
2593  if (shared_chain->orders.list == NULL) {
2594  assert(shared_chain->previous_shared == NULL);
2595  assert(shared_chain->next_shared == NULL);
2596  this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
2597  }
2598 
2599  this->next_shared = shared_chain->next_shared;
2600  this->previous_shared = shared_chain;
2601 
2602  shared_chain->next_shared = this;
2603 
2604  if (this->next_shared != NULL) this->next_shared->previous_shared = this;
2605 
2606  shared_chain->orders.list->AddVehicle(this);
2607 }
2608 
2613 {
2614  /* Remember if we were first and the old window number before RemoveVehicle()
2615  * as this changes first if needed. */
2616  bool were_first = (this->FirstShared() == this);
2617  VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2618 
2619  this->orders.list->RemoveVehicle(this);
2620 
2621  if (!were_first) {
2622  /* We are not the first shared one, so only relink our previous one. */
2623  this->previous_shared->next_shared = this->NextShared();
2624  }
2625 
2626  if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
2627 
2628 
2629  if (this->orders.list->GetNumVehicles() == 1) {
2630  /* When there is only one vehicle, remove the shared order list window. */
2632  InvalidateVehicleOrder(this->FirstShared(), 0);
2633  } else if (were_first) {
2634  /* If we were the first one, update to the new first one.
2635  * Note: FirstShared() is already the new first */
2636  InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2637  }
2638 
2639  this->next_shared = NULL;
2640  this->previous_shared = NULL;
2641 }
2642 
2643 void VehiclesYearlyLoop()
2644 {
2645  Vehicle *v;
2646  FOR_ALL_VEHICLES(v) {
2647  if (v->IsPrimaryVehicle()) {
2648  /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2649  Money profit = v->GetDisplayProfitThisYear();
2650  if (v->age >= 730 && profit < 0) {
2652  SetDParam(0, v->index);
2653  SetDParam(1, profit);
2654  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2655  }
2656  AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2657  }
2658 
2660  v->profit_this_year = 0;
2662  }
2663  }
2669 }
2670 
2671 
2681 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2682 {
2683  const Engine *e = Engine::GetIfValid(engine_type);
2684  assert(e != NULL);
2685 
2686  switch (e->type) {
2687  case VEH_TRAIN:
2688  return (st->facilities & FACIL_TRAIN) != 0;
2689 
2690  case VEH_ROAD:
2691  /* For road vehicles we need the vehicle to know whether it can actually
2692  * use the station, but if it doesn't have facilities for RVs it is
2693  * certainly not possible that the station can be used. */
2694  return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2695 
2696  case VEH_SHIP:
2697  return (st->facilities & FACIL_DOCK) != 0;
2698 
2699  case VEH_AIRCRAFT:
2700  return (st->facilities & FACIL_AIRPORT) != 0 &&
2702 
2703  default:
2704  return false;
2705  }
2706 }
2707 
2714 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2715 {
2716  if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
2717 
2718  return CanVehicleUseStation(v->engine_type, st);
2719 }
2720 
2727 {
2728  assert(this->IsGroundVehicle());
2729  if (this->type == VEH_TRAIN) {
2730  return &Train::From(this)->gcache;
2731  } else {
2732  return &RoadVehicle::From(this)->gcache;
2733  }
2734 }
2735 
2742 {
2743  assert(this->IsGroundVehicle());
2744  if (this->type == VEH_TRAIN) {
2745  return &Train::From(this)->gcache;
2746  } else {
2747  return &RoadVehicle::From(this)->gcache;
2748  }
2749 }
2750 
2757 {
2758  assert(this->IsGroundVehicle());
2759  if (this->type == VEH_TRAIN) {
2760  return Train::From(this)->gv_flags;
2761  } else {
2762  return RoadVehicle::From(this)->gv_flags;
2763  }
2764 }
2765 
2771 const uint16 &Vehicle::GetGroundVehicleFlags() const
2772 {
2773  assert(this->IsGroundVehicle());
2774  if (this->type == VEH_TRAIN) {
2775  return Train::From(this)->gv_flags;
2776  } else {
2777  return RoadVehicle::From(this)->gv_flags;
2778  }
2779 }
2780 
2789 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2790 {
2791  if (v->type == VEH_TRAIN) {
2792  Train *u = Train::From(v);
2793  /* Only include whole vehicles, so start with the first articulated part */
2794  u = u->GetFirstEnginePart();
2795 
2796  /* Include num_vehicles vehicles, not counting articulated parts */
2797  for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2798  do {
2799  /* Include current vehicle in the selection. */
2800  set.Include(u->index);
2801 
2802  /* If the vehicle is multiheaded, add the other part too. */
2803  if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
2804 
2805  u = u->Next();
2806  } while (u != NULL && u->IsArticulatedPart());
2807  }
2808  }
2809 }